From d40232638faaab19de557e70a3ee938da7a35295 Mon Sep 17 00:00:00 2001 From: Dave Wilson Date: Wed, 29 Apr 2015 09:48:49 -0700 Subject: samples update for //build --- README.md | 20 +- avstream/avshws/ReadMe.md | 10 - avstream/avshws/avshws.h | 232 - avstream/avshws/avshws.htm | 458 - avstream/avshws/avshws.inf | 172 - avstream/avshws/avshws.rc | 22 - avstream/avshws/avshws.sln | 28 - avstream/avshws/avshws.vcxproj | 201 - avstream/avshws/avshws.vcxproj.Filters | 46 - avstream/avshws/capture.cpp | 1704 ---- avstream/avshws/capture.h | 313 - avstream/avshws/device.cpp | 875 -- avstream/avshws/device.h | 294 - avstream/avshws/filter.cpp | 203 - avstream/avshws/filter.h | 88 - avstream/avshws/hwsim.cpp | 868 -- avstream/avshws/hwsim.h | 290 - avstream/avshws/image.cpp | 605 -- avstream/avshws/image.h | 478 - avstream/avshws/purecall.c | 50 - avstream/samplemft0/SampleMft0.sln | 18 +- avstream/samplemft0/SampleMft0.vcxproj | 4 +- avstream/samplemft0/SampleMft0.vcxproj.Filters | 6 +- bluetooth/bthecho/ReadMe.md | 235 + bluetooth/bthecho/bthcli/app/BthEcho.vcxproj | 191 + .../bthecho/bthcli/app/BthEcho.vcxproj.Filters | 22 + bluetooth/bthecho/bthcli/app/main.cpp | 182 + bluetooth/bthecho/bthcli/sys/BthEchoSampleCli.inx | 101 + .../bthecho/bthcli/sys/BthEchoSampleCli.vcxproj | 201 + .../bthcli/sys/BthEchoSampleCli.vcxproj.Filters | 43 + bluetooth/bthecho/bthcli/sys/client.c | 1207 +++ bluetooth/bthecho/bthcli/sys/client.h | 58 + bluetooth/bthecho/bthcli/sys/device.c | 458 + bluetooth/bthecho/bthcli/sys/device.h | 91 + bluetooth/bthecho/bthcli/sys/driver.c | 210 + bluetooth/bthecho/bthcli/sys/driver.h | 34 + bluetooth/bthecho/bthcli/sys/queue.c | 349 + bluetooth/bthecho/bthcli/sys/queue.h | 31 + bluetooth/bthecho/bthecho.htm | 2222 +++++ bluetooth/bthecho/bthecho.sln | 102 + bluetooth/bthecho/bthsrv/inst/bthsrvinst.vcxproj | 191 + .../bthecho/bthsrv/inst/bthsrvinst.vcxproj.Filters | 22 + bluetooth/bthecho/bthsrv/inst/main.cpp | 210 + bluetooth/bthecho/bthsrv/sys/BthEchoSampleSrv.inx | 102 + .../bthecho/bthsrv/sys/BthEchoSampleSrv.vcxproj | 201 + .../bthsrv/sys/BthEchoSampleSrv.vcxproj.Filters | 46 + bluetooth/bthecho/bthsrv/sys/device.c | 422 + bluetooth/bthecho/bthsrv/sys/device.h | 116 + bluetooth/bthecho/bthsrv/sys/driver.c | 211 + bluetooth/bthecho/bthsrv/sys/driver.h | 34 + bluetooth/bthecho/bthsrv/sys/echo.c | 227 + bluetooth/bthecho/bthsrv/sys/echo.h | 37 + bluetooth/bthecho/bthsrv/sys/sdp.c | 582 ++ bluetooth/bthecho/bthsrv/sys/sdp.h | 40 + bluetooth/bthecho/bthsrv/sys/server.c | 1463 ++++ bluetooth/bthecho/bthsrv/sys/server.h | 89 + bluetooth/bthecho/common/inc/clisrv.h | 137 + bluetooth/bthecho/common/inc/connection.h | 217 + bluetooth/bthecho/common/inc/public.h | 38 + bluetooth/bthecho/common/inc/trace.h | 117 + bluetooth/bthecho/common/lib/bthecho.vcxproj | 202 + .../bthecho/common/lib/bthecho.vcxproj.Filters | 29 + bluetooth/bthecho/common/lib/clisrv.c | 435 + bluetooth/bthecho/common/lib/connection.c | 1343 +++ .../serialhcibus/BluetoothHCISampleBusDriver.htm | 2333 +++++ bluetooth/serialhcibus/WDK/SerialBusWdk.vcxproj | 4 +- .../serialhcibus/WDK/SerialBusWdk.vcxproj.Filters | 8 +- bluetooth/serialhcibus/serialhcibus.sln | 18 +- filesys/cdfs/cddata.c | 17 +- filesys/cdfs/cdfs.sln | 18 +- filesys/cdfs/cdfs.vcxproj | 4 +- filesys/cdfs/cdfs.vcxproj.Filters | 8 +- filesys/cdfs/cdprocs.h | 28 +- filesys/cdfs/deviosup.c | 9 +- .../miniFilter/MetadataManager/MetadataManager.sln | 18 +- filesys/miniFilter/MetadataManager/fmm.vcxproj | 4 +- .../miniFilter/MetadataManager/fmm.vcxproj.Filters | 8 +- filesys/miniFilter/NameChanger/NameChanger.inf | 105 + filesys/miniFilter/NameChanger/NameChanger.sln | 28 + filesys/miniFilter/NameChanger/NameChanger.vcxproj | 205 + .../NameChanger/NameChanger.vcxproj.Filters | 70 + filesys/miniFilter/NameChanger/ReadMe.md | 116 + filesys/miniFilter/NameChanger/nc.c | 2017 +++++ filesys/miniFilter/NameChanger/nc.h | 1040 +++ filesys/miniFilter/NameChanger/nc.rc | 10 + filesys/miniFilter/NameChanger/nccompat.c | 468 + filesys/miniFilter/NameChanger/nccontext.c | 304 + filesys/miniFilter/NameChanger/nccreate.c | 451 + filesys/miniFilter/NameChanger/ncdirenum.c | 1420 +++ filesys/miniFilter/NameChanger/ncdirnotify.c | 3526 ++++++++ filesys/miniFilter/NameChanger/ncfileinfo.c | 1971 +++++ filesys/miniFilter/NameChanger/ncfsctrl.c | 3634 ++++++++ filesys/miniFilter/NameChanger/nchelper.c | 365 + filesys/miniFilter/NameChanger/ncinit.c | 491 ++ filesys/miniFilter/NameChanger/ncmapping.c | 796 ++ filesys/miniFilter/NameChanger/ncnameprov.c | 576 ++ filesys/miniFilter/NameChanger/ncoffsets.c | 632 ++ filesys/miniFilter/NameChanger/ncpath.c | 674 ++ filesys/miniFilter/avscan/avscan.sln | 44 +- filesys/miniFilter/avscan/filter/avscan.vcxproj | 4 +- .../avscan/filter/avscan.vcxproj.Filters | 8 +- filesys/miniFilter/avscan/user/avscan.vcxproj | 4 +- .../miniFilter/avscan/user/avscan.vcxproj.Filters | 6 +- filesys/miniFilter/cancelSafe/cancelSafe.c | 14 + filesys/miniFilter/cancelSafe/cancelSafe.sln | 18 +- filesys/miniFilter/cancelSafe/cancelSafe.vcxproj | 4 +- .../cancelSafe/cancelSafe.vcxproj.Filters | 8 +- filesys/miniFilter/cdo/cdo.sln | 18 +- filesys/miniFilter/cdo/cdo.vcxproj | 4 +- filesys/miniFilter/cdo/cdo.vcxproj.Filters | 8 +- filesys/miniFilter/change/change.sln | 18 +- filesys/miniFilter/change/change.vcxproj | 4 +- filesys/miniFilter/change/change.vcxproj.Filters | 8 +- filesys/miniFilter/ctx/ctx.sln | 18 +- filesys/miniFilter/ctx/ctx.vcxproj | 4 +- filesys/miniFilter/ctx/ctx.vcxproj.Filters | 8 +- filesys/miniFilter/delete/delete.sln | 18 +- filesys/miniFilter/delete/delete.vcxproj | 4 +- filesys/miniFilter/delete/delete.vcxproj.Filters | 8 +- filesys/miniFilter/minispy/filter/minispy.vcxproj | 4 +- .../minispy/filter/minispy.vcxproj.Filters | 8 +- filesys/miniFilter/minispy/minispy.sln | 44 +- filesys/miniFilter/minispy/user/minispy.vcxproj | 4 +- .../minispy/user/minispy.vcxproj.Filters | 6 +- filesys/miniFilter/nullFilter/nullFilter.sln | 18 +- filesys/miniFilter/nullFilter/nullFilter.vcxproj | 4 +- .../nullFilter/nullFilter.vcxproj.Filters | 8 +- filesys/miniFilter/passThrough/passThrough.sln | 18 +- filesys/miniFilter/passThrough/passThrough.vcxproj | 4 +- .../passThrough/passThrough.vcxproj.Filters | 8 +- filesys/miniFilter/scanner/filter/scanner.vcxproj | 4 +- .../scanner/filter/scanner.vcxproj.Filters | 8 +- filesys/miniFilter/scanner/scanner.sln | 44 +- filesys/miniFilter/scanner/user/scanuser.vcxproj | 4 +- .../scanner/user/scanuser.vcxproj.Filters | 6 +- filesys/miniFilter/simrep/simrep.sln | 18 +- filesys/miniFilter/simrep/simrep.vcxproj | 4 +- filesys/miniFilter/simrep/simrep.vcxproj.Filters | 8 +- filesys/miniFilter/swapBuffers/swapBuffers.c | 3 +- filesys/miniFilter/swapBuffers/swapBuffers.sln | 18 +- filesys/miniFilter/swapBuffers/swapBuffers.vcxproj | 4 +- .../swapBuffers/swapBuffers.vcxproj.Filters | 8 +- general/PLX9x5x/PLX9x5x.sln | 44 +- general/PLX9x5x/sys/Pci9x5x.vcxproj | 4 +- general/PLX9x5x/sys/Pci9x5x.vcxproj.Filters | 8 +- general/PLX9x5x/sys/pci9x5x.inx | 7 - general/PLX9x5x/test/plx.vcxproj | 4 +- general/PLX9x5x/test/plx.vcxproj.Filters | 6 +- general/SystemDma/wdm/SystemDma.sln | 44 +- general/SystemDma/wdm/exe/SystemDmaApp.vcxproj | 4 +- .../SystemDma/wdm/exe/SystemDmaApp.vcxproj.Filters | 6 +- general/SystemDma/wdm/sys/SDma.vcxproj | 4 +- general/SystemDma/wdm/sys/SDma.vcxproj.Filters | 8 +- general/SystemDma/wdm/systemdma.htm | 741 ++ general/cancel/cancel.htm | 302 + general/cancel/cancel.sln | 66 +- general/cancel/exe/canclapp.vcxproj | 4 +- general/cancel/exe/canclapp.vcxproj.Filters | 6 +- general/cancel/startio/cancel.vcxproj | 4 +- general/cancel/startio/cancel.vcxproj.Filters | 8 +- general/cancel/sys/cancel.vcxproj | 4 +- general/cancel/sys/cancel.vcxproj.Filters | 8 +- general/echo/kmdf/ReadMe.md | 3 + general/echo/kmdf/driver/AutoSync/device.c | 5 +- general/echo/kmdf/driver/AutoSync/echo.vcxproj | 4 +- .../echo/kmdf/driver/AutoSync/echo.vcxproj.Filters | 8 +- general/echo/kmdf/driver/AutoSync/queue.c | 8 +- general/echo/kmdf/driver/DriverSync/device.c | 6 +- general/echo/kmdf/driver/DriverSync/echo_2.vcxproj | 4 +- .../kmdf/driver/DriverSync/echo_2.vcxproj.Filters | 8 +- general/echo/kmdf/driver/DriverSync/queue.c | 8 +- general/echo/kmdf/exe/echoapp.cpp | 176 +- general/echo/kmdf/exe/echoapp.vcxproj | 56 +- general/echo/kmdf/exe/echoapp.vcxproj.Filters | 6 +- general/echo/kmdf/kmdfecho.sln | 72 +- general/echo/umdf/WUDFEchoDriver.inx | 2 +- general/echo/umdf/WUDFEchoDriver.vcxproj | 4 +- general/echo/umdf/WUDFEchoDriver.vcxproj.Filters | 8 +- general/echo/umdf/echo.sln | 18 +- general/echo/umdf2/ReadMe.md | 3 + general/echo/umdf2/driver/AutoSync/echo.vcxproj | 4 +- .../umdf2/driver/AutoSync/echo.vcxproj.Filters | 8 +- general/echo/umdf2/driver/AutoSync/echoum.inx | 2 +- general/echo/umdf2/exe/echoapp.cpp | 176 +- general/echo/umdf2/exe/echoapp.vcxproj | 56 +- general/echo/umdf2/exe/echoapp.vcxproj.Filters | 6 +- general/echo/umdf2/umdf2echo.sln | 48 +- .../echo/umdfSocketEcho/Driver/SocketEcho.vcxproj | 4 +- .../Driver/SocketEcho.vcxproj.Filters | 8 +- .../umdfSocketEcho/Exe/socketechoserver.vcxproj | 4 +- .../Exe/socketechoserver.vcxproj.Filters | 6 +- general/echo/umdfSocketEcho/umdfsocketecho.sln | 44 +- general/event/event.htm | 229 + general/event/eventsample.sln | 44 +- general/event/exe/event.vcxproj | 4 +- general/event/exe/event.vcxproj.Filters | 6 +- general/event/wdm/event.vcxproj | 4 +- general/event/wdm/event.vcxproj.Filters | 8 +- general/filehistory/exe/fhsetup.vcxproj | 4 +- general/filehistory/exe/fhsetup.vcxproj.Filters | 6 +- general/filehistory/filehistory.sln | 18 +- general/installwdf/InstallWdf.vcxproj | 4 +- general/installwdf/InstallWdf.vcxproj.Filters | 6 +- general/installwdf/installwdf.sln | 18 +- general/ioctl/wdm/exe/ioctlapp.vcxproj | 4 +- general/ioctl/wdm/exe/ioctlapp.vcxproj.Filters | 6 +- general/ioctl/wdm/ioctl.htm | 742 ++ general/ioctl/wdm/ioctl.sln | 44 +- general/ioctl/wdm/sys/sioctl.vcxproj | 4 +- general/ioctl/wdm/sys/sioctl.vcxproj.Filters | 8 +- .../obcallback/control/ObCallbackTestCtrl.vcxproj | 4 +- .../control/ObCallbackTestCtrl.vcxproj.Filters | 6 +- general/obcallback/driver/ObCallbackTest.vcxproj | 4 +- .../driver/ObCallbackTest.vcxproj.Filters | 8 +- general/obcallback/obcallback.sln | 44 +- general/pcidrv/kmdf/HW/PCIDRV.vcxproj | 4 +- general/pcidrv/kmdf/HW/PCIDRV.vcxproj.Filters | 8 +- general/pcidrv/kmdf/genpci.inx | 9 - general/pcidrv/pcidrv.sln | 48 +- general/pcidrv/test/myping.vcxproj | 4 +- general/pcidrv/test/myping.vcxproj.Filters | 6 +- general/perfcounters/kcs/kcs.htm | 757 ++ general/perfcounters/kcs/kcs.sln | 18 +- general/perfcounters/kcs/kcs.vcxproj | 4 +- general/perfcounters/kcs/kcs.vcxproj.Filters | 8 +- general/registry/regfltr/exe/regctrl.vcxproj | 4 +- .../registry/regfltr/exe/regctrl.vcxproj.Filters | 6 +- general/registry/regfltr/regfltr.sln | 44 +- general/registry/regfltr/sys/regfltr.vcxproj | 4 +- .../registry/regfltr/sys/regfltr.vcxproj.Filters | 8 +- general/toaster/toastpkg/toastapp/toastapp.vcxproj | 4 +- .../toastpkg/toastapp/toastapp.vcxproj.Filters | 6 +- general/toaster/toastpkg/toastcd/tostx86.cat | Bin 10350 -> 7892 bytes general/toaster/toastpkg/toastcd/tstamd64.cat | Bin 10252 -> 7794 bytes general/toaster/toastpkg/toastco/tostrco2.vcxproj | 4 +- .../toastpkg/toastco/tostrco2.vcxproj.Filters | 6 +- general/toaster/toastpkg/toastpkg.htm | 186 + general/toaster/toastpkg/toastpkg.sln | 68 +- general/toaster/toastpkg/toastva/toastva.vcxproj | 4 +- .../toastpkg/toastva/toastva.vcxproj.Filters | 6 +- general/toaster/umdf2/Package/package.VcxProj | 91 - .../toaster/umdf2/Package/package.VcxProj.Filters | 21 - general/toaster/umdf2/ReadMe.md | 58 - general/toaster/umdf2/exe/enum/Enum.vcxproj | 171 - .../toaster/umdf2/exe/enum/Enum.vcxproj.Filters | 22 - general/toaster/umdf2/exe/enum/enum.c | 317 - general/toaster/umdf2/exe/notify/notify.c | 1244 --- general/toaster/umdf2/exe/notify/notify.h | 182 - general/toaster/umdf2/exe/notify/notify.rc | 77 - general/toaster/umdf2/exe/notify/notify.vcxproj | 172 - .../umdf2/exe/notify/notify.vcxproj.Filters | 27 - general/toaster/umdf2/exe/notify/toaster.ico | Bin 4534 -> 0 bytes general/toaster/umdf2/exe/toast/toast.c | 343 - general/toaster/umdf2/exe/toast/toast.vcxproj | 171 - .../toaster/umdf2/exe/toast/toast.vcxproj.Filters | 22 - general/toaster/umdf2/filter/generic/filter.c | 387 - general/toaster/umdf2/filter/generic/filter.h | 85 - general/toaster/umdf2/filter/generic/filter.rc | 12 - general/toaster/umdf2/filter/generic/filterum.inx | 98 - .../toaster/umdf2/filter/generic/filterum.vcxproj | 188 - .../umdf2/filter/generic/filterum.vcxproj.Filters | 34 - general/toaster/umdf2/func/featured/power.c | 385 - general/toaster/umdf2/func/featured/toaster.c | 862 -- general/toaster/umdf2/func/featured/toaster.rc | 12 - .../toaster/umdf2/func/featured/wdffeaturedum.inx | 98 - .../umdf2/func/featured/wdffeaturedum.vcxproj | 180 - .../func/featured/wdffeaturedum.vcxproj.Filters | 42 - general/toaster/umdf2/func/shared/toaster.h | 118 - general/toaster/umdf2/func/simple/toaster.c | 418 - general/toaster/umdf2/func/simple/wdfsimpleum.inx | 97 - .../toaster/umdf2/func/simple/wdfsimpleum.vcxproj | 180 - .../umdf2/func/simple/wdfsimpleum.vcxproj.Filters | 34 - general/toaster/umdf2/inc/driver.h | 69 - general/toaster/umdf2/inc/public.h | 167 - general/toaster/umdf2/umdf2toaster.sln | 123 - .../SystemTraceControl/SystemTraceControl.sln | 18 +- .../SystemTraceControl/SystemTraceControl.vcxproj | 4 +- .../SystemTraceControl.vcxproj.Filters | 6 +- general/tracing/evntdrv/Eventdrv/Eventdrv.vcxproj | 4 +- .../evntdrv/Eventdrv/Eventdrv.vcxproj.Filters | 8 +- general/tracing/evntdrv/eventdrv.sln | 44 +- general/tracing/evntdrv/evntctrl/evntctrl.vcxproj | 4 +- .../evntdrv/evntctrl/evntctrl.vcxproj.Filters | 6 +- general/tracing/evntdrv/evntdrv.htm | 189 + .../tracing/tracedriver/tracectl/tracectl.vcxproj | 4 +- .../tracedriver/tracectl/tracectl.vcxproj.Filters | 6 +- general/tracing/tracedriver/tracedrv.htm | 1052 +++ general/tracing/tracedriver/tracedrv.sln | 44 +- .../tracing/tracedriver/tracedrv/tracedrv.vcxproj | 4 +- .../tracedriver/tracedrv/tracedrv.vcxproj.Filters | 8 +- general/umdfSkeleton/UMDFSkeleton.vcxproj | 4 +- general/umdfSkeleton/UMDFSkeleton.vcxproj.Filters | 8 +- general/umdfSkeleton/UMDFSkeleton_OSR.inx | 3 +- general/umdfSkeleton/umdfSkeleton.sln | 18 +- gpio/samples/sim.sln | 88 +- gpio/samples/simdevice/simdevice.vcxproj | 4 +- gpio/samples/simdevice/simdevice.vcxproj.Filters | 8 +- gpio/samples/simdeviceumdf/SimdeviceUMDF.vcxproj | 4 +- .../simdeviceumdf/SimdeviceUMDF.vcxproj.Filters | 8 +- gpio/samples/simgpio/simgpio.vcxproj | 4 +- gpio/samples/simgpio/simgpio.vcxproj.Filters | 8 +- gpio/samples/simgpio_i2c/simgpio_i2c.vcxproj | 4 +- .../simgpio_i2c/simgpio_i2c.vcxproj.Filters | 8 +- hid/hclient/ReadMe.md | 22 + hid/hclient/buffers.c | 424 + hid/hclient/buffers.h | 108 + hid/hclient/ecdisp.c | 4347 ++++++++++ hid/hclient/ecdisp.h | 88 + hid/hclient/hclient.c | 3858 +++++++++ hid/hclient/hclient.h | 153 + hid/hclient/hclient.htm | 775 ++ hid/hclient/hclient.mk | 39 + hid/hclient/hclient.rc | 370 + hid/hclient/hclient.sln | 28 + hid/hclient/hclient.vcxproj | 185 + hid/hclient/hclient.vcxproj.Filters | 42 + hid/hclient/hid.h | 206 + hid/hclient/list.h | 282 + hid/hclient/pnp.c | 993 +++ hid/hclient/report.c | 600 ++ hid/hclient/resource.h | 137 + hid/hclient/strings.c | 411 + hid/hclient/strings.h | 49 + hid/vhidmini2/ReadMe.md | 22 + hid/vhidmini2/app/testvhid.c | 792 ++ hid/vhidmini2/app/testvhid.rc | 12 + hid/vhidmini2/app/testvhid.vcxproj | 188 + hid/vhidmini2/app/testvhid.vcxproj.Filters | 27 + hid/vhidmini2/driver/kmdf/util.c | 84 + hid/vhidmini2/driver/kmdf/vhidmini.inx | 96 + hid/vhidmini2/driver/kmdf/vhidmini.rc | 16 + hid/vhidmini2/driver/kmdf/vhidmini.vcxproj | 180 + hid/vhidmini2/driver/kmdf/vhidmini.vcxproj.Filters | 42 + hid/vhidmini2/driver/umdf2/VhidminiUm.inx | 101 + hid/vhidmini2/driver/umdf2/VhidminiUm.vcxproj | 208 + .../driver/umdf2/VhidminiUm.vcxproj.Filters | 42 + hid/vhidmini2/driver/umdf2/util.c | 149 + hid/vhidmini2/driver/umdf2/vhidmini.rc | 16 + hid/vhidmini2/driver/vhidmini.c | 1493 ++++ hid/vhidmini2/driver/vhidmini.h | 180 + hid/vhidmini2/inc/common.h | 120 + hid/vhidmini2/vhidmini2.sln | 63 + network/config/bindview/bindview.sln | 18 +- network/config/bindview/bindview.vcxproj | 4 +- network/config/bindview/bindview.vcxproj.Filters | 6 +- network/modem/fakemodem/fakemodem.htm | 926 ++ network/modem/fakemodem/fakemodem.sln | 18 +- network/modem/fakemodem/fakemodem.vcxproj | 4 +- network/modem/fakemodem/fakemodem.vcxproj.Filters | 8 +- network/ndis/extension/base/sxbase.vcxproj | 4 +- network/ndis/extension/base/sxbase.vcxproj.Filters | 8 +- network/ndis/extension/extensions.sln | 52 +- .../extension/samples/forward/msforwardext.vcxproj | 4 +- .../samples/forward/msforwardext.vcxproj.Filters | 8 +- .../samples/passthrough/mspassthroughext.vcxproj | 4 +- .../passthrough/mspassthroughext.vcxproj.Filters | 8 +- network/ndis/filter/filter.htm | 152 + network/ndis/filter/filter.sln | 18 +- network/ndis/filter/ndislwf.vcxproj | 4 +- network/ndis/filter/ndislwf.vcxproj.Filters | 8 +- network/ndis/mux/driver/60/novlan/mux.vcxproj | 4 +- .../ndis/mux/driver/60/novlan/mux.vcxproj.Filters | 8 +- network/ndis/mux/driver/60/vlan/muxvlan.vcxproj | 4 +- .../mux/driver/60/vlan/muxvlan.vcxproj.Filters | 8 +- network/ndis/mux/mux.sln | 76 +- network/ndis/mux/notifyob/mux.vcxproj | 4 +- network/ndis/mux/notifyob/mux.vcxproj.Filters | 6 +- network/ndis/ndisprot/6x/ndisprot.htm | 393 + network/ndis/ndisprot/6x/ndisprot60.sln | 72 +- network/ndis/ndisprot/6x/sys/60/ndisprot60.vcxproj | 4 +- .../ndisprot/6x/sys/60/ndisprot60.vcxproj.Filters | 8 +- .../ndis/ndisprot/6x/sys/630/ndisprot630.vcxproj | 4 +- .../6x/sys/630/ndisprot630.vcxproj.Filters | 8 +- network/ndis/ndisprot/6x/test/prottest.vcxproj | 4 +- .../ndis/ndisprot/6x/test/prottest.vcxproj.Filters | 6 +- network/ndis/netvmini/6x/60/netvmini60.vcxproj | 4 +- .../ndis/netvmini/6x/60/netvmini60.vcxproj.Filters | 8 +- network/ndis/netvmini/6x/620/netvmini620.vcxproj | 4 +- .../netvmini/6x/620/netvmini620.vcxproj.Filters | 8 +- network/ndis/netvmini/6x/630/netvmini630.vcxproj | 4 +- .../netvmini/6x/630/netvmini630.vcxproj.Filters | 8 +- network/ndis/netvmini/6x/netvmini.sln | 66 +- .../HidSwitchDriverSample.sln | 28 + ...EADFIRST_InstructionsForDevelopingHIDDriver.htm | 944 ++ network/radio/HidSwitchDriverSample/README.htm | 1437 +++ .../HidSwitchDriverSample/RadioSwitchHidUsbFx2.h | 156 + .../HidSwitchDriverSample/RadioSwitchHidUsbFx2.inx | 114 + .../HidSwitchDriverSample/RadioSwitchHidUsbFx2.rc | 11 + .../RadioSwitchHidUsbFx2.vcxproj | 182 + .../RadioSwitchHidUsbFx2.vcxproj.Filters | 45 + network/radio/HidSwitchDriverSample/ReadMe.md | 74 + network/radio/HidSwitchDriverSample/driver.c | 156 + network/radio/HidSwitchDriverSample/hid.c | 659 ++ network/radio/HidSwitchDriverSample/trace.h | 13 + network/radio/HidSwitchDriverSample/usb.c | 466 + .../RadioManagerSample/RadioManagerSample.sln | 28 + network/radio/RadioManagerSample/ReadMe.md | 171 + network/radio/RadioManagerSample/SampleRM.reg | Bin 0 -> 1982 bytes .../RadioManagerSample/cpp/InternalInterfaces.h | 23 + network/radio/RadioManagerSample/cpp/RadioMgr.idl | 155 + .../RadioManagerSample/cpp/RadioMgr_interface.cpp | 3 + .../cpp/SampleInstanceCollection.cpp | 102 + .../cpp/SampleInstanceCollection.h | 32 + network/radio/RadioManagerSample/cpp/SampleRM.def | 8 + network/radio/RadioManagerSample/cpp/SampleRM.rc | 10 + .../radio/RadioManagerSample/cpp/SampleRM.vcxproj | 326 + .../cpp/SampleRM.vcxproj.Filters | 45 + .../RadioManagerSample/cpp/SampleRadioInstance.cpp | 523 ++ .../RadioManagerSample/cpp/SampleRadioInstance.h | 71 + .../RadioManagerSample/cpp/SampleRadioManager.cpp | 570 ++ .../RadioManagerSample/cpp/SampleRadioManager.h | 79 + network/radio/RadioManagerSample/cpp/dllmain.cpp | 57 + network/radio/RadioManagerSample/cpp/precomp.h | 17 + .../radio/RadioManagerSample/cpp/precompsrc.cpp | 1 + network/radio/RadioManagerSample/cpp/sampleRM.idl | 21 + network/radio/RadioManagerSample/install.cmd | 3 + network/radio/RadioManagerSample/readme.txt | 192 + network/trans/ddproxy/ddproxy.sln | 18 +- network/trans/ddproxy/sys/ddproxy.vcxproj | 4 +- network/trans/ddproxy/sys/ddproxy.vcxproj.Filters | 8 +- network/trans/inspect/inspect.sln | 18 +- network/trans/inspect/sys/inspect.vcxproj | 4 +- network/trans/inspect/sys/inspect.vcxproj.Filters | 8 +- network/trans/msnmntr/exe/monitor.vcxproj | 4 +- network/trans/msnmntr/exe/monitor.vcxproj.Filters | 6 +- network/trans/msnmntr/msnmntr.sln | 44 +- network/trans/msnmntr/sys/msnmntr.vcxproj | 4 +- network/trans/msnmntr/sys/msnmntr.vcxproj.Filters | 8 +- network/trans/stmedit/stmedit.sln | 18 +- network/trans/stmedit/sys/stmedit.vcxproj | 4 +- network/trans/stmedit/sys/stmedit.vcxproj.Filters | 8 +- network/wlan/ihvsample/ihvsample.vcxproj | 4 +- network/wlan/ihvsample/ihvsample.vcxproj.Filters | 6 +- network/wlan/ihvsampleui/IHVSampleUI.vcxproj | 4 +- .../wlan/ihvsampleui/IHVSampleUI.vcxproj.Filters | 6 +- network/wlan/wlan.sln | 44 +- network/wsk/echosrv/echosrv.sln | 18 +- network/wsk/echosrv/echosrv.vcxproj | 4 +- network/wsk/echosrv/echosrv.vcxproj.Filters | 8 +- nfp/net/NetNfpProvider.htm | 1240 +++ nfp/net/driver/NetNfpProvider.vcxproj | 4 +- nfp/net/driver/NetNfpProvider.vcxproj.Filters | 8 +- nfp/net/exe/NetNfpControl.vcxproj | 4 +- nfp/net/exe/NetNfpControl.vcxproj.Filters | 6 +- nfp/net/netnfp.sln | 44 +- pofx/UMDF2/App/PowerFxApp.cpp | 149 +- pofx/UMDF2/App/PowerFxApp.vcxproj | 20 +- pofx/UMDF2/App/PowerFxApp.vcxproj.Filters | 6 +- pofx/UMDF2/App/include.h | 2 +- .../SingleComp/SingleComponentSingleStateUm.inx | 2 +- .../SingleComponentSingleStateUm.vcxproj | 4 +- .../SingleComponentSingleStateUm.vcxproj.Filters | 8 +- pofx/UMDF2/ReadMe.md | 3 + pofx/UMDF2/pofx.sln | 48 +- pofx/WDF/App/PowerFxApp.cpp | 149 +- pofx/WDF/App/PowerFxApp.vcxproj | 20 +- pofx/WDF/App/PowerFxApp.vcxproj.Filters | 6 +- pofx/WDF/App/include.h | 2 +- .../Driver/MultiComp/driver/WdfMultiComp.vcxproj | 4 +- .../MultiComp/driver/WdfMultiComp.vcxproj.Filters | 8 +- pofx/WDF/Driver/MultiComp/lib/WdfPoFx.vcxproj | 4 +- .../Driver/MultiComp/lib/WdfPoFx.vcxproj.Filters | 8 +- pofx/WDF/Driver/MultiComp/lib/init.c | 13 +- .../SingleComp/SingleComponentFStateDriver.vcxproj | 4 +- .../SingleComponentFStateDriver.vcxproj.Filters | 8 +- pofx/WDF/ReadMe.md | 3 + pofx/WDF/pofx.sln | 102 +- .../BlankProjSrc/BlankProject.vcxproj | 4 +- .../BlankProjSrc/BlankProject.vcxproj.Filters | 6 +- print/SampleOpenXPS/SampleOpenXPS.sln | 18 +- print/SampleXPS/BlankProjSrc/BlankProject.vcxproj | 4 +- .../BlankProjSrc/BlankProject.vcxproj.Filters | 6 +- print/SampleXPS/SampleXPS.sln | 18 +- .../SimplePipelineFilter/SimplePipelineFilter.sln | 18 +- .../SimplePipelineFilter/WdkPipelineFilter.vcxproj | 4 +- .../WdkPipelineFilter.vcxproj.Filters | 6 +- print/XPSDrvSmpl/Package/package.VcxProj | 115 + print/XPSDrvSmpl/Package/package.VcxProj.Filters | 21 + print/XPSDrvSmpl/ReadMe.md | 268 + print/XPSDrvSmpl/XPSDrvSmpl.sln | 217 + print/XPSDrvSmpl/install/xdCMYKPrinter.icc | Bin 0 -> 849080 bytes print/XPSDrvSmpl/install/xdbook.gpd | 87 + print/XPSDrvSmpl/install/xdcolman.gpd | 106 + print/XPSDrvSmpl/install/xdnames.gpd | 151 + print/XPSDrvSmpl/install/xdnup.gpd | 207 + print/XPSDrvSmpl/install/xdpgscl.gpd | 117 + print/XPSDrvSmpl/install/xdsmpl-PipelineConfig.xml | 55 + print/XPSDrvSmpl/install/xdsmpl.gpd | 467 + print/XPSDrvSmpl/install/xdsmpl.inf | 139 + print/XPSDrvSmpl/install/xdsmpl.ini | 22 + print/XPSDrvSmpl/install/xdwmark.gpd | 67 + print/XPSDrvSmpl/install/xdwscRGB.icc | Bin 0 -> 124856 bytes print/XPSDrvSmpl/readme.txt | 63 + print/XPSDrvSmpl/src/common/bkdata.h | 46 + print/XPSDrvSmpl/src/common/bkpchndlr.cpp | 201 + print/XPSDrvSmpl/src/common/bkpchndlr.h | 41 + print/XPSDrvSmpl/src/common/bkpthndlr.cpp | 318 + print/XPSDrvSmpl/src/common/bkpthndlr.h | 55 + print/XPSDrvSmpl/src/common/bkschema.cpp | 51 + print/XPSDrvSmpl/src/common/bkschema.h | 77 + print/XPSDrvSmpl/src/common/cmdata.h | 42 + print/XPSDrvSmpl/src/common/cmintentsdata.h | 42 + print/XPSDrvSmpl/src/common/cmintentsschema.cpp | 34 + print/XPSDrvSmpl/src/common/cmintentsschema.h | 55 + print/XPSDrvSmpl/src/common/cmintpthndlr.cpp | 156 + print/XPSDrvSmpl/src/common/cmintpthndlr.h | 43 + print/XPSDrvSmpl/src/common/cmprofiledata.h | 44 + print/XPSDrvSmpl/src/common/cmprofileschema.cpp | 49 + print/XPSDrvSmpl/src/common/cmprofileschema.h | 60 + print/XPSDrvSmpl/src/common/cmprofpchndlr.cpp | 179 + print/XPSDrvSmpl/src/common/cmprofpchndlr.h | 42 + print/XPSDrvSmpl/src/common/cmprofpthndlr.cpp | 206 + print/XPSDrvSmpl/src/common/cmprofpthndlr.h | 51 + print/XPSDrvSmpl/src/common/cmpthndlr.cpp | 154 + print/XPSDrvSmpl/src/common/cmpthndlr.h | 46 + print/XPSDrvSmpl/src/common/cmschema.cpp | 34 + print/XPSDrvSmpl/src/common/cmschema.h | 55 + print/XPSDrvSmpl/src/common/globals.cpp | 237 + print/XPSDrvSmpl/src/common/globals.h | 102 + print/XPSDrvSmpl/src/common/nupchndlr.cpp | 196 + print/XPSDrvSmpl/src/common/nupchndlr.h | 41 + print/XPSDrvSmpl/src/common/nupdata.h | 46 + print/XPSDrvSmpl/src/common/nupschema.cpp | 46 + print/XPSDrvSmpl/src/common/nupschema.h | 77 + print/XPSDrvSmpl/src/common/nupthndlr.cpp | 309 + print/XPSDrvSmpl/src/common/nupthndlr.h | 53 + print/XPSDrvSmpl/src/common/pchndlr.cpp | 640 ++ print/XPSDrvSmpl/src/common/pchndlr.h | 91 + print/XPSDrvSmpl/src/common/pgscdata.h | 52 + print/XPSDrvSmpl/src/common/pgscpchndlr.cpp | 349 + print/XPSDrvSmpl/src/common/pgscpchndlr.h | 41 + print/XPSDrvSmpl/src/common/pgscpthndlr.cpp | 479 + print/XPSDrvSmpl/src/common/pgscpthndlr.h | 55 + print/XPSDrvSmpl/src/common/pgscschema.cpp | 64 + print/XPSDrvSmpl/src/common/pgscschema.h | 112 + print/XPSDrvSmpl/src/common/pimagedata.h | 52 + print/XPSDrvSmpl/src/common/pimagepthndlr.cpp | 171 + print/XPSDrvSmpl/src/common/pimagepthndlr.h | 42 + print/XPSDrvSmpl/src/common/pimageschema.cpp | 40 + print/XPSDrvSmpl/src/common/pimageschema.h | 62 + print/XPSDrvSmpl/src/common/porientdata.h | 42 + print/XPSDrvSmpl/src/common/porientpthndlr.cpp | 150 + print/XPSDrvSmpl/src/common/porientpthndlr.h | 45 + print/XPSDrvSmpl/src/common/porientschema.cpp | 34 + print/XPSDrvSmpl/src/common/porientschema.h | 55 + print/XPSDrvSmpl/src/common/precomp.h | 99 + print/XPSDrvSmpl/src/common/precompsrc.cpp | 1 + print/XPSDrvSmpl/src/common/privatedefs.h | 300 + print/XPSDrvSmpl/src/common/pshndlr.cpp | 1836 ++++ print/XPSDrvSmpl/src/common/pshndlr.h | 218 + print/XPSDrvSmpl/src/common/psizedata.h | 44 + print/XPSDrvSmpl/src/common/psizepthndlr.cpp | 136 + print/XPSDrvSmpl/src/common/psizepthndlr.h | 45 + print/XPSDrvSmpl/src/common/psizeschema.cpp | 32 + print/XPSDrvSmpl/src/common/psizeschema.h | 55 + print/XPSDrvSmpl/src/common/pthndlr.cpp | 1385 +++ print/XPSDrvSmpl/src/common/pthndlr.h | 178 + print/XPSDrvSmpl/src/common/ptquerybld.cpp | 515 ++ print/XPSDrvSmpl/src/common/ptquerybld.h | 84 + print/XPSDrvSmpl/src/common/schema.cpp | 70 + print/XPSDrvSmpl/src/common/schema.h | 94 + print/XPSDrvSmpl/src/common/wmdata.h | 71 + print/XPSDrvSmpl/src/common/wmpchndlr.cpp | 555 ++ print/XPSDrvSmpl/src/common/wmpchndlr.h | 41 + print/XPSDrvSmpl/src/common/wmpthndlr.cpp | 1167 +++ print/XPSDrvSmpl/src/common/wmpthndlr.h | 116 + print/XPSDrvSmpl/src/common/wmschema.cpp | 60 + print/XPSDrvSmpl/src/common/wmschema.h | 114 + print/XPSDrvSmpl/src/common/workbuff.cpp | 233 + print/XPSDrvSmpl/src/common/workbuff.h | 51 + print/XPSDrvSmpl/src/common/xdsmplcmn.vcxproj | 414 + .../src/common/xdsmplcmn.vcxproj.Filters | 118 + print/XPSDrvSmpl/src/filters/booklet/bkflt.cpp | 591 ++ print/XPSDrvSmpl/src/filters/booklet/bkflt.h | 80 + print/XPSDrvSmpl/src/filters/booklet/bkflt.rc | 43 + print/XPSDrvSmpl/src/filters/booklet/bkprps.cpp | 124 + print/XPSDrvSmpl/src/filters/booklet/bkprps.h | 52 + print/XPSDrvSmpl/src/filters/booklet/bksax.cpp | 285 + print/XPSDrvSmpl/src/filters/booklet/bksax.h | 59 + print/XPSDrvSmpl/src/filters/booklet/dllentry.cpp | 143 + .../XPSDrvSmpl/src/filters/booklet/precompsrc.cpp | 1 + print/XPSDrvSmpl/src/filters/booklet/xdbook.def | 26 + .../XPSDrvSmpl/src/filters/booklet/xdbook.vcxproj | 305 + .../src/filters/booklet/xdbook.vcxproj.Filters | 42 + print/XPSDrvSmpl/src/filters/color/XDColMan.def | 26 + .../XPSDrvSmpl/src/filters/color/XDColMan.vcxproj | 375 + .../src/filters/color/XDColMan.vcxproj.Filters | 75 + print/XPSDrvSmpl/src/filters/color/bmpconv.cpp | 1187 +++ print/XPSDrvSmpl/src/filters/color/bmpconv.h | 168 + print/XPSDrvSmpl/src/filters/color/bmpdata.cpp | 253 + print/XPSDrvSmpl/src/filters/color/bmpdata.h | 768 ++ print/XPSDrvSmpl/src/filters/color/cmflt.cpp | 264 + print/XPSDrvSmpl/src/filters/color/cmflt.h | 51 + print/XPSDrvSmpl/src/filters/color/cmflt.rc | 43 + print/XPSDrvSmpl/src/filters/color/cmimg.cpp | 856 ++ print/XPSDrvSmpl/src/filters/color/cmimg.h | 87 + print/XPSDrvSmpl/src/filters/color/cmsax.cpp | 440 + print/XPSDrvSmpl/src/filters/color/cmsax.h | 80 + print/XPSDrvSmpl/src/filters/color/colchan.cpp | 1883 ++++ print/XPSDrvSmpl/src/filters/color/colchan.h | 289 + print/XPSDrvSmpl/src/filters/color/colconv.cpp | 1138 +++ print/XPSDrvSmpl/src/filters/color/colconv.h | 167 + print/XPSDrvSmpl/src/filters/color/dictionary.cpp | 289 + print/XPSDrvSmpl/src/filters/color/dictionary.h | 65 + print/XPSDrvSmpl/src/filters/color/dllentry.cpp | 145 + print/XPSDrvSmpl/src/filters/color/precompsrc.cpp | 1 + print/XPSDrvSmpl/src/filters/color/profile.cpp | 709 ++ print/XPSDrvSmpl/src/filters/color/profile.h | 124 + print/XPSDrvSmpl/src/filters/color/profman.cpp | 818 ++ print/XPSDrvSmpl/src/filters/color/profman.h | 126 + print/XPSDrvSmpl/src/filters/color/scaniter.cpp | 604 ++ print/XPSDrvSmpl/src/filters/color/scaniter.h | 218 + print/XPSDrvSmpl/src/filters/color/transform.cpp | 666 ++ print/XPSDrvSmpl/src/filters/color/transform.h | 83 + print/XPSDrvSmpl/src/filters/color/wcsapiconv.cpp | 813 ++ print/XPSDrvSmpl/src/filters/color/wcsapiconv.h | 280 + print/XPSDrvSmpl/src/filters/color/wictobmscn.cpp | 751 ++ print/XPSDrvSmpl/src/filters/color/wictobmscn.h | 88 + print/XPSDrvSmpl/src/filters/common/clasfact.h | 202 + print/XPSDrvSmpl/src/filters/common/precompsrc.cpp | 1 + print/XPSDrvSmpl/src/filters/common/ptmanage.cpp | 1216 +++ print/XPSDrvSmpl/src/filters/common/ptmanage.h | 153 + print/XPSDrvSmpl/src/filters/common/rescache.cpp | 309 + print/XPSDrvSmpl/src/filters/common/rescache.h | 132 + print/XPSDrvSmpl/src/filters/common/rescpy.cpp | 132 + print/XPSDrvSmpl/src/filters/common/rescpy.h | 40 + print/XPSDrvSmpl/src/filters/common/saxhndlr.cpp | 586 ++ print/XPSDrvSmpl/src/filters/common/saxhndlr.h | 129 + print/XPSDrvSmpl/src/filters/common/widetoutf8.cpp | 199 + print/XPSDrvSmpl/src/filters/common/widetoutf8.h | 48 + .../XPSDrvSmpl/src/filters/common/xdfltcmn.vcxproj | 326 + .../src/filters/common/xdfltcmn.vcxproj.Filters | 46 + print/XPSDrvSmpl/src/filters/common/xdrchflt.cpp | 508 ++ print/XPSDrvSmpl/src/filters/common/xdrchflt.h | 86 + print/XPSDrvSmpl/src/filters/common/xdsmplflt.cpp | 319 + print/XPSDrvSmpl/src/filters/common/xdsmplflt.h | 77 + print/XPSDrvSmpl/src/filters/common/xdstrmflt.cpp | 351 + print/XPSDrvSmpl/src/filters/common/xdstrmflt.h | 63 + print/XPSDrvSmpl/src/filters/nup/dllentry.cpp | 144 + print/XPSDrvSmpl/src/filters/nup/nupflt.cpp | 476 + print/XPSDrvSmpl/src/filters/nup/nupflt.h | 88 + print/XPSDrvSmpl/src/filters/nup/nupflt.rc | 43 + print/XPSDrvSmpl/src/filters/nup/nuppage.cpp | 581 ++ print/XPSDrvSmpl/src/filters/nup/nuppage.h | 107 + print/XPSDrvSmpl/src/filters/nup/nupsax.cpp | 522 ++ print/XPSDrvSmpl/src/filters/nup/nupsax.h | 76 + print/XPSDrvSmpl/src/filters/nup/nuptprps.cpp | 449 + print/XPSDrvSmpl/src/filters/nup/nuptprps.h | 97 + print/XPSDrvSmpl/src/filters/nup/nupxform.cpp | 623 ++ print/XPSDrvSmpl/src/filters/nup/nupxform.h | 101 + print/XPSDrvSmpl/src/filters/nup/precompsrc.cpp | 1 + print/XPSDrvSmpl/src/filters/nup/xdnup.def | 26 + print/XPSDrvSmpl/src/filters/nup/xdnup.vcxproj | 317 + .../src/filters/nup/xdnup.vcxproj.Filters | 48 + print/XPSDrvSmpl/src/filters/precomp.h | 107 + print/XPSDrvSmpl/src/filters/scaling/dllentry.cpp | 144 + print/XPSDrvSmpl/src/filters/scaling/pagescale.cpp | 761 ++ print/XPSDrvSmpl/src/filters/scaling/pagescale.h | 107 + .../XPSDrvSmpl/src/filters/scaling/pgscptprop.cpp | 478 + print/XPSDrvSmpl/src/filters/scaling/pgscptprop.h | 91 + .../XPSDrvSmpl/src/filters/scaling/precompsrc.cpp | 1 + print/XPSDrvSmpl/src/filters/scaling/scaleflt.cpp | 253 + print/XPSDrvSmpl/src/filters/scaling/scaleflt.h | 56 + print/XPSDrvSmpl/src/filters/scaling/scaleflt.rc | 43 + print/XPSDrvSmpl/src/filters/scaling/scalesax.cpp | 591 ++ print/XPSDrvSmpl/src/filters/scaling/scalesax.h | 75 + print/XPSDrvSmpl/src/filters/scaling/xdscale.def | 26 + .../XPSDrvSmpl/src/filters/scaling/xdscale.vcxproj | 327 + .../src/filters/scaling/xdscale.vcxproj.Filters | 45 + print/XPSDrvSmpl/src/filters/watermark/Raster1.png | Bin 0 -> 67501 bytes print/XPSDrvSmpl/src/filters/watermark/Vector1.xps | Bin 0 -> 1724 bytes .../XPSDrvSmpl/src/filters/watermark/dllentry.cpp | 143 + .../src/filters/watermark/precompsrc.cpp | 1 + print/XPSDrvSmpl/src/filters/watermark/wmbase.cpp | 416 + print/XPSDrvSmpl/src/filters/watermark/wmbase.h | 95 + print/XPSDrvSmpl/src/filters/watermark/wmflt.cpp | 340 + print/XPSDrvSmpl/src/filters/watermark/wmflt.h | 54 + print/XPSDrvSmpl/src/filters/watermark/wmflt.rc | 54 + print/XPSDrvSmpl/src/filters/watermark/wmfont.cpp | 413 + print/XPSDrvSmpl/src/filters/watermark/wmfont.h | 82 + print/XPSDrvSmpl/src/filters/watermark/wmimg.cpp | 503 ++ print/XPSDrvSmpl/src/filters/watermark/wmimg.h | 90 + .../XPSDrvSmpl/src/filters/watermark/wmptprop.cpp | 683 ++ print/XPSDrvSmpl/src/filters/watermark/wmptprop.h | 103 + print/XPSDrvSmpl/src/filters/watermark/wmrast.cpp | 271 + print/XPSDrvSmpl/src/filters/watermark/wmrast.h | 58 + print/XPSDrvSmpl/src/filters/watermark/wmres.h | 27 + print/XPSDrvSmpl/src/filters/watermark/wmsax.cpp | 427 + print/XPSDrvSmpl/src/filters/watermark/wmsax.h | 74 + print/XPSDrvSmpl/src/filters/watermark/wmtext.cpp | 250 + print/XPSDrvSmpl/src/filters/watermark/wmtext.h | 57 + print/XPSDrvSmpl/src/filters/watermark/wmvect.cpp | 278 + print/XPSDrvSmpl/src/filters/watermark/wmvect.h | 62 + print/XPSDrvSmpl/src/filters/watermark/wmxps.cpp | 291 + print/XPSDrvSmpl/src/filters/watermark/wmxps.h | 60 + print/XPSDrvSmpl/src/filters/watermark/xdwmark.def | 26 + .../src/filters/watermark/xdwmark.vcxproj | 347 + .../src/filters/watermark/xdwmark.vcxproj.Filters | 63 + print/XPSDrvSmpl/src/filters/xdcont/precompsrc.cpp | 1 + print/XPSDrvSmpl/src/filters/xdcont/xdcont.vcxproj | 282 + .../src/filters/xdcont/xdcont.vcxproj.Filters | 46 + print/XPSDrvSmpl/src/filters/xdcont/xps.h | 83 + print/XPSDrvSmpl/src/filters/xdcont/xpsarch.cpp | 639 ++ print/XPSDrvSmpl/src/filters/xdcont/xpsarch.h | 91 + print/XPSDrvSmpl/src/filters/xdcont/xpsfd.cpp | 285 + print/XPSDrvSmpl/src/filters/xdcont/xpsfd.h | 60 + print/XPSDrvSmpl/src/filters/xdcont/xpsfds.cpp | 285 + print/XPSDrvSmpl/src/filters/xdcont/xpsfds.h | 61 + print/XPSDrvSmpl/src/filters/xdcont/xpsfiler.cpp | 679 ++ print/XPSDrvSmpl/src/filters/xdcont/xpsfiler.h | 119 + print/XPSDrvSmpl/src/filters/xdcont/xpsfilew.cpp | 291 + print/XPSDrvSmpl/src/filters/xdcont/xpsfilew.h | 76 + print/XPSDrvSmpl/src/filters/xdcont/xpsproc.cpp | 916 ++ print/XPSDrvSmpl/src/filters/xdcont/xpsproc.h | 137 + print/XPSDrvSmpl/src/filters/xdcont/xpsrels.cpp | 419 + print/XPSDrvSmpl/src/filters/xdcont/xpsrels.h | 70 + print/XPSDrvSmpl/src/filters/xdcont/xpstype.cpp | 417 + print/XPSDrvSmpl/src/filters/xdcont/xpstype.h | 63 + print/XPSDrvSmpl/src/inc/cunknown.h | 212 + print/XPSDrvSmpl/src/inc/gdip.h | 121 + print/XPSDrvSmpl/src/inc/ipkarch.h | 230 + print/XPSDrvSmpl/src/inc/ipkfile.h | 128 + print/XPSDrvSmpl/src/inc/streamcnv.h | 593 ++ print/XPSDrvSmpl/src/inc/xdexcept.h | 104 + print/XPSDrvSmpl/src/inc/xdstring.h | 2889 +++++++ print/XPSDrvSmpl/src/ui/bkdmptcnv.cpp | 433 + print/XPSDrvSmpl/src/ui/bkdmptcnv.h | 84 + print/XPSDrvSmpl/src/ui/colctrls.cpp | 371 + print/XPSDrvSmpl/src/ui/colctrls.h | 83 + print/XPSDrvSmpl/src/ui/coldmptcnv.cpp | 395 + print/XPSDrvSmpl/src/ui/coldmptcnv.h | 76 + print/XPSDrvSmpl/src/ui/colppg.cpp | 160 + print/XPSDrvSmpl/src/ui/colppg.h | 42 + print/XPSDrvSmpl/src/ui/devmode.h | 82 + print/XPSDrvSmpl/src/ui/dllentry.cpp | 175 + print/XPSDrvSmpl/src/ui/docppg.cpp | 1314 +++ print/XPSDrvSmpl/src/ui/docppg.h | 186 + print/XPSDrvSmpl/src/ui/ftrctrls.cpp | 1667 ++++ print/XPSDrvSmpl/src/ui/ftrctrls.h | 288 + print/XPSDrvSmpl/src/ui/ftrdmptcnv.h | 631 ++ print/XPSDrvSmpl/src/ui/ftrppg.cpp | 270 + print/XPSDrvSmpl/src/ui/ftrppg.h | 42 + print/XPSDrvSmpl/src/ui/nupptcnv.cpp | 477 + print/XPSDrvSmpl/src/ui/nupptcnv.h | 86 + print/XPSDrvSmpl/src/ui/pgscdmptcnv.cpp | 468 + print/XPSDrvSmpl/src/ui/pgscdmptcnv.h | 76 + print/XPSDrvSmpl/src/ui/precomp.h | 100 + print/XPSDrvSmpl/src/ui/precompsrc.cpp | 1 + print/XPSDrvSmpl/src/ui/resource.h | 232 + print/XPSDrvSmpl/src/ui/uictrl.cpp | 2117 +++++ print/XPSDrvSmpl/src/ui/uictrl.h | 405 + print/XPSDrvSmpl/src/ui/uiproperties.cpp | 783 ++ print/XPSDrvSmpl/src/ui/uiproperties.h | 111 + print/XPSDrvSmpl/src/ui/wmctrls.cpp | 1381 +++ print/XPSDrvSmpl/src/ui/wmctrls.h | 259 + print/XPSDrvSmpl/src/ui/wmdmptcnv.cpp | 591 ++ print/XPSDrvSmpl/src/ui/wmdmptcnv.h | 75 + print/XPSDrvSmpl/src/ui/wmppg.cpp | 268 + print/XPSDrvSmpl/src/ui/wmppg.h | 42 + print/XPSDrvSmpl/src/ui/xdsmplcf.cpp | 192 + print/XPSDrvSmpl/src/ui/xdsmplcf.h | 56 + print/XPSDrvSmpl/src/ui/xdsmpldlg.rc | 326 + print/XPSDrvSmpl/src/ui/xdsmplptprov.cpp | 891 ++ print/XPSDrvSmpl/src/ui/xdsmplptprov.h | 124 + print/XPSDrvSmpl/src/ui/xdsmplui.cpp | 1018 +++ print/XPSDrvSmpl/src/ui/xdsmplui.def | 23 + print/XPSDrvSmpl/src/ui/xdsmplui.h | 161 + print/XPSDrvSmpl/src/ui/xdsmplui.vcxproj | 367 + print/XPSDrvSmpl/src/ui/xdsmplui.vcxproj.Filters | 84 + print/XpsRasFilter/XpsRasFilter.sln | 18 +- print/XpsRasFilter/src/xpsrasfilter.vcxproj | 4 +- .../XpsRasFilter/src/xpsrasfilter.vcxproj.Filters | 6 +- print/autoconfig/ACnfgPS.gdl | 100 + print/autoconfig/ACnfgUni.GDL | 111 + print/autoconfig/AutoCnfg.GPD | 733 ++ print/autoconfig/AutoCnfg.PPD | 479 + print/autoconfig/AutoCnfg.inf | 111 + print/autoconfig/AutoConfig.htm | 367 + print/autoconfig/AutoConfig.sln | 47 + print/autoconfig/AutoConfig.vcxproj | 160 + print/autoconfig/AutoConfig.vcxproj.Filters | 21 + print/autoconfig/Package/package.VcxProj | 88 + print/autoconfig/Package/package.VcxProj.Filters | 21 + print/autoconfig/ReadMe.md | 62 + print/cpsuisam/cpsui.htm | 236 + print/cpsuisam/cpsuisam.sln | 18 +- print/cpsuisam/cpsuisam.vcxproj | 4 +- print/cpsuisam/cpsuisam.vcxproj.Filters | 6 +- .../PrinterExtensionSample.sln | 8 +- .../ConstraintScript.sln | 18 +- .../ConstraintScript.vcxproj | 4 +- .../ConstraintScript.vcxproj.Filters | 8 +- .../HostBasedSampleDriver.sln | 43 + .../HostBasedSampleDriver.vcxproj | 162 + .../HostBasedSampleDriver.vcxproj.Filters | 41 + .../Package/package.VcxProj | 88 + .../Package/package.VcxProj.Filters | 21 + .../v4PrintDriver-HostBasedSampleDriver/ReadMe.md | 60 + .../usb_host_based_sample-manifest.ini | 13 + .../usb_host_based_sample-pipelineconfig.xml | 1 + .../usb_host_based_sample.gpd | 138 + .../usb_host_based_sample.inf | 108 + .../usb_host_based_sample.js | Bin 0 -> 35004 bytes .../usb_host_based_sample_events.xml | 11 + .../usb_host_based_sample_extension.xml | 8 + .../v4PrintDriver-Intellisense-Windows8.1.js | 126 + .../v4PrintDriver-Intellisense.js | 513 ++ .../USBMon-Bidi-Extension.sln | 18 +- .../USBMon-Bidi-Extension.vcxproj | 4 +- .../USBMon-Bidi-Extension.vcxproj.Filters | 8 +- .../WSDMon-Bidi-Extension.sln | 18 +- .../WSDMon-Bidi-Extension.vcxproj | 4 +- .../WSDMon-Bidi-Extension.vcxproj.Filters | 8 +- sd/miniport/sdhc/README.md | 13 + sd/miniport/sdhc/inbox/sdhc.vcxproj | 156 + sd/miniport/sdhc/inbox/sdhc.vcxproj.Filters | 39 + sd/miniport/sdhc/sdhc.c | 3291 +++++++ sd/miniport/sdhc/sdhc.h | 2091 +++++ sd/miniport/sdhc/sdhc.inx | Bin 0 -> 11250 bytes sd/miniport/sdhc/sdhc.rc | 15 + sd/miniport/sdhc/sdhc.sln | 28 + sd/sdiomars/mars.vcxproj | 4 +- sd/sdiomars/mars.vcxproj.Filters | 8 +- sd/sdiomars/sdiomars.sln | 18 +- sd/sdiomars/sdiosample.htm | 356 + security/elam/elam.sln | 18 +- security/elam/elamsample.htm | 1110 +++ security/elam/elamsample.vcxproj | 4 +- security/elam/elamsample.vcxproj.Filters | 8 +- sensors/ADXL345Acc/ADXL345Acc.sln | 18 +- sensors/ADXL345Acc/ADXL345Acc.vcxproj | 4 +- sensors/ADXL345Acc/ADXL345Acc.vcxproj.Filters | 8 +- sensors/Activity/Activity.sln | 18 +- sensors/Activity/Activity.vcxproj | 4 +- sensors/Activity/Activity.vcxproj.Filters | 8 +- sensors/CustomSensors/CustomSensors.sln | 18 +- sensors/CustomSensors/CustomSensors.vcxproj | 4 +- .../CustomSensors/CustomSensors.vcxproj.Filters | 8 +- sensors/Pedometer/Pedometer.sln | 18 +- sensors/Pedometer/Pedometer.vcxproj | 4 +- sensors/Pedometer/Pedometer.vcxproj.Filters | 8 +- sensors/Pedometer/device.cpp | 2 +- .../SimpleDeviceOrientationSensor.sln | 18 +- .../SimpleDeviceOrientationSensor.vcxproj | 4 +- .../SimpleDeviceOrientationSensor.vcxproj.Filters | 8 +- serial/VirtualSerial/ComPort/virtualserial.vcxproj | 4 +- .../ComPort/virtualserial.vcxproj.Filters | 8 +- serial/VirtualSerial/FakeModem/fakemodem.vcxproj | 4 +- .../FakeModem/fakemodem.vcxproj.Filters | 8 +- serial/VirtualSerial/VirtualSerial.sln | 44 +- .../ComPort/VirtualSerial2um.vcxproj | 194 + .../ComPort/VirtualSerial2um.vcxproj.Filters | 48 + serial/VirtualSerial2/ComPort/virtualserial2um.inx | 73 + serial/VirtualSerial2/ComPort/virtualserial2um.rc | 17 + serial/VirtualSerial2/FakeModem/fakemodem2um.inx | 193 + serial/VirtualSerial2/FakeModem/fakemodem2um.rc | 17 + .../VirtualSerial2/FakeModem/fakemodem2um.vcxproj | 194 + .../FakeModem/fakemodem2um.vcxproj.Filters | 48 + serial/VirtualSerial2/ReadMe.md | 59 + serial/VirtualSerial2/VirtualSerial.sln | 46 + serial/VirtualSerial2/device.c | 449 + serial/VirtualSerial2/device.h | 122 + serial/VirtualSerial2/driver.c | 72 + serial/VirtualSerial2/driver.h | 30 + serial/VirtualSerial2/internal.h | 58 + serial/VirtualSerial2/queue.c | 963 +++ serial/VirtualSerial2/queue.h | 113 + serial/VirtualSerial2/ringbuffer.c | 338 + serial/VirtualSerial2/ringbuffer.h | 117 + serial/VirtualSerial2/serial.h | 128 + serial/serenum/SerEnum_sample.vcxproj | 4 +- serial/serenum/SerEnum_sample.vcxproj.Filters | 8 +- serial/serenum/serenum.htm | 203 + serial/serenum/serenum.sln | 18 +- serial/serial/ioctl.c | 14 +- serial/serial/pnp.c | 16 +- serial/serial/serial.sln | 18 +- serial/serial/wdfserial.vcxproj | 4 +- serial/serial/wdfserial.vcxproj.Filters | 8 +- setup/DIFxAPI/AppDrv/AppDrv.vcxproj | 4 +- setup/DIFxAPI/AppDrv/AppDrv.vcxproj.Filters | 6 +- setup/DIFxAPI/DIFxAPI.sln | 44 +- setup/DIFxAPI/DIFxCmd/DIFxCmd.vcxproj | 4 +- setup/DIFxAPI/DIFxCmd/DIFxCmd.vcxproj.Filters | 6 +- setup/devcon/devcon.htm | 680 ++ setup/devcon/devcon.sln | 18 +- setup/devcon/devcon.vcxproj | 4 +- setup/devcon/devcon.vcxproj.Filters | 6 +- smartcrd/ReadMe.md | 41 + smartcrd/pscr/Pscr.vcxproj | 183 + smartcrd/pscr/Pscr.vcxproj.Filters | 51 + smartcrd/pscr/pscr.htm | 867 ++ smartcrd/pscr/pscr.inx | Bin 0 -> 6292 bytes smartcrd/pscr/pscr.rc | 48 + smartcrd/pscr/pscrcb.c | 1008 +++ smartcrd/pscr/pscrcb.h | 84 + smartcrd/pscr/pscrcmd.c | 981 +++ smartcrd/pscr/pscrcmd.h | 107 + smartcrd/pscr/pscrlog.mc | 103 + smartcrd/pscr/pscrnt.c | 1687 ++++ smartcrd/pscr/pscrnt.h | 187 + smartcrd/pscr/pscrrdwr.c | 509 ++ smartcrd/pscr/pscrrdwr.h | 366 + smartcrd/pscr/pscrvers.h | 43 + smartcrd/smartcrd.sln | 28 + spb/SkeletonI2C/SkeletonI2C.sln | 18 +- spb/SkeletonI2C/device.cpp | 4 +- spb/SkeletonI2C/skeletoni2c.vcxproj | 4 +- spb/SkeletonI2C/skeletoni2c.vcxproj.Filters | 8 +- spb/SpbTestTool/SpbTestTool.htm | 2688 ++++++ spb/SpbTestTool/SpbTestTool.sln | 44 +- spb/SpbTestTool/exe/SpbTestTool.vcxproj | 4 +- spb/SpbTestTool/exe/SpbTestTool.vcxproj.Filters | 6 +- spb/SpbTestTool/sys/SpbTestTool.vcxproj | 4 +- spb/SpbTestTool/sys/SpbTestTool.vcxproj.Filters | 8 +- storage/class/cdrom/ReadMe.md | 57 + storage/class/cdrom/cdrom.sln | 28 + storage/class/cdrom/src/aacs.c | 1481 ++++ storage/class/cdrom/src/autorun.c | 3076 +++++++ storage/class/cdrom/src/cdrom.c | 4225 +++++++++ storage/class/cdrom/src/cdrom.h | 1609 ++++ storage/class/cdrom/src/cdrom.htm | 86 + storage/class/cdrom/src/cdrom.inf | Bin 0 -> 10520 bytes storage/class/cdrom/src/cdrom.rc | 23 + storage/class/cdrom/src/cdrom.vcxproj | 169 + storage/class/cdrom/src/cdrom.vcxproj.Filters | 75 + storage/class/cdrom/src/cdromp.h | 383 + storage/class/cdrom/src/common.c | 3872 +++++++++ storage/class/cdrom/src/data.c | 283 + storage/class/cdrom/src/guid.c | 16 + storage/class/cdrom/src/init.c | 2741 ++++++ storage/class/cdrom/src/ioctl.c | 9132 ++++++++++++++++++++ storage/class/cdrom/src/ioctl.h | 847 ++ storage/class/cdrom/src/localwpp.ini | 17 + storage/class/cdrom/src/mmc.c | 1629 ++++ storage/class/cdrom/src/mmc.h | 122 + storage/class/cdrom/src/pnppower.c | 684 ++ storage/class/cdrom/src/scratch.c | 1464 ++++ storage/class/cdrom/src/scratch.h | 187 + storage/class/cdrom/src/sense.c | 2600 ++++++ storage/class/cdrom/src/zpodd.c | 825 ++ storage/class/classpnp/classpnp.sln | 18 +- storage/class/classpnp/src/classp.h | 2 +- storage/class/classpnp/src/classpnp.vcxproj | 4 +- .../class/classpnp/src/classpnp.vcxproj.Filters | 8 +- storage/class/classpnp/src/utils.c | 17 +- storage/class/classpnp/src/xferpkt.c | 14 +- storage/class/disk/ReadMe.md | 44 + storage/class/disk/disk.sln | 28 + storage/class/disk/src/data.c | 85 + storage/class/disk/src/disk.c | 6166 +++++++++++++ storage/class/disk/src/disk.h | 1257 +++ storage/class/disk/src/disk.htm | 42 + storage/class/disk/src/disk.rc | 23 + storage/class/disk/src/disk.vcxproj | 195 + storage/class/disk/src/disk.vcxproj.Filters | 43 + storage/class/disk/src/diskdev.inf | 113 + storage/class/disk/src/diskwmi.c | 3501 ++++++++ storage/class/disk/src/enum.c | 1313 +++ storage/class/disk/src/geometry.c | 1672 ++++ storage/class/disk/src/pnp.c | 1098 +++ storage/filters/addfilter/addfilter.sln | 18 +- storage/filters/addfilter/src/addfilter.vcxproj | 4 +- .../addfilter/src/addfilter.vcxproj.Filters | 6 +- storage/iscsi/iscsi.sln | 18 +- storage/iscsi/src/EmptyProject.vcxproj | 4 +- storage/iscsi/src/EmptyProject.vcxproj.Filters | 6 +- storage/iscsi/src/iscsihba.mof | 87 + storage/miniports/lsi_u3/lsi_u3.sln | 18 +- storage/miniports/lsi_u3/src/lsi_u3.vcxproj | 12 +- .../miniports/lsi_u3/src/lsi_u3.vcxproj.Filters | 8 +- storage/miniports/storahci/src/common.c | 17 +- storage/miniports/storahci/src/entrypts.c | 145 +- storage/miniports/storahci/src/entrypts.h | 9 +- .../miniports/storahci/src/inbox/storahci.vcxproj | 12 +- .../storahci/src/inbox/storahci.vcxproj.Filters | 8 +- storage/miniports/storahci/src/io.c | 38 +- storage/miniports/storahci/src/pnppower.c | 2 +- storage/miniports/storahci/src/util.h | 58 +- storage/miniports/storahci/storahci.sln | 18 +- storage/ramdisk/ReadMe.md | 188 + storage/ramdisk/ramdisk.sln | 28 + storage/ramdisk/src/WdfRamdisk.vcxproj | 160 + storage/ramdisk/src/WdfRamdisk.vcxproj.Filters | 42 + storage/ramdisk/src/forward_progress.c | 347 + storage/ramdisk/src/forward_progress.h | 52 + storage/ramdisk/src/ramdisk.c | 898 ++ storage/ramdisk/src/ramdisk.h | 196 + storage/ramdisk/src/ramdisk.inx | 102 + storage/ramdisk/src/ramdisk.rc | 11 + storage/sfloppy/sfloppy.sln | 18 +- storage/sfloppy/src/floppy.c | 4 +- storage/sfloppy/src/sfloppy.inf | 7 - storage/sfloppy/src/sfloppy.vcxproj | 4 +- storage/sfloppy/src/sfloppy.vcxproj.Filters | 8 +- storage/tools/spti/spti.sln | 18 +- storage/tools/spti/src/spti.vcxproj | 4 +- storage/tools/spti/src/spti.vcxproj.Filters | 6 +- thermal/simsensor/simsensor.sln | 18 +- thermal/simsensor/simsensor.vcxproj | 4 +- thermal/simsensor/simsensor.vcxproj.Filters | 8 +- thermal/thermalclient/simtc.vcxproj | 4 +- thermal/thermalclient/simtc.vcxproj.Filters | 8 +- thermal/thermalclient/thermalclient.sln | 18 +- .../SDV-FailDriver-KMDF/SDV-FailDriver-KMDF.sln | 46 +- .../driver/fail_driver1.vcxproj | 4 +- .../driver/fail_driver1.vcxproj.Filters | 8 +- .../library/fail_library1.vcxproj | 4 +- .../library/fail_library1.vcxproj.Filters | 8 +- .../SDV-FailDriver-NDIS/SDV-FailDriver-NDIS.sln | 18 +- .../SDV-FailDriver-NDIS/driver/sdvmp.vcxproj | 4 +- .../driver/sdvmp.vcxproj.Filters | 8 +- .../SDV-FailDriver-STORPORT.sln | 18 +- .../SDV-FailDriver-STORPORT/driver/lsi_u3.vcxproj | 4 +- .../driver/lsi_u3.vcxproj.Filters | 8 +- .../SDV-FailDriver-WDM/SDV-FailDriver-WDM.sln | 18 +- .../SDV-FailDriver-WDM/driver/fail_driver1.vcxproj | 4 +- .../driver/fail_driver1.vcxproj.Filters | 8 +- usb/kmdf_enumswitches/kmdf_enumswitches.sln | 18 +- .../sys/kmdf_enumswitches.vcxproj | 4 +- .../sys/kmdf_enumswitches.vcxproj.Filters | 8 +- usb/umdf2_fx2/ReadMe.md | 10 +- usb/umdf2_fx2/driver/osrusbfx2um.inx | 22 +- usb/umdf2_fx2/driver/osrusbfx2um.vcxproj | 4 +- usb/umdf2_fx2/driver/osrusbfx2um.vcxproj.Filters | 8 +- usb/umdf2_fx2/exe/osrusbfx2.vcxproj | 32 +- usb/umdf2_fx2/exe/osrusbfx2.vcxproj.Filters | 6 +- usb/umdf2_fx2/exe/testapp.c | 164 +- usb/umdf2_fx2/umdf2_fx2.sln | 44 +- usb/umdf_filter_kmdf/Package/package.VcxProj | 91 - .../Package/package.VcxProj.Filters | 21 - usb/umdf_filter_kmdf/ReadMe.md | 38 - usb/umdf_filter_kmdf/inc/WUDFOsrUsbPublic.h | 32 - usb/umdf_filter_kmdf/inc/list.h | 77 - usb/umdf_filter_kmdf/inc/public.h | 217 - usb/umdf_filter_kmdf/inc/usb_hw.h | 233 - usb/umdf_filter_kmdf/kmdf_driver/Device.c | 1051 --- usb/umdf_filter_kmdf/kmdf_driver/bulkrwr.c | 436 - usb/umdf_filter_kmdf/kmdf_driver/driver.c | 299 - usb/umdf_filter_kmdf/kmdf_driver/interrupt.c | 184 - usb/umdf_filter_kmdf/kmdf_driver/ioctl.c | 1057 --- usb/umdf_filter_kmdf/kmdf_driver/osrusbfx2.h | 335 - usb/umdf_filter_kmdf/kmdf_driver/osrusbfx2.man | 309 - usb/umdf_filter_kmdf/kmdf_driver/osrusbfx2.rc | 18 - usb/umdf_filter_kmdf/kmdf_driver/osrusbfx2.vcxproj | 245 - .../kmdf_driver/osrusbfx2.vcxproj.Filters | 46 - usb/umdf_filter_kmdf/kmdf_driver/trace.h | 115 - usb/umdf_filter_kmdf/umdf_filter/OsrUsbFilter.rc | 17 - .../umdf_filter/WUDFOsrUsbFilter.vcxproj | 287 - .../umdf_filter/WUDFOsrUsbFilter.vcxproj.Filters | 51 - .../umdf_filter/WUDFOsrUsbFilterOnKmDriver.inx | 123 - usb/umdf_filter_kmdf/umdf_filter/comsup.cpp | 351 - usb/umdf_filter_kmdf/umdf_filter/comsup.h | 215 - usb/umdf_filter_kmdf/umdf_filter/device.cpp | 243 - usb/umdf_filter_kmdf/umdf_filter/device.h | 114 - usb/umdf_filter_kmdf/umdf_filter/dllsup.cpp | 183 - usb/umdf_filter_kmdf/umdf_filter/driver.cpp | 207 - usb/umdf_filter_kmdf/umdf_filter/driver.h | 145 - usb/umdf_filter_kmdf/umdf_filter/exports.def | 4 - usb/umdf_filter_kmdf/umdf_filter/internal.h | 111 - usb/umdf_filter_kmdf/umdf_filter/queue.cpp | 538 -- usb/umdf_filter_kmdf/umdf_filter/queue.h | 253 - usb/umdf_filter_kmdf/umdf_filter_kmdf.sln | 59 - usb/umdf_filter_umdf/Package/package.VcxProj | 8 +- .../Package/package.VcxProj.Filters | 8 +- .../umdf_driver/WUDFOsrUsbFx2.vcxproj | 4 +- .../umdf_driver/WUDFOsrUsbFx2.vcxproj.Filters | 8 +- .../umdf_filter/WUDFOsrUsbFilter.vcxproj | 4 +- .../umdf_filter/WUDFOsrUsbFilter.vcxproj.Filters | 8 +- .../umdf_filter/WUDFOsrUsbFilterOnUmFx2Driver.inx | 3 +- usb/umdf_filter_umdf/umdf_filter_umdf.sln | 66 +- usb/umdf_fx2/ReadMe.md | 343 + ...5-1C56-4807-ACCD-B28C09D37FF0.devicemetadata-ms | Bin 0 -> 105893 bytes usb/umdf_fx2/driver/ControlQueue.cpp | 564 ++ usb/umdf_fx2/driver/ControlQueue.h | 101 + usb/umdf_fx2/driver/Device.cpp | 2087 +++++ usb/umdf_fx2/driver/Device.h | 604 ++ usb/umdf_fx2/driver/Driver.cpp | 220 + usb/umdf_fx2/driver/Driver.h | 149 + usb/umdf_fx2/driver/OsrUsbFx2.ctl | 1 + usb/umdf_fx2/driver/OsrUsbFx2.rc | 21 + usb/umdf_fx2/driver/ReadWriteQueue.cpp | 425 + usb/umdf_fx2/driver/ReadWriteQueue.h | 163 + usb/umdf_fx2/driver/WUDFOsrUsbFx2.inx | 115 + usb/umdf_fx2/driver/WUDFOsrUsbFx2.vcxproj | 319 + usb/umdf_fx2/driver/WUDFOsrUsbFx2.vcxproj.Filters | 60 + usb/umdf_fx2/driver/comsup.cpp | 344 + usb/umdf_fx2/driver/comsup.h | 215 + usb/umdf_fx2/driver/dllsup.cpp | 202 + usb/umdf_fx2/driver/exports.def | 4 + usb/umdf_fx2/driver/internal.h | 170 + usb/umdf_fx2/driver/queue.cpp | 147 + usb/umdf_fx2/driver/queue.h | 93 + usb/umdf_fx2/exe/WudfOsrUsbFx2Test.vcxproj | 212 + usb/umdf_fx2/exe/WudfOsrUsbFx2Test.vcxproj.Filters | 30 + usb/umdf_fx2/exe/dump.c | 444 + usb/umdf_fx2/exe/testapp.c | 1360 +++ usb/umdf_fx2/exe/testapp.rc | 13 + usb/umdf_fx2/inc/WUDFOsrUsbPublic.h | 32 + usb/umdf_fx2/inc/list.h | 77 + usb/umdf_fx2/inc/public.h | 217 + usb/umdf_fx2/inc/usb_hw.h | 233 + usb/umdf_fx2/umdf_fx2.sln | 46 + usb/usbview/usbview.htm | 400 + usb/usbview/usbview.sln | 18 +- usb/usbview/usbview.vcxproj | 4 +- usb/usbview/usbview.vcxproj.Filters | 6 +- video/KMDOD/KMDOD.sln | 28 - video/KMDOD/ReadMe.md | 71 - video/KMDOD/Sample/SampleDisplay.vcxproj | 198 - video/KMDOD/Sample/SampleDisplay.vcxproj.Filters | 49 - video/KMDOD/Sample/sampledisplay.inf | Bin 5754 -> 0 bytes video/KMDOD/bdd.cxx | 856 -- video/KMDOD/bdd.hxx | 649 -- video/KMDOD/bdd_ddi.cxx | 579 -- video/KMDOD/bdd_dmm.cxx | 1083 --- video/KMDOD/bdd_errorlog.hxx | 84 - video/KMDOD/bdd_util.cxx | 115 - video/KMDOD/bltfuncs.cxx | 346 - video/KMDOD/blthw.cxx | 556 -- video/KMDOD/memory.cxx | 78 - video/KMDOD/sampledisplay.rc | 30 - video/pixlib/PixLib.vcxproj | 4 +- video/pixlib/PixLib.vcxproj.Filters | 6 +- video/pixlib/pixlib.sln | 18 +- wmi/wmiacpi/ReadMe.md | 54 - wmi/wmiacpi/wmiacpi.sln | 18 +- wmi/wmiacpi/wmiacpi/ReadMe.md | 54 + wmi/wmiacpi/wmiacpi/acpimof.vcxproj | 4 +- wmi/wmiacpi/wmiacpi/acpimof.vcxproj.Filters | 6 +- wmi/wmiacpi/wmiacpi/readme.htm | 228 + wmi/wmiacpi/wmiacpi/wmi-acpi.htm | 1804 ++++ wmi/wmisamp/WmiSamp.vcxproj | 4 +- wmi/wmisamp/WmiSamp.vcxproj.Filters | 8 +- wmi/wmisamp/wmisamp.sln | 18 +- wpd/WpdBasicHardwareDriver/Device.cpp | 415 - wpd/WpdBasicHardwareDriver/Device.h | 89 - wpd/WpdBasicHardwareDriver/Driver.cpp | 197 - wpd/WpdBasicHardwareDriver/Driver.h | 44 - wpd/WpdBasicHardwareDriver/Queue.cpp | 340 - wpd/WpdBasicHardwareDriver/Queue.h | 93 - wpd/WpdBasicHardwareDriver/RS232Connection.cpp | 316 - wpd/WpdBasicHardwareDriver/RS232Connection.h | 153 - wpd/WpdBasicHardwareDriver/RS232Target.cpp | 433 - wpd/WpdBasicHardwareDriver/RS232Target.h | 53 - wpd/WpdBasicHardwareDriver/ReadMe.md | 43 - wpd/WpdBasicHardwareDriver/Stdafxsrc.cpp | 1 - wpd/WpdBasicHardwareDriver/WpdBaseDriver.cpp | 506 -- wpd/WpdBasicHardwareDriver/WpdBaseDriver.h | 69 - .../WpdBasicHardwareDriver.cpp | 60 - .../WpdBasicHardwareDriver.def | 9 - .../WpdBasicHardwareDriver.idl | 24 - .../WpdBasicHardwareDriver.inx | 81 - .../WpdBasicHardwareDriver.rc | 15 - .../WpdBasicHardwareDriver.rgs | 26 - .../WpdBasicHardwareDriver.sln | 28 - .../WpdBasicHardwareDriver.vcxproj | 341 - .../WpdBasicHardwareDriver.vcxproj.Filters | 75 - wpd/WpdBasicHardwareDriver/WpdCapabilities.cpp | 505 -- wpd/WpdBasicHardwareDriver/WpdCapabilities.h | 41 - wpd/WpdBasicHardwareDriver/WpdObjectEnum.cpp | 431 - wpd/WpdBasicHardwareDriver/WpdObjectEnum.h | 107 - wpd/WpdBasicHardwareDriver/WpdObjectProperties.cpp | 1314 --- wpd/WpdBasicHardwareDriver/WpdObjectProperties.h | 111 - .../firmware/compass_wpd_enabled.bs2 | 94 - .../firmware/flex_force_wpd_enabled.bs2 | 60 - .../firmware/h48c_3-axis_wpd_enabled.bs2 | 175 - .../firmware/memsic2125_wpd_enabled.bs2 | 107 - .../firmware/piezo_wpd_enabled.bs2 | 55 - .../firmware/ping_wpd_enabled.bs2 | 57 - .../firmware/pir_wpd_enabled.bs2 | 50 - .../firmware/qti_wpd_enabled.bs2 | 63 - .../firmware/temp_humidity_wpd_enabled.bs2 | 225 - wpd/WpdBasicHardwareDriver/resource.h | 3 - wpd/WpdBasicHardwareDriver/stdafx.h | 320 - wpd/WpdHelloWorldDriver/WpdHelloWorldDriver.htm | 536 ++ wpd/WpdHelloWorldDriver/WpdHelloWorldDriver.sln | 18 +- .../WpdHelloWorldDriver.vcxproj | 4 +- .../WpdHelloWorldDriver.vcxproj.Filters | 8 +- .../WpdMultiTransportDriver.htm | 535 ++ .../WpdMultiTransportDriver.sln | 18 +- .../WpdMultiTransportDriver.vcxproj | 4 +- .../WpdMultiTransportDriver.vcxproj.Filters | 8 +- .../WpdServiceSampleDriver.sln | 18 +- .../WpdServiceSampleDriver.vcxproj | 4 +- .../WpdServiceSampleDriver.vcxproj.Filters | 8 +- wpd/WpdWudfSampleDriver/WpdWudfSampleDriver.htm | 496 ++ wpd/WpdWudfSampleDriver/WpdWudfSampleDriver.sln | 18 +- .../WpdWudfSampleDriver.vcxproj | 4 +- .../WpdWudfSampleDriver.vcxproj.Filters | 8 +- 1190 files changed, 232492 insertions(+), 36138 deletions(-) delete mode 100644 avstream/avshws/ReadMe.md delete mode 100644 avstream/avshws/avshws.h delete mode 100644 avstream/avshws/avshws.htm delete mode 100644 avstream/avshws/avshws.inf delete mode 100644 avstream/avshws/avshws.rc delete mode 100644 avstream/avshws/avshws.sln delete mode 100644 avstream/avshws/avshws.vcxproj delete mode 100644 avstream/avshws/avshws.vcxproj.Filters delete mode 100644 avstream/avshws/capture.cpp delete mode 100644 avstream/avshws/capture.h delete mode 100644 avstream/avshws/device.cpp delete mode 100644 avstream/avshws/device.h delete mode 100644 avstream/avshws/filter.cpp delete mode 100644 avstream/avshws/filter.h delete mode 100644 avstream/avshws/hwsim.cpp delete mode 100644 avstream/avshws/hwsim.h delete mode 100644 avstream/avshws/image.cpp delete mode 100644 avstream/avshws/image.h delete mode 100644 avstream/avshws/purecall.c create mode 100644 bluetooth/bthecho/ReadMe.md create mode 100644 bluetooth/bthecho/bthcli/app/BthEcho.vcxproj create mode 100644 bluetooth/bthecho/bthcli/app/BthEcho.vcxproj.Filters create mode 100644 bluetooth/bthecho/bthcli/app/main.cpp create mode 100644 bluetooth/bthecho/bthcli/sys/BthEchoSampleCli.inx create mode 100644 bluetooth/bthecho/bthcli/sys/BthEchoSampleCli.vcxproj create mode 100644 bluetooth/bthecho/bthcli/sys/BthEchoSampleCli.vcxproj.Filters create mode 100644 bluetooth/bthecho/bthcli/sys/client.c create mode 100644 bluetooth/bthecho/bthcli/sys/client.h create mode 100644 bluetooth/bthecho/bthcli/sys/device.c create mode 100644 bluetooth/bthecho/bthcli/sys/device.h create mode 100644 bluetooth/bthecho/bthcli/sys/driver.c create mode 100644 bluetooth/bthecho/bthcli/sys/driver.h create mode 100644 bluetooth/bthecho/bthcli/sys/queue.c create mode 100644 bluetooth/bthecho/bthcli/sys/queue.h create mode 100644 bluetooth/bthecho/bthecho.htm create mode 100644 bluetooth/bthecho/bthecho.sln create mode 100644 bluetooth/bthecho/bthsrv/inst/bthsrvinst.vcxproj create mode 100644 bluetooth/bthecho/bthsrv/inst/bthsrvinst.vcxproj.Filters create mode 100644 bluetooth/bthecho/bthsrv/inst/main.cpp create mode 100644 bluetooth/bthecho/bthsrv/sys/BthEchoSampleSrv.inx create mode 100644 bluetooth/bthecho/bthsrv/sys/BthEchoSampleSrv.vcxproj create mode 100644 bluetooth/bthecho/bthsrv/sys/BthEchoSampleSrv.vcxproj.Filters create mode 100644 bluetooth/bthecho/bthsrv/sys/device.c create mode 100644 bluetooth/bthecho/bthsrv/sys/device.h create mode 100644 bluetooth/bthecho/bthsrv/sys/driver.c create mode 100644 bluetooth/bthecho/bthsrv/sys/driver.h create mode 100644 bluetooth/bthecho/bthsrv/sys/echo.c create mode 100644 bluetooth/bthecho/bthsrv/sys/echo.h create mode 100644 bluetooth/bthecho/bthsrv/sys/sdp.c create mode 100644 bluetooth/bthecho/bthsrv/sys/sdp.h create mode 100644 bluetooth/bthecho/bthsrv/sys/server.c create mode 100644 bluetooth/bthecho/bthsrv/sys/server.h create mode 100644 bluetooth/bthecho/common/inc/clisrv.h create mode 100644 bluetooth/bthecho/common/inc/connection.h create mode 100644 bluetooth/bthecho/common/inc/public.h create mode 100644 bluetooth/bthecho/common/inc/trace.h create mode 100644 bluetooth/bthecho/common/lib/bthecho.vcxproj create mode 100644 bluetooth/bthecho/common/lib/bthecho.vcxproj.Filters create mode 100644 bluetooth/bthecho/common/lib/clisrv.c create mode 100644 bluetooth/bthecho/common/lib/connection.c create mode 100644 bluetooth/serialhcibus/BluetoothHCISampleBusDriver.htm create mode 100644 filesys/miniFilter/NameChanger/NameChanger.inf create mode 100644 filesys/miniFilter/NameChanger/NameChanger.sln create mode 100644 filesys/miniFilter/NameChanger/NameChanger.vcxproj create mode 100644 filesys/miniFilter/NameChanger/NameChanger.vcxproj.Filters create mode 100644 filesys/miniFilter/NameChanger/ReadMe.md create mode 100644 filesys/miniFilter/NameChanger/nc.c create mode 100644 filesys/miniFilter/NameChanger/nc.h create mode 100644 filesys/miniFilter/NameChanger/nc.rc create mode 100644 filesys/miniFilter/NameChanger/nccompat.c create mode 100644 filesys/miniFilter/NameChanger/nccontext.c create mode 100644 filesys/miniFilter/NameChanger/nccreate.c create mode 100644 filesys/miniFilter/NameChanger/ncdirenum.c create mode 100644 filesys/miniFilter/NameChanger/ncdirnotify.c create mode 100644 filesys/miniFilter/NameChanger/ncfileinfo.c create mode 100644 filesys/miniFilter/NameChanger/ncfsctrl.c create mode 100644 filesys/miniFilter/NameChanger/nchelper.c create mode 100644 filesys/miniFilter/NameChanger/ncinit.c create mode 100644 filesys/miniFilter/NameChanger/ncmapping.c create mode 100644 filesys/miniFilter/NameChanger/ncnameprov.c create mode 100644 filesys/miniFilter/NameChanger/ncoffsets.c create mode 100644 filesys/miniFilter/NameChanger/ncpath.c create mode 100644 general/SystemDma/wdm/systemdma.htm create mode 100644 general/cancel/cancel.htm create mode 100644 general/event/event.htm create mode 100644 general/ioctl/wdm/ioctl.htm create mode 100644 general/perfcounters/kcs/kcs.htm create mode 100644 general/toaster/toastpkg/toastpkg.htm delete mode 100644 general/toaster/umdf2/Package/package.VcxProj delete mode 100644 general/toaster/umdf2/Package/package.VcxProj.Filters delete mode 100644 general/toaster/umdf2/ReadMe.md delete mode 100644 general/toaster/umdf2/exe/enum/Enum.vcxproj delete mode 100644 general/toaster/umdf2/exe/enum/Enum.vcxproj.Filters delete mode 100644 general/toaster/umdf2/exe/enum/enum.c delete mode 100644 general/toaster/umdf2/exe/notify/notify.c delete mode 100644 general/toaster/umdf2/exe/notify/notify.h delete mode 100644 general/toaster/umdf2/exe/notify/notify.rc delete mode 100644 general/toaster/umdf2/exe/notify/notify.vcxproj delete mode 100644 general/toaster/umdf2/exe/notify/notify.vcxproj.Filters delete mode 100644 general/toaster/umdf2/exe/notify/toaster.ico delete mode 100644 general/toaster/umdf2/exe/toast/toast.c delete mode 100644 general/toaster/umdf2/exe/toast/toast.vcxproj delete mode 100644 general/toaster/umdf2/exe/toast/toast.vcxproj.Filters delete mode 100644 general/toaster/umdf2/filter/generic/filter.c delete mode 100644 general/toaster/umdf2/filter/generic/filter.h delete mode 100644 general/toaster/umdf2/filter/generic/filter.rc delete mode 100644 general/toaster/umdf2/filter/generic/filterum.inx delete mode 100644 general/toaster/umdf2/filter/generic/filterum.vcxproj delete mode 100644 general/toaster/umdf2/filter/generic/filterum.vcxproj.Filters delete mode 100644 general/toaster/umdf2/func/featured/power.c delete mode 100644 general/toaster/umdf2/func/featured/toaster.c delete mode 100644 general/toaster/umdf2/func/featured/toaster.rc delete mode 100644 general/toaster/umdf2/func/featured/wdffeaturedum.inx delete mode 100644 general/toaster/umdf2/func/featured/wdffeaturedum.vcxproj delete mode 100644 general/toaster/umdf2/func/featured/wdffeaturedum.vcxproj.Filters delete mode 100644 general/toaster/umdf2/func/shared/toaster.h delete mode 100644 general/toaster/umdf2/func/simple/toaster.c delete mode 100644 general/toaster/umdf2/func/simple/wdfsimpleum.inx delete mode 100644 general/toaster/umdf2/func/simple/wdfsimpleum.vcxproj delete mode 100644 general/toaster/umdf2/func/simple/wdfsimpleum.vcxproj.Filters delete mode 100644 general/toaster/umdf2/inc/driver.h delete mode 100644 general/toaster/umdf2/inc/public.h delete mode 100644 general/toaster/umdf2/umdf2toaster.sln create mode 100644 general/tracing/evntdrv/evntdrv.htm create mode 100644 general/tracing/tracedriver/tracedrv.htm create mode 100644 hid/hclient/ReadMe.md create mode 100644 hid/hclient/buffers.c create mode 100644 hid/hclient/buffers.h create mode 100644 hid/hclient/ecdisp.c create mode 100644 hid/hclient/ecdisp.h create mode 100644 hid/hclient/hclient.c create mode 100644 hid/hclient/hclient.h create mode 100644 hid/hclient/hclient.htm create mode 100644 hid/hclient/hclient.mk create mode 100644 hid/hclient/hclient.rc create mode 100644 hid/hclient/hclient.sln create mode 100644 hid/hclient/hclient.vcxproj create mode 100644 hid/hclient/hclient.vcxproj.Filters create mode 100644 hid/hclient/hid.h create mode 100644 hid/hclient/list.h create mode 100644 hid/hclient/pnp.c create mode 100644 hid/hclient/report.c create mode 100644 hid/hclient/resource.h create mode 100644 hid/hclient/strings.c create mode 100644 hid/hclient/strings.h create mode 100644 hid/vhidmini2/ReadMe.md create mode 100644 hid/vhidmini2/app/testvhid.c create mode 100644 hid/vhidmini2/app/testvhid.rc create mode 100644 hid/vhidmini2/app/testvhid.vcxproj create mode 100644 hid/vhidmini2/app/testvhid.vcxproj.Filters create mode 100644 hid/vhidmini2/driver/kmdf/util.c create mode 100644 hid/vhidmini2/driver/kmdf/vhidmini.inx create mode 100644 hid/vhidmini2/driver/kmdf/vhidmini.rc create mode 100644 hid/vhidmini2/driver/kmdf/vhidmini.vcxproj create mode 100644 hid/vhidmini2/driver/kmdf/vhidmini.vcxproj.Filters create mode 100644 hid/vhidmini2/driver/umdf2/VhidminiUm.inx create mode 100644 hid/vhidmini2/driver/umdf2/VhidminiUm.vcxproj create mode 100644 hid/vhidmini2/driver/umdf2/VhidminiUm.vcxproj.Filters create mode 100644 hid/vhidmini2/driver/umdf2/util.c create mode 100644 hid/vhidmini2/driver/umdf2/vhidmini.rc create mode 100644 hid/vhidmini2/driver/vhidmini.c create mode 100644 hid/vhidmini2/driver/vhidmini.h create mode 100644 hid/vhidmini2/inc/common.h create mode 100644 hid/vhidmini2/vhidmini2.sln create mode 100644 network/modem/fakemodem/fakemodem.htm create mode 100644 network/ndis/filter/filter.htm create mode 100644 network/ndis/ndisprot/6x/ndisprot.htm create mode 100644 network/radio/HidSwitchDriverSample/HidSwitchDriverSample.sln create mode 100644 network/radio/HidSwitchDriverSample/READFIRST_InstructionsForDevelopingHIDDriver.htm create mode 100644 network/radio/HidSwitchDriverSample/README.htm create mode 100644 network/radio/HidSwitchDriverSample/RadioSwitchHidUsbFx2.h create mode 100644 network/radio/HidSwitchDriverSample/RadioSwitchHidUsbFx2.inx create mode 100644 network/radio/HidSwitchDriverSample/RadioSwitchHidUsbFx2.rc create mode 100644 network/radio/HidSwitchDriverSample/RadioSwitchHidUsbFx2.vcxproj create mode 100644 network/radio/HidSwitchDriverSample/RadioSwitchHidUsbFx2.vcxproj.Filters create mode 100644 network/radio/HidSwitchDriverSample/ReadMe.md create mode 100644 network/radio/HidSwitchDriverSample/driver.c create mode 100644 network/radio/HidSwitchDriverSample/hid.c create mode 100644 network/radio/HidSwitchDriverSample/trace.h create mode 100644 network/radio/HidSwitchDriverSample/usb.c create mode 100644 network/radio/RadioManagerSample/RadioManagerSample.sln create mode 100644 network/radio/RadioManagerSample/ReadMe.md create mode 100644 network/radio/RadioManagerSample/SampleRM.reg create mode 100644 network/radio/RadioManagerSample/cpp/InternalInterfaces.h create mode 100644 network/radio/RadioManagerSample/cpp/RadioMgr.idl create mode 100644 network/radio/RadioManagerSample/cpp/RadioMgr_interface.cpp create mode 100644 network/radio/RadioManagerSample/cpp/SampleInstanceCollection.cpp create mode 100644 network/radio/RadioManagerSample/cpp/SampleInstanceCollection.h create mode 100644 network/radio/RadioManagerSample/cpp/SampleRM.def create mode 100644 network/radio/RadioManagerSample/cpp/SampleRM.rc create mode 100644 network/radio/RadioManagerSample/cpp/SampleRM.vcxproj create mode 100644 network/radio/RadioManagerSample/cpp/SampleRM.vcxproj.Filters create mode 100644 network/radio/RadioManagerSample/cpp/SampleRadioInstance.cpp create mode 100644 network/radio/RadioManagerSample/cpp/SampleRadioInstance.h create mode 100644 network/radio/RadioManagerSample/cpp/SampleRadioManager.cpp create mode 100644 network/radio/RadioManagerSample/cpp/SampleRadioManager.h create mode 100644 network/radio/RadioManagerSample/cpp/dllmain.cpp create mode 100644 network/radio/RadioManagerSample/cpp/precomp.h create mode 100644 network/radio/RadioManagerSample/cpp/precompsrc.cpp create mode 100644 network/radio/RadioManagerSample/cpp/sampleRM.idl create mode 100644 network/radio/RadioManagerSample/install.cmd create mode 100644 network/radio/RadioManagerSample/readme.txt create mode 100644 nfp/net/NetNfpProvider.htm create mode 100644 print/XPSDrvSmpl/Package/package.VcxProj create mode 100644 print/XPSDrvSmpl/Package/package.VcxProj.Filters create mode 100644 print/XPSDrvSmpl/ReadMe.md create mode 100644 print/XPSDrvSmpl/XPSDrvSmpl.sln create mode 100644 print/XPSDrvSmpl/install/xdCMYKPrinter.icc create mode 100644 print/XPSDrvSmpl/install/xdbook.gpd create mode 100644 print/XPSDrvSmpl/install/xdcolman.gpd create mode 100644 print/XPSDrvSmpl/install/xdnames.gpd create mode 100644 print/XPSDrvSmpl/install/xdnup.gpd create mode 100644 print/XPSDrvSmpl/install/xdpgscl.gpd create mode 100644 print/XPSDrvSmpl/install/xdsmpl-PipelineConfig.xml create mode 100644 print/XPSDrvSmpl/install/xdsmpl.gpd create mode 100644 print/XPSDrvSmpl/install/xdsmpl.inf create mode 100644 print/XPSDrvSmpl/install/xdsmpl.ini create mode 100644 print/XPSDrvSmpl/install/xdwmark.gpd create mode 100644 print/XPSDrvSmpl/install/xdwscRGB.icc create mode 100644 print/XPSDrvSmpl/readme.txt create mode 100644 print/XPSDrvSmpl/src/common/bkdata.h create mode 100644 print/XPSDrvSmpl/src/common/bkpchndlr.cpp create mode 100644 print/XPSDrvSmpl/src/common/bkpchndlr.h create mode 100644 print/XPSDrvSmpl/src/common/bkpthndlr.cpp create mode 100644 print/XPSDrvSmpl/src/common/bkpthndlr.h create mode 100644 print/XPSDrvSmpl/src/common/bkschema.cpp create mode 100644 print/XPSDrvSmpl/src/common/bkschema.h create mode 100644 print/XPSDrvSmpl/src/common/cmdata.h create mode 100644 print/XPSDrvSmpl/src/common/cmintentsdata.h create mode 100644 print/XPSDrvSmpl/src/common/cmintentsschema.cpp create mode 100644 print/XPSDrvSmpl/src/common/cmintentsschema.h create mode 100644 print/XPSDrvSmpl/src/common/cmintpthndlr.cpp create mode 100644 print/XPSDrvSmpl/src/common/cmintpthndlr.h create mode 100644 print/XPSDrvSmpl/src/common/cmprofiledata.h create mode 100644 print/XPSDrvSmpl/src/common/cmprofileschema.cpp create mode 100644 print/XPSDrvSmpl/src/common/cmprofileschema.h create mode 100644 print/XPSDrvSmpl/src/common/cmprofpchndlr.cpp create mode 100644 print/XPSDrvSmpl/src/common/cmprofpchndlr.h create mode 100644 print/XPSDrvSmpl/src/common/cmprofpthndlr.cpp create mode 100644 print/XPSDrvSmpl/src/common/cmprofpthndlr.h create mode 100644 print/XPSDrvSmpl/src/common/cmpthndlr.cpp create mode 100644 print/XPSDrvSmpl/src/common/cmpthndlr.h create mode 100644 print/XPSDrvSmpl/src/common/cmschema.cpp create mode 100644 print/XPSDrvSmpl/src/common/cmschema.h create mode 100644 print/XPSDrvSmpl/src/common/globals.cpp create mode 100644 print/XPSDrvSmpl/src/common/globals.h create mode 100644 print/XPSDrvSmpl/src/common/nupchndlr.cpp create mode 100644 print/XPSDrvSmpl/src/common/nupchndlr.h create mode 100644 print/XPSDrvSmpl/src/common/nupdata.h create mode 100644 print/XPSDrvSmpl/src/common/nupschema.cpp create mode 100644 print/XPSDrvSmpl/src/common/nupschema.h create mode 100644 print/XPSDrvSmpl/src/common/nupthndlr.cpp create mode 100644 print/XPSDrvSmpl/src/common/nupthndlr.h create mode 100644 print/XPSDrvSmpl/src/common/pchndlr.cpp create mode 100644 print/XPSDrvSmpl/src/common/pchndlr.h create mode 100644 print/XPSDrvSmpl/src/common/pgscdata.h create mode 100644 print/XPSDrvSmpl/src/common/pgscpchndlr.cpp create mode 100644 print/XPSDrvSmpl/src/common/pgscpchndlr.h create mode 100644 print/XPSDrvSmpl/src/common/pgscpthndlr.cpp create mode 100644 print/XPSDrvSmpl/src/common/pgscpthndlr.h create mode 100644 print/XPSDrvSmpl/src/common/pgscschema.cpp create mode 100644 print/XPSDrvSmpl/src/common/pgscschema.h create mode 100644 print/XPSDrvSmpl/src/common/pimagedata.h create mode 100644 print/XPSDrvSmpl/src/common/pimagepthndlr.cpp create mode 100644 print/XPSDrvSmpl/src/common/pimagepthndlr.h create mode 100644 print/XPSDrvSmpl/src/common/pimageschema.cpp create mode 100644 print/XPSDrvSmpl/src/common/pimageschema.h create mode 100644 print/XPSDrvSmpl/src/common/porientdata.h create mode 100644 print/XPSDrvSmpl/src/common/porientpthndlr.cpp create mode 100644 print/XPSDrvSmpl/src/common/porientpthndlr.h create mode 100644 print/XPSDrvSmpl/src/common/porientschema.cpp create mode 100644 print/XPSDrvSmpl/src/common/porientschema.h create mode 100644 print/XPSDrvSmpl/src/common/precomp.h create mode 100644 print/XPSDrvSmpl/src/common/precompsrc.cpp create mode 100644 print/XPSDrvSmpl/src/common/privatedefs.h create mode 100644 print/XPSDrvSmpl/src/common/pshndlr.cpp create mode 100644 print/XPSDrvSmpl/src/common/pshndlr.h create mode 100644 print/XPSDrvSmpl/src/common/psizedata.h create mode 100644 print/XPSDrvSmpl/src/common/psizepthndlr.cpp create mode 100644 print/XPSDrvSmpl/src/common/psizepthndlr.h create mode 100644 print/XPSDrvSmpl/src/common/psizeschema.cpp create mode 100644 print/XPSDrvSmpl/src/common/psizeschema.h create mode 100644 print/XPSDrvSmpl/src/common/pthndlr.cpp create mode 100644 print/XPSDrvSmpl/src/common/pthndlr.h create mode 100644 print/XPSDrvSmpl/src/common/ptquerybld.cpp create mode 100644 print/XPSDrvSmpl/src/common/ptquerybld.h create mode 100644 print/XPSDrvSmpl/src/common/schema.cpp create mode 100644 print/XPSDrvSmpl/src/common/schema.h create mode 100644 print/XPSDrvSmpl/src/common/wmdata.h create mode 100644 print/XPSDrvSmpl/src/common/wmpchndlr.cpp create mode 100644 print/XPSDrvSmpl/src/common/wmpchndlr.h create mode 100644 print/XPSDrvSmpl/src/common/wmpthndlr.cpp create mode 100644 print/XPSDrvSmpl/src/common/wmpthndlr.h create mode 100644 print/XPSDrvSmpl/src/common/wmschema.cpp create mode 100644 print/XPSDrvSmpl/src/common/wmschema.h create mode 100644 print/XPSDrvSmpl/src/common/workbuff.cpp create mode 100644 print/XPSDrvSmpl/src/common/workbuff.h create mode 100644 print/XPSDrvSmpl/src/common/xdsmplcmn.vcxproj create mode 100644 print/XPSDrvSmpl/src/common/xdsmplcmn.vcxproj.Filters create mode 100644 print/XPSDrvSmpl/src/filters/booklet/bkflt.cpp create mode 100644 print/XPSDrvSmpl/src/filters/booklet/bkflt.h create mode 100644 print/XPSDrvSmpl/src/filters/booklet/bkflt.rc create mode 100644 print/XPSDrvSmpl/src/filters/booklet/bkprps.cpp create mode 100644 print/XPSDrvSmpl/src/filters/booklet/bkprps.h create mode 100644 print/XPSDrvSmpl/src/filters/booklet/bksax.cpp create mode 100644 print/XPSDrvSmpl/src/filters/booklet/bksax.h create mode 100644 print/XPSDrvSmpl/src/filters/booklet/dllentry.cpp create mode 100644 print/XPSDrvSmpl/src/filters/booklet/precompsrc.cpp create mode 100644 print/XPSDrvSmpl/src/filters/booklet/xdbook.def create mode 100644 print/XPSDrvSmpl/src/filters/booklet/xdbook.vcxproj create mode 100644 print/XPSDrvSmpl/src/filters/booklet/xdbook.vcxproj.Filters create mode 100644 print/XPSDrvSmpl/src/filters/color/XDColMan.def create mode 100644 print/XPSDrvSmpl/src/filters/color/XDColMan.vcxproj create mode 100644 print/XPSDrvSmpl/src/filters/color/XDColMan.vcxproj.Filters create mode 100644 print/XPSDrvSmpl/src/filters/color/bmpconv.cpp create mode 100644 print/XPSDrvSmpl/src/filters/color/bmpconv.h create mode 100644 print/XPSDrvSmpl/src/filters/color/bmpdata.cpp create mode 100644 print/XPSDrvSmpl/src/filters/color/bmpdata.h create mode 100644 print/XPSDrvSmpl/src/filters/color/cmflt.cpp create mode 100644 print/XPSDrvSmpl/src/filters/color/cmflt.h create mode 100644 print/XPSDrvSmpl/src/filters/color/cmflt.rc create mode 100644 print/XPSDrvSmpl/src/filters/color/cmimg.cpp create mode 100644 print/XPSDrvSmpl/src/filters/color/cmimg.h create mode 100644 print/XPSDrvSmpl/src/filters/color/cmsax.cpp create mode 100644 print/XPSDrvSmpl/src/filters/color/cmsax.h create mode 100644 print/XPSDrvSmpl/src/filters/color/colchan.cpp create mode 100644 print/XPSDrvSmpl/src/filters/color/colchan.h create mode 100644 print/XPSDrvSmpl/src/filters/color/colconv.cpp create mode 100644 print/XPSDrvSmpl/src/filters/color/colconv.h create mode 100644 print/XPSDrvSmpl/src/filters/color/dictionary.cpp create mode 100644 print/XPSDrvSmpl/src/filters/color/dictionary.h create mode 100644 print/XPSDrvSmpl/src/filters/color/dllentry.cpp create mode 100644 print/XPSDrvSmpl/src/filters/color/precompsrc.cpp create mode 100644 print/XPSDrvSmpl/src/filters/color/profile.cpp create mode 100644 print/XPSDrvSmpl/src/filters/color/profile.h create mode 100644 print/XPSDrvSmpl/src/filters/color/profman.cpp create mode 100644 print/XPSDrvSmpl/src/filters/color/profman.h create mode 100644 print/XPSDrvSmpl/src/filters/color/scaniter.cpp create mode 100644 print/XPSDrvSmpl/src/filters/color/scaniter.h create mode 100644 print/XPSDrvSmpl/src/filters/color/transform.cpp create mode 100644 print/XPSDrvSmpl/src/filters/color/transform.h create mode 100644 print/XPSDrvSmpl/src/filters/color/wcsapiconv.cpp create mode 100644 print/XPSDrvSmpl/src/filters/color/wcsapiconv.h create mode 100644 print/XPSDrvSmpl/src/filters/color/wictobmscn.cpp create mode 100644 print/XPSDrvSmpl/src/filters/color/wictobmscn.h create mode 100644 print/XPSDrvSmpl/src/filters/common/clasfact.h create mode 100644 print/XPSDrvSmpl/src/filters/common/precompsrc.cpp create mode 100644 print/XPSDrvSmpl/src/filters/common/ptmanage.cpp create mode 100644 print/XPSDrvSmpl/src/filters/common/ptmanage.h create mode 100644 print/XPSDrvSmpl/src/filters/common/rescache.cpp create mode 100644 print/XPSDrvSmpl/src/filters/common/rescache.h create mode 100644 print/XPSDrvSmpl/src/filters/common/rescpy.cpp create mode 100644 print/XPSDrvSmpl/src/filters/common/rescpy.h create mode 100644 print/XPSDrvSmpl/src/filters/common/saxhndlr.cpp create mode 100644 print/XPSDrvSmpl/src/filters/common/saxhndlr.h create mode 100644 print/XPSDrvSmpl/src/filters/common/widetoutf8.cpp create mode 100644 print/XPSDrvSmpl/src/filters/common/widetoutf8.h create mode 100644 print/XPSDrvSmpl/src/filters/common/xdfltcmn.vcxproj create mode 100644 print/XPSDrvSmpl/src/filters/common/xdfltcmn.vcxproj.Filters create mode 100644 print/XPSDrvSmpl/src/filters/common/xdrchflt.cpp create mode 100644 print/XPSDrvSmpl/src/filters/common/xdrchflt.h create mode 100644 print/XPSDrvSmpl/src/filters/common/xdsmplflt.cpp create mode 100644 print/XPSDrvSmpl/src/filters/common/xdsmplflt.h create mode 100644 print/XPSDrvSmpl/src/filters/common/xdstrmflt.cpp create mode 100644 print/XPSDrvSmpl/src/filters/common/xdstrmflt.h create mode 100644 print/XPSDrvSmpl/src/filters/nup/dllentry.cpp create mode 100644 print/XPSDrvSmpl/src/filters/nup/nupflt.cpp create mode 100644 print/XPSDrvSmpl/src/filters/nup/nupflt.h create mode 100644 print/XPSDrvSmpl/src/filters/nup/nupflt.rc create mode 100644 print/XPSDrvSmpl/src/filters/nup/nuppage.cpp create mode 100644 print/XPSDrvSmpl/src/filters/nup/nuppage.h create mode 100644 print/XPSDrvSmpl/src/filters/nup/nupsax.cpp create mode 100644 print/XPSDrvSmpl/src/filters/nup/nupsax.h create mode 100644 print/XPSDrvSmpl/src/filters/nup/nuptprps.cpp create mode 100644 print/XPSDrvSmpl/src/filters/nup/nuptprps.h create mode 100644 print/XPSDrvSmpl/src/filters/nup/nupxform.cpp create mode 100644 print/XPSDrvSmpl/src/filters/nup/nupxform.h create mode 100644 print/XPSDrvSmpl/src/filters/nup/precompsrc.cpp create mode 100644 print/XPSDrvSmpl/src/filters/nup/xdnup.def create mode 100644 print/XPSDrvSmpl/src/filters/nup/xdnup.vcxproj create mode 100644 print/XPSDrvSmpl/src/filters/nup/xdnup.vcxproj.Filters create mode 100644 print/XPSDrvSmpl/src/filters/precomp.h create mode 100644 print/XPSDrvSmpl/src/filters/scaling/dllentry.cpp create mode 100644 print/XPSDrvSmpl/src/filters/scaling/pagescale.cpp create mode 100644 print/XPSDrvSmpl/src/filters/scaling/pagescale.h create mode 100644 print/XPSDrvSmpl/src/filters/scaling/pgscptprop.cpp create mode 100644 print/XPSDrvSmpl/src/filters/scaling/pgscptprop.h create mode 100644 print/XPSDrvSmpl/src/filters/scaling/precompsrc.cpp create mode 100644 print/XPSDrvSmpl/src/filters/scaling/scaleflt.cpp create mode 100644 print/XPSDrvSmpl/src/filters/scaling/scaleflt.h create mode 100644 print/XPSDrvSmpl/src/filters/scaling/scaleflt.rc create mode 100644 print/XPSDrvSmpl/src/filters/scaling/scalesax.cpp create mode 100644 print/XPSDrvSmpl/src/filters/scaling/scalesax.h create mode 100644 print/XPSDrvSmpl/src/filters/scaling/xdscale.def create mode 100644 print/XPSDrvSmpl/src/filters/scaling/xdscale.vcxproj create mode 100644 print/XPSDrvSmpl/src/filters/scaling/xdscale.vcxproj.Filters create mode 100644 print/XPSDrvSmpl/src/filters/watermark/Raster1.png create mode 100644 print/XPSDrvSmpl/src/filters/watermark/Vector1.xps create mode 100644 print/XPSDrvSmpl/src/filters/watermark/dllentry.cpp create mode 100644 print/XPSDrvSmpl/src/filters/watermark/precompsrc.cpp create mode 100644 print/XPSDrvSmpl/src/filters/watermark/wmbase.cpp create mode 100644 print/XPSDrvSmpl/src/filters/watermark/wmbase.h create mode 100644 print/XPSDrvSmpl/src/filters/watermark/wmflt.cpp create mode 100644 print/XPSDrvSmpl/src/filters/watermark/wmflt.h create mode 100644 print/XPSDrvSmpl/src/filters/watermark/wmflt.rc create mode 100644 print/XPSDrvSmpl/src/filters/watermark/wmfont.cpp create mode 100644 print/XPSDrvSmpl/src/filters/watermark/wmfont.h create mode 100644 print/XPSDrvSmpl/src/filters/watermark/wmimg.cpp create mode 100644 print/XPSDrvSmpl/src/filters/watermark/wmimg.h create mode 100644 print/XPSDrvSmpl/src/filters/watermark/wmptprop.cpp create mode 100644 print/XPSDrvSmpl/src/filters/watermark/wmptprop.h create mode 100644 print/XPSDrvSmpl/src/filters/watermark/wmrast.cpp create mode 100644 print/XPSDrvSmpl/src/filters/watermark/wmrast.h create mode 100644 print/XPSDrvSmpl/src/filters/watermark/wmres.h create mode 100644 print/XPSDrvSmpl/src/filters/watermark/wmsax.cpp create mode 100644 print/XPSDrvSmpl/src/filters/watermark/wmsax.h create mode 100644 print/XPSDrvSmpl/src/filters/watermark/wmtext.cpp create mode 100644 print/XPSDrvSmpl/src/filters/watermark/wmtext.h create mode 100644 print/XPSDrvSmpl/src/filters/watermark/wmvect.cpp create mode 100644 print/XPSDrvSmpl/src/filters/watermark/wmvect.h create mode 100644 print/XPSDrvSmpl/src/filters/watermark/wmxps.cpp create mode 100644 print/XPSDrvSmpl/src/filters/watermark/wmxps.h create mode 100644 print/XPSDrvSmpl/src/filters/watermark/xdwmark.def create mode 100644 print/XPSDrvSmpl/src/filters/watermark/xdwmark.vcxproj create mode 100644 print/XPSDrvSmpl/src/filters/watermark/xdwmark.vcxproj.Filters create mode 100644 print/XPSDrvSmpl/src/filters/xdcont/precompsrc.cpp create mode 100644 print/XPSDrvSmpl/src/filters/xdcont/xdcont.vcxproj create mode 100644 print/XPSDrvSmpl/src/filters/xdcont/xdcont.vcxproj.Filters create mode 100644 print/XPSDrvSmpl/src/filters/xdcont/xps.h create mode 100644 print/XPSDrvSmpl/src/filters/xdcont/xpsarch.cpp create mode 100644 print/XPSDrvSmpl/src/filters/xdcont/xpsarch.h create mode 100644 print/XPSDrvSmpl/src/filters/xdcont/xpsfd.cpp create mode 100644 print/XPSDrvSmpl/src/filters/xdcont/xpsfd.h create mode 100644 print/XPSDrvSmpl/src/filters/xdcont/xpsfds.cpp create mode 100644 print/XPSDrvSmpl/src/filters/xdcont/xpsfds.h create mode 100644 print/XPSDrvSmpl/src/filters/xdcont/xpsfiler.cpp create mode 100644 print/XPSDrvSmpl/src/filters/xdcont/xpsfiler.h create mode 100644 print/XPSDrvSmpl/src/filters/xdcont/xpsfilew.cpp create mode 100644 print/XPSDrvSmpl/src/filters/xdcont/xpsfilew.h create mode 100644 print/XPSDrvSmpl/src/filters/xdcont/xpsproc.cpp create mode 100644 print/XPSDrvSmpl/src/filters/xdcont/xpsproc.h create mode 100644 print/XPSDrvSmpl/src/filters/xdcont/xpsrels.cpp create mode 100644 print/XPSDrvSmpl/src/filters/xdcont/xpsrels.h create mode 100644 print/XPSDrvSmpl/src/filters/xdcont/xpstype.cpp create mode 100644 print/XPSDrvSmpl/src/filters/xdcont/xpstype.h create mode 100644 print/XPSDrvSmpl/src/inc/cunknown.h create mode 100644 print/XPSDrvSmpl/src/inc/gdip.h create mode 100644 print/XPSDrvSmpl/src/inc/ipkarch.h create mode 100644 print/XPSDrvSmpl/src/inc/ipkfile.h create mode 100644 print/XPSDrvSmpl/src/inc/streamcnv.h create mode 100644 print/XPSDrvSmpl/src/inc/xdexcept.h create mode 100644 print/XPSDrvSmpl/src/inc/xdstring.h create mode 100644 print/XPSDrvSmpl/src/ui/bkdmptcnv.cpp create mode 100644 print/XPSDrvSmpl/src/ui/bkdmptcnv.h create mode 100644 print/XPSDrvSmpl/src/ui/colctrls.cpp create mode 100644 print/XPSDrvSmpl/src/ui/colctrls.h create mode 100644 print/XPSDrvSmpl/src/ui/coldmptcnv.cpp create mode 100644 print/XPSDrvSmpl/src/ui/coldmptcnv.h create mode 100644 print/XPSDrvSmpl/src/ui/colppg.cpp create mode 100644 print/XPSDrvSmpl/src/ui/colppg.h create mode 100644 print/XPSDrvSmpl/src/ui/devmode.h create mode 100644 print/XPSDrvSmpl/src/ui/dllentry.cpp create mode 100644 print/XPSDrvSmpl/src/ui/docppg.cpp create mode 100644 print/XPSDrvSmpl/src/ui/docppg.h create mode 100644 print/XPSDrvSmpl/src/ui/ftrctrls.cpp create mode 100644 print/XPSDrvSmpl/src/ui/ftrctrls.h create mode 100644 print/XPSDrvSmpl/src/ui/ftrdmptcnv.h create mode 100644 print/XPSDrvSmpl/src/ui/ftrppg.cpp create mode 100644 print/XPSDrvSmpl/src/ui/ftrppg.h create mode 100644 print/XPSDrvSmpl/src/ui/nupptcnv.cpp create mode 100644 print/XPSDrvSmpl/src/ui/nupptcnv.h create mode 100644 print/XPSDrvSmpl/src/ui/pgscdmptcnv.cpp create mode 100644 print/XPSDrvSmpl/src/ui/pgscdmptcnv.h create mode 100644 print/XPSDrvSmpl/src/ui/precomp.h create mode 100644 print/XPSDrvSmpl/src/ui/precompsrc.cpp create mode 100644 print/XPSDrvSmpl/src/ui/resource.h create mode 100644 print/XPSDrvSmpl/src/ui/uictrl.cpp create mode 100644 print/XPSDrvSmpl/src/ui/uictrl.h create mode 100644 print/XPSDrvSmpl/src/ui/uiproperties.cpp create mode 100644 print/XPSDrvSmpl/src/ui/uiproperties.h create mode 100644 print/XPSDrvSmpl/src/ui/wmctrls.cpp create mode 100644 print/XPSDrvSmpl/src/ui/wmctrls.h create mode 100644 print/XPSDrvSmpl/src/ui/wmdmptcnv.cpp create mode 100644 print/XPSDrvSmpl/src/ui/wmdmptcnv.h create mode 100644 print/XPSDrvSmpl/src/ui/wmppg.cpp create mode 100644 print/XPSDrvSmpl/src/ui/wmppg.h create mode 100644 print/XPSDrvSmpl/src/ui/xdsmplcf.cpp create mode 100644 print/XPSDrvSmpl/src/ui/xdsmplcf.h create mode 100644 print/XPSDrvSmpl/src/ui/xdsmpldlg.rc create mode 100644 print/XPSDrvSmpl/src/ui/xdsmplptprov.cpp create mode 100644 print/XPSDrvSmpl/src/ui/xdsmplptprov.h create mode 100644 print/XPSDrvSmpl/src/ui/xdsmplui.cpp create mode 100644 print/XPSDrvSmpl/src/ui/xdsmplui.def create mode 100644 print/XPSDrvSmpl/src/ui/xdsmplui.h create mode 100644 print/XPSDrvSmpl/src/ui/xdsmplui.vcxproj create mode 100644 print/XPSDrvSmpl/src/ui/xdsmplui.vcxproj.Filters create mode 100644 print/autoconfig/ACnfgPS.gdl create mode 100644 print/autoconfig/ACnfgUni.GDL create mode 100644 print/autoconfig/AutoCnfg.GPD create mode 100644 print/autoconfig/AutoCnfg.PPD create mode 100644 print/autoconfig/AutoCnfg.inf create mode 100644 print/autoconfig/AutoConfig.htm create mode 100644 print/autoconfig/AutoConfig.sln create mode 100644 print/autoconfig/AutoConfig.vcxproj create mode 100644 print/autoconfig/AutoConfig.vcxproj.Filters create mode 100644 print/autoconfig/Package/package.VcxProj create mode 100644 print/autoconfig/Package/package.VcxProj.Filters create mode 100644 print/autoconfig/ReadMe.md create mode 100644 print/cpsuisam/cpsui.htm create mode 100644 print/v4PrintDriverSamples/v4PrintDriver-HostBasedSampleDriver/HostBasedSampleDriver.sln create mode 100644 print/v4PrintDriverSamples/v4PrintDriver-HostBasedSampleDriver/HostBasedSampleDriver.vcxproj create mode 100644 print/v4PrintDriverSamples/v4PrintDriver-HostBasedSampleDriver/HostBasedSampleDriver.vcxproj.Filters create mode 100644 print/v4PrintDriverSamples/v4PrintDriver-HostBasedSampleDriver/Package/package.VcxProj create mode 100644 print/v4PrintDriverSamples/v4PrintDriver-HostBasedSampleDriver/Package/package.VcxProj.Filters create mode 100644 print/v4PrintDriverSamples/v4PrintDriver-HostBasedSampleDriver/ReadMe.md create mode 100644 print/v4PrintDriverSamples/v4PrintDriver-HostBasedSampleDriver/usb_host_based_sample-manifest.ini create mode 100644 print/v4PrintDriverSamples/v4PrintDriver-HostBasedSampleDriver/usb_host_based_sample-pipelineconfig.xml create mode 100644 print/v4PrintDriverSamples/v4PrintDriver-HostBasedSampleDriver/usb_host_based_sample.gpd create mode 100644 print/v4PrintDriverSamples/v4PrintDriver-HostBasedSampleDriver/usb_host_based_sample.inf create mode 100644 print/v4PrintDriverSamples/v4PrintDriver-HostBasedSampleDriver/usb_host_based_sample.js create mode 100644 print/v4PrintDriverSamples/v4PrintDriver-HostBasedSampleDriver/usb_host_based_sample_events.xml create mode 100644 print/v4PrintDriverSamples/v4PrintDriver-HostBasedSampleDriver/usb_host_based_sample_extension.xml create mode 100644 print/v4PrintDriverSamples/v4PrintDriver-HostBasedSampleDriver/v4PrintDriver-Intellisense-Windows8.1.js create mode 100644 print/v4PrintDriverSamples/v4PrintDriver-HostBasedSampleDriver/v4PrintDriver-Intellisense.js create mode 100644 sd/miniport/sdhc/README.md create mode 100644 sd/miniport/sdhc/inbox/sdhc.vcxproj create mode 100644 sd/miniport/sdhc/inbox/sdhc.vcxproj.Filters create mode 100644 sd/miniport/sdhc/sdhc.c create mode 100644 sd/miniport/sdhc/sdhc.h create mode 100644 sd/miniport/sdhc/sdhc.inx create mode 100644 sd/miniport/sdhc/sdhc.rc create mode 100644 sd/miniport/sdhc/sdhc.sln create mode 100644 sd/sdiomars/sdiosample.htm create mode 100644 security/elam/elamsample.htm create mode 100644 serial/VirtualSerial2/ComPort/VirtualSerial2um.vcxproj create mode 100644 serial/VirtualSerial2/ComPort/VirtualSerial2um.vcxproj.Filters create mode 100644 serial/VirtualSerial2/ComPort/virtualserial2um.inx create mode 100644 serial/VirtualSerial2/ComPort/virtualserial2um.rc create mode 100644 serial/VirtualSerial2/FakeModem/fakemodem2um.inx create mode 100644 serial/VirtualSerial2/FakeModem/fakemodem2um.rc create mode 100644 serial/VirtualSerial2/FakeModem/fakemodem2um.vcxproj create mode 100644 serial/VirtualSerial2/FakeModem/fakemodem2um.vcxproj.Filters create mode 100644 serial/VirtualSerial2/ReadMe.md create mode 100644 serial/VirtualSerial2/VirtualSerial.sln create mode 100644 serial/VirtualSerial2/device.c create mode 100644 serial/VirtualSerial2/device.h create mode 100644 serial/VirtualSerial2/driver.c create mode 100644 serial/VirtualSerial2/driver.h create mode 100644 serial/VirtualSerial2/internal.h create mode 100644 serial/VirtualSerial2/queue.c create mode 100644 serial/VirtualSerial2/queue.h create mode 100644 serial/VirtualSerial2/ringbuffer.c create mode 100644 serial/VirtualSerial2/ringbuffer.h create mode 100644 serial/VirtualSerial2/serial.h create mode 100644 serial/serenum/serenum.htm create mode 100644 setup/devcon/devcon.htm create mode 100644 smartcrd/ReadMe.md create mode 100644 smartcrd/pscr/Pscr.vcxproj create mode 100644 smartcrd/pscr/Pscr.vcxproj.Filters create mode 100644 smartcrd/pscr/pscr.htm create mode 100644 smartcrd/pscr/pscr.inx create mode 100644 smartcrd/pscr/pscr.rc create mode 100644 smartcrd/pscr/pscrcb.c create mode 100644 smartcrd/pscr/pscrcb.h create mode 100644 smartcrd/pscr/pscrcmd.c create mode 100644 smartcrd/pscr/pscrcmd.h create mode 100644 smartcrd/pscr/pscrlog.mc create mode 100644 smartcrd/pscr/pscrnt.c create mode 100644 smartcrd/pscr/pscrnt.h create mode 100644 smartcrd/pscr/pscrrdwr.c create mode 100644 smartcrd/pscr/pscrrdwr.h create mode 100644 smartcrd/pscr/pscrvers.h create mode 100644 smartcrd/smartcrd.sln create mode 100644 spb/SpbTestTool/SpbTestTool.htm create mode 100644 storage/class/cdrom/ReadMe.md create mode 100644 storage/class/cdrom/cdrom.sln create mode 100644 storage/class/cdrom/src/aacs.c create mode 100644 storage/class/cdrom/src/autorun.c create mode 100644 storage/class/cdrom/src/cdrom.c create mode 100644 storage/class/cdrom/src/cdrom.h create mode 100644 storage/class/cdrom/src/cdrom.htm create mode 100644 storage/class/cdrom/src/cdrom.inf create mode 100644 storage/class/cdrom/src/cdrom.rc create mode 100644 storage/class/cdrom/src/cdrom.vcxproj create mode 100644 storage/class/cdrom/src/cdrom.vcxproj.Filters create mode 100644 storage/class/cdrom/src/cdromp.h create mode 100644 storage/class/cdrom/src/common.c create mode 100644 storage/class/cdrom/src/data.c create mode 100644 storage/class/cdrom/src/guid.c create mode 100644 storage/class/cdrom/src/init.c create mode 100644 storage/class/cdrom/src/ioctl.c create mode 100644 storage/class/cdrom/src/ioctl.h create mode 100644 storage/class/cdrom/src/localwpp.ini create mode 100644 storage/class/cdrom/src/mmc.c create mode 100644 storage/class/cdrom/src/mmc.h create mode 100644 storage/class/cdrom/src/pnppower.c create mode 100644 storage/class/cdrom/src/scratch.c create mode 100644 storage/class/cdrom/src/scratch.h create mode 100644 storage/class/cdrom/src/sense.c create mode 100644 storage/class/cdrom/src/zpodd.c create mode 100644 storage/class/disk/ReadMe.md create mode 100644 storage/class/disk/disk.sln create mode 100644 storage/class/disk/src/data.c create mode 100644 storage/class/disk/src/disk.c create mode 100644 storage/class/disk/src/disk.h create mode 100644 storage/class/disk/src/disk.htm create mode 100644 storage/class/disk/src/disk.rc create mode 100644 storage/class/disk/src/disk.vcxproj create mode 100644 storage/class/disk/src/disk.vcxproj.Filters create mode 100644 storage/class/disk/src/diskdev.inf create mode 100644 storage/class/disk/src/diskwmi.c create mode 100644 storage/class/disk/src/enum.c create mode 100644 storage/class/disk/src/geometry.c create mode 100644 storage/class/disk/src/pnp.c create mode 100644 storage/ramdisk/ReadMe.md create mode 100644 storage/ramdisk/ramdisk.sln create mode 100644 storage/ramdisk/src/WdfRamdisk.vcxproj create mode 100644 storage/ramdisk/src/WdfRamdisk.vcxproj.Filters create mode 100644 storage/ramdisk/src/forward_progress.c create mode 100644 storage/ramdisk/src/forward_progress.h create mode 100644 storage/ramdisk/src/ramdisk.c create mode 100644 storage/ramdisk/src/ramdisk.h create mode 100644 storage/ramdisk/src/ramdisk.inx create mode 100644 storage/ramdisk/src/ramdisk.rc delete mode 100644 usb/umdf_filter_kmdf/Package/package.VcxProj delete mode 100644 usb/umdf_filter_kmdf/Package/package.VcxProj.Filters delete mode 100644 usb/umdf_filter_kmdf/ReadMe.md delete mode 100644 usb/umdf_filter_kmdf/inc/WUDFOsrUsbPublic.h delete mode 100644 usb/umdf_filter_kmdf/inc/list.h delete mode 100644 usb/umdf_filter_kmdf/inc/public.h delete mode 100644 usb/umdf_filter_kmdf/inc/usb_hw.h delete mode 100644 usb/umdf_filter_kmdf/kmdf_driver/Device.c delete mode 100644 usb/umdf_filter_kmdf/kmdf_driver/bulkrwr.c delete mode 100644 usb/umdf_filter_kmdf/kmdf_driver/driver.c delete mode 100644 usb/umdf_filter_kmdf/kmdf_driver/interrupt.c delete mode 100644 usb/umdf_filter_kmdf/kmdf_driver/ioctl.c delete mode 100644 usb/umdf_filter_kmdf/kmdf_driver/osrusbfx2.h delete mode 100644 usb/umdf_filter_kmdf/kmdf_driver/osrusbfx2.man delete mode 100644 usb/umdf_filter_kmdf/kmdf_driver/osrusbfx2.rc delete mode 100644 usb/umdf_filter_kmdf/kmdf_driver/osrusbfx2.vcxproj delete mode 100644 usb/umdf_filter_kmdf/kmdf_driver/osrusbfx2.vcxproj.Filters delete mode 100644 usb/umdf_filter_kmdf/kmdf_driver/trace.h delete mode 100644 usb/umdf_filter_kmdf/umdf_filter/OsrUsbFilter.rc delete mode 100644 usb/umdf_filter_kmdf/umdf_filter/WUDFOsrUsbFilter.vcxproj delete mode 100644 usb/umdf_filter_kmdf/umdf_filter/WUDFOsrUsbFilter.vcxproj.Filters delete mode 100644 usb/umdf_filter_kmdf/umdf_filter/WUDFOsrUsbFilterOnKmDriver.inx delete mode 100644 usb/umdf_filter_kmdf/umdf_filter/comsup.cpp delete mode 100644 usb/umdf_filter_kmdf/umdf_filter/comsup.h delete mode 100644 usb/umdf_filter_kmdf/umdf_filter/device.cpp delete mode 100644 usb/umdf_filter_kmdf/umdf_filter/device.h delete mode 100644 usb/umdf_filter_kmdf/umdf_filter/dllsup.cpp delete mode 100644 usb/umdf_filter_kmdf/umdf_filter/driver.cpp delete mode 100644 usb/umdf_filter_kmdf/umdf_filter/driver.h delete mode 100644 usb/umdf_filter_kmdf/umdf_filter/exports.def delete mode 100644 usb/umdf_filter_kmdf/umdf_filter/internal.h delete mode 100644 usb/umdf_filter_kmdf/umdf_filter/queue.cpp delete mode 100644 usb/umdf_filter_kmdf/umdf_filter/queue.h delete mode 100644 usb/umdf_filter_kmdf/umdf_filter_kmdf.sln create mode 100644 usb/umdf_fx2/ReadMe.md create mode 100644 usb/umdf_fx2/deviceMetadata/B4D697F5-1C56-4807-ACCD-B28C09D37FF0.devicemetadata-ms create mode 100644 usb/umdf_fx2/driver/ControlQueue.cpp create mode 100644 usb/umdf_fx2/driver/ControlQueue.h create mode 100644 usb/umdf_fx2/driver/Device.cpp create mode 100644 usb/umdf_fx2/driver/Device.h create mode 100644 usb/umdf_fx2/driver/Driver.cpp create mode 100644 usb/umdf_fx2/driver/Driver.h create mode 100644 usb/umdf_fx2/driver/OsrUsbFx2.ctl create mode 100644 usb/umdf_fx2/driver/OsrUsbFx2.rc create mode 100644 usb/umdf_fx2/driver/ReadWriteQueue.cpp create mode 100644 usb/umdf_fx2/driver/ReadWriteQueue.h create mode 100644 usb/umdf_fx2/driver/WUDFOsrUsbFx2.inx create mode 100644 usb/umdf_fx2/driver/WUDFOsrUsbFx2.vcxproj create mode 100644 usb/umdf_fx2/driver/WUDFOsrUsbFx2.vcxproj.Filters create mode 100644 usb/umdf_fx2/driver/comsup.cpp create mode 100644 usb/umdf_fx2/driver/comsup.h create mode 100644 usb/umdf_fx2/driver/dllsup.cpp create mode 100644 usb/umdf_fx2/driver/exports.def create mode 100644 usb/umdf_fx2/driver/internal.h create mode 100644 usb/umdf_fx2/driver/queue.cpp create mode 100644 usb/umdf_fx2/driver/queue.h create mode 100644 usb/umdf_fx2/exe/WudfOsrUsbFx2Test.vcxproj create mode 100644 usb/umdf_fx2/exe/WudfOsrUsbFx2Test.vcxproj.Filters create mode 100644 usb/umdf_fx2/exe/dump.c create mode 100644 usb/umdf_fx2/exe/testapp.c create mode 100644 usb/umdf_fx2/exe/testapp.rc create mode 100644 usb/umdf_fx2/inc/WUDFOsrUsbPublic.h create mode 100644 usb/umdf_fx2/inc/list.h create mode 100644 usb/umdf_fx2/inc/public.h create mode 100644 usb/umdf_fx2/inc/usb_hw.h create mode 100644 usb/umdf_fx2/umdf_fx2.sln create mode 100644 usb/usbview/usbview.htm delete mode 100644 video/KMDOD/KMDOD.sln delete mode 100644 video/KMDOD/ReadMe.md delete mode 100644 video/KMDOD/Sample/SampleDisplay.vcxproj delete mode 100644 video/KMDOD/Sample/SampleDisplay.vcxproj.Filters delete mode 100644 video/KMDOD/Sample/sampledisplay.inf delete mode 100644 video/KMDOD/bdd.cxx delete mode 100644 video/KMDOD/bdd.hxx delete mode 100644 video/KMDOD/bdd_ddi.cxx delete mode 100644 video/KMDOD/bdd_dmm.cxx delete mode 100644 video/KMDOD/bdd_errorlog.hxx delete mode 100644 video/KMDOD/bdd_util.cxx delete mode 100644 video/KMDOD/bltfuncs.cxx delete mode 100644 video/KMDOD/blthw.cxx delete mode 100644 video/KMDOD/memory.cxx delete mode 100644 video/KMDOD/sampledisplay.rc delete mode 100644 wmi/wmiacpi/ReadMe.md create mode 100644 wmi/wmiacpi/wmiacpi/ReadMe.md create mode 100644 wmi/wmiacpi/wmiacpi/readme.htm create mode 100644 wmi/wmiacpi/wmiacpi/wmi-acpi.htm delete mode 100644 wpd/WpdBasicHardwareDriver/Device.cpp delete mode 100644 wpd/WpdBasicHardwareDriver/Device.h delete mode 100644 wpd/WpdBasicHardwareDriver/Driver.cpp delete mode 100644 wpd/WpdBasicHardwareDriver/Driver.h delete mode 100644 wpd/WpdBasicHardwareDriver/Queue.cpp delete mode 100644 wpd/WpdBasicHardwareDriver/Queue.h delete mode 100644 wpd/WpdBasicHardwareDriver/RS232Connection.cpp delete mode 100644 wpd/WpdBasicHardwareDriver/RS232Connection.h delete mode 100644 wpd/WpdBasicHardwareDriver/RS232Target.cpp delete mode 100644 wpd/WpdBasicHardwareDriver/RS232Target.h delete mode 100644 wpd/WpdBasicHardwareDriver/ReadMe.md delete mode 100644 wpd/WpdBasicHardwareDriver/Stdafxsrc.cpp delete mode 100644 wpd/WpdBasicHardwareDriver/WpdBaseDriver.cpp delete mode 100644 wpd/WpdBasicHardwareDriver/WpdBaseDriver.h delete mode 100644 wpd/WpdBasicHardwareDriver/WpdBasicHardwareDriver.cpp delete mode 100644 wpd/WpdBasicHardwareDriver/WpdBasicHardwareDriver.def delete mode 100644 wpd/WpdBasicHardwareDriver/WpdBasicHardwareDriver.idl delete mode 100644 wpd/WpdBasicHardwareDriver/WpdBasicHardwareDriver.inx delete mode 100644 wpd/WpdBasicHardwareDriver/WpdBasicHardwareDriver.rc delete mode 100644 wpd/WpdBasicHardwareDriver/WpdBasicHardwareDriver.rgs delete mode 100644 wpd/WpdBasicHardwareDriver/WpdBasicHardwareDriver.sln delete mode 100644 wpd/WpdBasicHardwareDriver/WpdBasicHardwareDriver.vcxproj delete mode 100644 wpd/WpdBasicHardwareDriver/WpdBasicHardwareDriver.vcxproj.Filters delete mode 100644 wpd/WpdBasicHardwareDriver/WpdCapabilities.cpp delete mode 100644 wpd/WpdBasicHardwareDriver/WpdCapabilities.h delete mode 100644 wpd/WpdBasicHardwareDriver/WpdObjectEnum.cpp delete mode 100644 wpd/WpdBasicHardwareDriver/WpdObjectEnum.h delete mode 100644 wpd/WpdBasicHardwareDriver/WpdObjectProperties.cpp delete mode 100644 wpd/WpdBasicHardwareDriver/WpdObjectProperties.h delete mode 100644 wpd/WpdBasicHardwareDriver/firmware/compass_wpd_enabled.bs2 delete mode 100644 wpd/WpdBasicHardwareDriver/firmware/flex_force_wpd_enabled.bs2 delete mode 100644 wpd/WpdBasicHardwareDriver/firmware/h48c_3-axis_wpd_enabled.bs2 delete mode 100644 wpd/WpdBasicHardwareDriver/firmware/memsic2125_wpd_enabled.bs2 delete mode 100644 wpd/WpdBasicHardwareDriver/firmware/piezo_wpd_enabled.bs2 delete mode 100644 wpd/WpdBasicHardwareDriver/firmware/ping_wpd_enabled.bs2 delete mode 100644 wpd/WpdBasicHardwareDriver/firmware/pir_wpd_enabled.bs2 delete mode 100644 wpd/WpdBasicHardwareDriver/firmware/qti_wpd_enabled.bs2 delete mode 100644 wpd/WpdBasicHardwareDriver/firmware/temp_humidity_wpd_enabled.bs2 delete mode 100644 wpd/WpdBasicHardwareDriver/resource.h delete mode 100644 wpd/WpdBasicHardwareDriver/stdafx.h create mode 100644 wpd/WpdHelloWorldDriver/WpdHelloWorldDriver.htm create mode 100644 wpd/WpdMultiTransportDriver/WpdMultiTransportDriver.htm create mode 100644 wpd/WpdWudfSampleDriver/WpdWudfSampleDriver.htm diff --git a/README.md b/README.md index fc7cdbe6..0866bc45 100644 --- a/README.md +++ b/README.md @@ -1,30 +1,30 @@ -# Driver samples for Windows 10 # -These are the official Microsoft Windows Driver Kit (WDK) team driver code samples for Windows 10. They provide a foundation for universal driver support of all hardware form factors, from phones to desktop PCs. Use these samples with Microsoft Visual Studio 2015 CTP 6, Microsoft Visual Studio Tools for Windows 10 Technical Preview, Windows SDK for Windows 10, and WDK 10. +# Driver samples for Windows 10 +These are the official Microsoft Windows Driver Kit (WDK) team driver code samples for Windows 10. They provide a foundation for Universal Windows Driver support of all hardware form factors, from phones to desktop PCs. Use these samples with Microsoft Visual Studio 2015 RC, Windows SDK for Windows 10, and WDK 10. -## Windows 10 driver development ## -Use Visual Studio 2015 CTP 6 and the the Windows 10 Driver Kit (WDK) to build, test, and deploy your drivers. With Windows 10, the driver development environment is integrated into Visual Studio. To get Windows 10 Technical Preview and the driver development kits and tools, join the Windows Insider Program. +## Windows 10 driver development +Use Visual Studio 2015 CTP 6 and the the Windows 10 Driver Kit (WDK) to build, test, and deploy your drivers. With Windows 10, the driver development environment is integrated into Visual Studio. To get Windows 10 Insider Preview and the driver development kits and tools, join the Windows Insider Program. [Become a Windows Insider](https://insider.windows.com/ "Become a Windows Insider") -### Windows 10 Driver Kit (WDK) ### +### Windows 10 Driver Kit (WDK) Take a look at the compilation of the new and changed driver-related content for Windows 10. Areas of improvement include camera, print, display, Near Field Communication (NFC), WLAN, Bluetooth, and more. [Find out what’s new in the WDK](http://go.microsoft.com/fwlink/?LinkId=528349 "Find out what’s new in the WDK") -### Universal drivers in Windows 10 ### +### Universal Windows Drivers Write one driver that runs on both Windows 10 for desktop editions and Windows 10 for mobile devices, as well as other Windows 10 editions that share a common set of interfaces. -[Build your universal drivers](http://go.microsoft.com/fwlink/p/?LinkId=524488 "Build your universal drivers") +[Getting Started with Universal Windows drivers](http://go.microsoft.com/fwlink/p/?LinkId=524488 "Getting Started with Universal Windows drivers") -### Windows Driver Frameworks ### +### Windows Driver Frameworks The Windows Driver Frameworks (WDF) are a set of libraries that make it simple to write high-quality device drivers. [WDF driver development guide](http://go.microsoft.com/fwlink/p/?LinkId=524489 "WDF driver development guide") -### Samples ### +### Samples Use the samples in this repo to guide your Windows driver development. Whether you’re just getting started or porting an older driver to the newest version of Windows, code samples are valuable guides on how to write drivers. -### Build your first driver ### +### Build your first driver If you're writing your first driver, use these exercises to get started. Each exercise is independent of the others, so you can do them in any order. [Write a UMDF driver based on a template](http://go.microsoft.com/fwlink/p/?LinkId=524492 "Write a UMDF driver based on a template") diff --git a/avstream/avshws/ReadMe.md b/avstream/avshws/ReadMe.md deleted file mode 100644 index be81c949..00000000 --- a/avstream/avshws/ReadMe.md +++ /dev/null @@ -1,10 +0,0 @@ -AVStream simulated hardware sample driver (Avshws) -================================================== - -The AVStream simulated hardware sample driver (Avshws) provides a pin-centric [AVStream](http://msdn.microsoft.com/en-us/library/windows/hardware/ff554240) capture driver for a simulated piece of hardware. This streaming media driver performs video captures at 320 x 240 pixels in either RGB24 or YUV422 format using direct memory access (DMA) into capture buffers. The purpose of the sample is to demonstrate how to write a pin-centric AVStream minidriver. The sample also shows how to implement DMA by using the related functionality provided by the AVStream class driver. - -This sample features enhanced parameter validation and overflow detection. - -## Universal Compliant -This sample builds a Windows Universal driver. It uses only APIs and DDIs that are included in Windows Core. - diff --git a/avstream/avshws/avshws.h b/avstream/avshws/avshws.h deleted file mode 100644 index 3647c1ac..00000000 --- a/avstream/avshws/avshws.h +++ /dev/null @@ -1,232 +0,0 @@ -/************************************************************************** - - AVStream Simulated Hardware Sample - - Copyright (c) 2001, Microsoft Corporation. - - File: - - avshws.h - - Abstract: - - AVStream Simulated Hardware Sample header file. This is the - main header. - - History: - - created 3/12/2001 - -**************************************************************************/ - -/************************************************* - - Standard Includes - -*************************************************/ - -#ifndef _avshws_h_ -#define _avshws_h_ - -extern "C" { -#include -} - -#include -#include -#include -#include -#include -#define NOBITMAP -#include -#undef NOBITMAP -#include -#include -#include -#include - -/************************************************* - - Misc Definitions - -*************************************************/ -#pragma warning (disable : 4100 4127 4131 4189 4701 4706) -#define STR_MODULENAME "avshws: " -#define DEBUGLVL_VERBOSE 2 -#define DEBUGLVL_TERSE 1 -#define DEBUGLVL_ERROR 0 - -const DebugLevel = DEBUGLVL_TERSE; - -#if (DBG) -#define _DbgPrintF(lvl, strings) \ -{ \ - if (lvl <= DebugLevel) {\ - DbgPrint(STR_MODULENAME);\ - DbgPrint##strings;\ - DbgPrint("\n");\ - if ((lvl) == DEBUGLVL_ERROR) {\ - NT_ASSERT(0);\ - } \ - }\ -} -#else // !DBG - #define _DbgPrintF(lvl, strings) -#endif // !DBG - -#define ABS(x) ((x) < 0 ? (-(x)) : (x)) - -#ifndef mmioFOURCC -#define mmioFOURCC( ch0, ch1, ch2, ch3 ) \ - ( (DWORD)(BYTE)(ch0) | ( (DWORD)(BYTE)(ch1) << 8 ) | \ - ( (DWORD)(BYTE)(ch2) << 16 ) | ( (DWORD)(BYTE)(ch3) << 24 ) ) -#endif - -#define FOURCC_YUY2 mmioFOURCC('Y', 'U', 'Y', '2') -// -// CAPTURE_PIN_DATA_RANGE_COUNT: -// -// The number of ranges supported on the capture pin. -// -#define CAPTURE_PIN_DATA_RANGE_COUNT 2 - -// -// CAPTURE_FILTER_PIN_COUNT: -// -// The number of pins on the capture filter. -// -#define CAPTURE_FILTER_PIN_COUNT 1 - -// -// CAPTURE_FILTER_CATEGORIES_COUNT: -// -// The number of categories for the capture filter. -// -#define CAPTURE_FILTER_CATEGORIES_COUNT 3 - -#define AVSHWS_POOLTAG 'hSVA' - -/************************************************* - - Externed information - -*************************************************/ -// -// filter.cpp externs: -// -extern -const -KSFILTER_DISPATCH -CaptureFilterDispatch; - -extern -const -KSFILTER_DESCRIPTOR -CaptureFilterDescriptor; - -extern -const -KSPIN_DESCRIPTOR_EX -CaptureFilterPinDescriptors [CAPTURE_FILTER_PIN_COUNT]; - -extern -const -GUID -CaptureFilterCategories [CAPTURE_FILTER_CATEGORIES_COUNT]; - -// -// capture.cpp externs: -// -extern -const -KSALLOCATOR_FRAMING_EX -CapturePinAllocatorFraming; - -extern -const -KSPIN_DISPATCH -CapturePinDispatch; - -extern -const -PKSDATARANGE -CapturePinDataRanges [CAPTURE_PIN_DATA_RANGE_COUNT]; - -/************************************************* - - Enums / Typedefs - -*************************************************/ - -typedef enum _HARDWARE_STATE { - - HardwareStopped = 0, - HardwarePaused, - HardwareRunning - -} HARDWARE_STATE, *PHARDWARE_STATE; - -/************************************************* - - Class Definitions - -*************************************************/ - -// -// IHardwareSink: -// -// This interface is used by the hardware simulation to fake interrupt -// service routines. The Interrupt method is called at DPC as a fake -// interrupt. -// -class IHardwareSink { - -public: - - virtual - void - Interrupt ( - ) = 0; - -}; - -// -// ICaptureSink: -// -// This is a capture sink interface. The device level calls back the -// CompleteMappings method passing the number of completed mappings for -// the capture pin. This method is called during the device DPC. -// -class ICaptureSink { - -public: - - virtual - void - CompleteMappings ( - IN ULONG NumMappings - ) = 0; - -}; - - - -/************************************************* - - Global Functions - -*************************************************/ - -/************************************************* - - Internal Includes - -*************************************************/ - -#include "image.h" -#include "hwsim.h" -#include "device.h" -#include "filter.h" -#include "capture.h" -#include -#endif //_avshws_h_ \ No newline at end of file diff --git a/avstream/avshws/avshws.htm b/avstream/avshws/avshws.htm deleted file mode 100644 index bd715e2c..00000000 --- a/avstream/avshws/avshws.htm +++ /dev/null @@ -1,458 +0,0 @@ - - - - - - - - -AVSHwS - - - - - - - -
- -

AVSHwS: AVStream Simulated -Hardware Sample Driver

- -

SUMMARY

- -

The AVSHwS sample provides a pin-centric AVStream capture driver for a simulated piece of hardware. The -driver performs captures at 320x240 in either an RGB24 or YUV422 format via -direct DMA into capture buffers. The purpose of the sample is to demonstrate -how to write a pin-centric AVStream minidriver. The sample also shows how to implement DMA by -using the related functionality provided by AVStream. 

- -

This sample features enhanced -parameter validation and overflow detection.

- - - -

BUILDING THE SAMPLE

- -

Build the sample by typing build -cez in either the standard -checked or free WDK build environment. A successful build produces AVSHwS.sys.

- -

The sample works on -32-bit x86 and 64-bit amd64 platforms running Vista Beta 2 or higher, Windows XP -SP2, Windows Server 2003 SP1 and Windows 2000 (If DirectX 8 or higher is -installed on the system)

- -

Installation -instructions:

- -
    -
  • Copy AVSHwS.sys and AVSHwS.INF to a directory
  • -
  • Open “Add Hardware” wizard from Control Panel
  • -
  • Select "Install the hardware that I manually - select from a list (Advanced)"
  • -
  • When you see "What type of hardware do you want - to install", select Sound, Video, and Game Controllers
  • -
  • Select "Have Disk..."
  • -
  • Browse to " AVSHwS.INF "
  • -
  • Follow the on screen instructions
  • -
- -

PROGRAMMING TOUR

- -

DriverEntry in device.cpp -is the initial point of entry. This routine passes control to AVStream through a call to KsInitializeDriver. -In this call, the minidriver passes the device -descriptor, an AVStream structure that recursively -defines the AVStream object hierarchy for a driver. -This is common behavior for an AVStream minidriver.

- -

At device start time (see -the CcaptureDevice::PnpStart method in device.cpp), a simulated piece of capture hardware -is created (the ChardwareSimulation class), a DMA adapter is acquired from the operating system and is -registered with AVStream through a call to KsDeviceRegisterAdapterObject. This call is required -for a sample that performs DMA directly into the capture buffers, instead of -using DMA to write to a common buffer. In PnPStart -the driver creates the KS Filter for this device dynamically by calling KsCreateFilterFactory.

- -

Filter.cpp is where the sample lays out the -KSPIN_DESCRIPTOR_EX structure for the single capture pin. In addition, a -KSFILTER_DISPATCH structure and a KSFILTER_DESCRIPTOR structure are provided in -this source file. The filter dispatch provides only a create dispatch, a -routine that is included in Filter.cpp. The -process dispatch is provided on the pin, since this is a pin-centric sample.

- -

Capture.cpp contains source for the video -capture pin on the capture filter. This is where the KSPIN_DISPATCH structure -for the unique pin is provided. This dispatch structure specifies a Process -callback routine, also defined in this source file. This routine is where -stream pointer manipulation and cloning occurs.

- -

The process callback is -one of two routines of interest in Capture.cpp -that demonstrate how to do DMA transfers using AVStream -functionality. The other is CCapturePin::CompleteMappings. -These two methods show how to use the queue, obtain clone pointers, use -scatter/gather lists, and perform other DMA-related tasks.

- -

Hwsim.cpp contains the hardware simulation -code and also code that fills the scatter/gather mappings. This source file -includes the Start, Pause and Stop methods for the hardware simulation class (CHardwaresimulation). Image synthesis and overlay code is -also here. The supplied objects provide image synthesis (pixel, color-bar, -etc...) to RGB24 and UYVY buffers as well as software string overlay into these -buffers. The Image.cpp file, including data, -must exist in locked segments.

- -

See comments in all .cpp files. Also see complete AVStream -documentation in the WDK documentation.

- -

RUNNING THE SAMPLE

- -

Once -installation is complete, access the driver through the graphedt -tool. Graphedt.exe -is available in the Tools directory of the WDK. In the Graphedt application, click the Graph menu and select -Insert Filters. The sample appears under "WDM Streaming Capture -Devices" as "avshws Source." Click -Insert Filter and the sample appears in the graph as a single filter labelled as ”avshws -Source”. There is one output pin which is the video capture pin. It sends out -video in YUY2 format. Attach this filter to either a DirectShow Video Renderer or the VMR default video renderer -and click Play.

- -

The output produced by -the sample is a 320x240 image of standard EIA-189-A color bars. In the middle -of the image near the bottom, a clock appears over the image. This clock -displays the elapsed time since the graph was introduced into the run state -following the last stop. The clock shows MINUTES:SECONDS.HUNDREDTHS. -

- -

In the top left corner of -the image, a counter counts the number of frames that have been dropped since -the graph was introduced into the run state after the last stop.

- -

COMMENTS

- -

For more -information on AVStream, see the WDK documentation.

- -

CODE TOUR

- -

File -Manifest

- -
File           Description
 
AVSHwS.htm     The Sample Tour documentation for this sample (this file).
Sources        The generic file for building the code sample.
AVSHwS.inf     A sample installation file.
AVSHwS.h       The main header file for the sample.
device.cpp     DriverEntry, Plug and Play handling, initialization, device level code.
device.h       Header file for above.
filter.cpp     Filter level code for the capture filter.
filter.h       Header file for above.
capture.cpp    Pin level code for the capture pin, DMA handling.
capture.h      Header file for above.
hwsim.cpp      Hardware simulation code, filling scatter/gather mappings, etc.
hwsim.h        Header file for above.
image.cpp      RGB24 and UYVY image synthesis and overlay code.
image.h        Header file for above.
purecall.c     Purecall stub for virtual function usage
AVSHwS.rc      Resource file mainly for version.
 
 
- - - - - -
-

 

-
- -
 
- -

© -2004- 2006 Microsoft Corporation -

- -
 
- -

 

- -
- - - - diff --git a/avstream/avshws/avshws.inf b/avstream/avshws/avshws.inf deleted file mode 100644 index 5bf66468..00000000 --- a/avstream/avshws/avshws.inf +++ /dev/null @@ -1,172 +0,0 @@ -;/*++ -; -;Copyright (c) Microsoft Corporation. All rights reserved. -; -; THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY -; KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE -; IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR -; PURPOSE. -; -;Module Name: -; -; AVSHWS.INF -; -;Abstract: -; -; -;AVStream pin centric sample mini driver (AVSHWS.sys) installation file. -;Supports x86, amd64, arm and arm64 platforms -; -;--*/ - -[Version] -signature="$WINDOWS NT$" -Class=Media -ClassGUID={4d36e96c-e325-11ce-bfc1-08002be10318} -Provider=%Msft% -Catalogfile=avshws.cat -DriverVer=08/31/2006,6.0.5600.0 - -[SourceDisksNames] -1000=%cdname%,,, - -[SourceDisksFiles] -avshws.sys=1000 - -[DestinationDirs] -DefaultDestDir=12 -avshws.CopyFiles=12 - -[avshws.CopyFiles] -avshws.sys - -[Manufacturer] -%Msft%=Microsoft,NTx86,NTamd64,ntarm,ntarm64 - -[Microsoft.NTx86] -%avshws.DeviceDesc%=avshws.NTx86,AVSHWS - -[Microsoft.NTamd64] -%avshws.DeviceDesc%=avshws.NTamd64,AVSHWS - -[Microsoft.NTarm] -%avshws.DeviceDesc%=avshws.NTarm,AVSHWS - -[Microsoft.NTarm64] -%avshws.DeviceDesc%=avshws.NTarm64,AVSHWS - -;--------------------------------------------------------------- -; x 86 D D I n s t a l l -;--------------------------------------------------------------- - -[avshws.NTx86] -Include=ks.inf, KSCAPTUR.inf -Needs=KS.Registration,KSCAPTUR.Registration.NT -CopyFiles=avshws.CopyFiles - -;--------------------------------------------------------------- -; A M D 64 D D I n s t a l l -;--------------------------------------------------------------- - -[avshws.NTamd64] -Include=ks.inf,KSCAPTUR.inf -Needs=KS.Registration,KSCAPTUR.Registration.NT -CopyFiles=avshws.CopyFiles - -;--------------------------------------------------------------- -; A R M D D I n s t a l l -;--------------------------------------------------------------- - -[avshws.NTarm] -Include=ks.inf,KSCAPTUR.inf -Needs=KS.Registration,KSCAPTUR.Registration.NT -CopyFiles=avshws.CopyFiles - -;--------------------------------------------------------------- -; A R M 64 D D I n s t a l l -;--------------------------------------------------------------- - -[avshws.NTarm64] -Include=ks.inf,KSCAPTUR.inf -Needs=KS.Registration,KSCAPTUR.Registration.NT -CopyFiles=avshws.CopyFiles - -;--------------------------------------------------------------- -; I n t e r f a c e s -;--------------------------------------------------------------- - -[avshws.NTx86.Interfaces] -AddInterface=%KSCATEGORY_CAPTURE%,"GLOBAL",CaptureInterface.NT,0 -AddInterface=%KSCATEGORY_VIDEO%,"GLOBAL",CaptureInterface.NT,0 -AddInterface=%KSCATEGORY_VIDEO_CAMERA%,"GLOBAL",CaptureInterface.NT,0 - -[avshws.NTamd64.Interfaces] -AddInterface=%KSCATEGORY_CAPTURE%,"GLOBAL",CaptureInterface.NT,0 -AddInterface=%KSCATEGORY_VIDEO%,"GLOBAL",CaptureInterface.NT,0 -AddInterface=%KSCATEGORY_VIDEO_CAMERA%,"GLOBAL",CaptureInterface.NT,0 - -[avshws.NTarm.Interfaces] -AddInterface=%KSCATEGORY_CAPTURE%,"GLOBAL",CaptureInterface.NT,0 -AddInterface=%KSCATEGORY_VIDEO%,"GLOBAL",CaptureInterface.NT,0 -AddInterface=%KSCATEGORY_VIDEO_CAMERA%,"GLOBAL",CaptureInterface.NT,0 - -[avshws.NTarm64.Interfaces] -AddInterface=%KSCATEGORY_CAPTURE%,"GLOBAL",CaptureInterface.NT,0 -AddInterface=%KSCATEGORY_VIDEO%,"GLOBAL",CaptureInterface.NT,0 -AddInterface=%KSCATEGORY_VIDEO_CAMERA%,"GLOBAL",CaptureInterface.NT,0 - -[CaptureInterface.NT] -AddReg=avshws.Reader.AddReg - -;--------------------------------------------------------------- -; A d d R e g -;--------------------------------------------------------------- - -[avshws.Reader.AddReg] -HKR,,CLSID,,%Proxy.CLSID% -HKR,,FriendlyName,,%avshws.Reader.FriendlyName% - -;--------------------------------------------------------------- -; S e r v i c e s -;--------------------------------------------------------------- - -[avshws.NTx86.Services] -AddService=avshws, 0x00000002, avshws.ServiceInstall - -[avshws.NTamd64.Services] -AddService=avshws, 0x00000002, avshws.ServiceInstall - -[avshws.NTarm.Services] -AddService=avshws, 0x00000002, avshws.ServiceInstall - -[avshws.NTarm64.Services] -AddService=avshws, 0x00000002, avshws.ServiceInstall - -[avshws.ServiceInstall] -DisplayName=%avshws.DeviceDesc% -ServiceType=%SERVICE_KERNEL_DRIVER% -StartType=%SERVICE_DEMAND_START% -ErrorControl=%SERVICE_ERROR_NORMAL% -ServiceBinary=%12%\avshws.sys - -;--------------------------------------------------------------- -; S t r i n g s -;--------------------------------------------------------------- - -[Strings] -; non-localizable -Proxy.CLSID="{17CCA71B-ECD7-11D0-B908-00A0C9223196}" -KSCATEGORY_CAPTURE="{65E8773D-8F56-11D0-A3B9-00A0C9223196}" -KSCATEGORY_VIDEO="{6994AD05-93EF-11D0-A3CC-00A0C9223196}" -KSCATEGORY_VIDEO_CAMERA="{E5323777-F976-4f5b-9B55-B94699C46E44}" - -SERVICE_KERNEL_DRIVER=1 -SERVICE_DEMAND_START=3 -SERVICE_ERROR_NORMAL=1 -REG_DWORD=0x00010001 - -;localizable -Msft="Microsoft" -avshws.DeviceDesc="AVStream Simulated Hardware Sample" -avshws.Reader.FriendlyName="avshws Source" -cdname="AVSHWS Installation Disk" \ No newline at end of file diff --git a/avstream/avshws/avshws.rc b/avstream/avshws/avshws.rc deleted file mode 100644 index 3e8a3e6a..00000000 --- a/avstream/avshws/avshws.rc +++ /dev/null @@ -1,22 +0,0 @@ -//+------------------------------------------------------------------------- -// -// Microsoft Windows -// -// Copyright (C) Microsoft Corporation, 1999 - 1999 -// -// File: captst.rc -// -//-------------------------------------------------------------------------- - -#include - -#include - -#define VER_FILETYPE VFT_DRV -#define VER_FILESUBTYPE VFT2_UNKNOWN -#define VER_FILEDESCRIPTION_STR "AVStream Simulated Hardware Sample" -#define VER_INTERNALNAME_STR "avshws.sys" -#define VER_ORIGINALFILENAME_STR "avshws.sys" - -#include "common.ver" - diff --git a/avstream/avshws/avshws.sln b/avstream/avshws/avshws.sln deleted file mode 100644 index 08896741..00000000 --- a/avstream/avshws/avshws.sln +++ /dev/null @@ -1,28 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2013 -VisualStudioVersion = 12.0 -MinimumVisualStudioVersion = 12.0 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "avshws", "avshws.vcxproj", "{A186D470-31E9-4CAF-9919-6279777D8ABD}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Release|Win32 = Release|Win32 - Debug|x64 = Debug|x64 - Release|x64 = Release|x64 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {A186D470-31E9-4CAF-9919-6279777D8ABD}.Debug|Win32.ActiveCfg = Debug|Win32 - {A186D470-31E9-4CAF-9919-6279777D8ABD}.Debug|Win32.Build.0 = Debug|Win32 - {A186D470-31E9-4CAF-9919-6279777D8ABD}.Release|Win32.ActiveCfg = Release|Win32 - {A186D470-31E9-4CAF-9919-6279777D8ABD}.Release|Win32.Build.0 = Release|Win32 - {A186D470-31E9-4CAF-9919-6279777D8ABD}.Debug|x64.ActiveCfg = Debug|x64 - {A186D470-31E9-4CAF-9919-6279777D8ABD}.Debug|x64.Build.0 = Debug|x64 - {A186D470-31E9-4CAF-9919-6279777D8ABD}.Release|x64.ActiveCfg = Release|x64 - {A186D470-31E9-4CAF-9919-6279777D8ABD}.Release|x64.Build.0 = Release|x64 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/avstream/avshws/avshws.vcxproj b/avstream/avshws/avshws.vcxproj deleted file mode 100644 index af274dcc..00000000 --- a/avstream/avshws/avshws.vcxproj +++ /dev/null @@ -1,201 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - {A186D470-31E9-4CAF-9919-6279777D8ABD} - $(MSBuildProjectName) - Debug - Win32 - {FBEB03DA-BEFF-446C-AF78-E7ED9881996F} - - - - Windows10 - False - Universal - WDM - WindowsKernelModeDriver10.0 - Driver - - - Windows10 - True - Universal - WDM - WindowsKernelModeDriver10.0 - Driver - - - Windows10 - False - Universal - WDM - WindowsKernelModeDriver10.0 - Driver - - - Windows10 - True - Universal - WDM - WindowsKernelModeDriver10.0 - Driver - - - - $(IntDir) - - - - - - - - - - - - - - - - avshws - - - avshws - - - avshws - - - avshws - - - - %(AdditionalDependencies);$(DDK_LIB_PATH)\ks.lib - %(AdditionalOptions) -merge:PAGECONST=PAGE - - - %(AdditionalIncludeDirectories);$(DDK_INC_PATH) - %(PreprocessorDefinitions);UNICODE;_UNICODE;DEBUG_LEVEL=DEBUGLVL_BLAB;_WIN2K_COMPAT_SLIST_USAGE;_NO_SYS_GUID_OPERATOR_EQ_ - - - %(AdditionalIncludeDirectories);$(DDK_INC_PATH) - true - Level4 - %(PreprocessorDefinitions);UNICODE;_UNICODE;DEBUG_LEVEL=DEBUGLVL_BLAB;_WIN2K_COMPAT_SLIST_USAGE;_NO_SYS_GUID_OPERATOR_EQ_ - - - - - %(AdditionalIncludeDirectories);$(DDK_INC_PATH) - %(PreprocessorDefinitions);UNICODE;_UNICODE;DEBUG_LEVEL=DEBUGLVL_BLAB;_WIN2K_COMPAT_SLIST_USAGE;_NO_SYS_GUID_OPERATOR_EQ_ - - - - - %(AdditionalDependencies);$(DDK_LIB_PATH)\ks.lib - %(AdditionalOptions) -merge:PAGECONST=PAGE - - - %(AdditionalIncludeDirectories);$(DDK_INC_PATH) - %(PreprocessorDefinitions);UNICODE;_UNICODE;DEBUG_LEVEL=DEBUGLVL_BLAB;_WIN2K_COMPAT_SLIST_USAGE;_NO_SYS_GUID_OPERATOR_EQ_ - - - %(AdditionalIncludeDirectories);$(DDK_INC_PATH) - true - Level4 - %(PreprocessorDefinitions);UNICODE;_UNICODE;DEBUG_LEVEL=DEBUGLVL_BLAB;_WIN2K_COMPAT_SLIST_USAGE;_NO_SYS_GUID_OPERATOR_EQ_ - - - - - %(AdditionalIncludeDirectories);$(DDK_INC_PATH) - %(PreprocessorDefinitions);UNICODE;_UNICODE;DEBUG_LEVEL=DEBUGLVL_BLAB;_WIN2K_COMPAT_SLIST_USAGE;_NO_SYS_GUID_OPERATOR_EQ_ - - - - - %(AdditionalDependencies);$(DDK_LIB_PATH)\ks.lib - %(AdditionalOptions) -merge:PAGECONST=PAGE - - - %(AdditionalIncludeDirectories);$(DDK_INC_PATH) - %(PreprocessorDefinitions);UNICODE;_UNICODE;DEBUG_LEVEL=DEBUGLVL_BLAB;_WIN2K_COMPAT_SLIST_USAGE;_NO_SYS_GUID_OPERATOR_EQ_ - - - %(AdditionalIncludeDirectories);$(DDK_INC_PATH) - true - Level4 - %(PreprocessorDefinitions);UNICODE;_UNICODE;DEBUG_LEVEL=DEBUGLVL_BLAB;_WIN2K_COMPAT_SLIST_USAGE;_NO_SYS_GUID_OPERATOR_EQ_ - - - - - %(AdditionalIncludeDirectories);$(DDK_INC_PATH) - %(PreprocessorDefinitions);UNICODE;_UNICODE;DEBUG_LEVEL=DEBUGLVL_BLAB;_WIN2K_COMPAT_SLIST_USAGE;_NO_SYS_GUID_OPERATOR_EQ_ - - - - - %(AdditionalDependencies);$(DDK_LIB_PATH)\ks.lib - %(AdditionalOptions) -merge:PAGECONST=PAGE - - - %(AdditionalIncludeDirectories);$(DDK_INC_PATH) - %(PreprocessorDefinitions);UNICODE;_UNICODE;DEBUG_LEVEL=DEBUGLVL_BLAB;_WIN2K_COMPAT_SLIST_USAGE;_NO_SYS_GUID_OPERATOR_EQ_ - - - %(AdditionalIncludeDirectories);$(DDK_INC_PATH) - true - Level4 - %(PreprocessorDefinitions);UNICODE;_UNICODE;DEBUG_LEVEL=DEBUGLVL_BLAB;_WIN2K_COMPAT_SLIST_USAGE;_NO_SYS_GUID_OPERATOR_EQ_ - - - - - %(AdditionalIncludeDirectories);$(DDK_INC_PATH) - %(PreprocessorDefinitions);UNICODE;_UNICODE;DEBUG_LEVEL=DEBUGLVL_BLAB;_WIN2K_COMPAT_SLIST_USAGE;_NO_SYS_GUID_OPERATOR_EQ_ - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/avstream/avshws/avshws.vcxproj.Filters b/avstream/avshws/avshws.vcxproj.Filters deleted file mode 100644 index 318e9d42..00000000 --- a/avstream/avshws/avshws.vcxproj.Filters +++ /dev/null @@ -1,46 +0,0 @@ - - - - - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {C2894B1A-8188-468F-AF01-0EAE14CD2040} - - - h;hpp;hxx;hm;inl;inc;xsd - {73B3B8CC-EA08-420A-AD92-489BAEEF0DE5} - - - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {A91E7CB8-3994-4C84-8CBA-0B18FA3FDD11} - - - inf;inv;inx;mof;mc; - {8C5EEC35-3838-457C-A60E-507C6503A48D} - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Resource Files - - - \ No newline at end of file diff --git a/avstream/avshws/capture.cpp b/avstream/avshws/capture.cpp deleted file mode 100644 index 5632a4a1..00000000 --- a/avstream/avshws/capture.cpp +++ /dev/null @@ -1,1704 +0,0 @@ -/************************************************************************** - - AVStream Simulated Hardware Sample - - Copyright (c) 2001, Microsoft Corporation. - - File: - - capture.cpp - - Abstract: - - This file contains source for the video capture pin on the capture - filter. The capture sample performs "fake" DMA directly into - the capture buffers. Common buffer DMA will work slightly differently. - - For common buffer DMA, the general technique would be DPC schedules - processing with KsPinAttemptProcessing. The processing routine grabs - the leading edge, copies data out of the common buffer and advances. - Cloning would not be necessary with this technique. It would be - similiar to the way "AVSSamp" works, but it would be pin-centric. - - History: - - created 3/8/2001 - -**************************************************************************/ - -#include "avshws.h" -#include -#include "ntintsafe.h" - -/************************************************************************** - - PAGEABLE CODE - -**************************************************************************/ - - -#ifdef ALLOC_PRAGMA -#pragma code_seg("PAGE") -#endif // ALLOC_PRAGMA - -#define DMAX_X 320 -#define DMAX_Y 240 -#define D_X 320 -#define D_Y 240 - -CCapturePin:: -CCapturePin ( - IN PKSPIN Pin - ) : - m_Pin (Pin) - ,m_PresentationTime (0) - -/*++ - -Routine Description: - - Construct a new capture pin. - -Arguments: - - Pin - - The AVStream pin object corresponding to the capture pin - -Return Value: - - None - ---*/ - -{ - - PAGED_CODE(); - - PKSDEVICE Device = KsPinGetDevice (Pin); - - // - // Set up our device pointer. This gives us access to "hardware I/O" - // during the capture routines. - // - m_Device = reinterpret_cast (Device -> Context); -} - -/*************************************************/ - - -NTSTATUS -CCapturePin:: -DispatchCreate ( - IN PKSPIN Pin, - IN PIRP Irp - ) - -/*++ - -Routine Description: - - Create a new capture pin. This is the creation dispatch for - the video capture pin. - -Arguments: - - Pin - - The pin being created - - Irp - - The creation Irp - -Return Value: - - Success / Failure - ---*/ - -{ - - PAGED_CODE(); - - NTSTATUS Status = STATUS_SUCCESS; - - CCapturePin *CapPin = new (NonPagedPool) CCapturePin (Pin); - - if (!CapPin) { - // - // Return failure if we couldn't create the pin. - // - Status = STATUS_INSUFFICIENT_RESOURCES; - - } else { - // - // Add the item to the object bag if we we were successful. - // Whenever the pin closes, the bag is cleaned up and we will be - // freed. - // - Status = KsAddItemToObjectBag ( - Pin -> Bag, - reinterpret_cast (CapPin), - reinterpret_cast (CCapturePin::Cleanup) - ); - - if (!NT_SUCCESS (Status)) { - delete CapPin; - } else { - Pin -> Context = reinterpret_cast (CapPin); - } - - } - - // - // If we succeeded so far, stash the video info header away and change - // our allocator framing to reflect the fact that only now do we know - // the framing requirements based on the connection format. - // - PKS_VIDEOINFOHEADER VideoInfoHeader = NULL; - - if (NT_SUCCESS (Status)) { - - VideoInfoHeader = CapPin -> CaptureVideoInfoHeader (); - if (!VideoInfoHeader) { - Status = STATUS_INSUFFICIENT_RESOURCES; - } - } - - if (NT_SUCCESS(Status)) { - // - // We need to edit the descriptor to ensure we don't mess up any other - // pins using the descriptor or touch read-only memory. - // - Status = KsEdit ( - Pin, - &Pin -> Descriptor, - AVSHWS_POOLTAG); - - if (NT_SUCCESS (Status)) { - - // - // If the edits proceeded without running out of memory, adjust - // the framing based on the video info header. - // - Status = KsEdit ( - Pin, - &Pin -> Descriptor -> AllocatorFraming, - AVSHWS_POOLTAG); - - if (NT_SUCCESS (Status)) { - - // - // We've KsEdit'ed this... I'm safe to cast away constness as - // long as the edit succeeded. - // - PKSALLOCATOR_FRAMING_EX Framing = - const_cast ( - Pin -> Descriptor -> AllocatorFraming - ); - - Framing -> FramingItem [0].Frames = 2; - - // - // The physical and optimal ranges must be biSizeImage. We only - // support one frame size, precisely the size of each capture - // image. - // - Framing -> FramingItem [0].PhysicalRange.MinFrameSize = - Framing -> FramingItem [0].PhysicalRange.MaxFrameSize = - Framing -> FramingItem [0].FramingRange.Range.MinFrameSize = - Framing -> FramingItem [0].FramingRange.Range.MaxFrameSize = - VideoInfoHeader -> bmiHeader.biSizeImage; - - Framing -> FramingItem [0].PhysicalRange.Stepping = - Framing -> FramingItem [0].FramingRange.Range.Stepping = - 0; - - } - - } - } - - if (NT_SUCCESS (Status)) { - // - // Adjust the stream header size. The video packets have extended - // header info (KS_FRAME_INFO). - // - Pin -> StreamHeaderSize = sizeof (KSSTREAM_HEADER) + - sizeof (KS_FRAME_INFO); - - } - return Status; -} - -/*************************************************/ - - -PKS_VIDEOINFOHEADER -CCapturePin:: -CaptureVideoInfoHeader ( - ) - -/*++ - -Routine Description: - - Capture the video info header out of the connection format. This - is what we use to base synthesized images off. - -Arguments: - - None - -Return Value: - - The captured video info header or NULL if there is insufficient - memory. - ---*/ - -{ - - PAGED_CODE(); - - PKS_VIDEOINFOHEADER ConnectionHeader = - &((reinterpret_cast - (m_Pin -> ConnectionFormat)) -> - VideoInfoHeader); - - m_VideoInfoHeader = reinterpret_cast ( - ExAllocatePoolWithTag ( - NonPagedPool, - KS_SIZE_VIDEOHEADER (ConnectionHeader), - AVSHWS_POOLTAG - ) - ); - - if (!m_VideoInfoHeader) - return NULL; - - // - // Bag the newly allocated header space. This will get cleaned up - // automatically when the pin closes. - // - NTSTATUS Status = - KsAddItemToObjectBag ( - m_Pin -> Bag, - reinterpret_cast (m_VideoInfoHeader), - NULL - ); - - if (!NT_SUCCESS (Status)) { - - ExFreePool (m_VideoInfoHeader); - return NULL; - - } else { - - // - // Copy the connection format video info header into the newly - // allocated "captured" video info header. - // - RtlCopyMemory ( - m_VideoInfoHeader, - ConnectionHeader, - KS_SIZE_VIDEOHEADER (ConnectionHeader) - ); - - } - - return m_VideoInfoHeader; - -} - - -NTSTATUS -CCapturePin:: -Process ( - ) - -/*++ - -Routine Description: - - The process dispatch for the pin bridges to this location. - We handle setting up scatter gather mappings, etc... - -Arguments: - - None - -Return Value: - - Success / Failure - ---*/ - -{ - - PAGED_CODE(); - - NTSTATUS Status = STATUS_SUCCESS; - PKSSTREAM_POINTER Leading; - - _DbgPrintF(DEBUGLVL_VERBOSE, ("Process")); - - Leading = KsPinGetLeadingEdgeStreamPointer ( - m_Pin, - KSSTREAM_POINTER_STATE_LOCKED - ); - - while (NT_SUCCESS (Status) && Leading) { - - PKSSTREAM_POINTER ClonePointer; - PSTREAM_POINTER_CONTEXT SPContext = NULL; - - // - // If no data is present in the Leading edge stream pointer, just - // move on to the next frame - // - if ( NULL == Leading -> StreamHeader -> Data ) { - Status = KsStreamPointerAdvance(Leading); - continue; - } - // - // For optimization sake in this particular sample, I will only keep - // one clone stream pointer per frame. This complicates the logic - // here but simplifies the completions. - // - // I'm also choosing to do this since I need to keep track of the - // virtual addresses corresponding to each mapping since I'm faking - // DMA. It simplifies that too. - // - if (!m_PreviousStreamPointer) { - // - // First thing we need to do is clone the leading edge. This allows - // us to keep reference on the frames while they're in DMA. - // - Status = KsStreamPointerClone ( - Leading, - NULL, - sizeof (STREAM_POINTER_CONTEXT), - &ClonePointer - ); - - // - // I use this for easy chunking of the buffer. We're not really - // dealing with physical addresses. This keeps track of what - // virtual address in the buffer the current scatter / gather - // mapping corresponds to for the fake hardware. - // - if (NT_SUCCESS (Status)) { - - // - // Set the stream header data used to 0. We update this - // in the DMA completions. For queues with DMA, we must - // update this field ourselves. - // - ClonePointer -> StreamHeader -> DataUsed = 0; - - SPContext = reinterpret_cast - (ClonePointer -> Context); - - SPContext -> BufferVirtual = - reinterpret_cast ( - ClonePointer -> StreamHeader -> Data - ); - } - - } else { - - ClonePointer = m_PreviousStreamPointer; - SPContext = reinterpret_cast - (ClonePointer -> Context); - Status = STATUS_SUCCESS; - } - - // - // If the clone failed, likely we're out of resources. Break out - // of the loop for now. We may end up starving DMA. - // - if (!NT_SUCCESS (Status)) { - KsStreamPointerUnlock (Leading, FALSE); - break; - } - - // - // Program the fake hardware. I would use Clone -> OffsetOut.*, but - // because of the optimization of one stream pointer per frame, it - // doesn't make complete sense. - // - ULONG MappingsUsed = - m_Device -> ProgramScatterGatherMappings ( - ClonePointer, - &(SPContext -> BufferVirtual), - Leading -> OffsetOut.Mappings, - Leading -> OffsetOut.Remaining - ); - - // - // In order to keep one clone per frame and simplify the fake DMA - // logic, make a check to see if we completely used the mappings in - // the leading edge. Set a flag. - // - if (MappingsUsed == Leading -> OffsetOut.Remaining) { - m_PreviousStreamPointer = NULL; - } else { - m_PreviousStreamPointer = ClonePointer; - } - - if (MappingsUsed) { - // - // If any mappings were added to scatter / gather queues, - // advance the leading edge by that number of mappings. If - // we run off the end of the queue, Status will be - // STATUS_DEVICE_NOT_READY. Otherwise, the leading edge will - // point to a new frame. The previous one will not have been - // dismissed (unless "DMA" completed) since there's a clone - // pointer referencing the frames. - // - Status = - KsStreamPointerAdvanceOffsets ( - Leading, - 0, - MappingsUsed, - FALSE - ); - } else { - - // - // The hardware was incapable of adding more entries. The S/G - // table is full. - // - Status = STATUS_PENDING; - break; - - } - - } - - // - // If the leading edge failed to lock (this is always possible, remember - // that locking CAN occassionally fail), don't blow up passing NULL - // into KsStreamPointerUnlock. Also, set m_PendIo to kick us later... - // - if (!Leading) { - - m_PendIo = TRUE; - - // - // If the lock failed, there's no point in getting called back - // immediately. The lock could fail due to insufficient memory, - // etc... In this case, we don't want to get called back immediately. - // Return pending. The m_PendIo flag will cause us to get kicked - // later. - // - Status = STATUS_PENDING; - } - - // - // If we didn't run the leading edge off the end of the queue, unlock it. - // - if (NT_SUCCESS (Status) && Leading) { - KsStreamPointerUnlock (Leading, FALSE); - } else { - // - // DEVICE_NOT_READY indicates that the advancement ran off the end - // of the queue. We couldn't lock the leading edge. - // - if (Status == STATUS_DEVICE_NOT_READY) Status = STATUS_SUCCESS; - } - - // - // If we failed with something that requires pending, set the pending I/O - // flag so we know we need to start it again in a completion DPC. - // - if (!NT_SUCCESS (Status) || Status == STATUS_PENDING) { - m_PendIo = TRUE; - } - - _DbgPrintF(DEBUGLVL_VERBOSE, ("Leaving Process...")); - return Status; - -} - -/*************************************************/ - - -NTSTATUS -CCapturePin:: -CleanupReferences ( - ) - -/*++ - -Routine Description: - - Clean up any references we're holding on frames after we abruptly - stop the hardware. - -Arguments: - - None - -Return Value: - - Success / Failure - ---*/ - -{ - - PAGED_CODE(); - - PKSSTREAM_POINTER Clone = KsPinGetFirstCloneStreamPointer (m_Pin); - PKSSTREAM_POINTER NextClone = NULL; - - // - // Walk through the clones, deleting them, and setting DataUsed to - // zero since we didn't use any data! - // - while (Clone) { - - NextClone = KsStreamPointerGetNextClone (Clone); - - Clone -> StreamHeader -> DataUsed = 0; - KsStreamPointerDelete (Clone); - - Clone = NextClone; - - } - - return STATUS_SUCCESS; - -} - -/*************************************************/ - - -NTSTATUS -CCapturePin:: -SetState ( - IN KSSTATE ToState, - IN KSSTATE FromState - ) - -/*++ - -Routine Description: - - This is called when the caputre pin transitions state. The routine - attempts to acquire / release any hardware resources and start up - or shut down capture based on the states we are transitioning to - and away from. - -Arguments: - - ToState - - The state we're transitioning to - - FromState - - The state we're transitioning away from - -Return Value: - - Success / Failure - ---*/ - -{ - - PAGED_CODE(); - - NTSTATUS Status = STATUS_SUCCESS; - - switch (ToState) { - - case KSSTATE_STOP: - - // - // First, stop the hardware if we actually did anything to it. - // - if (m_HardwareState != HardwareStopped) { - Status = m_Device -> Stop (); - NT_ASSERT (NT_SUCCESS (Status)); - - m_HardwareState = HardwareStopped; - } - - // - // We've stopped the "fake hardware". It has cleared out - // it's scatter / gather tables and will no longer be - // completing clones. We had locks on some frames that were, - // however, in hardware. This will clean them up. An - // alternative location would be in the reset dispatch. - // Note, however, that the reset dispatch can occur in any - // state and this should be understood. - // - // Some hardware may fill all S/G mappings before stopping... - // in this case, you may not have to do this. The - // "fake hardware" here simply stops filling mappings and - // cleans its scatter / gather tables out on the Stop call. - // - Status = CleanupReferences (); - - // - // Release any hardware resources related to this pin. - // - if (m_AcquiredResources) { - // - // If we got an interface to the clock, we must release it. - // - if (m_Clock) { - m_Clock -> Release (); - m_Clock = NULL; - } - - m_Device -> ReleaseHardwareResources ( - ); - - m_AcquiredResources = FALSE; - } - - break; - - case KSSTATE_ACQUIRE: - // - // Acquire any hardware resources related to this pin. We should - // only acquire them here -- **NOT** at filter create time. - // This means we do not fail creation of a filter because of - // limited hardware resources. - // - if (FromState == KSSTATE_STOP) { - Status = m_Device -> AcquireHardwareResources ( - this, - m_VideoInfoHeader - ); - - if (NT_SUCCESS (Status)) { - m_AcquiredResources = TRUE; - - // - // Attempt to get an interface to the master clock. - // This will fail if one has not been assigned. Since - // one must be assigned while the pin is still in - // KSSTATE_STOP, this is a guranteed method of getting - // the clock should one be assigned. - // - if (!NT_SUCCESS ( - KsPinGetReferenceClockInterface ( - m_Pin, - &m_Clock - ) - )) { - - // - // If we could not get an interface to the clock, - // don't use one. - // - m_Clock = NULL; - - } - - } else { - m_AcquiredResources = FALSE; - } - - } else { - // - // Standard transport pins will always receive transitions in - // +/- 1 manner. This means we'll always see a PAUSE->ACQUIRE - // transition before stopping the pin. - // - // The below is done because on DirectX 8.0, when the pin gets - // a message to stop, the queue is inaccessible. The reset - // which comes on every stop happens after this (at which time - // the queue is inaccessible also). So, for compatibility with - // DirectX 8.0, I am stopping the "fake" hardware at this - // point and cleaning up all references we have on frames. See - // the comments above regarding the CleanupReferences call. - // - // If this sample were targeting XP only, the below code would - // not be here. Again, I only do this so the sample does not - // hang when it is stopped running on a configuration such as - // Win2K + DX8. - // - if (m_HardwareState != HardwareStopped) { - Status = m_Device -> Stop (); - NT_ASSERT (NT_SUCCESS (Status)); - - m_HardwareState = HardwareStopped; - } - - Status = CleanupReferences (); - } - - m_FrameNumber = 0; - m_DroppedFrames = 0; - break; - - case KSSTATE_PAUSE: - // - // Stop the hardware simulation if we're coming down from run. - // - if (FromState == KSSTATE_RUN) { - - m_PresentationTime = 0; - Status = m_Device -> Pause (TRUE); - - if (NT_SUCCESS (Status)) { - m_HardwareState = HardwarePaused; - } - - } - m_FrameNumber = 0; - break; - - case KSSTATE_RUN: - // - // Start the hardware simulation or unpause it depending on - // whether we're initially running or we've paused and restarted. - // - if (m_HardwareState == HardwarePaused) { - Status = m_Device -> Pause (FALSE); - } else { - Status = m_Device -> Start (); - } - - if (NT_SUCCESS (Status)) { - m_HardwareState = HardwareRunning; - } - - break; - - } - - return Status; - -} - -/*************************************************/ - - -NTSTATUS -CCapturePin:: -IntersectHandler ( - IN PKSFILTER Filter, - IN PIRP Irp, - IN PKSP_PIN PinInstance, - IN PKSDATARANGE CallerDataRange, - IN PKSDATARANGE DescriptorDataRange, - IN ULONG BufferSize, - OUT PVOID Data OPTIONAL, - OUT PULONG DataSize - ) - -/*++ - -Routine Description: - - This routine handles video pin intersection queries by determining the - intersection between two data ranges. - -Arguments: - - Filter - - Contains a void pointer to the filter structure. - - Irp - - Contains a pointer to the data intersection property request. - - PinInstance - - Contains a pointer to a structure indicating the pin in question. - - CallerDataRange - - Contains a pointer to one of the data ranges supplied by the client - in the data intersection request. The format type, subtype and - specifier are compatible with the DescriptorDataRange. - - DescriptorDataRange - - Contains a pointer to one of the data ranges from the pin descriptor - for the pin in question. The format type, subtype and specifier are - compatible with the CallerDataRange. - - BufferSize - - Contains the size in bytes of the buffer pointed to by the Data - argument. For size queries, this value will be zero. - - Data - - Optionally contains a pointer to the buffer to contain the data - format structure representing the best format in the intersection - of the two data ranges. For size queries, this pointer will be - NULL. - - DataSize - - Contains a pointer to the location at which to deposit the size - of the data format. This information is supplied by the function - when the format is actually delivered and in response to size - queries. - -Return Value: - - STATUS_SUCCESS if there is an intersection and it fits in the supplied - buffer, STATUS_BUFFER_OVERFLOW for successful size queries, - STATUS_NO_MATCH if the intersection is empty, or - STATUS_BUFFER_TOO_SMALL if the supplied buffer is too small. - ---*/ - -{ - PAGED_CODE(); - - const GUID VideoInfoSpecifier = - {STATICGUIDOF(KSDATAFORMAT_SPECIFIER_VIDEOINFO)}; - - NT_ASSERT(Filter); - NT_ASSERT(Irp); - NT_ASSERT(PinInstance); - NT_ASSERT(CallerDataRange); - NT_ASSERT(DescriptorDataRange); - NT_ASSERT(DataSize); - - ULONG DataFormatSize; - - // - // Specifier FORMAT_VideoInfo for VIDEOINFOHEADER - // - if (IsEqualGUID(CallerDataRange->Specifier, VideoInfoSpecifier) && - CallerDataRange -> FormatSize >= sizeof (KS_DATARANGE_VIDEO)) { - - PKS_DATARANGE_VIDEO callerDataRange = - reinterpret_cast (CallerDataRange); - - PKS_DATARANGE_VIDEO descriptorDataRange = - reinterpret_cast (DescriptorDataRange); - - PKS_DATAFORMAT_VIDEOINFOHEADER FormatVideoInfoHeader; - - // - // Check that the other fields match - // - if ((callerDataRange->bFixedSizeSamples != - descriptorDataRange->bFixedSizeSamples) || - (callerDataRange->bTemporalCompression != - descriptorDataRange->bTemporalCompression) || - (callerDataRange->StreamDescriptionFlags != - descriptorDataRange->StreamDescriptionFlags) || - (callerDataRange->MemoryAllocationFlags != - descriptorDataRange->MemoryAllocationFlags) || - (RtlCompareMemory (&callerDataRange->ConfigCaps, - &descriptorDataRange->ConfigCaps, - sizeof (KS_VIDEO_STREAM_CONFIG_CAPS)) != - sizeof (KS_VIDEO_STREAM_CONFIG_CAPS))) - { - return STATUS_NO_MATCH; - } - - // - // KS_SIZE_VIDEOHEADER() below is relying on bmiHeader.biSize from - // the caller's data range. This **MUST** be validated; the - // extended bmiHeader size (biSize) must not extend past the end - // of the range buffer. Possible arithmetic overflow is also - // checked for. - // - { - ULONG VideoHeaderSize = KS_SIZE_VIDEOHEADER ( - &callerDataRange->VideoInfoHeader - ); - - ULONG DataRangeSize = - FIELD_OFFSET (KS_DATARANGE_VIDEO, VideoInfoHeader) + - VideoHeaderSize; - - // - // Check that biSize does not extend past the buffer. The - // first two checks are for arithmetic overflow on the - // operations to compute the alleged size. (On unsigned - // math, a+b < a iff an arithmetic overflow occurred). - // - if ( - VideoHeaderSize < callerDataRange-> - VideoInfoHeader.bmiHeader.biSize || - DataRangeSize < VideoHeaderSize || - DataRangeSize > callerDataRange -> DataRange.FormatSize - ) { - - return STATUS_INVALID_PARAMETER; - - } - - } - - DataFormatSize = - sizeof (KSDATAFORMAT) + - KS_SIZE_VIDEOHEADER (&callerDataRange->VideoInfoHeader); - - - // - // If the passed buffer size is 0, it indicates that this is a size - // only query. Return the size of the intersecting data format and - // pass back STATUS_BUFFER_OVERFLOW. - // - if (BufferSize == 0) { - - *DataSize = DataFormatSize; - return STATUS_BUFFER_OVERFLOW; - - } - - // - // Verify that the provided structure is large enough to - // accept the result. - // - if (BufferSize < DataFormatSize) - { - return STATUS_BUFFER_TOO_SMALL; - } - - // - // Copy over the KSDATAFORMAT, followed by the actual VideoInfoHeader - // - *DataSize = DataFormatSize; - - FormatVideoInfoHeader = PKS_DATAFORMAT_VIDEOINFOHEADER( Data ); - - // - // Copy over the KSDATAFORMAT. This is precisely the same as the - // KSDATARANGE (it's just the GUIDs, etc... not the format information - // following any data format. - // - RtlCopyMemory ( - &FormatVideoInfoHeader->DataFormat, - DescriptorDataRange, - sizeof (KSDATAFORMAT)); - - FormatVideoInfoHeader->DataFormat.FormatSize = DataFormatSize; - - // - // Copy over the callers requested VIDEOINFOHEADER - // - - RtlCopyMemory ( - &FormatVideoInfoHeader->VideoInfoHeader, - &callerDataRange->VideoInfoHeader, - KS_SIZE_VIDEOHEADER (&callerDataRange->VideoInfoHeader) - ); - - // - // Calculate biSizeImage for this request, and put the result in both - // the biSizeImage field of the bmiHeader AND in the SampleSize field - // of the DataFormat. - // - // Note that for compressed sizes, this calculation will probably not - // be just width * height * bitdepth - // - FormatVideoInfoHeader->VideoInfoHeader.bmiHeader.biSizeImage = - FormatVideoInfoHeader->DataFormat.SampleSize = - KS_DIBSIZE (FormatVideoInfoHeader->VideoInfoHeader.bmiHeader); - - // - // REVIEW - Perform other validation such as cropping and scaling checks - // - - return STATUS_SUCCESS; - - } // End of VIDEOINFOHEADER specifier - - return STATUS_NO_MATCH; -} - -/*************************************************/ - -BOOL -MultiplyCheckOverflow ( - ULONG a, - ULONG b, - ULONG *pab - ) - -/*++ - -Routine Description: - - Perform a 32 bit unsigned multiplication and check for arithmetic overflow. - -Arguments: - - a - - First operand - - b - - Second operand - - pab - - Result - -Return Value: - - TRUE - - no overflow - - FALSE - - overflow occurred - ---*/ - -{ - PAGED_CODE(); - - *pab = a * b; - if ((a == 0) || (((*pab) / a) == b)) { - return TRUE; - } - return FALSE; -} - -/*************************************************/ - - -NTSTATUS -CCapturePin:: -DispatchSetFormat ( - IN PKSPIN Pin, - IN PKSDATAFORMAT OldFormat OPTIONAL, - IN PKSMULTIPLE_ITEM OldAttributeList OPTIONAL, - IN const KSDATARANGE *DataRange, - IN const KSATTRIBUTE_LIST *AttributeRange OPTIONAL - ) - -/*++ - -Routine Description: - - This is the set data format dispatch for the capture pin. It is called - in two circumstances. - - 1: before Pin's creation dispatch has been made to verify that - Pin -> ConnectionFormat is an acceptable format for the range - DataRange. In this case OldFormat is NULL. - - 2: after Pin's creation dispatch has been made and an initial format - selected in order to change the format for the pin. In this case, - OldFormat will not be NULL. - - Validate that the format is acceptible and perform the actions necessary - to change format if appropriate. - -Arguments: - - Pin - - The pin this format is being set on. The format itself will be in - Pin -> ConnectionFormat. - - OldFormat - - The previous format used on this pin. If this is NULL, it is an - indication that Pin's creation dispatch has not yet been made and - that this is a request to validate the initial format and not to - change formats. - - OldAttributeList - - The old attribute list for the prior format - - DataRange - - A range out of our list of data ranges which was determined to be - at least a partial match for Pin -> ConnectionFormat. If the format - there is unacceptable for the range, STATUS_NO_MATCH should be - returned. - - AttributeRange - - The attribute range - -Return Value: - - Success / Failure - - STATUS_SUCCESS - - The format is acceptable / the format has been changed - - STATUS_NO_MATCH - - The format is not-acceptable / the format has not been changed - ---*/ - -{ - - PAGED_CODE(); - - NTSTATUS Status = STATUS_NO_MATCH; - - const GUID VideoInfoSpecifier = - {STATICGUIDOF(KSDATAFORMAT_SPECIFIER_VIDEOINFO)}; - - CCapturePin *CapPin = NULL; - - // - // Find the pin, if it exists yet. OldFormat will be an indication of - // this. If we're changing formats, OldFormat will be non-NULL. - // - // You cannot use Pin -> Context to make the determination. AVStream - // preinitializes this to the filter's context. - // - if (OldFormat) { - CapPin = reinterpret_cast (Pin -> Context); - } - - if (IsEqualGUID (Pin -> ConnectionFormat -> Specifier, - VideoInfoSpecifier) && - Pin -> ConnectionFormat -> FormatSize >= - sizeof (KS_DATAFORMAT_VIDEOINFOHEADER)) { - - PKS_DATAFORMAT_VIDEOINFOHEADER ConnectionFormat = - reinterpret_cast - (Pin -> ConnectionFormat); - - // - // DataRange comes out of OUR data range list. I know the range - // is valid as such. - // - const KS_DATARANGE_VIDEO *VIRange = - reinterpret_cast - (DataRange); - - // - // Check that bmiHeader.biSize is valid since we use it later. - // - ULONG VideoHeaderSize = KS_SIZE_VIDEOHEADER ( - &ConnectionFormat -> VideoInfoHeader - ); - - ULONG DataFormatSize = FIELD_OFFSET ( - KS_DATAFORMAT_VIDEOINFOHEADER, VideoInfoHeader - ) + VideoHeaderSize; - - if ( - VideoHeaderSize < ConnectionFormat-> - VideoInfoHeader.bmiHeader.biSize || - DataFormatSize < VideoHeaderSize || - DataFormatSize > ConnectionFormat -> DataFormat.FormatSize - ) { - - Status = STATUS_INVALID_PARAMETER; - - } - - // - // Check that the format is a match for the selected range. - // - else if ( - (ConnectionFormat -> VideoInfoHeader.bmiHeader.biWidth != - VIRange -> VideoInfoHeader.bmiHeader.biWidth) || - - (ConnectionFormat -> VideoInfoHeader.bmiHeader.biHeight != - VIRange -> VideoInfoHeader.bmiHeader.biHeight) || - - (ConnectionFormat -> VideoInfoHeader.bmiHeader.biCompression != - VIRange -> VideoInfoHeader.bmiHeader.biCompression) - - ) { - - Status = STATUS_NO_MATCH; - - } else { - - // - // Compute the minimum size of our buffers to validate against. - // The image synthesis routines synthesize |biHeight| rows of - // biWidth pixels in either RGB24 or UYVY. In order to ensure - // safe synthesis into the buffer, we need to know how large an - // image this will produce. - // - // I do this explicitly because of the method that the data is - // synthesized. A variation of this may or may not be necessary - // depending on the mechanism the driver in question fills the - // capture buffers. The important thing is to ensure that they - // aren't overrun during capture. - // - ULONG ImageSize; - - if (!MultiplyCheckOverflow ( - (ULONG)ConnectionFormat->VideoInfoHeader.bmiHeader.biWidth, - (ULONG)abs (ConnectionFormat-> - VideoInfoHeader.bmiHeader.biHeight), - &ImageSize - )) { - - Status = STATUS_INVALID_PARAMETER; - } - - // - // We only support KS_BI_RGB (24) and KS_BI_YUV422 (16), so - // this is valid for those formats. - // - else if (!MultiplyCheckOverflow ( - ImageSize, - (ULONG)(ConnectionFormat-> - VideoInfoHeader.bmiHeader.biBitCount / 8), - &ImageSize - )) { - - Status = STATUS_INVALID_PARAMETER; - - } - - // - // Valid for the formats we use. Otherwise, this would be - // checked later. - // - else if (ConnectionFormat->VideoInfoHeader.bmiHeader.biSizeImage < - ImageSize) { - - Status = STATUS_INVALID_PARAMETER; - - } else { - - // - // We can accept the format. - // - Status = STATUS_SUCCESS; - - // - // OldFormat is an indication that this is a format change. - // Since I do not implement the - // KSPROPERTY_CONNECTION_PROPOSEDATAFORMAT, by default, I do - // not handle dynamic format changes. - // - // If something changes while we're in the stop state, we're - // fine to handle it since we haven't "configured the hardware" - // yet. - // - if (OldFormat) { - // - // If we're in the stop state, we can handle just about any - // change. We don't support dynamic format changes. - // - if (Pin -> DeviceState == KSSTATE_STOP) { - if (!CapPin -> CaptureVideoInfoHeader ()) { - Status = STATUS_INSUFFICIENT_RESOURCES; - } - } else { - // - // Because we don't accept dynamic format changes, we - // should never get here. Just being over-protective. - // - Status = STATUS_INVALID_DEVICE_STATE; - } - } - - } - - } - - } - return Status; -} - -/************************************************************************** - - LOCKED CODE - -**************************************************************************/ - -#ifdef ALLOC_PRAGMA -#pragma code_seg() -#endif // ALLOC_PRAGMA - -void -CCapturePin:: -CompleteMappings ( - IN ULONG NumMappings - ) - -/*++ - -Routine Description: - - Called to notify the pin that a given number of scatter / gather - mappings have completed. Let the buffers go if possible. - We're called at DPC. - -Arguments: - - NumMappings - - The number of mappings that have completed. - -Return Value: - - None - ---*/ - -{ - - ULONG MappingsRemaining = NumMappings; - - // - // Walk through the clones list and delete clones whose time has come. - // The list is guaranteed to be kept in the order they were cloned. - // - PKSSTREAM_POINTER Clone = KsPinGetFirstCloneStreamPointer (m_Pin); - - while (MappingsRemaining && Clone) { - - PKSSTREAM_POINTER NextClone = KsStreamPointerGetNextClone (Clone); - -#if defined(_X86_) - // - // Count up the number of bytes we've completed and mark this - // in the Stream Header. In mapped queues - // (KSPIN_FLAG_GENERATE_MAPPINGS), this is the responsibility of - // the minidriver. In non-mapped queues, AVStream performs this. - // - ULONG MappingsToCount = - (MappingsRemaining > Clone -> OffsetOut.Remaining) ? - Clone -> OffsetOut.Remaining : - MappingsRemaining; - - // - // Update DataUsed according to the mappings. - // - for (ULONG CurMapping = 0; CurMapping < MappingsToCount; CurMapping++) { - Clone -> StreamHeader -> DataUsed += - Clone -> OffsetOut.Mappings [CurMapping].ByteCount; - } -#endif - - // - // If we have completed all remaining mappings in this clone, it - // is an indication that the clone is ready to be deleted and the - // buffer released. Set anything required in the stream header which - // has not yet been set. If we have a clock, we can timestamp the - // sample. - // -#if !defined(_X86_) - if (Clone -> StreamHeader -> DataUsed >= Clone -> OffsetOut.Remaining) { -#else - if (MappingsRemaining >= Clone -> OffsetOut.Remaining) { -#endif - Clone -> StreamHeader -> Duration = - m_VideoInfoHeader -> AvgTimePerFrame; - - Clone -> StreamHeader -> PresentationTime.Numerator = - Clone -> StreamHeader -> PresentationTime.Denominator = 1; - - // - // If a clock has been assigned, timestamp the packets with the - // time shown on the clock. - // - if (m_Clock) { - - LONGLONG ClockTime = m_Clock -> GetTime (); - - Clone -> StreamHeader -> PresentationTime.Time = ClockTime; - - Clone -> StreamHeader -> OptionsFlags = - KSSTREAM_HEADER_OPTIONSF_TIMEVALID | - KSSTREAM_HEADER_OPTIONSF_DURATIONVALID; - - } else { - // - // If there is no clock, don't time stamp the packets. - // - Clone -> StreamHeader -> PresentationTime.Time = 0; - - } - - // - // Increment the frame number. This is the total count of frames which - // have attempted capture. - // - m_FrameNumber++; - - // - // Double check the Stream Header size. AVStream makes no guarantee - // that because StreamHeaderSize is set to a specific size that you - // will get that size. If the proper data type handlers are not - // installed, the stream header will be of default size. - // - if ( Clone -> StreamHeader -> Size >= sizeof (KSSTREAM_HEADER) + - sizeof (KS_FRAME_INFO)) { - - PKS_FRAME_INFO FrameInfo = reinterpret_cast ( - Clone -> StreamHeader + 1 - ); - - FrameInfo -> ExtendedHeaderSize = sizeof (KS_FRAME_INFO); - FrameInfo -> dwFrameFlags = KS_VIDEO_FLAG_FRAME; - FrameInfo -> PictureNumber = (LONGLONG)m_FrameNumber; - - // I don't really have a way to tell if the device has dropped a frame - // or was not able to send a frame on time. - FrameInfo -> DropCount = (LONGLONG)m_DroppedFrames; - } - - - // - // If all of the mappings in this clone have been completed, - // delete the clone. We've already updated DataUsed above. - // - -#if !defined(_X86_) - MappingsRemaining--; -#else - MappingsRemaining -= Clone -> OffsetOut.Remaining; -#endif - KsStreamPointerDelete (Clone); - - } else { - // - // If only part of the mappings in this clone have been completed, - // update the pointers. Since we're guaranteed this won't advance - // to a new frame by the check above, it won't fail. - // -#if !defined(_X86_) - (void)KsStreamPointerAdvanceOffsets ( - Clone, - 0, - Clone -> StreamHeader -> DataUsed, - FALSE - ); - -#else - (void)KsStreamPointerAdvanceOffsets ( - Clone, - 0, - MappingsRemaining, - FALSE - ); - -#endif - MappingsRemaining = 0; - - } - - // - // Go to the next clone. - // - Clone = NextClone; - - } - - // - // If we've used all the mappings in hardware and pended, we can kick - // processing to happen again if we've completed mappings. - // - if (m_PendIo) { - m_PendIo = TRUE; - KsPinAttemptProcessing (m_Pin, TRUE); - } - -} - -/************************************************************************** - - DISPATCH AND DESCRIPTOR LAYOUT - -**************************************************************************/ - -// -// FormatRGB24Bpp_Capture: -// -// This is the data range description of the RGB24 capture format we support. -// -const -KS_DATARANGE_VIDEO -FormatRGB24Bpp_Capture = { - - // - // KSDATARANGE - // - { - sizeof (KS_DATARANGE_VIDEO), // FormatSize - 0, // Flags - D_X * D_Y * 3, // SampleSize - 0, // Reserved - - STATICGUIDOF (KSDATAFORMAT_TYPE_VIDEO), // aka. MEDIATYPE_Video - 0xe436eb7d, 0x524f, 0x11ce, 0x9f, 0x53, 0x00, 0x20, - 0xaf, 0x0b, 0xa7, 0x70, // aka. MEDIASUBTYPE_RGB24, - STATICGUIDOF (KSDATAFORMAT_SPECIFIER_VIDEOINFO) // aka. FORMAT_VideoInfo - }, - - TRUE, // BOOL, bFixedSizeSamples (all samples same size?) - FALSE, // BOOL, bTemporalCompression (all I frames?) - 0, // Reserved (was StreamDescriptionFlags) - 0, // Reserved (was MemoryAllocationFlags - // (KS_VIDEO_ALLOC_*)) - // - // _KS_VIDEO_STREAM_CONFIG_CAPS - // - { - STATICGUIDOF( KSDATAFORMAT_SPECIFIER_VIDEOINFO ), // GUID - KS_AnalogVideo_None, // AnalogVideoStandard - D_X,D_Y, // InputSize, (the inherent size of the incoming signal - // with every digitized pixel unique) - D_X,D_Y, // MinCroppingSize, smallest rcSrc cropping rect allowed - D_X,D_Y, // MaxCroppingSize, largest rcSrc cropping rect allowed - 8, // CropGranularityX, granularity of cropping size - 1, // CropGranularityY - 8, // CropAlignX, alignment of cropping rect - 1, // CropAlignY; - D_X, D_Y, // MinOutputSize, smallest bitmap stream can produce - D_X, D_Y, // MaxOutputSize, largest bitmap stream can produce - 8, // OutputGranularityX, granularity of output bitmap size - 1, // OutputGranularityY; - 0, // StretchTapsX (0 no stretch, 1 pix dup, 2 interp...) - 0, // StretchTapsY - 0, // ShrinkTapsX - 0, // ShrinkTapsY - 333667, // MinFrameInterval, 100 nS units - 640000000, // MaxFrameInterval, 100 nS units - 8 * 3 * 30 * D_X * D_Y, // MinBitsPerSecond; - 8 * 3 * 30 * D_X * D_Y // MaxBitsPerSecond; - }, - - // - // KS_VIDEOINFOHEADER (default format) - // - { - 0,0,0,0, // RECT rcSource; - 0,0,0,0, // RECT rcTarget; - D_X * D_Y * 3 * 8 * 30, // DWORD dwBitRate; - 0L, // DWORD dwBitErrorRate; - 333667, // REFERENCE_TIME AvgTimePerFrame; - sizeof (KS_BITMAPINFOHEADER), // DWORD biSize; - D_X, // LONG biWidth; - D_Y, // LONG biHeight; - 1, // WORD biPlanes; - 24, // WORD biBitCount; - KS_BI_RGB, // DWORD biCompression; - D_X * D_Y * 3, // DWORD biSizeImage; - 0, // LONG biXPelsPerMeter; - 0, // LONG biYPelsPerMeter; - 0, // DWORD biClrUsed; - 0 // DWORD biClrImportant; - } -}; - -// -// FormatYUY2_Capture: -// -// This is the data range description of the YUY2 format we support. -// -const -KS_DATARANGE_VIDEO -FormatYUY2_Capture = { - - // - // KSDATARANGE - // - { - sizeof (KS_DATARANGE_VIDEO), // FormatSize - 0, // Flags - DMAX_X * DMAX_Y * 2, // SampleSize - 0, // Reserved - STATICGUIDOF (KSDATAFORMAT_TYPE_VIDEO), // aka. MEDIATYPE_Video - 0x32595559, 0x0000, 0x0010, 0x80, 0x00, - 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71, //aka. MEDIASUBTYPE_YUY2, - STATICGUIDOF (KSDATAFORMAT_SPECIFIER_VIDEOINFO) // aka. FORMAT_VideoInfo - }, - - TRUE, // BOOL, bFixedSizeSamples (all samples same size?) - FALSE, // BOOL, bTemporalCompression (all I frames?) - 0, // Reserved (was StreamDescriptionFlags) - 0, // Reserved (was MemoryAllocationFlags - // (KS_VIDEO_ALLOC_*)) - - // - // _KS_VIDEO_STREAM_CONFIG_CAPS - // - { - STATICGUIDOF( KSDATAFORMAT_SPECIFIER_VIDEOINFO ), // GUID - KS_AnalogVideo_None, // AnalogVideoStandard - DMAX_X, DMAX_Y, // InputSize, (the inherent size of the incoming signal - // with every digitized pixel unique) - D_X,D_Y, // MinCroppingSize, smallest rcSrc cropping rect allowed - DMAX_X, DMAX_Y, // MaxCroppingSize, largest rcSrc cropping rect allowed - 8, // CropGranularityX, granularity of cropping size - 1, // CropGranularityY - 8, // CropAlignX, alignment of cropping rect - 1, // CropAlignY; - D_X, D_Y, // MinOutputSize, smallest bitmap stream can produce - DMAX_X, DMAX_Y, // MaxOutputSize, largest bitmap stream can produce - 8, // OutputGranularityX, granularity of output bitmap size - 1, // OutputGranularityY; - 0, // StretchTapsX (0 no stretch, 1 pix dup, 2 interp...) - 0, // StretchTapsY - 0, // ShrinkTapsX - 0, // ShrinkTapsY - 333667, // MinFrameInterval, 100 nS units - 640000000, // MaxFrameInterval, 100 nS units - 8 * 2 * 30 * D_X * D_Y, // MinBitsPerSecond; - 8 * 2 * 30 * DMAX_X * DMAX_Y, // MaxBitsPerSecond; - }, - - // - // KS_VIDEOINFOHEADER (default format) - // - { - 0, 0, 0, 0, // RECT rcSource; - 0, 0, 0, 0, // RECT rcTarget; - DMAX_X * DMAX_Y * 2 * 8 * 30, // DWORD dwBitRate; - 0L, // DWORD dwBitErrorRate; - 333667, // REFERENCE_TIME AvgTimePerFrame; - sizeof (KS_BITMAPINFOHEADER), // DWORD biSize; - DMAX_X, // LONG biWidth; - DMAX_Y, // LONG biHeight; - 1, // WORD biPlanes; - 16, // WORD biBitCount; - FOURCC_YUY2, // DWORD biCompression; - DMAX_X * DMAX_Y * 2, // DWORD biSizeImage; - 0, // LONG biXPelsPerMeter; - 0, // LONG biYPelsPerMeter; - 0, // DWORD biClrUsed; - 0 // DWORD biClrImportant; - } -}; - -// -// CapturePinDispatch: -// -// This is the dispatch table for the capture pin. It provides notifications -// about creation, closure, processing, data formats, etc... -// -const -KSPIN_DISPATCH -CapturePinDispatch = { - CCapturePin::DispatchCreate, // Pin Create - NULL, // Pin Close - CCapturePin::DispatchProcess, // Pin Process - NULL, // Pin Reset - CCapturePin::DispatchSetFormat, // Pin Set Data Format - CCapturePin::DispatchSetState, // Pin Set Device State - NULL, // Pin Connect - NULL, // Pin Disconnect - NULL, // Clock Dispatch - NULL // Allocator Dispatch -}; - -// -// CapturePinAllocatorFraming: -// -// This is the simple framing structure for the capture pin. Note that this -// will be modified via KsEdit when the actual capture format is determined. -// -DECLARE_SIMPLE_FRAMING_EX ( - CapturePinAllocatorFraming, - STATICGUIDOF (KSMEMORY_TYPE_KERNEL_NONPAGED), - KSALLOCATOR_REQUIREMENTF_SYSTEM_MEMORY | - KSALLOCATOR_REQUIREMENTF_PREFERENCES_ONLY, - 2, - 0, - 2 * PAGE_SIZE, - 2 * PAGE_SIZE - ); - -// -// CapturePinDataRanges: -// -// This is the list of data ranges supported on the capture pin. We support -// two: one RGB24, and one YUY2. -// -const -PKSDATARANGE -CapturePinDataRanges [CAPTURE_PIN_DATA_RANGE_COUNT] = { - (PKSDATARANGE) &FormatYUY2_Capture, - (PKSDATARANGE) &FormatRGB24Bpp_Capture - }; diff --git a/avstream/avshws/capture.h b/avstream/avshws/capture.h deleted file mode 100644 index 502e01e3..00000000 --- a/avstream/avshws/capture.h +++ /dev/null @@ -1,313 +0,0 @@ -/************************************************************************** - - AVStream Simulated Hardware Sample - - Copyright (c) 2001, Microsoft Corporation. - - File: - - capture.h - - Abstract: - - This file contains header for the video capture pin on the capture - filter. The capture sample performs "fake" DMA directly into - the capture buffers. Common buffer DMA will work slightly differently. - - For common buffer DMA, the general technique would be DPC schedules - processing with KsPinAttemptProcessing. The processing routine grabs - the leading edge, copies data out of the common buffer and advances. - Cloning would not be necessary with this technique. It would be - similiar to the way "AVSSamp" works, but it would be pin-centric. - - History: - - created 3/8/2001 - -**************************************************************************/ -#include -// -// STREAM_POINTER_CONTEXT: -// -// This is the context structure we associate with all clone stream pointers. -// It allows the mapping code to rip apart the buffer into chunks the same -// size as the scatter/gather mappings in order to fake scatter / gather -// bus-master DMA. -// -typedef struct _STREAM_POINTER_CONTEXT { - - PUCHAR BufferVirtual; - -} STREAM_POINTER_CONTEXT, *PSTREAM_POINTER_CONTEXT; - -// -// CCapturePin: -// -// The video capture pin class. -// -class CCapturePin : - public ICaptureSink { - -private: - - // - // The AVStream pin we're associated with. - // - PKSPIN m_Pin; - - // - // Pointer to the internal device object for our capture device. - // We access the "fake" hardware through this object. - // - CCaptureDevice *m_Device; - - // - // The state we've put the hardware into. This allows us to keep track - // of whether to do things like unpausing or restarting. - // - HARDWARE_STATE m_HardwareState; - - // - // The clock we've been assigned. As with other capture filters, we do - // not expose a clock. If one has been assigned, we will use it to - // time stamp packets (plus a reasonable delta to work the capture stream - // in a preview graph). - // - PIKSREFERENCECLOCK m_Clock; - - // - // The captured video info header. The settings for "fake" hardware will be - // programmed via this video info header. - // - PKS_VIDEOINFOHEADER m_VideoInfoHeader; - - // - // If we are unable to insert all of the mappings in a stream pointer into - // the "fake" hardware's scatter / gather table, we set this to the - // stream pointer that's incomplete. This is done both to make the - // relasing easier and to make it easier to fake the scatter / gather - // hardware. - // - PKSSTREAM_POINTER m_PreviousStreamPointer; - - // - // An indication of whether or not we pended I/O for some reason. If this - // is set, the DPC will resume I/O when any mappings are completed. - // - BOOLEAN m_PendIo; - - // - // An indication of whether or not this pin has acquired the necessary - // hardware resources to operate. When the pin reaches KSSTATE_ACQUIRE, - // we attempt to acquire the hardware. This flag will be set based on - // our success / failure. - // - BOOLEAN m_AcquiredResources; - - // - // Presentation time for the sample - // - LONGLONG m_PresentationTime; - - LONGLONG m_FrameNumber; - LONGLONG m_DroppedFrames; - - // - // CleanupReferences(): - // - // Clean up any references we hold on frames in the queue. This is called - // when we abruptly stop the fake hardware. - // - NTSTATUS - CleanupReferences ( - ); - - // - // SetState(): - // - // This is the state transition handler for the capture pin. It attempts - // to acquire resources for the capture pin (or releasing them if - // necessary) and starts and stops the hardware as required. - // - NTSTATUS - SetState ( - IN KSSTATE ToState, - IN KSSTATE FromState - ); - - // - // Process(): - // - // This is the processing dispatch for the capture pin. It handles - // programming the scatter / gather tables for the hardware as buffers - // become available. This processing routine is designed for a direct - // into the capture buffers kind of DMA as opposed to common-buffer - // and copy strategies. - // - NTSTATUS - Process ( - ); - // - // CaptureVideoInfoHeader(): - // - // This routine stashes the video info header set on the pin connection - // in the CCapturePin object. This is used to base hardware settings. - // - PKS_VIDEOINFOHEADER - CaptureVideoInfoHeader ( - ); - - // - // Cleanup(): - // - // This is the free callback from the bagged item (CCapturePin). If we - // do not provide a callback when we bag the CCapturePin, ExFreePool - // would be called. This is not desirable for C++ constructed objects. - // We merely delete the object here. - // - static - void - Cleanup ( - IN CCapturePin *Pin - ) - { - delete Pin; - } - -public: - // - // CCapturePin(): - // - // The capture pin's constructor. Initialize any non-0, non-NULL fields - // (since new will have zero'ed the memory anyway) and set up our - // device level pointers for access during capture routines. - // - CCapturePin ( - IN PKSPIN Pin - ); - - // - // ~CCapturePin(): - // - // The capture pin's destructor. - // - ~CCapturePin ( - ) - { - } - - // - // ICaptureSink::CompleteMappings() - // - // This is the capture sink notification mechanism for mapping completion. - // When the device DPC detects that a given number of mappings have been - // completed by the fake hardware, it signals the capture sink of this - // through this method. - // - virtual - void - CompleteMappings ( - IN ULONG NumMappings - ); - - /************************************************* - - Dispatch Routines - - *************************************************/ - - // - // DispatchCreate(): - // - // This is the creation dispatch for the capture pin. It creates - // the CCapturePin object and associates it with the AVStream object - // bagging it in the process. - // - static - NTSTATUS - DispatchCreate ( - IN PKSPIN Pin, - IN PIRP Irp - ); - - // - // DispatchSetState(): - // - // This is the set device state dispatch for the pin. The routine bridges - // to SetState() in the context of the CCapturePin. - // - static - NTSTATUS - DispatchSetState ( - IN PKSPIN Pin, - IN KSSTATE ToState, - IN KSSTATE FromState - ) - { - return - (reinterpret_cast (Pin -> Context)) -> - SetState (ToState, FromState); - } - - // - // DispatchSetFormat(): - // - // This is the set data format dispatch for the pin. This will be called - // BEFORE pin creation to validate that a data format selected is a match - // for the range pulled out of our range list. It will also be called - // for format changes. - // - // If OldFormat is NULL, this is an indication that it's the initial - // call and not a format change. Even fixed format pins get this call - // once. - // - static - NTSTATUS - DispatchSetFormat ( - IN PKSPIN Pin, - IN PKSDATAFORMAT OldFormat OPTIONAL, - IN PKSMULTIPLE_ITEM OldAttributeList OPTIONAL, - IN const KSDATARANGE *DataRange, - IN const KSATTRIBUTE_LIST *AttributeRange OPTIONAL - ); - - // - // DispatchProcess(): - // - // This is the processing dispatch for the capture pin. The routine - // bridges to Process() in the context of the CCapturePin. - // - static - NTSTATUS - DispatchProcess ( - IN PKSPIN Pin - ) - { - return - (reinterpret_cast (Pin -> Context)) -> - Process (); - - } - - // - // IntersectHandler(): - // - // This is the data intersection handler for the capture pin. This - // determines an optimal format in the intersection of two ranges, - // one local and one possibly foreign. If there is no compatible format, - // STATUS_NO_MATCH is returned. - // - static - NTSTATUS - IntersectHandler ( - IN PKSFILTER Filter, - IN PIRP Irp, - IN PKSP_PIN PinInstance, - IN PKSDATARANGE CallerDataRange, - IN PKSDATARANGE DescriptorDataRange, - IN ULONG BufferSize, - OUT PVOID Data OPTIONAL, - OUT PULONG DataSize - ); - -}; \ No newline at end of file diff --git a/avstream/avshws/device.cpp b/avstream/avshws/device.cpp deleted file mode 100644 index ce4818b8..00000000 --- a/avstream/avshws/device.cpp +++ /dev/null @@ -1,875 +0,0 @@ -/************************************************************************** - - AVStream Simulated Hardware Sample - - Copyright (c) 2001, Microsoft Corporation. - - File: - - device.cpp - - Abstract: - - This file contains the device level implementation of the AVStream - hardware sample. Note that this is not the "fake" hardware. The - "fake" hardware is in hwsim.cpp. - - History: - - created 3/9/2001 - -**************************************************************************/ - -#include "avshws.h" -/************************************************************************** - - PAGEABLE CODE - -**************************************************************************/ - -#ifdef ALLOC_PRAGMA -#pragma code_seg("PAGE") -#endif // ALLOC_PRAGMA - -NTSTATUS -CCaptureDevice:: -DispatchCreate ( - IN PKSDEVICE Device - ) - -/*++ - -Routine Description: - - Create the capture device. This is the creation dispatch for the - capture device. - -Arguments: - - Device - - The AVStream device being created. - -Return Value: - - Success / Failure - ---*/ - -{ - - PAGED_CODE(); - - NTSTATUS Status; - - CCaptureDevice *CapDevice = new (NonPagedPool) CCaptureDevice (Device); - - if (!CapDevice) { - // - // Return failure if we couldn't create the pin. - // - Status = STATUS_INSUFFICIENT_RESOURCES; - - } else { - - // - // Add the item to the object bag if we were successful. - // Whenever the device goes away, the bag is cleaned up and - // we will be freed. - // - // For backwards compatibility with DirectX 8.0, we must grab - // the device mutex before doing this. For Windows XP, this is - // not required, but it is still safe. - // - KsAcquireDevice (Device); - Status = KsAddItemToObjectBag ( - Device -> Bag, - reinterpret_cast (CapDevice), - reinterpret_cast (CCaptureDevice::Cleanup) - ); - KsReleaseDevice (Device); - - if (!NT_SUCCESS (Status)) { - delete CapDevice; - } else { - Device -> Context = reinterpret_cast (CapDevice); - } - - } - - return Status; - -} - -/*************************************************/ - - -NTSTATUS -CCaptureDevice:: -PnpStart ( - IN PCM_RESOURCE_LIST TranslatedResourceList, - IN PCM_RESOURCE_LIST UntranslatedResourceList - ) - -/*++ - -Routine Description: - - Called at Pnp start. We start up our virtual hardware simulation. - -Arguments: - - TranslatedResourceList - - The translated resource list from Pnp - - UntranslatedResourceList - - The untranslated resource list from Pnp - -Return Value: - - Success / Failure - ---*/ - -{ - - PAGED_CODE(); - - // - // Normally, we'd do things here like parsing the resource lists and - // connecting our interrupt. Since this is a simulation, there isn't - // much to parse. The parsing and connection should be the same as - // any WDM driver. The sections that will differ are illustrated below - // in setting up a simulated DMA. - // - - NTSTATUS Status = STATUS_SUCCESS; - - if (!m_Device -> Started) { - // Create the Filter for the device - KsAcquireDevice(m_Device); - Status = KsCreateFilterFactory( m_Device->FunctionalDeviceObject, - &CaptureFilterDescriptor, - L"GLOBAL", - NULL, - KSCREATE_ITEM_FREEONSTOP, - NULL, - NULL, - NULL ); - KsReleaseDevice(m_Device); - - } - // - // By PnP, it's possible to receive multiple starts without an intervening - // stop (to reevaluate resources, for example). Thus, we only perform - // creations of the simulation on the initial start and ignore any - // subsequent start. Hardware drivers with resources should evaluate - // resources and make changes on 2nd start. - // - if (NT_SUCCESS(Status) && (!m_Device -> Started)) { - - m_HardwareSimulation = new (NonPagedPool) CHardwareSimulation (this); - if (!m_HardwareSimulation) { - // - // If we couldn't create the hardware simulation, fail. - // - Status = STATUS_INSUFFICIENT_RESOURCES; - - } else { - Status = KsAddItemToObjectBag ( - m_Device -> Bag, - reinterpret_cast (m_HardwareSimulation), - reinterpret_cast (CHardwareSimulation::Cleanup) - ); - - if (!NT_SUCCESS (Status)) { - delete m_HardwareSimulation; - } - } -#if defined(_X86_) - // - // DMA operations illustrated in this sample are applicable only for 32bit platform. - // - INTERFACE_TYPE InterfaceBuffer; - ULONG InterfaceLength; - DEVICE_DESCRIPTION DeviceDescription; - - if (NT_SUCCESS (Status)) { - // - // Set up DMA... - // - // Ordinarilly, we'd be using InterfaceBuffer or - // InterfaceTypeUndefined if !NT_SUCCESS (IfStatus) as the - // InterfaceType below; however, for the purposes of this sample, - // we lie and say we're on the PCI Bus. Otherwise, we're using map - // registers on x86 32 bit physical to 32 bit logical and this isn't - // what I want to show in this sample. - // - // - // NTSTATUS IfStatus = - - IoGetDeviceProperty ( - m_Device -> PhysicalDeviceObject, - DevicePropertyLegacyBusType, - sizeof (INTERFACE_TYPE), - &InterfaceBuffer, - &InterfaceLength - ); - - // - // Initialize our fake device description. We claim to be a - // bus-mastering 32-bit scatter/gather capable piece of hardware. - // - DeviceDescription.Version = DEVICE_DESCRIPTION_VERSION; - DeviceDescription.DmaChannel = ((ULONG) ~0); - DeviceDescription.InterfaceType = PCIBus; - DeviceDescription.DmaWidth = Width32Bits; - DeviceDescription.DmaSpeed = Compatible; - DeviceDescription.ScatterGather = TRUE; - DeviceDescription.Master = TRUE; - DeviceDescription.Dma32BitAddresses = TRUE; - DeviceDescription.AutoInitialize = FALSE; - DeviceDescription.MaximumLength = (ULONG) -1; - - // - // Get a DMA adapter object from the system. - // - m_DmaAdapterObject = IoGetDmaAdapter ( - m_Device -> PhysicalDeviceObject, - &DeviceDescription, - &m_NumberOfMapRegisters - ); - - if (!m_DmaAdapterObject) { - Status = STATUS_UNSUCCESSFUL; - } - - } - - if (NT_SUCCESS (Status)) { - // - // Initialize our DMA adapter object with AVStream. This is - // **ONLY** necessary **IF** you are doing DMA directly into - // capture buffers as this sample does. For this, - // KSPIN_FLAG_GENERATE_MAPPINGS must be specified on a queue. - // - - // - // The (1 << 20) below is the maximum size of a single s/g mapping - // that this hardware can handle. Note that I have pulled this - // number out of thin air for the "fake" hardware. - // - KsDeviceRegisterAdapterObject ( - m_Device, - m_DmaAdapterObject, - (1 << 20), - sizeof (KSMAPPING) - ); - - } -#endif - } - - return Status; - -} - -/*************************************************/ - - -void -CCaptureDevice:: -PnpStop ( - ) - -/*++ - -Routine Description: - - This is the pnp stop dispatch for the capture device. It releases any - adapter object previously allocated by IoGetDmaAdapter during Pnp Start. - -Arguments: - - None - -Return Value: - - None - ---*/ - -{ - - PAGED_CODE(); - - if (m_DmaAdapterObject) { - // - // Return the DMA adapter back to the system. - // - m_DmaAdapterObject -> DmaOperations -> - PutDmaAdapter (m_DmaAdapterObject); - - m_DmaAdapterObject = NULL; - } - -} - -/*************************************************/ - - -NTSTATUS -CCaptureDevice:: -AcquireHardwareResources ( - IN ICaptureSink *CaptureSink, - IN PKS_VIDEOINFOHEADER VideoInfoHeader - ) - -/*++ - -Routine Description: - - Acquire hardware resources for the capture hardware. If the - resources are already acquired, this will return an error. - The hardware configuration must be passed as a VideoInfoHeader. - -Arguments: - - CaptureSink - - The capture sink attempting to acquire resources. When scatter / - gather mappings are completed, the capture sink specified here is - what is notified of the completions. - - VideoInfoHeader - - Information about the capture stream. This **MUST** remain - stable until the caller releases hardware resources. Note - that this could also be guaranteed by bagging it in the device - object bag as well. - -Return Value: - - Success / Failure - ---*/ - -{ - - PAGED_CODE(); - - NTSTATUS Status = STATUS_SUCCESS; - - // - // If we're the first pin to go into acquire (remember we can have - // a filter in another graph going simultaneously), grab the resources. - // - if (InterlockedCompareExchange ( - &m_PinsWithResources, - 1, - 0) == 0) { - - m_VideoInfoHeader = VideoInfoHeader; - - // - // If there's an old hardware simulation sitting around for some - // reason, blow it away. - // - if (m_ImageSynth) { - delete m_ImageSynth; - m_ImageSynth = NULL; - } - - // - // Create the necessary type of image synthesizer. - // - if (m_VideoInfoHeader -> bmiHeader.biBitCount == 24 && - m_VideoInfoHeader -> bmiHeader.biCompression == KS_BI_RGB) { - - // - // If we're RGB24, create a new RGB24 synth. RGB24 surfaces - // can be in either orientation. The origin is lower left if - // height < 0. Otherwise, it's upper left. - // - m_ImageSynth = new (NonPagedPool, 'RysI') - CRGB24Synthesizer ( - m_VideoInfoHeader -> bmiHeader.biHeight >= 0 - ); - - } else - if (m_VideoInfoHeader -> bmiHeader.biBitCount == 16 && - (m_VideoInfoHeader -> bmiHeader.biCompression == FOURCC_YUY2)) { - - // - // If we're UYVY, create the YUV synth. - // - m_ImageSynth = new(NonPagedPool, 'YysI') CYUVSynthesizer; - - } - else - // - // We don't synthesize anything but RGB 24 and UYVY. - // - Status = STATUS_INVALID_PARAMETER; - - if (NT_SUCCESS (Status) && !m_ImageSynth) { - - Status = STATUS_INSUFFICIENT_RESOURCES; - - } - - if (NT_SUCCESS (Status)) { - // - // If everything has succeeded thus far, set the capture sink. - // - m_CaptureSink = CaptureSink; - - } else { - // - // If anything failed in here, we release the resources we've - // acquired. - // - ReleaseHardwareResources (); - } - - } else { - - // - // TODO: Better status code? - // - Status = STATUS_SHARING_VIOLATION; - - } - - return Status; - -} - -/*************************************************/ - - -void -CCaptureDevice:: -ReleaseHardwareResources ( - ) - -/*++ - -Routine Description: - - Release hardware resources. This should only be called by - an object which has acquired them. - -Arguments: - - None - -Return Value: - - None - ---*/ - -{ - - PAGED_CODE(); - - // - // Blow away the image synth. - // - if (m_ImageSynth) { - delete m_ImageSynth; - m_ImageSynth = NULL; - - } - - m_VideoInfoHeader = NULL; - m_CaptureSink = NULL; - - // - // Release our "lock" on hardware resources. This will allow another - // pin (perhaps in another graph) to acquire them. - // - InterlockedExchange ( - &m_PinsWithResources, - 0 - ); - -} - -/*************************************************/ - - -NTSTATUS -CCaptureDevice:: -Start ( - ) - -/*++ - -Routine Description: - - Start the capture device based on the video info header we were told - about when resources were acquired. - -Arguments: - - None - -Return Value: - - Success / Failure - ---*/ - -{ - - PAGED_CODE(); - - m_LastMappingsCompleted = 0; - m_InterruptTime = 0; - - return - m_HardwareSimulation -> Start ( - m_ImageSynth, - m_VideoInfoHeader -> AvgTimePerFrame, - m_VideoInfoHeader -> bmiHeader.biWidth, - ABS (m_VideoInfoHeader -> bmiHeader.biHeight), - m_VideoInfoHeader -> bmiHeader.biSizeImage - ); - - -} - -/*************************************************/ - - -NTSTATUS -CCaptureDevice:: -Pause ( - IN BOOLEAN Pausing - ) - -/*++ - -Routine Description: - - Pause or unpause the hardware simulation. This is an effective start - or stop without resetting counters and formats. Note that this can - only be called to transition from started -> paused -> started. Calling - this without starting the hardware with Start() does nothing. - -Arguments: - - Pausing - - An indicatation of whether we are pausing or unpausing - - TRUE - - Pause the hardware simulation - - FALSE - - Unpause the hardware simulation - -Return Value: - - Success / Failure - ---*/ - -{ - - PAGED_CODE(); - - return - m_HardwareSimulation -> Pause ( - Pausing - ); - -} - -/*************************************************/ - - -NTSTATUS -CCaptureDevice:: -Stop ( - ) - -/*++ - -Routine Description: - - Stop the capture device. - -Arguments: - - None - -Return Value: - - Success / Failure - ---*/ - -{ - - PAGED_CODE(); - - return - m_HardwareSimulation -> Stop (); - -} - -/*************************************************/ - - -ULONG -CCaptureDevice:: -ProgramScatterGatherMappings ( - IN PKSSTREAM_POINTER Clone, - IN PUCHAR *Buffer, - IN PKSMAPPING Mappings, - IN ULONG MappingsCount - ) - -/*++ - -Routine Description: - - Program the scatter / gather mappings for the "fake" hardware. - -Arguments: - - Buffer - - Points to a pointer to the virtual address of the topmost - scatter / gather chunk. The pointer will be updated as the - device "programs" mappings. Reason for this is that we get - the physical addresses and sizes, but must calculate the virtual - addresses... This is used as scratch space for that. - - Mappings - - An array of mappings to program - - MappingsCount - - The count of mappings in the array - -Return Value: - - The number of mappings successfully programmed - ---*/ - -{ - - PAGED_CODE(); - - - - return - m_HardwareSimulation -> ProgramScatterGatherMappings ( - Clone, - Buffer, - Mappings, - MappingsCount, - sizeof (KSMAPPING) - ); - -} - -/************************************************************************* - - LOCKED CODE - -**************************************************************************/ - -#ifdef ALLOC_PRAGMA -#pragma code_seg() -#endif // ALLOC_PRAGMA - - -ULONG -CCaptureDevice:: -QueryInterruptTime ( - ) - -/*++ - -Routine Description: - - Return the number of frame intervals that have elapsed since the - start of the device. This will be the frame number. - -Arguments: - - None - -Return Value: - - The interrupt time of the device (the number of frame intervals that - have elapsed since the start of the device). - ---*/ - -{ - - return m_InterruptTime; - -} - -/*************************************************/ - - -void -CCaptureDevice:: -Interrupt ( - ) - -/*++ - -Routine Description: - - This is the "faked" interrupt service routine for this device. It - is called at dispatch level by the hardware simulation. - -Arguments: - - None - -Return Value: - - None - ---*/ - -{ - - m_InterruptTime++; - - // - // Realistically, we'd do some hardware manipulation here and then queue - // a DPC. Since this is fake hardware, we do what's necessary here. This - // is pretty much what the DPC would look like short of the access - // of hardware registers (ReadNumberOfMappingsCompleted) which would likely - // be done in the ISR. - // - ULONG NumMappingsCompleted = - m_HardwareSimulation -> ReadNumberOfMappingsCompleted (); - - // - // Inform the capture sink that a given number of scatter / gather - // mappings have completed. - // - m_CaptureSink -> CompleteMappings ( - NumMappingsCompleted - m_LastMappingsCompleted - ); - - m_LastMappingsCompleted = NumMappingsCompleted; - -} - -/************************************************************************** - - DESCRIPTOR AND DISPATCH LAYOUT - -**************************************************************************/ - -// -// CaptureFilterDescriptor: -// -// The filter descriptor for the capture device. -DEFINE_KSFILTER_DESCRIPTOR_TABLE (FilterDescriptors) { - &CaptureFilterDescriptor -}; - -// -// CaptureDeviceDispatch: -// -// This is the dispatch table for the capture device. Plug and play -// notifications as well as power management notifications are dispatched -// through this table. -// -const -KSDEVICE_DISPATCH -CaptureDeviceDispatch = { - CCaptureDevice::DispatchCreate, // Pnp Add Device - CCaptureDevice::DispatchPnpStart, // Pnp Start - NULL, // Post-Start - NULL, // Pnp Query Stop - NULL, // Pnp Cancel Stop - CCaptureDevice::DispatchPnpStop, // Pnp Stop - NULL, // Pnp Query Remove - NULL, // Pnp Cancel Remove - NULL, // Pnp Remove - NULL, // Pnp Query Capabilities - NULL, // Pnp Surprise Removal - NULL, // Power Query Power - NULL, // Power Set Power - NULL // Pnp Query Interface -}; - -// -// CaptureDeviceDescriptor: -// -// This is the device descriptor for the capture device. It points to the -// dispatch table and contains a list of filter descriptors that describe -// filter-types that this device supports. Note that the filter-descriptors -// can be created dynamically and the factories created via -// KsCreateFilterFactory as well. -// -const -KSDEVICE_DESCRIPTOR -CaptureDeviceDescriptor = { - &CaptureDeviceDispatch, - 0, - NULL -}; - -/************************************************************************** - - INITIALIZATION CODE - -**************************************************************************/ - - -extern "C" DRIVER_INITIALIZE DriverEntry; - -extern "C" -NTSTATUS -DriverEntry ( - IN PDRIVER_OBJECT DriverObject, - IN PUNICODE_STRING RegistryPath - ) - -/*++ - -Routine Description: - - Driver entry point. Pass off control to the AVStream initialization - function (KsInitializeDriver) and return the status code from it. - -Arguments: - - DriverObject - - The WDM driver object for our driver - - RegistryPath - - The registry path for our registry info - -Return Value: - - As from KsInitializeDriver - ---*/ - -{ - // - // Simply pass the device descriptor and parameters off to AVStream - // to initialize us. This will cause filter factories to be set up - // at add & start. Everything is done based on the descriptors passed - // here. - // - return - KsInitializeDriver ( - DriverObject, - RegistryPath, - &CaptureDeviceDescriptor - ); - -} diff --git a/avstream/avshws/device.h b/avstream/avshws/device.h deleted file mode 100644 index 2bd9899d..00000000 --- a/avstream/avshws/device.h +++ /dev/null @@ -1,294 +0,0 @@ -/************************************************************************** - - AVStream Simulated Hardware Sample - - Copyright (c) 2001, Microsoft Corporation. - - File: - - device.h - - Abstract: - - The header for the device level of the simulated hardware. This is - not actually the hardware simulation itself. The hardware simulation - is contained in hwsim.*, image.*. - - History: - - created 3/9/2001 - -**************************************************************************/ - -class CCaptureDevice : - public IHardwareSink { - -private: - - // - // The AVStream device we're associated with. - // - PKSDEVICE m_Device; - - // - // Number of pins with resources acquired. This is used as a locking - // mechanism for resource acquisition on the device. - // - LONG m_PinsWithResources; - - // - // Since we don't have physical hardware, this provides the hardware - // simulation. m_HardwareSimulation provides the fake ISR, fake DPC, - // etc... m_ImageSynth provides RGB24 and UYVY image synthesis and - // overlay in software. - // - CHardwareSimulation *m_HardwareSimulation; - CImageSynthesizer *m_ImageSynth; - - // - // The number of ISR's that have occurred since capture started. - // - ULONG m_InterruptTime; - - // - // The last reading of mappings completed. - // - ULONG m_LastMappingsCompleted; - - // - // The Dma adapter object we acquired through IoGetDmaAdapter() during - // Pnp start. This must be initialized with AVStream in order to perform - // Dma directly into the capture buffers. - // - PADAPTER_OBJECT m_DmaAdapterObject; - - // - // The number of map registers returned from IoGetDmaAdapter(). - // - ULONG m_NumberOfMapRegisters; - - // - // The capture sink. When we complete scatter / gather mappings, we - // notify the capture sink. - // - ICaptureSink *m_CaptureSink; - - // - // The video info header we're basing hardware settings on. The pin - // provides this to us when acquiring resources and must guarantee its - // stability until resources are released. - // - PKS_VIDEOINFOHEADER m_VideoInfoHeader; - - // - // Cleanup(): - // - // This is the free callback for the bagged capture device. Not providing - // one will call ExFreePool, which is not what we want for a constructed - // C++ object. This simply deletes the capture device. - // - static - void - Cleanup ( - IN CCaptureDevice *CapDevice - ) - { - delete CapDevice; - } - - // - // PnpStart(): - // - // This is the Pnp start routine for our simulated hardware. Note that - // DispatchStart bridges to here in the context of the CCaptureDevice. - // - NTSTATUS - PnpStart ( - IN PCM_RESOURCE_LIST TranslatedResourceList, - IN PCM_RESOURCE_LIST UntranslatedResourceList - ); - - // - // PnpStop(): - // - // This is the Pnp stop routine for our simulated hardware. Note that - // DispatchStop bridges to here in the context of the CCaptureDevice. - // - void - PnpStop ( - ); - -public: - - // - // CCaptureDevice(): - // - // The capture device class constructor. Since everything should have - // been zero'ed by the new operator, don't bother setting anything to - // zero or NULL. Only initialize non-NULL, non-0 fields. - // - CCaptureDevice ( - IN PKSDEVICE Device - ) : - m_Device (Device) - { - } - - // - // ~CCaptureDevice(): - // - // The capture device destructor. - // - ~CCaptureDevice ( - ) - { - } - - // - // DispatchCreate(): - // - // This is the Add Device dispatch for the capture device. It creates - // the CCaptureDevice and associates it with the device via the bag. - // - static - NTSTATUS - DispatchCreate ( - IN PKSDEVICE Device - ); - // - // DispatchPnpStart(): - // - // This is the Pnp Start dispatch for the capture device. It simply - // bridges to PnpStart() in the context of the CCaptureDevice. - // - static - NTSTATUS - DispatchPnpStart ( - IN PKSDEVICE Device, - IN PIRP Irp, - IN PCM_RESOURCE_LIST TranslatedResourceList, - IN PCM_RESOURCE_LIST UntranslatedResourceList - ) - { - return - (reinterpret_cast (Device -> Context)) -> - PnpStart ( - TranslatedResourceList, - UntranslatedResourceList - ); - } - - // - // DispatchPnpStop(): - // - // This is the Pnp stop dispatch for the capture device. It simply - // bridges to PnpStop() in the context of the CCaptureDevice. - // - static - void - DispatchPnpStop ( - IN PKSDEVICE Device, - IN PIRP Irp - ) - { - return - (reinterpret_cast (Device -> Context)) -> - PnpStop ( - ); - } - - // - // AcquireHardwareResources(): - // - // Called to acquire hardware resources for the device based on a given - // video info header. This will fail if another object has already - // acquired hardware resources since we emulate a single capture - // device. - // - NTSTATUS - AcquireHardwareResources ( - IN ICaptureSink *CaptureSink, - IN PKS_VIDEOINFOHEADER VideoInfoHeader - ); - - // - // ReleaseHardwareResources(): - // - // Called to release hardware resources for the device. - // - void - ReleaseHardwareResources ( - ); - - // - // Start(): - // - // Called to start the hardware simulation. This causes us to simulate - // interrupts, simulate filling buffers with synthesized data, etc... - // - NTSTATUS - Start ( - ); - - // - // Pause(): - // - // Called to pause or unpause the hardware simulation. This will be - // indentical to a start or stop but it will not reset formats and - // counters. - // - NTSTATUS - Pause ( - IN BOOLEAN Pausing - ); - - // - // Stop(): - // - // Called to stop the hardware simulation. This causes interrupts to - // stop issuing. When this call returns, the "fake" hardware has - // stopped accessing all s/g buffers, etc... - // - NTSTATUS - Stop ( - ); - - // - // ProgramScatterGatherMappings(): - // - // Called to program the hardware simulation's scatter / gather table. - // This synchronizes with the "fake" ISR and hardware simulation via - // a spinlock. - // - ULONG - ProgramScatterGatherMappings ( - IN PKSSTREAM_POINTER Clone, - IN PUCHAR *Buffer, - IN PKSMAPPING Mappings, - IN ULONG MappingsCount - ); - - // - // QueryInterruptTime(): - // - // Determine the frame number that this frame corresponds to. - // - ULONG - QueryInterruptTime ( - ); - - // - // IHardwareSink::Interrupt(): - // - // The interrupt service routine as called through the hardware sink - // interface. The "fake" hardware uses this method to inform the device - // of a "fake" ISR. The routine is called at dispatch level and must - // be in locked code. - // - virtual - void - Interrupt ( - ); - - LONG GetDroppedFrameCount(){return m_HardwareSimulation->GetSkippedFrameCount();}; -}; diff --git a/avstream/avshws/filter.cpp b/avstream/avshws/filter.cpp deleted file mode 100644 index be0012cb..00000000 --- a/avstream/avshws/filter.cpp +++ /dev/null @@ -1,203 +0,0 @@ -/************************************************************************** - - AVStream Simulated Hardware Sample - - Copyright (c) 2001, Microsoft Corporation. - - File: - - filter.cpp - - Abstract: - - This file contains the filter level implementation for the - capture filter. - - History: - - created 3/12/2001 - -**************************************************************************/ - -#include "avshws.h" - -/************************************************************************** - - PAGEABLE CODE - -**************************************************************************/ - -#ifdef ALLOC_PRAGMA -#pragma code_seg("PAGE") -#endif // ALLOC_PRAGMA - - -NTSTATUS -CCaptureFilter:: -DispatchCreate ( - IN PKSFILTER Filter, - IN PIRP Irp - ) - -/*++ - -Routine Description: - - This is the creation dispatch for the capture filter. It creates - the CCaptureFilter object, associates it with the AVStream filter - object, and bag the CCaptureFilter for later cleanup. - -Arguments: - - Filter - - The AVStream filter being created - - Irp - - The creation Irp - -Return Value: - - Success / failure - ---*/ - -{ - - PAGED_CODE(); - - NTSTATUS Status = STATUS_SUCCESS; - - CCaptureFilter *CapFilter = new (NonPagedPool) CCaptureFilter (Filter); - - if (!CapFilter) { - // - // Return failure if we couldn't create the filter. - // - Status = STATUS_INSUFFICIENT_RESOURCES; - - } else { - // - // Add the item to the object bag if we we were successful. - // Whenever the filter closes, the bag is cleaned up and we will be - // freed. - // - Status = KsAddItemToObjectBag ( - Filter -> Bag, - reinterpret_cast (CapFilter), - reinterpret_cast (CCaptureFilter::Cleanup) - ); - - if (!NT_SUCCESS (Status)) { - delete CapFilter; - } else { - Filter -> Context = reinterpret_cast (CapFilter); - } - - } - - return Status; - -} - -/************************************************************************** - - DESCRIPTOR AND DISPATCH LAYOUT - -**************************************************************************/ - -GUID g_PINNAME_VIDEO_CAPTURE = {STATIC_PINNAME_VIDEO_CAPTURE}; - -// -// CaptureFilterCategories: -// -// The list of category GUIDs for the capture filter. -// -const -GUID -CaptureFilterCategories [CAPTURE_FILTER_CATEGORIES_COUNT] = { - STATICGUIDOF (KSCATEGORY_VIDEO), - STATICGUIDOF (KSCATEGORY_CAPTURE), - STATICGUIDOF (KSCATEGORY_VIDEO_CAMERA) -}; - -// -// CaptureFilterPinDescriptors: -// -// The list of pin descriptors on the capture filter. -// -const -KSPIN_DESCRIPTOR_EX -CaptureFilterPinDescriptors [CAPTURE_FILTER_PIN_COUNT] = { - // - // Video Capture Pin - // - { - &CapturePinDispatch, - NULL, - { - 0, // Interfaces (NULL, 0 == default) - NULL, - 0, // Mediums (NULL, 0 == default) - NULL, - SIZEOF_ARRAY(CapturePinDataRanges),// Range Count - CapturePinDataRanges, // Ranges - KSPIN_DATAFLOW_OUT, // Dataflow - KSPIN_COMMUNICATION_BOTH, // Communication - &PIN_CATEGORY_CAPTURE, // Category - &g_PINNAME_VIDEO_CAPTURE, // Name - 0 // Reserved - }, -#ifdef _X86_ - KSPIN_FLAG_GENERATE_MAPPINGS | // Pin Flags -#endif - KSPIN_FLAG_PROCESS_IN_RUN_STATE_ONLY, - 1, // Instances Possible - 1, // Instances Necessary - &CapturePinAllocatorFraming, // Allocator Framing - reinterpret_cast - (CCapturePin::IntersectHandler) - } -}; - -// -// CaptureFilterDispatch: -// -// This is the dispatch table for the capture filter. It provides notification -// of creation, closure, processing (for filter-centrics, not for the capture -// filter), and resets (for filter-centrics, not for the capture filter). -// -const -KSFILTER_DISPATCH -CaptureFilterDispatch = { - CCaptureFilter::DispatchCreate, // Filter Create - NULL, // Filter Close - NULL, // Filter Process - NULL // Filter Reset -}; - - -// -// CaptureFilterDescription: -// -// The descriptor for the capture filter. We don't specify any topology -// since there's only one pin on the filter. Realistically, there would -// be some topological relationships here because there would be input -// pins from crossbars and the like. -// -const -KSFILTER_DESCRIPTOR -CaptureFilterDescriptor = { - &CaptureFilterDispatch, // Dispatch Table - NULL, // Automation Table - KSFILTER_DESCRIPTOR_VERSION, // Version - 0, // Flags - &KSNAME_Filter, // Reference GUID - DEFINE_KSFILTER_PIN_DESCRIPTORS (CaptureFilterPinDescriptors), - DEFINE_KSFILTER_CATEGORIES (CaptureFilterCategories), - 0, - sizeof (KSNODE_DESCRIPTOR), - NULL, - 0, - NULL, - NULL // Component ID -}; \ No newline at end of file diff --git a/avstream/avshws/filter.h b/avstream/avshws/filter.h deleted file mode 100644 index e5cb9895..00000000 --- a/avstream/avshws/filter.h +++ /dev/null @@ -1,88 +0,0 @@ -/************************************************************************** - - AVStream Simulated Hardware Sample - - Copyright (c) 2001, Microsoft Corporation. - - File: - - filter.h - - Abstract: - - This file contains the filter level header for the capture filter. - - History: - - created 3/12/2001 - -**************************************************************************/ - -class CCaptureFilter { - -private: - - // - // The AVStream filter object associated with this CCaptureFilter. - // - PKSFILTER m_Filter; - - // - // Cleanup(): - // - // This is the bag cleanup callback for the CCaptureFilter. Not providing - // one would cause ExFreePool to be used. This is not good for C++ - // constructed objects. We simply delete the object here. - // - static - void - Cleanup ( - IN CCaptureFilter *CapFilter - ) - { - delete CapFilter; - } - -public: - - // - // CCaptureFilter(): - // - // The capture filter object constructor. Since the new operator will - // have zeroed the memory, do not bother initializing any NULL or 0 - // fields. Only initialize non-NULL, non-0 fields. - // - CCaptureFilter ( - IN PKSFILTER Filter - ) : - m_Filter (Filter) - { - } - - // - // ~CCaptureFilter(): - // - // The capture filter destructor. - // - ~CCaptureFilter ( - ) - { - } - - // - // DispatchCreate(): - // - // This is the filter creation dispatch for the capture filter. It - // creates the CCaptureFilter object, associates it with the AVStream - // object, and bags it for easy cleanup later. - // - static - NTSTATUS - DispatchCreate ( - IN PKSFILTER Filter, - IN PIRP Irp - ); - -}; - - diff --git a/avstream/avshws/hwsim.cpp b/avstream/avshws/hwsim.cpp deleted file mode 100644 index 8966f7a1..00000000 --- a/avstream/avshws/hwsim.cpp +++ /dev/null @@ -1,868 +0,0 @@ -/************************************************************************** - - AVStream Simulated Hardware Sample - - Copyright (c) 2001, Microsoft Corporation. - - File: - - hwsim.cpp - - Abstract: - - This file contains the hardware simulation. It fakes "DMA" transfers, - scatter gather mapping handling, ISR's, etc... The ISR routine in - here will be called when an ISR would be generated by the fake hardware - and it will directly call into the device level ISR for more accurate - simulation. - - History: - - created 3/9/2001 - -**************************************************************************/ - -#include "avshws.h" - - -/*************************************************/ -KDEFERRED_ROUTINE SimulatedInterrupt; - -void -SimulatedInterrupt ( - IN PKDPC Dpc, - IN PVOID DeferredContext, - IN PVOID SystemArg1, - IN PVOID SystemArg2 - ) -{ - CHardwareSimulation* HardwareSim = (CHardwareSimulation*)DeferredContext; - - if (HardwareSim) - { - HardwareSim -> FakeHardware (); - } -} - - -/************************************************************************** - - PAGEABLE CODE - -**************************************************************************/ - -#ifdef ALLOC_PRAGMA -#pragma code_seg("PAGE") -#endif // ALLOC_PRAGMA - - - -CHardwareSimulation:: -CHardwareSimulation ( - IN IHardwareSink *HardwareSink - ) : - m_HardwareSink (HardwareSink), - m_ScatterGatherMappingsMax (SCATTER_GATHER_MAPPINGS_MAX) - -/*++ - -Routine Description: - - Construct a hardware simulation - -Arguments: - - HardwareSink - - The hardware sink interface. This is used to trigger - fake interrupt service routines from. - -Return Value: - - Success / Failure - ---*/ - -{ - - PAGED_CODE(); - - // - // Initialize the DPC's, timer's, and locks necessary to simulate - // this capture hardware. - // - KeInitializeDpc ( - &m_IsrFakeDpc, - SimulatedInterrupt, - this - ); - - KeInitializeEvent ( - &m_HardwareEvent, - SynchronizationEvent, - FALSE - ); - - KeInitializeTimer (&m_IsrTimer); - - KeInitializeSpinLock (&m_ListLock); - -} - -/*************************************************/ - - -CHardwareSimulation * -CHardwareSimulation:: -Initialize ( - IN KSOBJECT_BAG Bag, - IN IHardwareSink *HardwareSink - ) - -/*++ - -Routine Description: - - Initialize the hardware simulation - -Arguments: - - HardwareSink - - The hardware sink interface. This is what ISR's will be - triggered through. - -Return Value: - - A fully initialized hardware simulation or NULL if the simulation - could not be initialized. - ---*/ - -{ - - PAGED_CODE(); - - CHardwareSimulation *HwSim = - new (NonPagedPool) CHardwareSimulation (HardwareSink); - - return HwSim; - -} - -/*************************************************/ - - -NTSTATUS -CHardwareSimulation:: -Start ( - IN CImageSynthesizer *ImageSynth, - IN LONGLONG TimePerFrame, - IN ULONG Width, - IN ULONG Height, - IN ULONG ImageSize - ) - -/*++ - -Routine Description: - - Start the hardware simulation. This will kick the interrupts on, - begin issuing DPC's, filling in capture information, etc... - We keep track of starvation starting at this point. - -Arguments: - - ImageSynth - - The image synthesizer to use to generate pictures to display - on the capture buffer. - - TimePerFrame - - The time per frame... we issue interrupts this often. - - Width - - The image width - - Height - - The image height - - ImageSize - - The size of the image. We allocate a temporary scratch buffer - based on this size to fake hardware. - -Return Value: - - Success / Failure (typical failure will be out of memory on the - scratch buffer, etc...) - ---*/ - -{ - - PAGED_CODE(); - - NTSTATUS Status = STATUS_SUCCESS; - - m_ImageSynth = ImageSynth; - m_TimePerFrame = TimePerFrame; - m_ImageSize = ImageSize; - m_Height = Height; - m_Width = Width; - - InitializeListHead (&m_ScatterGatherMappings); - m_NumMappingsCompleted = 0; - m_ScatterGatherMappingsQueued = 0; - m_NumFramesSkipped = 0; - m_InterruptTime = 0; - - KeQuerySystemTime (&m_StartTime); - - // - // Allocate a scratch buffer for the synthesizer. - // - m_SynthesisBuffer = reinterpret_cast ( - ExAllocatePoolWithTag ( - NonPagedPool, - m_ImageSize, - AVSHWS_POOLTAG - ) - ); - - if (!m_SynthesisBuffer) { - Status = STATUS_INSUFFICIENT_RESOURCES; - } - - // - // If everything is ok, start issuing interrupts. - // - if (NT_SUCCESS (Status)) { - - // - // Initialize the entry lookaside. - // - ExInitializeNPagedLookasideList ( - &m_ScatterGatherLookaside, - NULL, - NULL, - 0, - sizeof (SCATTER_GATHER_ENTRY), - 'nEGS', - 0 - ); - - // - // Set up the synthesizer with the width, height, and scratch buffer. - // - m_ImageSynth -> SetImageSize (m_Width, m_Height); - m_ImageSynth -> SetBuffer (m_SynthesisBuffer); - - LARGE_INTEGER NextTime; - NextTime.QuadPart = m_StartTime.QuadPart + m_TimePerFrame; - - m_HardwareState = HardwareRunning; - KeSetTimer (&m_IsrTimer, NextTime, &m_IsrFakeDpc); - - } - - return Status; - -} - -/*************************************************/ - - -NTSTATUS -CHardwareSimulation:: -Pause ( - BOOLEAN Pausing - ) - -/*++ - -Routine Description: - - Pause the hardware simulation... When the hardware simulation is told - to pause, it stops issuing interrupts, etc... but it does not reset - the counters - -Arguments: - - Pausing - - Indicates whether the hardware is pausing or not. - - TRUE - - Pause the hardware - - FALSE - - Unpause the hardware from a previous pause - - -Return Value: - - Success / Failure - ---*/ - -{ - - PAGED_CODE(); - - if (Pausing && m_HardwareState == HardwareRunning) { - // - // If we were running, stop completing mappings, etc... - // - m_StopHardware = TRUE; - - KeWaitForSingleObject ( - &m_HardwareEvent, - Suspended, - KernelMode, - FALSE, - NULL - ); - - NT_ASSERT (m_StopHardware == FALSE); - - m_HardwareState = HardwarePaused; - - } else if (!Pausing && m_HardwareState == HardwarePaused) { - - // - // For unpausing the hardware, we need to compute the relative time - // and restart interrupts. - // - LARGE_INTEGER UnpauseTime; - - KeQuerySystemTime (&UnpauseTime); - m_InterruptTime = (ULONG) ( - (UnpauseTime.QuadPart - m_StartTime.QuadPart) / - m_TimePerFrame - ); - - UnpauseTime.QuadPart = m_StartTime.QuadPart + - (m_InterruptTime + 1) * m_TimePerFrame; - - m_HardwareState = HardwareRunning; - KeSetTimer (&m_IsrTimer, UnpauseTime, &m_IsrFakeDpc); - - } - - return STATUS_SUCCESS; - -} - -/************************************************************************** - - LOCKED CODE - -**************************************************************************/ - -#ifdef ALLOC_PRAGMA -#pragma code_seg() -#endif // ALLOC_PRAGMA - -NTSTATUS -CHardwareSimulation:: -Stop ( - ) - -/*++ - -Routine Description: - - Stop the hardware simulation.... Wait until the hardware simulation - has successfully stopped and then return. - -Arguments: - - None - -Return Value: - - Success / Failure - ---*/ - -{ - KIRQL Irql; - // - // If the hardware is told to stop while it's running, we need to - // halt the interrupts first. If we're already paused, this has - // already been done. - // - if (m_HardwareState == HardwareRunning) { - - m_StopHardware = TRUE; - - KeWaitForSingleObject ( - &m_HardwareEvent, - Suspended, - KernelMode, - FALSE, - NULL - ); - - NT_ASSERT (m_StopHardware == FALSE); - - } - - m_HardwareState = HardwareStopped; - - // - // The image synthesizer may still be around. Just for safety's - // sake, NULL out the image synthesis buffer and toast it. - // - m_ImageSynth -> SetBuffer (NULL); - - if (m_SynthesisBuffer) { - ExFreePool (m_SynthesisBuffer); - m_SynthesisBuffer = NULL; - } - - // - // Protect the S/G list - // - KeAcquireSpinLock (&m_ListLock, &Irql); - // - // Free S/G buffer - // - // - while (m_ScatterGatherMappingsQueued > 0) { - LIST_ENTRY *listEntry = RemoveHeadList (&m_ScatterGatherMappings); - m_ScatterGatherMappingsQueued--; - PSCATTER_GATHER_ENTRY SGEntry = - reinterpret_cast ( - CONTAINING_RECORD ( - listEntry, - SCATTER_GATHER_ENTRY, - ListEntry - ) - ); - // - // Release the scatter / gather entry back to our lookaside. - // - ExFreeToNPagedLookasideList ( - &m_ScatterGatherLookaside, - reinterpret_cast (SGEntry) - ); - } - - m_NumMappingsCompleted = 0; - m_ScatterGatherBytesQueued = 0; - // - // Delete the scatter / gather lookaside for this run. - // - ExDeleteNPagedLookasideList (&m_ScatterGatherLookaside); - - KeReleaseSpinLock (&m_ListLock, Irql); - - return STATUS_SUCCESS; - -} - - -ULONG -CHardwareSimulation:: -ReadNumberOfMappingsCompleted ( - ) - -/*++ - -Routine Description: - - Read the number of scatter / gather mappings which have been - completed (TOTAL NUMBER) since the last reset of the simulated - hardware - -Arguments: - - None - -Return Value: - - Total number of completed mappings. - ---*/ - -{ - - // - // Don't care if this is being updated this moment in the DPC... I only - // need a number to return which isn't too great (too small is ok). - // In real hardware, this wouldn't be done this way anyway. - // - return m_NumMappingsCompleted; - -} - -/*************************************************/ - - -ULONG -CHardwareSimulation:: -ProgramScatterGatherMappings ( - IN PKSSTREAM_POINTER Clone, - IN PUCHAR *Buffer, - IN PKSMAPPING Mappings, - IN ULONG MappingsCount, - IN ULONG MappingStride - ) - -/*++ - -Routine Description: - - Program the scatter gather mapping list. This shoves a bunch of - entries on a list for access during the fake interrupt. Note that - we have physical addresses here only for simulation. We really - access via the virtual address.... although we chunk it into multiple - buffers to more realistically simulate S/G - -Arguments: - - Buffer - - The virtual address of the buffer mapped by the mapping list - - Mappings - - The KSMAPPINGS array corresponding to the buffer - - MappingsCount - - The number of mappings in the mappings array - - MappingStride - - The mapping stride used in initialization of AVStream DMA - -Return Value: - - Number of mappings actually inserted. - ---*/ - -{ - - KIRQL Irql; - - ULONG MappingsInserted = 0; - - // - // Protect our S/G list with a spinlock. - // - KeAcquireSpinLock (&m_ListLock, &Irql); - - // - // Loop through the scatter / gather list and break the buffer up into - // chunks equal to the scatter / gather mappings. Stuff the virtual - // addresses of these chunks on a list somewhere. We update the buffer - // pointer the caller passes as a more convenient way of doing this. - // - // If I could just remap physical in the list to virtual easily here, - // I wouldn't need to do it. - // -#if !defined(_X86_) - do - { - PSCATTER_GATHER_ENTRY Entry = - reinterpret_cast ( - ExAllocateFromNPagedLookasideList ( - &m_ScatterGatherLookaside - ) - ); - - if (!Entry) { - break; - } - Entry -> Virtual = *Buffer; - Entry -> ByteCount = MappingsCount; - Entry -> CloneEntry = Clone; - - // - // Move forward a specific number of bytes in chunking this into - // mapping sized va buffers. - // - *Buffer += MappingsCount; - Mappings = reinterpret_cast ( - (reinterpret_cast (Mappings) + MappingStride) - ); - - InsertTailList (&m_ScatterGatherMappings, &(Entry -> ListEntry)); - MappingsInserted = MappingsCount; - m_ScatterGatherMappingsQueued++; - m_ScatterGatherBytesQueued += MappingsCount; - - } - while(FALSE); - -#else - for (ULONG MappingNum = 0; - MappingNum < MappingsCount && - m_ScatterGatherMappingsQueued < m_ScatterGatherMappingsMax; - MappingNum++) { - - PSCATTER_GATHER_ENTRY Entry = - reinterpret_cast ( - ExAllocateFromNPagedLookasideList ( - &m_ScatterGatherLookaside - ) - ); - - if (!Entry) { - break; - } - - Entry -> Virtual = *Buffer; - Entry -> ByteCount = Mappings -> ByteCount; - - // - // Move forward a specific number of bytes in chunking this into - // mapping sized va buffers. - // - *Buffer += Entry -> ByteCount; - Mappings = reinterpret_cast ( - (reinterpret_cast (Mappings) + MappingStride) - ); - - InsertTailList (&m_ScatterGatherMappings, &(Entry -> ListEntry)); - MappingsInserted++; - m_ScatterGatherMappingsQueued++; - m_ScatterGatherBytesQueued += Entry -> ByteCount; - - } -#endif - - KeReleaseSpinLock (&m_ListLock, Irql); - - return MappingsInserted; - -} - -/*************************************************/ - - -NTSTATUS -CHardwareSimulation:: -FillScatterGatherBuffers ( - ) - -/*++ - -Routine Description: - - The hardware has synthesized a buffer in scratch space and we're to - fill scatter / gather buffers. - -Arguments: - - None - -Return Value: - - Success / Failure - ---*/ - -{ - - // - // We're using this list lock to protect our scatter / gather lists instead - // of some hardware mechanism / KeSynchronizeExecution / whatever. - // - KeAcquireSpinLockAtDpcLevel (&m_ListLock); - - PUCHAR Buffer = reinterpret_cast (m_SynthesisBuffer); - ULONG BufferRemaining = m_ImageSize; - - // - // For simplification, if there aren't enough scatter / gather buffers - // queued, we don't partially fill the ones that are available. We just - // skip the frame and consider it starvation. - // - // This could be enforced by only programming scatter / gather mappings - // for a buffer if all of them fit in the table also... - // - while (BufferRemaining && - m_ScatterGatherMappingsQueued > 0 && - m_ScatterGatherBytesQueued >= BufferRemaining) { - - LIST_ENTRY *listEntry = RemoveHeadList (&m_ScatterGatherMappings); - m_ScatterGatherMappingsQueued--; - - PSCATTER_GATHER_ENTRY SGEntry = - reinterpret_cast ( - CONTAINING_RECORD ( - listEntry, - SCATTER_GATHER_ENTRY, - ListEntry - ) - ); - - // - // Since we're software, we'll be accessing this by virtual address... - // - ULONG BytesToCopy = - (BufferRemaining < SGEntry -> ByteCount) ? - BufferRemaining : - SGEntry -> ByteCount; - - LONG Width = m_Width*(m_ImageSynth->GetBytesPerPixel()); - - LONG Stride = Width; - if(SGEntry->CloneEntry->StreamHeader->Size >= sizeof(KSSTREAM_HEADER)+sizeof(KS_FRAME_INFO)) - { - PKS_FRAME_INFO FrameInfo = reinterpret_cast (SGEntry->CloneEntry->StreamHeader+1); - if(FrameInfo->lSurfacePitch != 0) - { - Stride = FrameInfo->lSurfacePitch; - if(FrameInfo->lSurfacePitch < 0) - { - Stride = -Stride; - } - } - } - - for(ULONG y = 0; y < m_Height; y++) - { - RtlCopyMemory((SGEntry->Virtual+(ULONG)Stride*y), Buffer, Width); - Buffer += Width; - BytesToCopy -= Width; - BufferRemaining -= Width; - } - - m_NumMappingsCompleted++; - m_ScatterGatherBytesQueued -= SGEntry -> ByteCount; - - // - // Release the scatter / gather entry back to our lookaside. - // - ExFreeToNPagedLookasideList ( - &m_ScatterGatherLookaside, - reinterpret_cast (SGEntry) - ); - - } - - KeReleaseSpinLockFromDpcLevel (&m_ListLock); - - if (BufferRemaining) return STATUS_INSUFFICIENT_RESOURCES; - else return STATUS_SUCCESS; - -} - -/*************************************************/ - - -void -CHardwareSimulation:: -FakeHardware ( - ) - -/*++ - -Routine Description: - - Simulate an interrupt and what the hardware would have done in the - time since the previous interrupt. - -Arguments: - - None - -Return Value: - - None - ---*/ - -{ - - m_InterruptTime++; - - // - // The hardware can be in a pause state in which case, it issues interrupts - // but does not complete mappings. In this case, don't bother synthesizing - // a frame and doing the work of looking through the mappings table. - // - if (m_HardwareState == HardwareRunning) { - - // - // Generate a "time stamp" just to overlay it onto the capture image. - // It makes it more exciting than bars that do nothing. - // - LONGLONG PtsRel = ((m_InterruptTime + 1) * m_TimePerFrame); - - ULONG Min = (ULONG)(PtsRel / 600000000); - ULONG RemMin = (ULONG)(PtsRel % 600000000); - ULONG Sec = (ULONG)(RemMin / 10000000); - ULONG RemSec = (ULONG)(RemMin % 10000000); - ULONG Hund = (ULONG)(RemSec / 100000); - - // - // Synthesize a buffer in scratch space. - // - m_ImageSynth -> SynthesizeBars (); - - CHAR Text [256]; - Text[0] = '\0'; - (void) RtlStringCbPrintfA(Text, sizeof(Text), "%ld:%02ld.%02ld", Min, Sec, Hund); - - // - // Overlay a clock onto the scratch space image. - // - m_ImageSynth -> OverlayText ( - POSITION_CENTER, - (m_Height - 28), - 1, - Text, - BLACK, - WHITE - ); - - // - // Overlay a counter of skipped frames onto the scratch image. - // - (void) RtlStringCbPrintfA(Text, sizeof(Text), "Skipped: %ld", m_NumFramesSkipped); - m_ImageSynth -> OverlayText ( - 10, - 10, - 1, - Text, - TRANSPARENT, - BLUE - ); - - // - // Fill scatter gather buffers - // - if (!NT_SUCCESS (FillScatterGatherBuffers ())) { - InterlockedIncrement (PLONG (&m_NumFramesSkipped)); - } - - } - - // - // Issue an interrupt to our hardware sink. This is a "fake" interrupt. - // It will occur at DISPATCH_LEVEL. - // - m_HardwareSink -> Interrupt (); - - // - // Reschedule the timer if the hardware isn't being stopped. - // - if (!m_StopHardware) { - - // - // Reschedule the timer for the next interrupt time. - // - LARGE_INTEGER NextTime; - NextTime.QuadPart = m_StartTime.QuadPart + - (m_TimePerFrame * (m_InterruptTime + 1)); - - KeSetTimer (&m_IsrTimer, NextTime, &m_IsrFakeDpc); - - } else { - // - // If someone is waiting on the hardware to stop, raise the stop - // event and clear the flag. - // - m_StopHardware = FALSE; - KeSetEvent (&m_HardwareEvent, IO_NO_INCREMENT, FALSE); - } - -} diff --git a/avstream/avshws/hwsim.h b/avstream/avshws/hwsim.h deleted file mode 100644 index 21ddcb41..00000000 --- a/avstream/avshws/hwsim.h +++ /dev/null @@ -1,290 +0,0 @@ -/************************************************************************** - - AVStream Simulated Hardware Sample - - Copyright (c) 2001, Microsoft Corporation. - - File: - - hwsim.cpp - - Abstract: - - This file is the hardware simulation header. - - The simulation fakes "DMA" transfers, scatter gather mapping handling, - ISR's, etc... The ISR routine in here will be called when an ISR - would be generated by the fake hardware and it will directly call into - the device level ISR for more accurate simulation. - - History: - - created 3/9/2001 - -**************************************************************************/ - -// -// SCATTER_GATHER_MAPPINGS_MAX: -// -// The maximum number of entries in the hardware's scatter/gather list. I -// am making this so large for a few reasons: -// -// 1) we're faking this with uncompressed surfaces -- -// these are large buffers which will map to a lot of s/g entries -// 2) the fake hardware implementation requires at least one frame's -// worth of s/g entries to generate a frame -// -#define SCATTER_GATHER_MAPPINGS_MAX 128 - -// -// SCATTER_GATHER_ENTRY: -// -// This structure is used to keep the scatter gather table for the fake -// hardware as a doubly linked list. -// -typedef struct _SCATTER_GATHER_ENTRY { - - LIST_ENTRY ListEntry; - PKSSTREAM_POINTER CloneEntry; - PUCHAR Virtual; - ULONG ByteCount; - -} SCATTER_GATHER_ENTRY, *PSCATTER_GATHER_ENTRY; - -// -// CHardwareSimulation: -// -// The hardware simulation class. -// -class CHardwareSimulation { - -private: - - // - // The image synthesizer. This is a piece of code which actually draws - // the requested images. - // - CImageSynthesizer *m_ImageSynth; - - // - // The synthesis buffer. This is a private buffer we use to generate the - // capture image in. The fake "scatter / gather" mappings are filled - // in from this buffer during each interrupt. - // - PUCHAR m_SynthesisBuffer; - - // - // Key information regarding the frames we generate. - // - LONGLONG m_TimePerFrame; - ULONG m_Width; - ULONG m_Height; - ULONG m_ImageSize; - - // - // Scatter gather mappings for the simulated hardware. - // - KSPIN_LOCK m_ListLock; - LIST_ENTRY m_ScatterGatherMappings; - - // - // Lookaside for memory for the scatter / gather entries on the scatter / - // gather list. - // - NPAGED_LOOKASIDE_LIST m_ScatterGatherLookaside; - - // - // The current state of the fake hardware. - // - HARDWARE_STATE m_HardwareState; - - // - // The pause / stop hardware flag and event. - // - BOOLEAN m_StopHardware; - KEVENT m_HardwareEvent; - - // - // Maximum number of scatter / gather mappins in the s/g table of the - // fake hardware. - // - ULONG m_ScatterGatherMappingsMax; - - // - // Number of scatter / gather mappings that have been completed (total) - // since the start of the hardware or any reset. - // - ULONG m_NumMappingsCompleted; - - // - // Number of scatter / gather mappings that are queued for this hardware. - // - ULONG m_ScatterGatherMappingsQueued; - ULONG m_ScatterGatherBytesQueued; - - // - // Number of frames skipped due to lack of scatter / gather mappings. - // - ULONG m_NumFramesSkipped; - - // - // The "Interrupt Time". Number of "fake" interrupts that have occurred - // since the hardware was started. - // - ULONG m_InterruptTime; - - // - // The system time at start. - // - LARGE_INTEGER m_StartTime; - - // - // The DPC used to "fake" ISR - // - KDPC m_IsrFakeDpc; - KTIMER m_IsrTimer; - - // - // The hardware sink that will be used for interrupt notifications. - // - IHardwareSink *m_HardwareSink; - - // - // FillScatterGatherBuffers(): - // - // This is called by the hardware simulation to fill a series of scatter / - // gather buffers with synthesized data. - // - NTSTATUS - FillScatterGatherBuffers ( - ); - -public: - - LONG GetSkippedFrameCount() - { - return InterlockedExchange((LONG*)&this->m_NumFramesSkipped, this->m_NumFramesSkipped); - } - // - // CHardwareSimulation(): - // - // The hardware simulation constructor. Since the new operator will - // have zeroed the memory, only initialize non-NULL, non-0 fields. - // - CHardwareSimulation ( - IN IHardwareSink *HardwareSink - ); - - // - // ~CHardwareSimulation(): - // - // The hardware simulation destructor. - // - ~CHardwareSimulation ( - ) - { - } - - // - // Cleanup(): - // - // This is the free callback for the bagged hardware sim. Not providing - // one will call ExFreePool, which is not what we want for a constructed - // C++ object. This simply deletes the simulation. - // - static - void - Cleanup ( - IN CHardwareSimulation *HwSim - ) - { - delete HwSim; - } - - // - // FakeHardware(): - // - // Called from the simulated interrupt. First we fake the hardware's - // actions (at DPC) then we call the "Interrupt service routine" on - // the hardware sink. - // - void - FakeHardware ( - ); - - // - // Start(): - // - // "Start" the fake hardware. This will start issuing interrupts and - // DPC's. - // - // The frame rate, image size, and a synthesizer must be provided. - // - NTSTATUS - Start ( - CImageSynthesizer *ImageSynth, - IN LONGLONG TimePerFrame, - IN ULONG Width, - IN ULONG Height, - IN ULONG ImageSize - ); - - // - // Pause(): - // - // "Pause" or "unpause" the fake hardware. This will stop issuing - // interrupts or DPC's on a pause and restart them on an unpause. Note - // that this will not reset counters as a Stop() would. - // - NTSTATUS - Pause ( - IN BOOLEAN Pausing - ); - - // - // Stop(): - // - // "Stop" the fake hardware. This will stop issuing interrupts and - // DPC's. - // - NTSTATUS - Stop ( - ); - - // - // ProgramScatterGatherMappings(): - // - // Program a series of scatter gather mappings into the fake hardware. - // - ULONG - ProgramScatterGatherMappings ( - IN PKSSTREAM_POINTER Clone, - IN PUCHAR *Buffer, - IN PKSMAPPING Mappings, - IN ULONG MappingsCount, - IN ULONG MappingStride - ); - - // - // Initialize(): - // - // Initialize a piece of simulated hardware. - // - static - CHardwareSimulation * - Initialize ( - IN KSOBJECT_BAG Bag, - IN IHardwareSink *HardwareSink - ); - - // - // ReadNumberOfMappingsCompleted(): - // - // Read the number of mappings completed since the last hardware reset. - // - ULONG - ReadNumberOfMappingsCompleted ( - ); - -}; - diff --git a/avstream/avshws/image.cpp b/avstream/avshws/image.cpp deleted file mode 100644 index 8ab35624..00000000 --- a/avstream/avshws/image.cpp +++ /dev/null @@ -1,605 +0,0 @@ -/************************************************************************** - - AVStream Simulated Hardware Sample - - Copyright (c) 2001, Microsoft Corporation. - - File: - - image.cpp - - Abstract: - - The image synthesis and overlay code. These objects provide image - synthesis (pixel, color-bar, etc...) onto RGB24 and UYVY buffers as - well as software string overlay into these buffers. - - This entire file, data and all, must be in locked segments. - - History: - - created 1/16/2001 - -**************************************************************************/ - -#include "avshws.h" - -/************************************************************************** - - Constants - -**************************************************************************/ - -// -// g_FontData: -// -// The following is an 8x8 bitmapped font for use in the text overlay -// code. -// -UCHAR g_FontData [256][8] = { - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e}, - {0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e}, - {0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00}, - {0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00}, - {0x38, 0x7c, 0x38, 0xfe, 0xfe, 0x7c, 0x38, 0x7c}, - {0x10, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x7c}, - {0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00}, - {0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff}, - {0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00}, - {0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff}, - {0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78}, - {0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18}, - {0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0}, - {0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0}, - {0x99, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x99}, - {0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00}, - {0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00}, - {0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18}, - {0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00}, - {0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00}, - {0x3e, 0x63, 0x38, 0x6c, 0x6c, 0x38, 0xcc, 0x78}, - {0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00}, - {0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff}, - {0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00}, - {0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00}, - {0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00}, - {0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00}, - {0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00}, - {0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00}, - {0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00}, - {0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00}, - {0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00}, - {0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00}, - {0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00}, - {0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00}, - {0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00}, - {0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00}, - {0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00}, - {0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60}, - {0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00}, - {0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00}, - {0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0x7c, 0x00}, - {0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00}, - {0x78, 0xcc, 0x0c, 0x38, 0x60, 0xcc, 0xfc, 0x00}, - {0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00}, - {0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00}, - {0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00}, - {0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00}, - {0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00}, - {0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00}, - {0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00}, - {0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00}, - {0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60}, - {0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00}, - {0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00}, - {0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00}, - {0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00}, - {0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00}, - {0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00}, - {0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00}, - {0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00}, - {0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00}, - {0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00}, - {0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00}, - {0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00}, - {0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00}, - {0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00}, - {0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00}, - {0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00}, - {0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00}, - {0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00}, - {0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00}, - {0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00}, - {0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00}, - {0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00}, - {0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00}, - {0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00}, - {0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00}, - {0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0x00}, - {0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00}, - {0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00}, - {0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00}, - {0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00}, - {0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00}, - {0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00}, - {0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00}, - {0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00}, - {0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff}, - {0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00}, - {0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00}, - {0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00}, - {0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00}, - {0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00}, - {0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00}, - {0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8}, - {0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00}, - {0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00}, - {0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78}, - {0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00}, - {0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00}, - {0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00}, - {0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00}, - {0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00}, - {0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0}, - {0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e}, - {0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00}, - {0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00}, - {0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00}, - {0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00}, - {0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00}, - {0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00}, - {0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00}, - {0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8}, - {0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00}, - {0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00}, - {0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00}, - {0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00}, - {0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00}, - {0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x18, 0x0c, 0x78}, - {0x00, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00}, - {0x1c, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00}, - {0x7e, 0xc3, 0x3c, 0x06, 0x3e, 0x66, 0x3f, 0x00}, - {0xcc, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00}, - {0xe0, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00}, - {0x30, 0x30, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00}, - {0x00, 0x00, 0x78, 0xc0, 0xc0, 0x78, 0x0c, 0x38}, - {0x7e, 0xc3, 0x3c, 0x66, 0x7e, 0x60, 0x3c, 0x00}, - {0xcc, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00}, - {0xe0, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00}, - {0xcc, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00}, - {0x7c, 0xc6, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00}, - {0xe0, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00}, - {0xc6, 0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0xc6, 0x00}, - {0x30, 0x30, 0x00, 0x78, 0xcc, 0xfc, 0xcc, 0x00}, - {0x1c, 0x00, 0xfc, 0x60, 0x78, 0x60, 0xfc, 0x00}, - {0x00, 0x00, 0x7f, 0x0c, 0x7f, 0xcc, 0x7f, 0x00}, - {0x3e, 0x6c, 0xcc, 0xfe, 0xcc, 0xcc, 0xce, 0x00}, - {0x78, 0xcc, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00}, - {0x00, 0xcc, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00}, - {0x00, 0xe0, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00}, - {0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00}, - {0x00, 0xe0, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00}, - {0x00, 0xcc, 0x00, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8}, - {0xc3, 0x18, 0x3c, 0x66, 0x66, 0x3c, 0x18, 0x00}, - {0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00}, - {0x18, 0x18, 0x7e, 0xc0, 0xc0, 0x7e, 0x18, 0x18}, - {0x38, 0x6c, 0x64, 0xf0, 0x60, 0xe6, 0xfc, 0x00}, - {0xcc, 0xcc, 0x78, 0xfc, 0x30, 0xfc, 0x30, 0x30}, - {0xf8, 0xcc, 0xcc, 0xfa, 0xc6, 0xcf, 0xc6, 0xc7}, - {0x0e, 0x1b, 0x18, 0x3c, 0x18, 0x18, 0xd8, 0x70}, - {0x1c, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00}, - {0x38, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00}, - {0x00, 0x1c, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00}, - {0x00, 0x1c, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00}, - {0x00, 0xf8, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0x00}, - {0xfc, 0x00, 0xcc, 0xec, 0xfc, 0xdc, 0xcc, 0x00}, - {0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 0x00}, - {0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00}, - {0x30, 0x00, 0x30, 0x60, 0xc0, 0xcc, 0x78, 0x00}, - {0x00, 0x00, 0x00, 0xfc, 0xc0, 0xc0, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0xfc, 0x0c, 0x0c, 0x00, 0x00}, - {0xc3, 0xc6, 0xcc, 0xde, 0x33, 0x66, 0xcc, 0x0f}, - {0xc3, 0xc6, 0xcc, 0xdb, 0x37, 0x6f, 0xcf, 0x03}, - {0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00}, - {0x00, 0x33, 0x66, 0xcc, 0x66, 0x33, 0x00, 0x00}, - {0x00, 0xcc, 0x66, 0x33, 0x66, 0xcc, 0x00, 0x00}, - {0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88}, - {0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa}, - {0xdb, 0x77, 0xdb, 0xee, 0xdb, 0x77, 0xdb, 0xee}, - {0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18}, - {0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18}, - {0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18}, - {0x36, 0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36}, - {0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36}, - {0x00, 0x00, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18}, - {0x36, 0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36}, - {0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36}, - {0x00, 0x00, 0xfe, 0x06, 0xf6, 0x36, 0x36, 0x36}, - {0x36, 0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00}, - {0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00}, - {0x18, 0x18, 0xf8, 0x18, 0xf8, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18}, - {0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00}, - {0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18}, - {0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18}, - {0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00}, - {0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18}, - {0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18}, - {0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36}, - {0x36, 0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36}, - {0x36, 0x36, 0xf7, 0x00, 0xff, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36}, - {0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36}, - {0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00}, - {0x36, 0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36}, - {0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00}, - {0x36, 0x36, 0x36, 0x36, 0xff, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18}, - {0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36}, - {0x36, 0x36, 0x36, 0x36, 0x3f, 0x00, 0x00, 0x00}, - {0x18, 0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18}, - {0x00, 0x00, 0x00, 0x00, 0x3f, 0x36, 0x36, 0x36}, - {0x36, 0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36}, - {0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18}, - {0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18}, - {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, - {0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff}, - {0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0}, - {0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f}, - {0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x76, 0xdc, 0xc8, 0xdc, 0x76, 0x00}, - {0x00, 0x78, 0xcc, 0xf8, 0xcc, 0xf8, 0xc0, 0xc0}, - {0x00, 0xfc, 0xcc, 0xc0, 0xc0, 0xc0, 0xc0, 0x00}, - {0x00, 0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00}, - {0xfc, 0xcc, 0x60, 0x30, 0x60, 0xcc, 0xfc, 0x00}, - {0x00, 0x00, 0x7e, 0xd8, 0xd8, 0xd8, 0x70, 0x00}, - {0x00, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0xc0}, - {0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x00}, - {0xfc, 0x30, 0x78, 0xcc, 0xcc, 0x78, 0x30, 0xfc}, - {0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0x6c, 0x38, 0x00}, - {0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x6c, 0xee, 0x00}, - {0x1c, 0x30, 0x18, 0x7c, 0xcc, 0xcc, 0x78, 0x00}, - {0x00, 0x00, 0x7e, 0xdb, 0xdb, 0x7e, 0x00, 0x00}, - {0x06, 0x0c, 0x7e, 0xdb, 0xdb, 0x7e, 0x60, 0xc0}, - {0x38, 0x60, 0xc0, 0xf8, 0xc0, 0x60, 0x38, 0x00}, - {0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x00}, - {0x00, 0xfc, 0x00, 0xfc, 0x00, 0xfc, 0x00, 0x00}, - {0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0xfc, 0x00}, - {0x60, 0x30, 0x18, 0x30, 0x60, 0x00, 0xfc, 0x00}, - {0x18, 0x30, 0x60, 0x30, 0x18, 0x00, 0xfc, 0x00}, - {0x0e, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18}, - {0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0x70}, - {0x30, 0x30, 0x00, 0xfc, 0x00, 0x30, 0x30, 0x00}, - {0x00, 0x76, 0xdc, 0x00, 0x76, 0xdc, 0x00, 0x00}, - {0x38, 0x6c, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00}, - {0x0f, 0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x3c, 0x1c}, - {0x78, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00}, - {0x70, 0x18, 0x30, 0x60, 0x78, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} -}; - -// -// Standard definition of EIA-189-A color bars. The actual color definitions -// are either in CRGB24Synthesizer or CYUVSynthesizer. -// -const COLOR g_ColorBars[] = - {WHITE, YELLOW, CYAN, GREEN, MAGENTA, RED, BLUE, BLACK}; - -const UCHAR CRGB24Synthesizer::Colors [MAX_COLOR][3] = { - {0, 0, 0}, // BLACK - {255, 255, 255}, // WHITE - {0, 255, 255}, // YELLOW - {255, 255, 0}, // CYAN - {0, 255, 0}, // GREEN - {255, 0, 255}, // MAGENTA - {0, 0, 255}, // RED - {255, 0, 0}, // BLUE - {128, 128, 128} // GREY -}; - -const UCHAR CYUVSynthesizer::Colors [MAX_COLOR][3] = { - {128, 16, 128}, // BLACK - {128, 235, 128}, // WHITE - {16, 211, 146}, // YELLOW - {166, 170, 16}, // CYAN - {54, 145, 34}, // GREEN - {202, 106, 222}, // MAGENTA - {90, 81, 240}, // RED - {240, 41, 109}, // BLUE - {128, 125, 128}, // GREY -}; - -/************************************************************************** - - LOCKED CODE - -**************************************************************************/ - -#ifdef ALLOC_PRAGMA -#pragma code_seg() -#endif // ALLOC_PRAGMA - - -void -CImageSynthesizer:: -SynthesizeBars ( - ) - -/*++ - -Routine Description: - - Synthesize EIA-189-A standard color bars onto the Image. The image - in question is the current synthesis buffer. - -Arguments: - - None - -Return Value: - - None - ---*/ - -{ - const COLOR *CurColor = g_ColorBars; - ULONG ColorCount = SIZEOF_ARRAY (g_ColorBars); - - // - // Set the default cursor... - // - GetImageLocation (0, 0); - - // - // Synthesize a single line. - // - PUCHAR ImageStart = m_Cursor; - for (ULONG x = 0; x < m_Width; x++) - PutPixel (g_ColorBars [((x * ColorCount) / m_Width)]); - - PUCHAR ImageEnd = m_Cursor; - - // - // Copy the synthesized line to all subsequent lines. - // - for (ULONG line = 1; line < m_Height; line++) { - - GetImageLocation (0, line); - - RtlCopyMemory ( - m_Cursor, - ImageStart, - ImageEnd - ImageStart - ); - } -} - -/*************************************************/ - - -void -CImageSynthesizer:: -OverlayText ( - _In_ ULONG LocX, - _In_ ULONG LocY, - _In_ ULONG Scaling, - _In_ LPSTR Text, - _In_ COLOR BgColor, - _In_ COLOR FgColor - ) - -/*++ - -Routine Description: - - Overlay text onto the synthesized image. Clip to fit the image - if the overlay does not fit. The image buffer used is the set - synthesis buffer. - -Arguments: - - LocX - - The X location on the image to begin the overlay. This MUST - be inside the image. POSITION_CENTER may be used to indicate - horizontal centering. - - LocY - - The Y location on the image to begin the overlay. This MUST - be inside the image. POSITION_CENTER may be used to indicate - vertical centering. - - Scaling - - Normally, the overlay is done in 8x8 font. A scaling of - 2 indicates 16x16, 3 indicates 24x24 and so forth. - - Text - - A character string containing the information to overlay - - BgColor - - The background color of the overlay window. For transparency, - indicate TRANSPARENT here. - - FgColor - - The foreground color for the text overlay. - -Return Value: - - None - ---*/ - -{ - - NT_ASSERT ((LocX <= m_Width || LocX == POSITION_CENTER) && - (LocY <= m_Height || LocY == POSITION_CENTER)); - - ULONG StrLen = 0; - CHAR* CurChar; - - // - // Determine the character length of the string. - // - for (CurChar = Text; CurChar && *CurChar; CurChar++) - StrLen++; - - // - // Determine the physical size of the string plus border. There is - // a definable NO_CHARACTER_SEPARATION. If this is defined, there will - // be no added space between font characters. Otherwise, one empty pixel - // column is added between characters. - // - #ifndef NO_CHARACTER_SEPARATION - ULONG LenX = (StrLen * (Scaling << 3)) + 1 + StrLen; - #else // NO_CHARACTER_SEPARATION - ULONG LenX = (StrLen * (Scaling << 3)) + 2; - #endif // NO_CHARACTER_SEPARATION - - ULONG LenY = 2 + (Scaling << 3); - - // - // Adjust for center overlays. - // - // NOTE: If the overlay doesn't fit into the synthesis buffer, this - // merely left aligns the overlay and clips off the right side. - // - if (LocX == POSITION_CENTER) { - if (LenX >= m_Width) { - LocX = 0; - } else { - LocX = (m_Width >> 1) - (LenX >> 1); - } - } - - if (LocY == POSITION_CENTER) { - if (LenY >= m_Height) { - LocY = 0; - } else { - LocY = (m_Height >> 1) - (LenY >> 1); - } - } - - // - // Determine the amount of space available on the synthesis buffer. - // We will clip anything that finds itself outside the synthesis buffer. - // - ULONG SpaceX = m_Width - LocX; - ULONG SpaceY = m_Height - LocY; - - // - // Set the default cursor position. - // - GetImageLocation (LocX, LocY); - - // - // Overlay a background color row. - // - if (BgColor != TRANSPARENT && SpaceY) { - for (ULONG x = 0; x < LenX && x < SpaceX; x++) { - PutPixel (BgColor); - } - } - LocY++; - if (SpaceY) SpaceY--; - - // - // Loop across each row of the image. - // - for (ULONG row = 0; row < 8 && SpaceY; row++) { - // - // Generate a line. - // - GetImageLocation (LocX, LocY++); - - PUCHAR ImageStart = m_Cursor; - - ULONG CurSpaceX = SpaceX; - if (CurSpaceX) { - PutPixel (BgColor); - CurSpaceX--; - } - - // - // Generate the row'th row of the overlay. - // - CurChar = Text; - while (CurChar && *CurChar) { - - UCHAR CharBase = g_FontData [*CurChar++][row]; - for (ULONG mask = 0x80; mask && CurSpaceX; mask >>= 1) { - for (ULONG scale = 0; scale < Scaling && CurSpaceX; scale++) { - if (CharBase & mask) { - PutPixel (FgColor); - } else { - PutPixel (BgColor); - } - CurSpaceX--; - } - } - - // - // Separate each character by one space. Account for the border - // space at the end by placing the separator after the last - // character also. - // - #ifndef NO_CHARACTER_SEPARATION - if (CurSpaceX) { - PutPixel (BgColor); - CurSpaceX--; - } - #endif // NO_CHARACTER_SEPARATION - - } - - // - // If there is no separation character defined, account for the - // border. - // - #ifdef NO_CHARACTER_SEPARATION - if (CurSpaceX) { - PutPixel (BgColor); - CurSpaceX--; - } - #endif // NO_CHARACTER_SEPARATION - - - PUCHAR ImageEnd = m_Cursor; - // - // Copy the line downward scale times. - // - for (ULONG scale = 1; scale < Scaling && SpaceY; scale++) { - GetImageLocation (LocX, LocY++); - RtlCopyMemory (m_Cursor, ImageStart, ImageEnd - ImageStart); - SpaceY--; - } - - } - - // - // Add the bottom section of the overlay. - // - GetImageLocation (LocX, LocY); - if (BgColor != TRANSPARENT && SpaceY) { - for (ULONG x = 0; x < LenX && x < SpaceX; x++) { - PutPixel (BgColor); - } - } - -} diff --git a/avstream/avshws/image.h b/avstream/avshws/image.h deleted file mode 100644 index 95574479..00000000 --- a/avstream/avshws/image.h +++ /dev/null @@ -1,478 +0,0 @@ -/************************************************************************** - - AVStream Simulated Hardware Sample - - Copyright (c) 2001, Microsoft Corporation. - - File: - - image.h - - Abstract: - - The image synthesis and overlay header. These objects provide image - synthesis (pixel, color-bar, etc...) onto RGB24 and UYVY buffers as - well as software string overlay into these buffers. - - History: - - created 1/16/2001 - -**************************************************************************/ - -/************************************************************************** - - Constants - -**************************************************************************/ - -// -// COLOR: -// -// Pixel color for placement onto the synthesis buffer. -// -typedef enum { - - BLACK = 0, - WHITE, - YELLOW, - CYAN, - GREEN, - MAGENTA, - RED, - BLUE, - GREY, - - MAX_COLOR, - TRANSPARENT, - -} COLOR; - -// -// POSITION_CENTER: -// -// Only useful for text overlay. This can be substituted for LocX or LocY -// in order to center the text screen on the synthesis buffer. -// -#define POSITION_CENTER ((ULONG)-1) - -/************************************************* - - CImageSynthesizer - - This class synthesizes images in various formats for output from the - capture filter. It is capable of performing various text overlays onto - the image surface. - -*************************************************/ - -class CImageSynthesizer { - -protected: - - // - // The width and height the synthesizer is set to. - // - ULONG m_Width; - ULONG m_Height; - - // - // The synthesis buffer. All scan conversion happens in the synthesis - // buffer. This must be set with SetBuffer() before any scan conversion - // routines are called. - // - PUCHAR m_SynthesisBuffer; - - // - // The default cursor. This is a pointer into the synthesis buffer where - // a non specific PutPixel will be placed. - // - PUCHAR m_Cursor; - -public: - - // - // PutPixel(): - // - // Place a pixel at the specified image cursor and move right - // by one pixel. No bounds checking... wrap around occurs. - // - virtual void - PutPixel ( - PUCHAR *ImageLocation, - COLOR Color - ) = 0; - - // - // PutPixel(): - // - // Place a pixel at the default image cursor and move right - // by one pixel. No bounds checking... wrap around occurs. - // - // If the derived class doesn't provide an implementation, provide - // one. - // - virtual void - PutPixel ( - COLOR Color - ) - { - PutPixel (&m_Cursor, Color); - } - - virtual long - GetBytesPerPixel() = 0; - - - // - // GetImageLocation(): - // - // Get the location into the image buffer for a specific X/Y location. - // This also sets the synthesizer's default cursor to the position - // LocX, LocY. - // - virtual PUCHAR - GetImageLocation ( - ULONG LocX, - ULONG LocY - ) = 0; - - // - // SetImageSize(): - // - // Set the image size of the synthesis buffer. - // - void - SetImageSize ( - ULONG Width, - ULONG Height - ) - { - m_Width = Width; - m_Height = Height; - } - - // - // SetBuffer(): - // - // Set the buffer the synthesizer generates images to. - // - void - SetBuffer ( - PUCHAR SynthesisBuffer - ) - { - m_SynthesisBuffer = SynthesisBuffer; - } - - // - // SynthesizeBars(): - // - // Synthesize EIA-189-A standard color bars. - // - void - SynthesizeBars ( - ); - - // - // OverlayText(): - // - // Overlay a text string onto the image. - // - void - OverlayText ( - _In_ ULONG LocX, - _In_ ULONG LocY, - _In_ ULONG Scaling, - _In_ LPSTR Text, - _In_ COLOR BgColor, - _In_ COLOR FgColor - ); - - // - // DEFAULT CONSTRUCTOR - // - CImageSynthesizer ( - ) : - m_Width (0), - m_Height (0), - m_SynthesisBuffer (NULL) - { - } - - // - // CONSTRUCTOR: - // - CImageSynthesizer ( - ULONG Width, - ULONG Height - ) : - m_Width (Width), - m_Height (Height), - m_SynthesisBuffer (NULL) - { - } - - // - // DESTRUCTOR: - // - virtual - ~CImageSynthesizer ( - ) - { - } - -}; - -/************************************************* - - CRGB24Synthesizer - - Image synthesizer for RGB24 format. - -*************************************************/ - -class CRGB24Synthesizer : public CImageSynthesizer { - -private: - - const static UCHAR Colors [MAX_COLOR][3]; - - BOOLEAN m_FlipVertical; - -public: - - // - // PutPixel(): - // - // Place a pixel at a specific cursor location. *ImageLocation must - // reside within the synthesis buffer. - // - virtual void - PutPixel ( - PUCHAR *ImageLocation, - COLOR Color - ) - { - if (Color != TRANSPARENT) { - *(*ImageLocation)++ = Colors [(ULONG)Color][0]; - *(*ImageLocation)++ = Colors [(ULONG)Color][1]; - *(*ImageLocation)++ = Colors [(ULONG)Color][2]; - } else { - *ImageLocation += 3; - } - } - - // - // PutPixel(): - // - // Place a pixel at the default cursor location. The cursor location - // must be set via GetImageLocation(x, y). - // - virtual void - PutPixel ( - COLOR Color - ) - { - if (Color != TRANSPARENT) { - *m_Cursor++ = Colors [(ULONG)Color][0]; - *m_Cursor++ = Colors [(ULONG)Color][1]; - *m_Cursor++ = Colors [(ULONG)Color][2]; - } else { - m_Cursor += 3; - } - } - - virtual long - GetBytesPerPixel () - { - return 3; - } - - virtual PUCHAR - GetImageLocation ( - ULONG LocX, - ULONG LocY - ) - { - if (m_FlipVertical) { - return (m_Cursor = - (m_SynthesisBuffer + 3 * - (LocX + (m_Height - 1 - LocY) * m_Width)) - ); - } else { - return (m_Cursor = - (m_SynthesisBuffer + 3 * (LocX + LocY * m_Width)) - ); - } - } - - // - // DEFAULT CONSTRUCTOR: - // - CRGB24Synthesizer ( - BOOLEAN FlipVertical - ) : - m_FlipVertical (FlipVertical) - { - } - - // - // CONSTRUCTOR: - // - CRGB24Synthesizer ( - BOOLEAN FlipVertical, - ULONG Width, - ULONG Height - ) : - CImageSynthesizer (Width, Height), - m_FlipVertical (FlipVertical) - { - } - - // - // DESTRUCTOR: - // - virtual - ~CRGB24Synthesizer ( - ) - { - } - -}; - -/************************************************* - - CYUVSynthesizer - - Image synthesizer for YUV format. - -*************************************************/ - -class CYUVSynthesizer : public CImageSynthesizer { - -private: - - const static UCHAR Colors [MAX_COLOR][3]; - - BOOLEAN m_Parity; - -public: - - // - // PutPixel(): - // - // Place a pixel at a specific cursor location. *ImageLocation must - // reside within the synthesis buffer. - // - virtual void - PutPixel ( - PUCHAR *ImageLocation, - COLOR Color - ) - { - - BOOLEAN Parity = (((*ImageLocation - m_SynthesisBuffer) & 0x2) != 0); - -#if DBG - // - // Check that the current pixel points to a valid start pixel - // in the UYVY buffer. - // - BOOLEAN Odd = (((*ImageLocation - m_SynthesisBuffer) & 0x1) != 0); - NT_ASSERT ((m_Parity && Odd) || (!m_Parity && !Odd)); -#endif // DBG - - if (Color != TRANSPARENT) { - if (Parity) { - *(*ImageLocation)++ = Colors [(ULONG)Color][2]; - } else { - *(*ImageLocation)++ = Colors [(ULONG)Color][1]; - *(*ImageLocation)++ = Colors [(ULONG)Color][0]; - *(*ImageLocation)++ = Colors [(ULONG)Color][1]; - } - } else { - *ImageLocation += (Parity ? 1 : 3); - } - - } - - // - // PutPixel(): - // - // Place a pixel at the default cursor location. The cursor location - // must be set via GetImageLocation(x, y). - // - virtual void - PutPixel ( - COLOR Color - ) - - { - - if (Color != TRANSPARENT) { - if (m_Parity) { - *m_Cursor++ = Colors [(ULONG)Color][2]; - } else { - *m_Cursor++ = Colors [(ULONG)Color][1]; - *m_Cursor++ = Colors [(ULONG)Color][0]; - *m_Cursor++ = Colors [(ULONG)Color][1]; - } - } else { - m_Cursor += (m_Parity ? 1 : 3); - } - - m_Parity = !m_Parity; - - } - - virtual long - GetBytesPerPixel () - { - return 2; - } - - virtual PUCHAR - GetImageLocation ( - ULONG LocX, - ULONG LocY - ) - { - - m_Cursor = m_SynthesisBuffer + ((LocX + LocY * m_Width) << 1); - if (m_Parity = ((LocX & 1) != 0)) - m_Cursor++; - - return m_Cursor; - } - - // - // DEFAULT CONSTRUCTOR: - // - CYUVSynthesizer ( - ) - { - } - - // - // CONSTRUCTOR: - // - CYUVSynthesizer ( - ULONG Width, - ULONG Height - ) : - CImageSynthesizer (Width, Height) - { - } - - // - // DESTRUCTOR: - // - virtual - ~CYUVSynthesizer ( - ) - { - } - -}; - diff --git a/avstream/avshws/purecall.c b/avstream/avshws/purecall.c deleted file mode 100644 index ea61fbff..00000000 --- a/avstream/avshws/purecall.c +++ /dev/null @@ -1,50 +0,0 @@ -/************************************************************************** - - AVStream Simulated Hardware Sample - - Copyright (c) 2001, Microsoft Corporation. - - File: - - purecall.c - - Abstract: - - This file contains the _purecall stub necessary for virtual function - usage in drivers on 98 gold. - - History: - - created 9/16/02 - -**************************************************************************/ - -/************************************************* - - Function: - - _purecall - - Description: - - _purecall stub for virtual function usage - - Arguments: - - None - - Return Value: - - 0 - -*************************************************/ -#pragma warning (disable : 4100 4131) -int __cdecl -_purecall ( - VOID - ) - -{ - return 0; -} - diff --git a/avstream/samplemft0/SampleMft0.sln b/avstream/samplemft0/SampleMft0.sln index fc84dbf4..64e3c78f 100644 --- a/avstream/samplemft0/SampleMft0.sln +++ b/avstream/samplemft0/SampleMft0.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SampleMft0", "SampleMft0.vcxproj", "{3661ABB3-1FA5-44BC-8027-1B444A275EEE}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SampleMft0", "SampleMft0.vcxproj", "{88F464FD-A174-4CAD-BB13-A599CA5873D6}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +13,14 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {3661ABB3-1FA5-44BC-8027-1B444A275EEE}.Debug|Win32.ActiveCfg = Debug|Win32 - {3661ABB3-1FA5-44BC-8027-1B444A275EEE}.Debug|Win32.Build.0 = Debug|Win32 - {3661ABB3-1FA5-44BC-8027-1B444A275EEE}.Release|Win32.ActiveCfg = Release|Win32 - {3661ABB3-1FA5-44BC-8027-1B444A275EEE}.Release|Win32.Build.0 = Release|Win32 - {3661ABB3-1FA5-44BC-8027-1B444A275EEE}.Debug|x64.ActiveCfg = Debug|x64 - {3661ABB3-1FA5-44BC-8027-1B444A275EEE}.Debug|x64.Build.0 = Debug|x64 - {3661ABB3-1FA5-44BC-8027-1B444A275EEE}.Release|x64.ActiveCfg = Release|x64 - {3661ABB3-1FA5-44BC-8027-1B444A275EEE}.Release|x64.Build.0 = Release|x64 + {88F464FD-A174-4CAD-BB13-A599CA5873D6}.Debug|Win32.ActiveCfg = Debug|Win32 + {88F464FD-A174-4CAD-BB13-A599CA5873D6}.Debug|Win32.Build.0 = Debug|Win32 + {88F464FD-A174-4CAD-BB13-A599CA5873D6}.Release|Win32.ActiveCfg = Release|Win32 + {88F464FD-A174-4CAD-BB13-A599CA5873D6}.Release|Win32.Build.0 = Release|Win32 + {88F464FD-A174-4CAD-BB13-A599CA5873D6}.Debug|x64.ActiveCfg = Debug|x64 + {88F464FD-A174-4CAD-BB13-A599CA5873D6}.Debug|x64.Build.0 = Debug|x64 + {88F464FD-A174-4CAD-BB13-A599CA5873D6}.Release|x64.ActiveCfg = Release|x64 + {88F464FD-A174-4CAD-BB13-A599CA5873D6}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/avstream/samplemft0/SampleMft0.vcxproj b/avstream/samplemft0/SampleMft0.vcxproj index 0bf821f3..ef9548b8 100644 --- a/avstream/samplemft0/SampleMft0.vcxproj +++ b/avstream/samplemft0/SampleMft0.vcxproj @@ -19,11 +19,11 @@ - {3661ABB3-1FA5-44BC-8027-1B444A275EEE} + {88F464FD-A174-4CAD-BB13-A599CA5873D6} $(MSBuildProjectName) Debug Win32 - {47328477-96F3-446D-8354-FC9AC4B6154D} + {01B26604-84E9-4055-B490-900335F245E9} diff --git a/avstream/samplemft0/SampleMft0.vcxproj.Filters b/avstream/samplemft0/SampleMft0.vcxproj.Filters index b8df8584..fe1c62a2 100644 --- a/avstream/samplemft0/SampleMft0.vcxproj.Filters +++ b/avstream/samplemft0/SampleMft0.vcxproj.Filters @@ -3,15 +3,15 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {60B49576-F845-4721-98B6-4B94304459BD} + {1D447F88-CC6C-422F-8181-8A5880E77E15} h;hpp;hxx;hm;inl;inc;xsd - {176EFA30-A762-4CC7-98E3-21230AC1411A} + {E18FF6EE-9EED-46A0-A204-040342E4F4EF} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {87076883-275D-4C8B-84E7-B0108688E1C1} + {E441010A-8812-4C39-8275-FCAE9832E077} diff --git a/bluetooth/bthecho/ReadMe.md b/bluetooth/bthecho/ReadMe.md new file mode 100644 index 00000000..8bc6e35f --- /dev/null +++ b/bluetooth/bthecho/ReadMe.md @@ -0,0 +1,235 @@ +Bluetooth Echo L2CAP Profile Driver +=================================== + +This sample demonstrates developing [Bluetooth L2CAP profile drivers](http://msdn.microsoft.com/en-us/library/windows/hardware/ff536598) using [Bluetooth L2CAP DDIs](http://msdn.microsoft.com/en-us/library/windows/hardware/ff536585).The sample includes two drivers. One for a device that acts as an L2CAP server and another for a device that acts as an L2CAP client. The server simply echoes back any data that it receives from client on the same L2CA channel. These drivers can be used with devices that can be installed with bth.inf. Such devices get installed as ‘Generic Bluetooth Radio’. Examples of such devices are Bluetooth USB dongles such as (but not limited to): + +``` {.syntax xml:space="preserve"} +Generic Bluetooth Radio=\ + BthUsb, USB\Vid_0a12&Pid_0001 +CSR Nanosira=\ + BthUsb, USB\Vid_0a12&Pid_0003 +CSR Nanosira WHQL Reference Radio=\ + BthUsb, USB\Vid_0a12&Pid_0004 +CSR Nanosira-Multimedia=\ + BthUsb, USB\Vid_0a12&Pid_0005 +CSR Nanosira-Multimedia WHQL Reference Radio=\ + BthUsb, USB\Vid_0a12&Pid_0006 +``` + +Please refer to bth.inf for the complete list of devices. The installation steps below describe how to install echo server and client with such a device. Please note that RFCOMM based profiles must be developed and accessed using user-mode socket APIs. This sample is applicable to Windows® Vista, Windows® 7 and Windows® 8 operating systems. + +**Note**   + +To build this sample, you can use Microsoft Visual Studio 2013 (Express, Professional, or Ultimate) and Windows Driver Kit (WDK) 8.1 Update. You can get Visual Studio 2013 and WDK 8.1 Update [here](http://go.microsoft.com/fwlink/p/?LInkID=239721). + +You can also build this sample with Visual Studio 2013 (Professional or Ultimate) and [Windows Driver Kit (WDK) 8.1](http://go.microsoft.com/fwlink/p/?LInkID=391348). + +For Windows Driver Kit (WDK) 8 samples, download the [WDK 8 samples pack](%20http://go.microsoft.com/fwlink/?LinkId=317090). The samples in the WDK 8 samples pack will build only with Microsoft Visual Studio Professional 2012 (Professional or Ultimate) and WDK 8. + +Operating system requirements +----------------------------- + +Client + +Windows 7 + +Server + +Windows Server 2008 R2 + +Build the sample +---------------- + +Starting in the WDK, you can build the sample in two ways: using the Visual Studio Integrated Development Environment (IDE) or from the command line using the Visual Studio Command Prompt window and the Microsoft Build Engine (MSBuild.exe). + +**Building the sample using Visual Studio** + +1. Open Visual Studio. From the **File** menu, select **Open Project/Solution**. Within your WDK installation, navigate to src\\bluetooth\\bthecho and open the bthecho.sln project file. +2. Right-click the solution in the **Solution Explorer** and select **Configuration Manager**. +3. From the **Configuration Manager**, select the **Active Solution Configuration** (for example, Windows 8.1 Debug or Windows 8.1 Release) and the **Active Solution Platform** (for example, Win32) that correspond to the type of build you are interested in. +4. From the **Build** menu, click **Build Solution** (Ctrl+Shift+B). + +Previous versions of the WDK used the Windows Build utility (Build.exe) and provided separate build environment windows for each of the supported build configurations. Starting in the WDK, you can use the Visual Studio Command Prompt window for all build configurations. + +**Building the sample using the command line (MSBuild)** + +1. Open a Visual Studio Command Prompt window. Click **Start** and search for **Developer Command Prompt**. If your project is under %PROGRAMFILES%, you need to open the command prompt window using elevated permissions (**Run as administrator**). From this window you can use MsBuild.exe to build any Visual Studio project by specifying the project (.VcxProj) or solutions (.Sln) file. +2. Navigate to each of the respective project directories and enter the appropriate **MSbuild** command for your target. For example, to perform a clean build of a Visual Studio driver project called BthEcho.vcxproj, navigate to the samples\\bluetooth\\bthecho\\bthcli\\sys project directory and enter the following MSBuild command: **msbuild /t:clean /t:build .\\BthEchoSampleCli.vcxproj**. +3. If the build succeeds, you will find the driver (BthEchoSampleCli.sys) in the binary output directory corresponding to the target platform, for example src\\bluetooth\\bthecho\\PackageWindows 8.1 Debug. + +Run the sample +-------------- + +**INSTALLATION** + +**Note**: Bluetooth echo server device and echo client device must be installed on two different machines, as described below. + +**Server Installation** + +1. Copy KMDF coinstaller (wdfcoinstallerMMmmm.dll, from redist\\wdf\\ ), BthEchoSampleSrv.Sys, BthEchoSampleSrv.inf and bthsrvinst.exe on a temporary directory on the target machine. + +2. Run bthsrvinst.exe /i to install the echo server device. This enables the Bluetooth Enumerator (BthEnum.sys) to enumerate echo server device and create a PDO for the device (please refer to the device tree below). + +3. Step \#2 causes BthEnum.sys to create a PDO. Consequently hardware installation wizard gets launched. Either go through the UI (Device Manager – Update Driver Software in Windows® 7, ‘Found New Hardware’ wizard in Windows® Vista) and point it to the temporary directory where you copied the binaries in step \#1, or using devcon.exe from the tools\\devcon folder, run the following command from the temporary directory: + +``` {.syntax xml:space="preserve"} +devcon.exe update BthEchoSampleSrv.inf BTHENUM\{c07508f2-b970-43ca-b5dd-cc4f2391bef4} +``` + +If devcon.exe fails check the error level using: + +``` {.syntax xml:space="preserve"} +echo %errorlevel% +``` + +If errorlevel is 1, you need to reboot the machine for KMDF update to take effect. If errorlevel is 2, please make sure that you have the driver files described in \#1 available in the current directory. For more information on installation failure please check setup logs. + +4. Upon successful installation you will see ‘Bluetooth Echo Sample Server’ in Device Manager under Bluetooth devices. + +5. (This steps in needed only on Windows® Vista) Navigate to the system tray, right click on the Bluetooth icon, and select ‘Open Settings’. This launches the ‘Bluetooth Settings’ dialog. On the ‘Options’ tab, check ‘Allow Bluetooth devices to find this Computer’. Note that this will make your computer discoverable to other Bluetooth devices, and should be disabled again when no longer required. + +**Device tree for Echo Server device** + +(Drivers for FDOs are shown for each devnode in the tree.) + +``` {.syntax xml:space="preserve"} + -------------------- +|BthEchoSampleSrv.sys|<----Function driver for PDO ejected by BthEnum.sys + -------------------- + ^ + | -------------------- + | |Bluetooth Enumerator| + -----| (BthEnum.SYS) | + -------------------- + ^ + | (Bth port driver loaded by bthusb.sys) + | --------------------- ---------------------- + -----| bthport.SYS |<--->| bthusb.SYS | + --------------------- ---------------------- + ^ + | + V + ---------------------- + | USB Stack | + ---------------------- + ^ + | + V + ---------------------- + | USB Bluetooth Dongle | + ---------------------- +``` + +**Client Installation** + +1. **Important**: This must be done on a separate machine from the one where echo server device was installed. + +2. Copy KMDF coinstaller (wdfcoinstallerMMmmm.dll, from redist\\wdf\\), BthEchoSampleCli.Sys, BthEchoSampleCli.inf and bthecho.exe on a temporary directory on the target machine. + +3. Run bthprops.cpl from a command line or right click on the Bluetooth icon in the system tray and select ‘Show Devices' to bring up a list of installed Bluetooth devices. + +4. Windows® 7: In the ‘Bluetooth Devices’ window click the ‘Add a device’ button. Windows® Vista: In the ‘Devices’ tab, click Add button. + +5. In the Add a Device wizard select the server machine (the machine where you installed the echo server) as a Bluetooth device. If the server machine does not appear, please check the echo server installation and make sure that you have enabled ‘Allow Bluetooth device to find this computer’ on the server machine as explained above. When the server machine is correctly displayed, select it and pick ‘Next’. + +6. The wizard should default to a numeric compare ceremony for pairing the machines. When this happens, ensure the numbers match on both the client and the server, select ‘Yes’ on both machines to indicate they match, and click ‘Next’ on both machines to complete the pairing. + +7. The ‘Found New Hardware’ wizard will be launched on Windows® Vista. On Windows® 7 and Windows® 8 you will need to go through Device Manager and update driver software for it. Either point the wizard to the temporary directory created in step \#2, or use devcon.exe from the tools\\devcon folder to install the client device: + +``` {.syntax xml:space="preserve"} +Devcon.exe update BthEchoSampleCli.inf BTHENUM\{c07508f2-b970-43ca-b5dd-cc4f2391bef4} +``` + +Check for any error from devcon.exe as described in server installation. + +If the installation is successful, you will see ‘Bluetooth Echo Sample Client’ in Device Manager under Bluetooth devices. + +The device tree for echo client device is similar to the one shown for the echo server device, since both client and server are enumerated by BthEnum.sys (although the installation mechanism and properties of client and server are different). + +**Uninstalling Server** + +1. Uninstall the device and delete driver software using the Bluetooth Devices window by running bthprops.cpl, right clicking on the device, and selecting ‘Remove Device’ + +2. Run bthsrvinst.exe /u to uninstall the echo server. This would make bthenum.sys stop enumerating the echo server. Without this step ‘Found New Hardware’ wizard will be launched again when you reconnect the device. + +**Uninstalling Client** + +1. Uninstall the device and delete driver software using the Bluetooth Devices window by running bthprops.cpl, right clicking on the device, and selecting ‘Remove Device’ + +**TESTING** + +Run BthEcho.exe on the client machine. You should see client sending data to the server and receiving the same data echoed back. Press Ctrl+c to terminate the application. You will see output similar to below: + +``` {.syntax xml:space="preserve"} +D:\bth\wdfcli>BthEcho.exe +DevicePath: \\?\bthenum#{c07508f2-b970-43ca-b5dd-cc4f2391bef4}_localmfg&000a#7&3 +62d0a3&0&000c55ff727a_c00000001#{fc71b33d-d528-4763-a86c-78777c7bcd7b} +Opened device successfully +Written 26 bytes: WDF Bluetooth Sample Echo +Reply from server 26 bytes: WDF Bluetooth Sample Echo +Written 26 bytes: WDF Bluetooth Sample Echo +Reply from server 26 bytes: WDF Bluetooth Sample Echo +Written 26 bytes: WDF Bluetooth Sample Echo +Reply from server 26 bytes: WDF Bluetooth Sample Echo +Written 26 bytes: WDF Bluetooth Sample Echo +Reply from server 26 bytes: WDF Bluetooth Sample Echo +Written 26 bytes: WDF Bluetooth Sample Echo +^C +``` + +You can launch multiple instances of BthEcho.exe. Each client application would cause echo client device to have an independent connection to the echo server and thereby have an independent echo session. You can also have echo client devices and apps installed on multiple machines and talking to a single echo server. + +**CODE TOUR** + +**Common code** + +**Connection object**: The common code contains implementation of a connection object (in connection.\*) that is utilized by both client and the server. Client uses this object to maintain the information about opened connection and the server uses this object to maintain information about the accepted connection. Connection object also supports continuous reader which is utilized by server to read the data sent by client. Connection object is implemented as a WDF user object. Connection details are maintained in BTHECHO\_CONNECTION structure. This structure is used as the context for WDF user object. Passive dispose is used to make the connection object cleanup wait for disconnect completion and continuous reader rundown. Please see WDF documentation for WDF user object and passive dispose (see WdfObjectCreate). + +**Server** + +**Startup**: Server registers PSM and L2CA server and published SDP record on startup in BthEchoSrvEvtDeviceSelfManagedIoInit (this callback is invoked by WDF during device start). While registering the L2CA server it passes BthEchoSrvIndicationCallback as the callback for incoming connection notifications. + +**Server SDP record creation**: The sample uses dynamic creation of server SDP record using Bluetooth DDIs. Please note that for your particular device you may be able to use static data for the SDP record. + +**Incoming connections**: Bluetooth stack invokes BthEchoSrvIndicationCallback for the incoming connections from clients. In response server accepts the connection and passes BthEchoSrvConnectionIndicationCallback callback to Bluetooth stack for disconnect notification. It is possible to use the same indication callback for server and connection but the sample uses different callbacks for clarity. Server adds the accepted connection to the connection list it maintains. Please see below for connection rundown details. + +**Connection rundown**: Server maintains a list of all the connections it has accepted. This allows server to properly close down these connections on orderly removal. On surprise removal bthport.sys itself gets removed and takes care of running down the connections, but in case of orderly removal driver has to make sure to rundown the connections. + +**Connection state machine**: + +``` {.syntax xml:space="preserve"} + ConnectFailed + ^ + | + | + | (connection failure) +Uninitialized ----> Connecting -------> Connected + | (disconnect) / ^ + | / / + | / / + V V / (connection complete) + Disconnecting + | (disconnect complete) + | + | + V + Disconnected +``` + +One transition to note here is that if disconnect is received in the connecting state (i.e. when the connection is not completed) we wait for connection to completed (transition to connected state) and then invoke disconnect. + +**Important**: Such state machine is needed only if Disconnect is initiated by something other than Bluetooth stack (for example device removal in our case). Bluetooth stack itself would not send disconnect before connect completion. If you adapt this sample for your device please evaluate whether your driver would require such state machine. For example, the echo client device does not need such state machine (although we use common connection code for client and the server). + +**Shutdown**: Server removes the SDP record and unregisters L2CAP server and PSM in BthEchoSrvEvtDeviceSelfManagedIoCleanup (this callback is invoked by WDF during device removal). It also disconnects any open connections (see Connection rundown above). + +**Client** + +**Startup**: Client retrieves local and server Bluetooth address in BthEchoSrvEvtDeviceSelfManagedIoInit (this callback is invoked by WDF during device start). Please note that server Bluetooth address would be available regardless of presence of the server. Thus echo client device start doesn’t fail even if echo server is not available. + +**Connecting to server**: Client connects to echo server when application opens a handle to it (BthEchoCliEvtDeviceFileCreate) and closes the connection on file close (BthEchoCliEvtFileClose). + +**Sending and receiving data from server**: When application writes data to the client, client sends this data to server on the connection opened for the given handle. Server would echo back this data. This data is retrieved by the application using a read operation. Echo Sample Client doesn’t do any draining of echoed data on its own. Application read/write are handled using a parallel WDF I/O queue. + +**Shutdown**: Client doesn’t need any specific shutdown code as connection open/close and read/write are done within the context of application’s handle open. + + diff --git a/bluetooth/bthecho/bthcli/app/BthEcho.vcxproj b/bluetooth/bthecho/bthcli/app/BthEcho.vcxproj new file mode 100644 index 00000000..f982f9b7 --- /dev/null +++ b/bluetooth/bthecho/bthcli/app/BthEcho.vcxproj @@ -0,0 +1,191 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {B506A244-2ADC-4C65-85B8-8B19764B4849} + $(MSBuildProjectName) + Debug + Win32 + {ED7BAD90-5755-4501-83C1-30383B8C2D76} + + + + Windows10 + False + Desktop + + WindowsApplicationForDrivers10.0 + Application + + + Windows10 + True + Desktop + + WindowsApplicationForDrivers10.0 + Application + + + Windows10 + False + Desktop + + WindowsApplicationForDrivers10.0 + Application + + + Windows10 + True + Desktop + + WindowsApplicationForDrivers10.0 + Application + + + + $(IntDir) + + + + + + + + + + + + + + + + BthEcho + + + BthEcho + + + BthEcho + + + BthEcho + + + + true + Level4 + %(PreprocessorDefinitions);UNICODE;_UNICODE + %(AdditionalIncludeDirectories);..\..\common\inc;$(DDK_INC_PATH) + + + + + %(PreprocessorDefinitions);UNICODE;_UNICODE + %(AdditionalIncludeDirectories);..\..\common\inc;$(DDK_INC_PATH) + + + %(PreprocessorDefinitions);UNICODE;_UNICODE + %(AdditionalIncludeDirectories);..\..\common\inc;$(DDK_INC_PATH) + + + %(AdditionalDependencies);cfgmgr32.lib + + + + + true + Level4 + %(PreprocessorDefinitions);UNICODE;_UNICODE + %(AdditionalIncludeDirectories);..\..\common\inc;$(DDK_INC_PATH) + + + + + %(PreprocessorDefinitions);UNICODE;_UNICODE + %(AdditionalIncludeDirectories);..\..\common\inc;$(DDK_INC_PATH) + + + %(PreprocessorDefinitions);UNICODE;_UNICODE + %(AdditionalIncludeDirectories);..\..\common\inc;$(DDK_INC_PATH) + + + %(AdditionalDependencies);cfgmgr32.lib + + + + + true + Level4 + %(PreprocessorDefinitions);UNICODE;_UNICODE + %(AdditionalIncludeDirectories);..\..\common\inc;$(DDK_INC_PATH) + + + + + %(PreprocessorDefinitions);UNICODE;_UNICODE + %(AdditionalIncludeDirectories);..\..\common\inc;$(DDK_INC_PATH) + + + %(PreprocessorDefinitions);UNICODE;_UNICODE + %(AdditionalIncludeDirectories);..\..\common\inc;$(DDK_INC_PATH) + + + %(AdditionalDependencies);cfgmgr32.lib + + + + + true + Level4 + %(PreprocessorDefinitions);UNICODE;_UNICODE + %(AdditionalIncludeDirectories);..\..\common\inc;$(DDK_INC_PATH) + + + + + %(PreprocessorDefinitions);UNICODE;_UNICODE + %(AdditionalIncludeDirectories);..\..\common\inc;$(DDK_INC_PATH) + + + %(PreprocessorDefinitions);UNICODE;_UNICODE + %(AdditionalIncludeDirectories);..\..\common\inc;$(DDK_INC_PATH) + + + %(AdditionalDependencies);cfgmgr32.lib + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/bluetooth/bthecho/bthcli/app/BthEcho.vcxproj.Filters b/bluetooth/bthecho/bthcli/app/BthEcho.vcxproj.Filters new file mode 100644 index 00000000..bb3d32ad --- /dev/null +++ b/bluetooth/bthecho/bthcli/app/BthEcho.vcxproj.Filters @@ -0,0 +1,22 @@ + + + + + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* + {0A8DC157-9CD8-47FC-96AB-AB876FCB97C8} + + + h;hpp;hxx;hm;inl;inc;xsd + {B0233FE1-6785-4466-886B-FC81C40F8257} + + + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml + {6E8F0465-6F65-432E-9958-9869CF84EB6B} + + + + + Source Files + + + \ No newline at end of file diff --git a/bluetooth/bthecho/bthcli/app/main.cpp b/bluetooth/bthecho/bthcli/app/main.cpp new file mode 100644 index 00000000..07b100e0 --- /dev/null +++ b/bluetooth/bthecho/bthcli/app/main.cpp @@ -0,0 +1,182 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + Main.cpp + +Abstract: + + A simple test for bthecho sample. + +Environment: + + user mode only + +--*/ + +#define INITGUID + +#include +#include +#include +#include +#include + +#include "public.h" + +char testData[] = "WDF Bluetooth Sample Echo"; +char replyData[sizeof(testData)]; + +DWORD +GetDevicePath( + _In_ LPGUID InterfaceGuid, + _Out_ LPWSTR * DevicePath + ); + +BOOL +DoEcho( + HANDLE hDevice + ); + +VOID +__cdecl +wmain() +{ + HANDLE hDevice = INVALID_HANDLE_VALUE; + BOOL echo = TRUE; + LPWSTR devicePath = NULL; + DWORD err = GetDevicePath((LPGUID)&BTHECHOSAMPLE_DEVICE_INTERFACE, &devicePath); + + if (ERROR_SUCCESS != err) { + printf("Failed to find the BTHECHO device\n"); + exit(1); + } + + hDevice = CreateFile(devicePath, + GENERIC_READ|GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + 0, + NULL ); + + if (hDevice == INVALID_HANDLE_VALUE) { + printf("Failed to open device. Error %d\n",GetLastError()); + LocalFree(devicePath); + exit(1); + } + + printf("Opened device successfully\n"); + + while (echo) + { + echo = DoEcho(hDevice); + } + + if (INVALID_HANDLE_VALUE != hDevice) { + CloseHandle(hDevice); + printf("Closed device\n"); + } + + if (NULL != devicePath) { + LocalFree(devicePath); + } +} + +BOOL +DoEcho( + HANDLE hDevice + ) +{ + BOOL retval = FALSE; + DWORD cbWritten = 0; + DWORD cbRead = 0; + + BOOL bRet = WriteFile( + hDevice, + testData, + sizeof(testData), + &cbWritten, + NULL + ); + + if (!bRet) + { + printf("Write failed. Error: %d\n", GetLastError()); + goto exit; + } + else + { + printf("Written \t\t%d bytes: %s\n", cbWritten, testData); + } + + bRet = ReadFile( + hDevice, + replyData, + cbWritten, + &cbRead, + NULL + ); + + if (!bRet) + { + printf("Read failed. Error: %d\n", GetLastError()); + goto exit; + } + else + { + printf("Reply from server \t%d bytes: %s\n", cbRead, replyData); + } + + if (cbRead == cbWritten) + { + retval = memcmp(replyData, testData, cbRead) ? FALSE : TRUE; + } + +exit: + return retval; +} + +DWORD +GetDevicePath( + _In_ LPGUID InterfaceGuid, + _Out_ LPWSTR * DevicePath + ) +{ + CONFIGRET cmRet = CR_SUCCESS; + ULONG interfaceListSize = 0; + + *DevicePath = NULL; + + cmRet = CM_Get_Device_Interface_List_Size_Ex(&interfaceListSize, InterfaceGuid, 0, CM_GET_DEVICE_INTERFACE_LIST_PRESENT, NULL); + if (cmRet != CR_SUCCESS) { + goto exit; + } + + *DevicePath = (LPWSTR)LocalAlloc(LMEM_ZEROINIT, interfaceListSize * sizeof((*DevicePath)[0])); + if (NULL == *DevicePath) { + cmRet = CR_OUT_OF_MEMORY; + goto exit; + } + + cmRet = CM_Get_Device_Interface_List_Ex(InterfaceGuid, 0, *DevicePath, interfaceListSize, CM_GET_DEVICE_INTERFACE_LIST_PRESENT, NULL); + +exit: + + if (cmRet != CR_SUCCESS) { + if (NULL != *DevicePath) { + LocalFree(*DevicePath); + *DevicePath = NULL; + } + } + + return CM_MapCrToWin32Err(cmRet, ERROR_UNIDENTIFIED_ERROR); +} + diff --git a/bluetooth/bthecho/bthcli/sys/BthEchoSampleCli.inx b/bluetooth/bthecho/bthcli/sys/BthEchoSampleCli.inx new file mode 100644 index 00000000..9f55cc59 --- /dev/null +++ b/bluetooth/bthecho/bthcli/sys/BthEchoSampleCli.inx @@ -0,0 +1,101 @@ +;/*++ +; +;Copyright (c) 1990-2000 Microsoft Corporation +; +; THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY +; KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +; IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR +; PURPOSE. +; +;Module Name: +; BthEchoSampleCli.inx +; +;Abstract: +; INF file for installing the Bluetooth Echo Sample Client +; +; devcon.exe BthEchoSampleCli.inf BTHENUM\{c07508f2-b970-43ca-b5dd-cc4f2391bef4} +; +;--*/ + +[Version] +Signature="$WINDOWS NT$" +Class=Sample +ClassGuid={e0cbf06c-cd8b-4647-bb8a-263b43f0f974} +Provider=%MSFTSAMPLE% +DriverVer=06/21/2006,6.0.5841. +CatalogFile=KmdfSamples.cat + +[DestinationDirs] +DefaultDestDir = 12 + +[SourceDisksNames] +1 = %DiskId1%,,,"" + +[SourceDisksFiles] +BthEchoSampleCli.sys = 1,, + +;***************************************** +; BthEchoSampleCli Install Section +;***************************************** + +[Manufacturer] +%MSFTSAMPLE%=Microsoft,NTamd64...1 +%MSFTSAMPLE%=Microsoft,NTx86...1 + +[Microsoft.NTamd64...1] +%BthEchoSampleCli.DeviceDesc% = BthEchoSampleCli_Inst,BTHENUM\{c07508f2-b970-43ca-b5dd-cc4f2391bef4} + +[Microsoft.NTx86...1] +%BthEchoSampleCli.DeviceDesc% = BthEchoSampleCli_Inst,BTHENUM\{c07508f2-b970-43ca-b5dd-cc4f2391bef4} +[BthEchoSampleCli_Inst.NT] +CopyFiles=Drivers_Dir + +[Drivers_Dir] +BthEchoSampleCli.sys + + +;-------------- Service installation +[BthEchoSampleCli_Inst.NT.Services] +AddService = BthEchoSampleCli,%SPSVCINST_ASSOCSERVICE%, BthEchoSampleCli_Service_Inst + +; -------------- BthEchoSampleCli driver install sections +[BthEchoSampleCli_Service_Inst] +DisplayName = %BthEchoSampleCli.SVCDESC% +ServiceType = 1 ; SERVICE_KERNEL_DRIVER +StartType = 3 ; SERVICE_DEMAND_START +ErrorControl = 1 ; SERVICE_ERROR_NORMAL +ServiceBinary = %12%\BthEchoSampleCli.sys + +; +;--- BthEchoSampleCli_Inst Coinstaller installation ------ +; + +[DestinationDirs] +BthEchoSampleCli_Inst_CoInstaller_CopyFiles = 11 + +[BthEchoSampleCli_Inst.NT.CoInstallers] +AddReg=BthEchoSampleCli_Inst_CoInstaller_AddReg +CopyFiles=BthEchoSampleCli_Inst_CoInstaller_CopyFiles + +[BthEchoSampleCli_Inst_CoInstaller_AddReg] +HKR,,CoInstallers32,0x00010000, "WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll,WdfCoInstaller" + +[BthEchoSampleCli_Inst_CoInstaller_CopyFiles] +WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll + +[SourceDisksFiles] +WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll=1 ; make sure the number matches with SourceDisksNames + +[BthEchoSampleCli_Inst.NT.Wdf] +KmdfService = BthEchoSampleCli, BthEchoSampleCli_Inst_wdfsect +[BthEchoSampleCli_Inst_wdfsect] +KmdfLibraryVersion = $KMDFVERSION$ + + +[Strings] +SPSVCINST_ASSOCSERVICE= 0x00000002 +MSFTSAMPLE = "Microsoft Sample" +StdMfg = "(Standard system devices)" +DiskId1 = "BthEchoSampleCli installation disk" +BthEchoSampleCli.DeviceDesc = "Bluetooth Echo Sample Client" +BthEchoSampleCli.SVCDESC = "BthEchoSampleCli" diff --git a/bluetooth/bthecho/bthcli/sys/BthEchoSampleCli.vcxproj b/bluetooth/bthecho/bthcli/sys/BthEchoSampleCli.vcxproj new file mode 100644 index 00000000..f30cb9f3 --- /dev/null +++ b/bluetooth/bthecho/bthcli/sys/BthEchoSampleCli.vcxproj @@ -0,0 +1,201 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {AADDAE40-9C46-4C50-AC5F-FF957C3A6E94} + $(MSBuildProjectName) + 1 + Debug + Win32 + {FA5BA6C8-691B-4FF7-9AFB-B50CE61C8ED1} + + + + Windows10 + False + Desktop + KMDF + WindowsKernelModeDriver10.0 + Driver + + + Windows10 + True + Desktop + KMDF + WindowsKernelModeDriver10.0 + Driver + + + Windows10 + False + Desktop + KMDF + WindowsKernelModeDriver10.0 + Driver + + + Windows10 + True + Desktop + KMDF + WindowsKernelModeDriver10.0 + Driver + + + + $(IntDir) + + + + + + + + + + + + + + + + true + true + TraceEvents(LEVEL,FLAGS,MSG,...) + {km-WdfDefault.tpl}*.tmh + + + $(InfArch) + true + .\$(IntDir)\BthEchoSampleCli.inf + + + + BthEchoSampleCli + + + BthEchoSampleCli + + + BthEchoSampleCli + + + BthEchoSampleCli + + + + true + Level4 + %(AdditionalIncludeDirectories);..\..\common\inc + %(PreprocessorDefinitions);EVENT_TRACING + + + + + %(AdditionalIncludeDirectories);..\..\common\inc + %(PreprocessorDefinitions);EVENT_TRACING + + + %(AdditionalIncludeDirectories);..\..\common\inc + %(PreprocessorDefinitions);EVENT_TRACING + + + %(AdditionalDependencies);.\..\..\common\lib\$(IntDir)\bthecho.lib + + + + + true + Level4 + %(AdditionalIncludeDirectories);..\..\common\inc + %(PreprocessorDefinitions);EVENT_TRACING + + + + + %(AdditionalIncludeDirectories);..\..\common\inc + %(PreprocessorDefinitions);EVENT_TRACING + + + %(AdditionalIncludeDirectories);..\..\common\inc + %(PreprocessorDefinitions);EVENT_TRACING + + + %(AdditionalDependencies);.\..\..\common\lib\$(IntDir)\bthecho.lib + + + + + true + Level4 + %(AdditionalIncludeDirectories);..\..\common\inc + %(PreprocessorDefinitions);EVENT_TRACING + + + + + %(AdditionalIncludeDirectories);..\..\common\inc + %(PreprocessorDefinitions);EVENT_TRACING + + + %(AdditionalIncludeDirectories);..\..\common\inc + %(PreprocessorDefinitions);EVENT_TRACING + + + %(AdditionalDependencies);.\..\..\common\lib\$(IntDir)\bthecho.lib + + + + + true + Level4 + %(AdditionalIncludeDirectories);..\..\common\inc + %(PreprocessorDefinitions);EVENT_TRACING + + + + + %(AdditionalIncludeDirectories);..\..\common\inc + %(PreprocessorDefinitions);EVENT_TRACING + + + %(AdditionalIncludeDirectories);..\..\common\inc + %(PreprocessorDefinitions);EVENT_TRACING + + + %(AdditionalDependencies);.\..\..\common\lib\$(IntDir)\bthecho.lib + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/bluetooth/bthecho/bthcli/sys/BthEchoSampleCli.vcxproj.Filters b/bluetooth/bthecho/bthcli/sys/BthEchoSampleCli.vcxproj.Filters new file mode 100644 index 00000000..176a771f --- /dev/null +++ b/bluetooth/bthecho/bthcli/sys/BthEchoSampleCli.vcxproj.Filters @@ -0,0 +1,43 @@ + + + + + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* + {12E8E936-7BEE-4822-9BB5-A95B2C6C6537} + + + h;hpp;hxx;hm;inl;inc;xsd + {379796ED-172B-4B2C-9E23-302F90088C9F} + + + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml + {5B69AC41-D941-4D63-82AB-FAED650522CE} + + + inf;inv;inx;mof;mc; + {1907D7F9-002C-43DE-BB60-1544D4D62A74} + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Driver Files + + + Driver Files + + + \ No newline at end of file diff --git a/bluetooth/bthecho/bthcli/sys/client.c b/bluetooth/bthecho/bthcli/sys/client.c new file mode 100644 index 00000000..a3947b2a --- /dev/null +++ b/bluetooth/bthecho/bthcli/sys/client.c @@ -0,0 +1,1207 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + client.c + +Abstract: + + Contains Bluetooth client functionality. + +Environment: + + Kernel mode only + + +--*/ + +#include "clisrv.h" +#include "device.h" +#include "client.h" + +#define INITGUID +#include "public.h" + +#if defined(EVENT_TRACING) +#include "client.tmh" +#endif + +#ifdef ALLOC_PRAGMA +#pragma alloc_text (PAGE, BthEchoCliBthQueryInterfaces) +#pragma alloc_text (PAGE, BthEchoCliRetrieveServerSdpRecord) +#endif + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +BthEchoCliBthQueryInterfaces( + _In_ PBTHECHOSAMPLE_CLIENT_CONTEXT DevCtx + ) +/*++ + +Description: + + Query profile driver interface + +Arguments: + + DevCtx - Client context where we store the interface + +Return Value: + + NTSTATUS Status code. + +--*/ +{ + NTSTATUS status; + + PAGED_CODE(); + + status = WdfFdoQueryForInterface( + DevCtx->Header.Device, + &GUID_BTHDDI_PROFILE_DRIVER_INTERFACE, + (PINTERFACE) (&DevCtx->Header.ProfileDrvInterface), + sizeof(DevCtx->Header.ProfileDrvInterface), + BTHDDI_PROFILE_DRIVER_INTERFACE_VERSION_FOR_QI, + NULL + ); + + if (!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "QueryInterface failed for Interface profile driver interface, version %d, Status code %!STATUS!\n", + BTHDDI_PROFILE_DRIVER_INTERFACE_VERSION_FOR_QI, + status); + + goto exit; + } + +exit: + return status; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +BthEchoCliRetrieveServerBthAddress( + _In_ PBTHECHOSAMPLE_CLIENT_CONTEXT DevCtx + ) +/*++ + +Description: + + Retrieve server Bth address + +Arguments: + + DevCtx - Client context where we store bth address + +Return Value: + + NTSTATUS Status code. + +--*/ +{ + NTSTATUS status, statusReuse; + WDF_MEMORY_DESCRIPTOR outMemDesc; + WDF_REQUEST_REUSE_PARAMS ReuseParams; + BTH_DEVICE_INFO serverDeviceInfo; + + WDF_REQUEST_REUSE_PARAMS_INIT(&ReuseParams, WDF_REQUEST_REUSE_NO_FLAGS, STATUS_NOT_SUPPORTED); + statusReuse = WdfRequestReuse(DevCtx->Header.Request, &ReuseParams); + NT_ASSERT(NT_SUCCESS(statusReuse)); + UNREFERENCED_PARAMETER(statusReuse); + + RtlZeroMemory( &serverDeviceInfo, sizeof(serverDeviceInfo) ); + + WDF_MEMORY_DESCRIPTOR_INIT_BUFFER( + &outMemDesc, + &serverDeviceInfo, + sizeof(serverDeviceInfo) + ); + + status = WdfIoTargetSendInternalIoctlSynchronously( + DevCtx->Header.IoTarget, + DevCtx->Header.Request, + IOCTL_INTERNAL_BTHENUM_GET_DEVINFO, + NULL, //inMemDesc + &outMemDesc, + NULL, //sendOptions + NULL //bytesReturned + ); + + if (!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "Failed to obtain server device info, Status code %!STATUS!\n", status); + + goto exit; + } + + DevCtx->ServerBthAddress = serverDeviceInfo.address; + +exit: + return status; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +BthEchoCliRetrieveServerSdpRecord( + _In_ PBTHECHOSAMPLE_CLIENT_CONTEXT DevCtx, + _Out_ PBTH_SDP_STREAM_RESPONSE * ServerSdpRecord + ) +/*++ + +Description: + + Retrive server SDP record. + We call this function on every file open to get the PSM + +Arguments: + + DevCtx - Client context + ServerSdpRecord - SDP record retrieved + +Return Value: + + NTSTATUS Status code. + +--*/ +{ + NTSTATUS status, statusReuse, disconnectStatus; + WDF_MEMORY_DESCRIPTOR inMemDesc; + WDF_MEMORY_DESCRIPTOR outMemDesc; + WDF_REQUEST_REUSE_PARAMS ReuseParams; + BTH_SDP_CONNECT connect = {0}; + BTH_SDP_DISCONNECT disconnect = {0}; + BTH_SDP_SERVICE_ATTRIBUTE_SEARCH_REQUEST requestSdp = {0}; + BTH_SDP_STREAM_RESPONSE responseSdp = {0}; + ULONG requestSize; + PBTH_SDP_STREAM_RESPONSE serverSdpRecord = NULL; + WDFREQUEST request; + WDF_OBJECT_ATTRIBUTES attributes; + + + PAGED_CODE(); + + // + // Allocate the request we will use for obtaining sdp record + // NOTE that we do it for every file open, hence we + // + // can't use reserve request from the context + // + + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + + status = WdfRequestCreate( + &attributes, + DevCtx->Header.IoTarget, + &request + ); + + if (!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "Failed to allocate request for retriving server sdp record, Status code %!STATUS!\n", status); + + goto exit; + } + + connect.bthAddress = DevCtx->ServerBthAddress; + connect.requestTimeout = SDP_REQUEST_TO_DEFAULT; + connect.fSdpConnect = 0; + + // + // Connect to the SDP service. + // + + WDF_MEMORY_DESCRIPTOR_INIT_BUFFER( + &inMemDesc, + &connect, + sizeof(connect) + ); + + WDF_MEMORY_DESCRIPTOR_INIT_BUFFER( + &outMemDesc, + &connect, + sizeof(connect) + ); + + status = WdfIoTargetSendIoctlSynchronously( + DevCtx->Header.IoTarget, + request, + IOCTL_BTH_SDP_CONNECT, + &inMemDesc, + &outMemDesc, + NULL, //sendOptions + NULL //bytesReturned + ); + + if (!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "IOCTL_BTH_SDP_CONNECT failed, Status code %!STATUS!\n", status); + + goto exit1; + } + + // + // Obtain the required size of the SDP record + // + requestSdp.hConnection = connect.hConnection; + requestSdp.uuids[0].u.uuid128 = BTHECHOSAMPLE_SVC_GUID; + requestSdp.uuids[0].uuidType = SDP_ST_UUID128; + requestSdp.range[0].minAttribute = 0; + requestSdp.range[0].maxAttribute = 0xFFFF; + + WDF_REQUEST_REUSE_PARAMS_INIT(&ReuseParams, WDF_REQUEST_REUSE_NO_FLAGS, STATUS_NOT_SUPPORTED); + statusReuse = WdfRequestReuse(request, &ReuseParams); + NT_ASSERT(NT_SUCCESS(statusReuse)); + UNREFERENCED_PARAMETER(statusReuse); + + WDF_MEMORY_DESCRIPTOR_INIT_BUFFER( + &inMemDesc, + &requestSdp, + sizeof(requestSdp) + ); + + WDF_MEMORY_DESCRIPTOR_INIT_BUFFER( + &outMemDesc, + &responseSdp, + sizeof(responseSdp) + ); + + status = WdfIoTargetSendIoctlSynchronously( + DevCtx->Header.IoTarget, + request, + IOCTL_BTH_SDP_SERVICE_ATTRIBUTE_SEARCH, + &inMemDesc, + &outMemDesc, + NULL, //sendOptions + NULL //bytesReturned + ); + + if (!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, DBG_SDP, + "IOCTL_BTH_SDP_SERVICE_ATTRIBUTE_SEARCH failed while querying response size, " + "status code %!STATUS!\n", status); + + goto exit2; + } + + // + // Allocate the required size for SDP record + // + + status = RtlULongAdd( + responseSdp.requiredSize, + sizeof(BTH_SDP_STREAM_RESPONSE), + &requestSize + ); + + if(!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, DBG_SDP, + "SDP record size too large, status code %!STATUS!\n", status); + + goto exit2; + } + + serverSdpRecord = ExAllocatePoolWithTag(NonPagedPoolNx, requestSize, POOLTAG_BTHECHOSAMPLE); + if (NULL == serverSdpRecord) + { + status = STATUS_INSUFFICIENT_RESOURCES; + TraceEvents(TRACE_LEVEL_ERROR, DBG_SDP, + "Allocating SDP record failed, returning status code %!STATUS!\n", status); + + goto exit2; + } + + // + // Send request with required size + // + + WDF_REQUEST_REUSE_PARAMS_INIT(&ReuseParams, WDF_REQUEST_REUSE_NO_FLAGS, STATUS_NOT_SUPPORTED); + statusReuse = WdfRequestReuse(request, &ReuseParams); + NT_ASSERT(NT_SUCCESS(statusReuse)); + UNREFERENCED_PARAMETER(statusReuse); + + WDF_MEMORY_DESCRIPTOR_INIT_BUFFER( + &inMemDesc, + &requestSdp, + sizeof(requestSdp) + ); + + WDF_MEMORY_DESCRIPTOR_INIT_BUFFER( + &outMemDesc, + serverSdpRecord, + requestSize + ); + + status = WdfIoTargetSendIoctlSynchronously( + DevCtx->Header.IoTarget, + request, + IOCTL_BTH_SDP_SERVICE_ATTRIBUTE_SEARCH, + &inMemDesc, + &outMemDesc, + NULL, //sendOptions + NULL //bytesReturned + ); + + if (!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, DBG_SDP, + "IOCTL_BTH_SDP_SERVICE_ATTRIBUTE_SEARCH failed, status code %!STATUS!\n", status); + + ExFreePoolWithTag(serverSdpRecord, POOLTAG_BTHECHOSAMPLE); + } + else + { + *ServerSdpRecord = serverSdpRecord; + } + +exit2: + + // + // Disconnect from SDP service. + // + + WDF_REQUEST_REUSE_PARAMS_INIT(&ReuseParams, WDF_REQUEST_REUSE_NO_FLAGS, STATUS_NOT_SUPPORTED); + statusReuse = WdfRequestReuse(request, &ReuseParams); + NT_ASSERT(NT_SUCCESS(statusReuse)); + UNREFERENCED_PARAMETER(statusReuse); + + disconnect.hConnection = connect.hConnection; + + WDF_MEMORY_DESCRIPTOR_INIT_BUFFER( + &inMemDesc, + &disconnect, + sizeof(disconnect) + ); + + disconnectStatus = WdfIoTargetSendIoctlSynchronously( + DevCtx->Header.IoTarget, + request, + IOCTL_BTH_SDP_DISCONNECT, + &inMemDesc, + NULL, //outMemDesc + NULL, //sendOptions + NULL //bytesReturned + ); + + NT_ASSERT(NT_SUCCESS(disconnectStatus)); //Disconnect should not fail + + if (!NT_SUCCESS(disconnectStatus)) + { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "IOCTL_BTH_SDP_DISCONNECT failed, Status code %!STATUS!\n", status); + } + +exit1: + WdfObjectDelete(request); +exit: + return status; +} + +NTSTATUS +BthEchoCliRetrievePsmFromSdpRecord( + _In_ PBTHDDI_SDP_PARSE_INTERFACE SdpParseInterface, + _In_ PBTH_SDP_STREAM_RESPONSE ServerSdpRecord, + _Out_ USHORT * Psm + ) +/*++ + +Description: + + Retrieve PSM from the SDP record + +Arguments: + + sdpParseInterface - Parse interface used for sdp parse functions + ServerSdpRecord - SDP record to obtain Psm from + Psm - Psm retrieved + +Return Value: + + NTSTATUS Status code. + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PUCHAR nextElement; + ULONG nextElementSize; + + PSDP_TREE_ROOT_NODE sdpTree = NULL; + PSDP_NODE nodeProtoDescList = NULL; + PSDP_NODE nodeProto0 = NULL; + PSDP_NODE nodeProto0UUID = NULL; + PSDP_NODE nodeProto0SParam0 = NULL; + + SdpParseInterface->SdpGetNextElement( + &(ServerSdpRecord->response[0]), + ServerSdpRecord->responseSize, + NULL, + &nextElement, + &nextElementSize + ); + + if(nextElementSize == 0) + { + status = STATUS_DEVICE_DATA_ERROR; + TraceEvents(TRACE_LEVEL_ERROR, DBG_SDP, + "Getting first element from SDP record failed, returning status code %!STATUS!\n", status); + goto exit; + } + + status = SdpParseInterface->SdpConvertStreamToTree( + nextElement, + nextElementSize, + &sdpTree, + POOLTAG_BTHECHOSAMPLE + ); + + if(!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, DBG_SDP, + "Converting SDP record to tree failed, status code %!STATUS!\n", status); + goto exit; + } + + // + //Find PROTOCOL_DESCRIPTOR_LIST in the tree + // + status = SdpParseInterface->SdpFindAttributeInTree( + sdpTree, + (USHORT)SDP_ATTRIB_PROTOCOL_DESCRIPTOR_LIST, + &nodeProtoDescList + ); + + if(!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, DBG_SDP, + "FindAttribute failed for SDP_ATTRIB_PROTOCOL_DESCRIPTOR_LIST, status code %!STATUS!\n", status); + goto exit0; + } + + if(nodeProtoDescList->hdr.Type != SDP_TYPE_SEQUENCE) + { + goto SdpFormatError; + } + + // + // Get the next sequence. + // + + if(nodeProtoDescList->u.sequence.Link.Flink == NULL) + { + goto SdpFormatError; + } + + nodeProto0 = CONTAINING_RECORD(nodeProtoDescList->u.sequence.Link.Flink, SDP_NODE, hdr.Link); + + if(nodeProto0->hdr.Type != SDP_TYPE_SEQUENCE) + { + goto SdpFormatError; + } + + if(nodeProto0->u.sequence.Link.Flink == NULL) + { + goto SdpFormatError; + } + + // + // Get the first GUID, (L2CAP) + // + + nodeProto0UUID = CONTAINING_RECORD(nodeProto0->u.sequence.Link.Flink, SDP_NODE, hdr.Link); + + if(nodeProto0UUID->hdr.Type != SDP_TYPE_UUID) + { + goto SdpFormatError; + } + + if(nodeProto0UUID->hdr.Link.Flink == NULL) + { + goto SdpFormatError; + } + + // + // Get the PSM + // + + nodeProto0SParam0 = CONTAINING_RECORD(nodeProto0UUID->hdr.Link.Flink, SDP_NODE, hdr.Link); + if(nodeProto0SParam0->hdr.SpecificType != SDP_ST_UINT16) + { + goto SdpFormatError; + } + + *Psm = nodeProto0SParam0->u.uint16; + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_SDP, + "Psm: %d", *Psm); + + goto exit0; + +SdpFormatError: + + status = STATUS_DEVICE_DATA_ERROR; + + TraceEvents(TRACE_LEVEL_ERROR, DBG_SDP, + "Parsing error due to invalid SDP record, returning status code %!STATUS!\n", status); + +exit0: + + SdpParseInterface->SdpFreeTree(sdpTree); + +exit: + return status; +} + + +EVT_WDF_REQUEST_COMPLETION_ROUTINE +BthEchoCliRemoteConnectCompletion; + + +#if (NTDDI_VERSION >= NTDDI_WIN8) + +_IRQL_requires_max_(DISPATCH_LEVEL) +void +BthEchoCliIndicationCallback( + _In_ PVOID Context, + _In_ INDICATION_CODE Indication, + _In_ PINDICATION_PARAMETERS_ENHANCED Parameters + ) +/*++ + +Description: + + Indication callback passed to bth stack while sending open channel BRB + Bth stack sends notification related to the connection. + +Arguments: + + Context - We receive data connection as the context + Indication - Type of indication + Parameters - Parameters of indication + +--*/ +{ + PBTHECHO_CONNECTION connection = (PBTHECHO_CONNECTION) Context; + + UNREFERENCED_PARAMETER(Parameters); + + // + // Only supporting connect and disconnect + // + + switch(Indication) + { + // + // We don't add/release reference to anything because our connection + // is scoped within file object lifetime + // + case IndicationAddReference: + case IndicationReleaseReference: + break; + case IndicationRemoteConnect: + { + // + // We don't expect connection + // + NT_ASSERT(FALSE); + break; + } + case IndicationRemoteDisconnect: + { + // + // This is an indication that server has disconnected + // In response we disconnect from our end + // + + BthEchoConnectionObjectRemoteDisconnect( + connection->DevCtxHdr, + connection + ); + + break; + } + case IndicationRemoteConfigRequest: + case IndicationRemoteConfigResponse: + case IndicationFreeExtraOptions: + break; + } +} + + +VOID +BthEchoCliRemoteConnectCompletion( + _In_ WDFREQUEST Request, + _In_ WDFIOTARGET Target, + _In_ PWDF_REQUEST_COMPLETION_PARAMS Params, + _In_ WDFCONTEXT Context + ) + +/*++ +Description: + + Completion routine for Create request which we format as open + channel BRB and send down the stack. We complete the Create request + in this routine. + + We receive open channel BRB as the context. This BRB + is part of the request context and doesn't need to be freed + explicitly. + + Connection is part of the context in the BRB. + +Arguments: + + Request - Create request that we formatted with open channel BRB + Target - Target to which we sent the request + Params - Completion params + Context - We receive BRB as the context + +Return Value: + + NTSTATUS Status code. +--*/ + +{ + NTSTATUS status; + struct _BRB_L2CA_OPEN_ENHANCED_CHANNEL *brb; + PBTHECHOSAMPLE_CLIENT_CONTEXT DevCtx; + PBTHECHO_CONNECTION connection; + + DevCtx = GetClientDeviceContext(WdfIoTargetGetDevice(Target)); + + status = Params->IoStatus.Status; + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_CONNECT, + "Connection completion, status: %!STATUS!", status); + + brb = (struct _BRB_L2CA_OPEN_ENHANCED_CHANNEL *) Context; + + connection = (PBTHECHO_CONNECTION) brb->Hdr.ClientContext[0]; + + // + // In the client we don't check for ConnectionStateDisconnecting state + // because only file close generates disconnect which + // cannot happen before create completes. And we complete Create + // only after we process this completion. + // + + if(NT_SUCCESS(status)) + { + connection->OutMTU = brb->OutResults.Params.Mtu; + connection->InMTU = brb->InResults.Params.Mtu; + connection->ChannelHandle = brb->ChannelHandle; + connection->RemoteAddress = brb->BtAddress; + + connection->ConnectionState = ConnectionStateConnected; + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_CONNECT, + "Connection (0x%x) established to server", brb->OutResults.Params.RetransmissionAndFlow.Mode); + + // + // Call the function in device.c (BthEchoCliConnectionStateConnected) + // for any post processing after connection has been established + // + status = BthEchoCliConnectionStateConnected(WdfRequestGetFileObject(Request), connection); + if (!NT_SUCCESS(status)) + { + // + // If such post processing fails we disconnect + // + BthEchoConnectionObjectRemoteDisconnect( + &(DevCtx->Header), + connection + ); + } + } + else + { + connection->ConnectionState = ConnectionStateConnectFailed; + } + + // + // Complete the Create request + // + WdfRequestComplete(Request, status); + + return; +} + + +_IRQL_requires_same_ +NTSTATUS +BthEchoCliOpenRemoteConnection( + _In_ PBTHECHOSAMPLE_CLIENT_CONTEXT DevCtx, + _In_ WDFFILEOBJECT FileObject, + _In_ WDFREQUEST Request + ) +/*++ + +Description: + + This routine is invoked by BthEchoCliEvtDeviceFileCreate. + In this routine we send down open channel BRB. + + This routine allocates open channel BRB. If the request + is sent down successfully completion routine needs to free + this BRB. + +Arguments: + + _In_ PBTHECHOSAMPLE_CLIENT_CONTEXT DevCtx - + _In_ WDFFILEOBJECT FileObject - + _In_ WDFREQUEST Request - + +Return Value: + + NTSTATUS Status code. + +--*/ +{ + NTSTATUS status; + WDFOBJECT connectionObject; + struct _BRB_L2CA_OPEN_ENHANCED_CHANNEL *brb = NULL; + PBTHECHO_CONNECTION connection = NULL; + PBTHECHOSAMPLE_CLIENT_FILE_CONTEXT fileCtx = GetFileContext(FileObject); + ULONG modeConfigFlag = CM_BASIC; + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_CONNECT, + "Connect request"); + + // + // Create the connection object that would store information + // about the open channel + // + // Set file object as the parent for this connection object + // + status = BthEchoConnectionObjectCreate( + &DevCtx->Header, + FileObject, //parent + &connectionObject + ); + + if (!NT_SUCCESS(status)) + { + goto exit; + } + + connection = GetConnectionObjectContext(connectionObject); + + connection->ConnectionState = ConnectionStateConnecting; + + // + // Get the BRB from request context and initialize it as + // BRB_L2CA_OPEN_CHANNEL BRB + // + brb = (struct _BRB_L2CA_OPEN_ENHANCED_CHANNEL *)GetRequestContext(Request); + + DevCtx->Header.ProfileDrvInterface.BthReuseBrb( + (PBRB)brb, + BRB_L2CA_OPEN_ENHANCED_CHANNEL + ); + + brb->Hdr.ClientContext[0] = connection; + brb->BtAddress = DevCtx->ServerBthAddress; + brb->Psm = fileCtx->ServerPsm; + + brb->ChannelFlags = CF_ROLE_EITHER; + + brb->ConfigOut.Flags = CFG_ENHANCED; + // + // Open an ERTM channel if the local host supports it + // + if (DevCtx->Header.LocalFeatures.Mask & BTH_HOST_FEATURE_ENHANCED_RETRANSMISSION_MODE) { + modeConfigFlag |= CM_RETRANSMISSION_AND_FLOW; + brb->ConfigOut.ModeConfig.Flags = modeConfigFlag; + + // + // Mode is specified using Flags above and this should be 0. + // + brb->ConfigOut.ModeConfig.RetransmissionAndFlow.Mode = 0; + brb->ConfigOut.ModeConfig.RetransmissionAndFlow.MaxTransmit = L2CAP_RAF_DEFAULT_MAXTRANSMIT; + brb->ConfigOut.ModeConfig.RetransmissionAndFlow.MaxPDUSize = L2CAP_RAF_DEFAULT_MAX_PDU_SIZE; + brb->ConfigOut.ModeConfig.RetransmissionAndFlow.TxWindowSize = L2CAP_RAF_DEFAULT_TX_WINDOW_SIZE; + } + + brb->ConfigOut.Flags |= CFG_MTU; + brb->ConfigOut.Mtu.Max = L2CAP_DEFAULT_MTU; + brb->ConfigOut.Mtu.Min = L2CAP_MIN_MTU; + brb->ConfigOut.Mtu.Preferred = L2CAP_DEFAULT_MTU; + + brb->ConfigIn.Flags = CFG_MTU; + brb->ConfigIn.Mtu.Max = brb->ConfigOut.Mtu.Max; + brb->ConfigIn.Mtu.Min = brb->ConfigOut.Mtu.Min; + brb->ConfigIn.Mtu.Preferred = brb->ConfigOut.Mtu.Max; + + // + // Get notificaiton about remote disconnect + // + brb->CallbackFlags = CALLBACK_DISCONNECT; + + brb->Callback = &BthEchoCliIndicationCallback; + brb->CallbackContext = connection; + brb->ReferenceObject = (PVOID) WdfDeviceWdmGetDeviceObject(DevCtx->Header.Device); + brb->IncomingQueueDepth = 50; + + status = BthEchoSharedSendBrbAsync( + DevCtx->Header.IoTarget, + Request, + (PBRB) brb, + sizeof(*brb), + BthEchoCliRemoteConnectCompletion, + brb //Context + ); + + if (!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, DBG_CONNECT, + "Sending brb for opening connection failed, returning status code %!STATUS!\n", status); + + goto exit; + } + +exit: + + if(!NT_SUCCESS(status)) + { + if (connection) + { + // + // Set the right state to facilitate debugging + // + connection->ConnectionState = ConnectionStateConnectFailed; + } + + // + // In case of failure of this routine we will fail + // Create which will delete file object and since connection object + // is child of the file object, it will be deleted too + // + } + + return status; +} + + +#else + +_IRQL_requires_max_(DISPATCH_LEVEL) +void +BthEchoCliIndicationCallback( + _In_ PVOID Context, + _In_ INDICATION_CODE Indication, + _In_ PINDICATION_PARAMETERS Parameters + ) +/*++ + +Description: + + Indication callback passed to bth stack while sending open channel BRB + Bth stack sends notification related to the connection. + +Arguments: + + Context - We receive data connection as the context + Indication - Type of indication + Parameters - Parameters of indication + +--*/ +{ + PBTHECHO_CONNECTION connection = (PBTHECHO_CONNECTION) Context; + + UNREFERENCED_PARAMETER(Parameters); + + // + // Only supporting connect and disconnect + // + + switch(Indication) + { + // + // We don't add/release reference to anything because our connection + // is scoped within file object lifetime + // + case IndicationAddReference: + case IndicationReleaseReference: + break; + case IndicationRemoteConnect: + { + // + // We don't expect connection + // + NT_ASSERT(FALSE); + break; + } + case IndicationRemoteDisconnect: + { + // + // This is an indication that server has disconnected + // In response we disconnect from our end + // + + BthEchoConnectionObjectRemoteDisconnect( + connection->DevCtxHdr, + connection + ); + + break; + } + case IndicationRemoteConfigRequest: + case IndicationRemoteConfigResponse: + case IndicationFreeExtraOptions: + break; + } +} + +VOID +BthEchoCliRemoteConnectCompletion( + _In_ WDFREQUEST Request, + _In_ WDFIOTARGET Target, + _In_ PWDF_REQUEST_COMPLETION_PARAMS Params, + _In_ WDFCONTEXT Context + ) + +/*++ +Description: + + Completion routine for Create request which we format as open + channel BRB and send down the stack. We complete the Create request + in this routine. + + We receive open channel BRB as the context. This BRB + is part of the request context and doesn't need to be freed + explicitly. + + Connection is part of the context in the BRB. + +Arguments: + + Request - Create request that we formatted with open channel BRB + Target - Target to which we sent the request + Params - Completion params + Context - We receive BRB as the context + +Return Value: + + NTSTATUS Status code. +--*/ + +{ + NTSTATUS status; + struct _BRB_L2CA_OPEN_CHANNEL *brb; + PBTHECHOSAMPLE_CLIENT_CONTEXT DevCtx; + PBTHECHO_CONNECTION connection; + + DevCtx = GetClientDeviceContext(WdfIoTargetGetDevice(Target)); + + status = Params->IoStatus.Status; + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_CONNECT, + "Connection completion, status: %!STATUS!", status); + + brb = (struct _BRB_L2CA_OPEN_CHANNEL *) Context; + + connection = (PBTHECHO_CONNECTION) brb->Hdr.ClientContext[0]; + + // + // In the client we don't check for ConnectionStateDisconnecting state + // because only file close generates disconnect which + // cannot happen before create completes. And we complete Create + // only after we process this completion. + // + + if(NT_SUCCESS(status)) + { + connection->OutMTU = brb->OutResults.Params.Mtu; + connection->InMTU = brb->InResults.Params.Mtu; + connection->ChannelHandle = brb->ChannelHandle; + connection->RemoteAddress = brb->BtAddress; + + connection->ConnectionState = ConnectionStateConnected; + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_CONNECT, + "Connection established to server"); + + // + // Call the function in device.c (BthEchoCliConnectionStateConnected) + // for any post processing after connection has been established + // + status = BthEchoCliConnectionStateConnected(WdfRequestGetFileObject(Request), connection); + if (!NT_SUCCESS(status)) + { + // + // If such post processing fails we disconnect + // + BthEchoConnectionObjectRemoteDisconnect( + &(DevCtx->Header), + connection + ); + } + } + else + { + connection->ConnectionState = ConnectionStateConnectFailed; + } + + // + // Complete the Create request + // + WdfRequestComplete(Request, status); + + return; +} + + + +_IRQL_requires_same_ +NTSTATUS +BthEchoCliOpenRemoteConnection( + _In_ PBTHECHOSAMPLE_CLIENT_CONTEXT DevCtx, + _In_ WDFFILEOBJECT FileObject, + _In_ WDFREQUEST Request + ) +/*++ + +Description: + + This routine is invoked by BthEchoCliEvtDeviceFileCreate. + In this routine we send down open channel BRB. + + This routine allocates open channel BRB. If the request + is sent down successfully completion routine needs to free + this BRB. + +Arguments: + + _In_ PBTHECHOSAMPLE_CLIENT_CONTEXT DevCtx - + _In_ WDFFILEOBJECT FileObject - + _In_ WDFREQUEST Request - + +Return Value: + + NTSTATUS Status code. + +--*/ +{ + NTSTATUS status; + WDFOBJECT connectionObject; + struct _BRB_L2CA_OPEN_CHANNEL *brb = NULL; + PBTHECHO_CONNECTION connection = NULL; + PBTHECHOSAMPLE_CLIENT_FILE_CONTEXT fileCtx = GetFileContext(FileObject); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_CONNECT, + "Connect request"); + + // + // Create the connection object that would store information + // about the open channel + // + // Set file object as the parent for this connection object + // + status = BthEchoConnectionObjectCreate( + &DevCtx->Header, + FileObject, //parent + &connectionObject + ); + + if (!NT_SUCCESS(status)) + { + goto exit; + } + + connection = GetConnectionObjectContext(connectionObject); + + connection->ConnectionState = ConnectionStateConnecting; + + // + // Get the BRB from request context and initialize it as + // BRB_L2CA_OPEN_CHANNEL BRB + // + brb = (struct _BRB_L2CA_OPEN_CHANNEL *)GetRequestContext(Request); + + DevCtx->Header.ProfileDrvInterface.BthReuseBrb( + (PBRB)brb, + BRB_L2CA_OPEN_CHANNEL + ); + + brb->Hdr.ClientContext[0] = connection; + brb->BtAddress = DevCtx->ServerBthAddress; + brb->Psm = fileCtx->ServerPsm; + + brb->ChannelFlags = CF_ROLE_EITHER; + + brb->ConfigOut.Flags = 0; + brb->ConfigIn.Flags = 0; + + brb->ConfigOut.Flags |= CFG_MTU; + brb->ConfigOut.Mtu.Max = L2CAP_DEFAULT_MTU; + brb->ConfigOut.Mtu.Min = L2CAP_MIN_MTU; + brb->ConfigOut.Mtu.Preferred = L2CAP_DEFAULT_MTU; + + brb->ConfigIn.Flags = CFG_MTU; + brb->ConfigIn.Mtu.Max = brb->ConfigOut.Mtu.Max; + brb->ConfigIn.Mtu.Min = brb->ConfigOut.Mtu.Min; + brb->ConfigIn.Mtu.Preferred = brb->ConfigOut.Mtu.Max; + + // + // Get notificaiton about remote disconnect + // + brb->CallbackFlags = CALLBACK_DISCONNECT; + + brb->Callback = &BthEchoCliIndicationCallback; + brb->CallbackContext = connection; + brb->ReferenceObject = (PVOID) WdfDeviceWdmGetDeviceObject(DevCtx->Header.Device); + brb->IncomingQueueDepth = 50; + + status = BthEchoSharedSendBrbAsync( + DevCtx->Header.IoTarget, + Request, + (PBRB) brb, + sizeof(*brb), + BthEchoCliRemoteConnectCompletion, + brb //Context + ); + + if (!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, DBG_CONNECT, + "Sending brb for opening connection failed, returning status code %!STATUS!\n", status); + + goto exit; + } + +exit: + + if(!NT_SUCCESS(status)) + { + if (connection) + { + // + // Set the right state to facilitate debugging + // + connection->ConnectionState = ConnectionStateConnectFailed; + } + + // + // In case of failure of this routine we will fail + // Create which will delete file object and since connection object + // is child of the file object, it will be deleted too + // + } + + return status; +} + + +#endif + diff --git a/bluetooth/bthecho/bthcli/sys/client.h b/bluetooth/bthecho/bthcli/sys/client.h new file mode 100644 index 00000000..548420aa --- /dev/null +++ b/bluetooth/bthecho/bthcli/sys/client.h @@ -0,0 +1,58 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + client.h + +Abstract: + + Contains declarations for Bluetooth client functionality. + +Environment: + + Kernel mode only + + +--*/ + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +BthEchoCliBthQueryInterfaces( + _In_ PBTHECHOSAMPLE_CLIENT_CONTEXT DevCtx + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +BthEchoCliRetrieveServerBthAddress( + _In_ PBTHECHOSAMPLE_CLIENT_CONTEXT DevCtx + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +BthEchoCliRetrieveServerSdpRecord( + _In_ PBTHECHOSAMPLE_CLIENT_CONTEXT DevCtx, + _Out_ PBTH_SDP_STREAM_RESPONSE * ServerSdpRecord + ); + +NTSTATUS +BthEchoCliRetrievePsmFromSdpRecord( + _In_ PBTHDDI_SDP_PARSE_INTERFACE sdpParseInterface, + _In_ PBTH_SDP_STREAM_RESPONSE ServerSdpRecord, + _Out_ USHORT * Psm + ); + +_IRQL_requires_same_ +NTSTATUS +BthEchoCliOpenRemoteConnection( + _In_ PBTHECHOSAMPLE_CLIENT_CONTEXT DevCtx, + _In_ WDFFILEOBJECT FileObject, + _In_ WDFREQUEST Request + ); + diff --git a/bluetooth/bthecho/bthcli/sys/device.c b/bluetooth/bthecho/bthcli/sys/device.c new file mode 100644 index 00000000..177fb823 --- /dev/null +++ b/bluetooth/bthecho/bthcli/sys/device.c @@ -0,0 +1,458 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + Device.c + +Abstract: + + Device and file object related functionality for bthecho client device + +Environment: + + Kernel mode only + + +--*/ + +#include "clisrv.h" +#include "device.h" +#include "client.h" +#include "queue.h" + +#define INITGUID +#include "public.h" + +#if defined(EVENT_TRACING) +#include "device.tmh" +#endif + +#ifdef ALLOC_PRAGMA +#pragma alloc_text (PAGE, BthEchoCliEvtDriverDeviceAdd) +#pragma alloc_text (PAGE, BthEchoCliEvtDeviceFileCreate) +#pragma alloc_text (PAGE, BthEchoCliEvtFileClose) +#endif + +NTSTATUS +BthEchoCliEvtDriverDeviceAdd( + _In_ WDFDRIVER Driver, + _Inout_ PWDFDEVICE_INIT DeviceInit +) +/*++ +Routine Description: + + BthEchoCliEvtDeviceAdd is called by the framework in response to AddDevice + call from the PnP manager. We create and initialize a device object to + represent a new instance of the device. All the software resources + should be allocated in this callback. + +Arguments: + + Driver - Handle to a framework driver object created in DriverEntry + + DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure. + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status; + WDFDEVICE device; + WDF_OBJECT_ATTRIBUTES deviceAttributes; + WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks; + WDF_FILEOBJECT_CONFIG fileobjectConfig; + WDF_OBJECT_ATTRIBUTES fileAttributes, requestAttributes; + WDF_IO_QUEUE_CONFIG ioQueueConfig; + WDFQUEUE queue; + PBTHECHOSAMPLE_CLIENT_CONTEXT devCtx; + + UNREFERENCED_PARAMETER(Driver); + + PAGED_CODE(); + + // + // Configure Pnp/power callbacks + // + WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks); + pnpPowerCallbacks.EvtDeviceSelfManagedIoInit = BthEchoCliEvtDeviceSelfManagedIoInit; + + WdfDeviceInitSetPnpPowerEventCallbacks( + DeviceInit, + &pnpPowerCallbacks + ); + + // + // Configure file callbacks + // + + WDF_FILEOBJECT_CONFIG_INIT( + &fileobjectConfig, + BthEchoCliEvtDeviceFileCreate, + BthEchoCliEvtFileClose, + WDF_NO_EVENT_CALLBACK // Cleanup + ); + + // + // Inform framework to create context area in every fileobject + // so that we can track information per open handle by the + // application. + // + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&fileAttributes, BTHECHOSAMPLE_CLIENT_FILE_CONTEXT); + + WdfDeviceInitSetFileObjectConfig( + DeviceInit, + &fileobjectConfig, + &fileAttributes + ); + + // + // Inform framework to create context area in every request object. + // + // We make BRB as the context since we need BRB for all the requests + // we handle (Create, Read, Write). + // + + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE( + &requestAttributes, + BRB + ); + + WdfDeviceInitSetRequestAttributes( + DeviceInit, + &requestAttributes + ); + + // + // Set device attributes + // + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&deviceAttributes, BTHECHOSAMPLE_CLIENT_CONTEXT); + + status = WdfDeviceCreate( + &DeviceInit, + &deviceAttributes, + &device + ); + + if (!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "WdfDeviceCreate failed with Status code %!STATUS!\n", status); + + goto exit; + } + + devCtx = GetClientDeviceContext(device); + + // + // Initialize our context + // + status = BthEchoCliContextInit(devCtx, device); + + if (!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "Initialization of context failed with Status code %!STATUS!\n", status); + + goto exit; + } + + status = BthEchoCliBthQueryInterfaces(devCtx); + if (!NT_SUCCESS(status)) + { + goto exit; + } + + // + // Set up our queue + // + + WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE( + &ioQueueConfig, + WdfIoQueueDispatchParallel + ); + + ioQueueConfig.EvtIoRead = BthEchoCliEvtQueueIoRead; + ioQueueConfig.EvtIoWrite = BthEchoCliEvtQueueIoWrite; + ioQueueConfig.EvtIoStop = BthEchoCliEvtQueueIoStop; + + status = WdfIoQueueCreate( + device, + &ioQueueConfig, + WDF_NO_OBJECT_ATTRIBUTES, + &queue + ); + + if (!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "WdfIoQueueCreate failed %!STATUS!\n", status); + goto exit; + } + + // + // Enable device interface so that app can open a handle to our device + // and talk to it + // + + status = WdfDeviceCreateDeviceInterface( + device, + &BTHECHOSAMPLE_DEVICE_INTERFACE, + NULL + ); + + if (!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "Enabling device interface failed with Status code %!STATUS!\n", status); + + goto exit; + } + +exit: + // + // We don't need to worry about deleting any objects on failure + // because all the object created so far are parented to device and when + // we return an error, framework will delete the device and as a + // result all the child objects will get deleted along with that. + // + return status; +} + +NTSTATUS +BthEchoCliEvtDeviceSelfManagedIoInit( + _In_ WDFDEVICE Device + ) +/*++ + +Description: + + This routine is called by the framework only once + and hence we use it for our one time initialization. + + Bth addresses for both our local device and server device + do not change, hence we retrieve them here. + + Features that the local device supports also do not change, + so checking for local L2cap support is done here and saved in the + device context header + + Please note that retrieveing server bth address does not + require presence of the server. It is remembered from + the installation time when the client gets installed for a + specific server. + +Arguments: + + Device - Framework device object + +Return Value: + + NTSTATUS Status code. + +--*/ +{ + NTSTATUS status; + PBTHECHOSAMPLE_CLIENT_CONTEXT devCtx = GetClientDeviceContext(Device); + + status = BthEchoSharedRetrieveLocalInfo(&devCtx->Header); + if (!NT_SUCCESS(status)) + { + goto exit; + } + + status = BthEchoCliRetrieveServerBthAddress(devCtx); + if (!NT_SUCCESS(status)) + { + goto exit; + } + +exit: + return status; +} + +NTSTATUS +BthEchoCliConnectionStateConnected( + _In_ WDFFILEOBJECT FileObject, + _In_ PBTHECHO_CONNECTION Connection + ) +/*++ +Description: + + This routine is invoked by BthEchoCliRemoteConnectCompletion + function in client.c when opening a remote + connection is completed. + + In this routine we set the file context to the connection passed in. + +Arguments: + + FileObject - File object whose open resulted in open connection + Connection - Our data strucutre to track open connection + +Return Value: + + NTSTATUS Status code. +--*/ +{ + GetFileContext(FileObject)->Connection = Connection; + + return STATUS_SUCCESS; +} + +VOID +BthEchoCliEvtDeviceFileCreate( + _In_ WDFDEVICE Device, + _In_ WDFREQUEST Request, + _In_ WDFFILEOBJECT FileObject + ) +/*++ +Description: + + This routine is invoked by Framework when an application opens a handle + to our device. + + In response we open a remote connection to the server. + +Arguments: + + Device - Framework device object + Request - Create request + FileObject - File object corresponding to Create +--*/ +{ + NTSTATUS status; + PBTH_SDP_STREAM_RESPONSE serverSdpRecord = NULL; + PBTHECHOSAMPLE_CLIENT_CONTEXT devCtx = GetClientDeviceContext(Device); + PBTHECHOSAMPLE_CLIENT_FILE_CONTEXT fileCtx = GetFileContext(FileObject); + BTHDDI_SDP_PARSE_INTERFACE sdpParseInterface; + + PAGED_CODE(); + + // + // We need to obtained PSM from the server + // For this, first we retrieve the SDP record + // + + status = BthEchoCliRetrieveServerSdpRecord(devCtx, &serverSdpRecord); + if (!NT_SUCCESS(status)) + { + goto exit; + } + + status = WdfFdoQueryForInterface( + Device, + &GUID_BTHDDI_SDP_PARSE_INTERFACE, + (PINTERFACE) (&sdpParseInterface), + sizeof(sdpParseInterface), + BTHDDI_SDP_PARSE_INTERFACE_VERSION_FOR_QI, + NULL + ); + + if (!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "QueryInterface failed for Interface sdp parse interface, version %d, Status code %!STATUS!\n", + BTHDDI_SDP_PARSE_INTERFACE_VERSION_FOR_QI, + status); + + goto exit; + } + + // + // Once we retrieved the server SDP record, we retrieve + // PSM from this record. + // + // We store this Psm in our file context and use it in open + // and close channel BRBs. + // + + status = BthEchoCliRetrievePsmFromSdpRecord( + &sdpParseInterface, + serverSdpRecord, + &fileCtx->ServerPsm + ); + + if (!NT_SUCCESS(status)) + { + goto exit; + } + + // + // Open remote connection to the server + // We format Create request for this purpose. + // + // This means that any cancellation of Create propagates + // to cancellation of open channel BRB. + // + status = BthEchoCliOpenRemoteConnection( + devCtx, + FileObject, + Request + ); + +exit: + if (NULL != serverSdpRecord) + { + // + // Free the Server SDP record + // + ExFreePoolWithTag(serverSdpRecord, POOLTAG_BTHECHOSAMPLE); + } + + // + // If we failed we complete the request here + // If it succeeds RemoteConnectCompletion will complete the request + // + + if (!NT_SUCCESS(status)) + { + WdfRequestComplete(Request, status); + } +} + +VOID +BthEchoCliEvtFileClose( + _In_ WDFFILEOBJECT FileObject + ) +/*++ +Description: + + This routine is invoked by Framework when I/O manager sends Close + IRP for a file. + + In response we close the remote connection to the server. + +Arguments: + + FileObject - File object corresponding to Close + +--*/ +{ + PBTHECHOSAMPLE_CLIENT_CONTEXT devCtx; + PBTHECHO_CONNECTION connection; + + PAGED_CODE(); + + devCtx = GetClientDeviceContext(WdfFileObjectGetDevice(FileObject)); + + connection = GetFileContext(FileObject)->Connection; + + // + // Since this routine is called at passive level we can disconnect + // synchronously. + // + BthEchoConnectionObjectRemoteDisconnectSynchronously( + &(devCtx->Header), + connection + ); +} + diff --git a/bluetooth/bthecho/bthcli/sys/device.h b/bluetooth/bthecho/bthcli/sys/device.h new file mode 100644 index 00000000..640cf2cf --- /dev/null +++ b/bluetooth/bthecho/bthcli/sys/device.h @@ -0,0 +1,91 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + Device.h + +Abstract: + + Conext and function declarations for bthecho client device + +Environment: + + Kernel mode only + + +--*/ + +#include "clisrv.h" + +typedef struct _BTHECHOSAMPLE_CLIENT_CONTEXT +{ + // + // Context common to client and server + // + BTHECHOSAMPLE_DEVICE_CONTEXT_HEADER Header; + + // + // Server address + // + BTH_ADDR ServerBthAddress; + +} BTHECHOSAMPLE_CLIENT_CONTEXT, *PBTHECHOSAMPLE_CLIENT_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(BTHECHOSAMPLE_CLIENT_CONTEXT, GetClientDeviceContext) + +typedef struct _BTHECHOSAMPLE_CLIENT_FILE_CONTEXT +{ + // + // Connection to server opened for this file + // + PBTHECHO_CONNECTION Connection; + + // + // Server PSM + // + USHORT ServerPsm; +} BTHECHOSAMPLE_CLIENT_FILE_CONTEXT, *PBTHECHOSAMPLE_CLIENT_FILE_CONTEXT; + +// +// Context for requests +// +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(BRB, GetRequestContext); + +// +// Context for file objects +// +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(BTHECHOSAMPLE_CLIENT_FILE_CONTEXT, GetFileContext); + +NTSTATUS +FORCEINLINE +BthEchoCliContextInit( + PBTHECHOSAMPLE_CLIENT_CONTEXT context, + WDFDEVICE Device + ) +{ + return BthEchoSharedDeviceContextHeaderInit(&context->Header, Device); +} + +EVT_WDF_DRIVER_DEVICE_ADD BthEchoCliEvtDriverDeviceAdd; + +EVT_WDF_DEVICE_SELF_MANAGED_IO_INIT BthEchoCliEvtDeviceSelfManagedIoInit; + +EVT_WDF_DEVICE_FILE_CREATE BthEchoCliEvtDeviceFileCreate; + +EVT_WDF_FILE_CLOSE BthEchoCliEvtFileClose; + +NTSTATUS +BthEchoCliConnectionStateConnected( + _In_ WDFFILEOBJECT FileObject, + _In_ PBTHECHO_CONNECTION Connection + ); + + + diff --git a/bluetooth/bthecho/bthcli/sys/driver.c b/bluetooth/bthecho/bthcli/sys/driver.c new file mode 100644 index 00000000..3b576a3d --- /dev/null +++ b/bluetooth/bthecho/bthcli/sys/driver.c @@ -0,0 +1,210 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + Driver.c + +Abstract: + + Driver object related functionality for bthecho client device + +Environment: + + Kernel mode only + + +--*/ + +#include "clisrv.h" +#include "driver.h" + +#if defined(EVENT_TRACING) +// +// The trace message header (.tmh) file must be included in a source file +// before any WPP macro calls and after defining a WPP_CONTROL_GUIDS +// macro (defined in toaster.h). During the compilation, WPP scans the source +// files for DoTraceMessage() calls and builds a .tmh file which stores a unique +// data GUID for each message, the text resource string for each message, +// and the data types of the variables passed in for each message. This file +// is automatically generated and used during post-processing. +// +#include "driver.tmh" +#else +#define _DRIVER_NAME_ "BthEchoSampleCli" +ULONG DebugLevel = TRACE_LEVEL_INFORMATION; +ULONG DebugFlag = 0xff; +#endif + +#ifdef ALLOC_PRAGMA +#pragma alloc_text (INIT, DriverEntry) +#pragma alloc_text (PAGE, BthEchoCliEvtDriverCleanup) +#endif + +NTSTATUS +DriverEntry( + _In_ PDRIVER_OBJECT DriverObject, + _In_ PUNICODE_STRING RegistryPath + ) +/*++ + +Routine Description: + DriverEntry initializes the driver and is the first routine called by the + system after the driver is loaded. + +Parameters Description: + + DriverObject - represents the instance of the function driver that is loaded + into memory. DriverEntry must initialize members of DriverObject before it + returns to the caller. DriverObject is allocated by the system before the + driver is loaded, and it is released by the system after the system unloads + the function driver from memory. + + RegistryPath - represents the driver specific path in the Registry. + The function driver can use the path to store driver related data between + reboots. The path does not store hardware instance specific data. + +Return Value: + + STATUS_SUCCESS if successful, + STATUS_UNSUCCESSFUL otherwise. + +--*/ +{ + NTSTATUS status; + WDFDRIVER driver; + WDF_OBJECT_ATTRIBUTES attributes; + + WDF_DRIVER_CONFIG DriverConfig; + WDF_DRIVER_CONFIG_INIT( + &DriverConfig, + BthEchoCliEvtDriverDeviceAdd + ); + + WPP_INIT_TRACING( DriverObject, RegistryPath ); + + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + attributes.EvtCleanupCallback = BthEchoCliEvtDriverCleanup; + + status = WdfDriverCreate( + DriverObject, + RegistryPath, + NULL, + &DriverConfig, + &driver + ); + + if(!NT_SUCCESS(status)) + { + WPP_CLEANUP(DriverObject); + } + + return status; +} + +VOID +BthEchoCliEvtDriverCleanup( + _In_ WDFOBJECT DriverObject + ) +/*++ +Routine Description: + + Free resources allocated in DriverEntry that are automatically + cleaned up framework. + +Arguments: + + DriverObject - handle to a WDF Driver object. + +Return Value: + + VOID. + +--*/ +{ + PAGED_CODE (); + + // + // Driver remains unreferenced if EVENT_TRACING is not defined + // in which case traces are sent to debugger instead of ETW + // + UNREFERENCED_PARAMETER(DriverObject); + + WPP_CLEANUP( WdfDriverWdmGetDriverObject( DriverObject ) ); +} + +#if !defined(EVENT_TRACING) + +VOID +TraceEvents ( + _In_ ULONG DebugPrintLevel, + _In_ ULONG DebugPrintFlag, + _Printf_format_string_ + _In_ PCSTR DebugMessage, + ... + ) + +/*++ + +Routine Description: + + Debug print for the sample driver. + +Arguments: + + TraceEventsLevel - print level between 0 and 3, with 3 the most verbose + +Return Value: + + None. + + --*/ + { +#if DBG +#define TEMP_BUFFER_SIZE 1024 + va_list list; + CHAR debugMessageBuffer[TEMP_BUFFER_SIZE]; + NTSTATUS status; + + va_start(list, DebugMessage); + + if (DebugMessage) { + + // + // Using new safe string functions instead of _vsnprintf. + // This function takes care of NULL terminating if the message + // is longer than the buffer. + // + status = RtlStringCbVPrintfA( debugMessageBuffer, + sizeof(debugMessageBuffer), + DebugMessage, + list ); + if(!NT_SUCCESS(status)) { + + DbgPrint (_DRIVER_NAME_": RtlStringCbVPrintfA failed 0x%x\n", status); + return; + } + if (DebugPrintLevel <= TRACE_LEVEL_ERROR || + (DebugPrintLevel <= DebugLevel && + ((DebugPrintFlag & DebugFlag) == DebugPrintFlag))) { + DbgPrint("%s %s", _DRIVER_NAME_, debugMessageBuffer); + } + } + va_end(list); + + return; +#else + UNREFERENCED_PARAMETER(DebugPrintLevel); + UNREFERENCED_PARAMETER(DebugPrintFlag); + UNREFERENCED_PARAMETER(DebugMessage); +#endif +} + +#endif + diff --git a/bluetooth/bthecho/bthcli/sys/driver.h b/bluetooth/bthecho/bthcli/sys/driver.h new file mode 100644 index 00000000..94ff858b --- /dev/null +++ b/bluetooth/bthecho/bthcli/sys/driver.h @@ -0,0 +1,34 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + Driver.c + +Abstract: + + Driver object related declarations for bthecho client device + +Environment: + + Kernel mode only + + +--*/ + +// +// WDFDRIVER Events +// + +DRIVER_INITIALIZE DriverEntry; + +EVT_WDF_DRIVER_DEVICE_ADD BthEchoCliEvtDriverDeviceAdd; + +EVT_WDF_OBJECT_CONTEXT_CLEANUP BthEchoCliEvtDriverCleanup; + diff --git a/bluetooth/bthecho/bthcli/sys/queue.c b/bluetooth/bthecho/bthcli/sys/queue.c new file mode 100644 index 00000000..6f1e244c --- /dev/null +++ b/bluetooth/bthecho/bthcli/sys/queue.c @@ -0,0 +1,349 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + Queue.c + +Abstract: + + Read/write functionality for bthecho client + +Environment: + + Kernel mode only + + +--*/ + +#include "clisrv.h" +#include "device.h" +#include "queue.h" + +#if defined(EVENT_TRACING) +#include "queue.tmh" +#endif + +void +BthEchoCliReadWriteCompletion( + _In_ WDFREQUEST Request, + _In_ WDFIOTARGET Target, + _In_ PWDF_REQUEST_COMPLETION_PARAMS Params, + _In_ WDFCONTEXT Context + ) +/*++ +Description: + + Completion routine for read/write requests + + We receive l2ca transfer BRB as the context. This BRB + is part of the request context and doesn't need to be freed + explicitly. + +Arguments: + + Request - Request that got completed + Target - Target to which request was sent + Params - Completion parameters for the request + Context - We receive BRB as the context + +--*/ +{ + struct _BRB_L2CA_ACL_TRANSFER *brb; + size_t information; + + UNREFERENCED_PARAMETER(Target); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_CONNECT, + "I/O completion, status: %!STATUS!", Params->IoStatus.Status); + + brb = (struct _BRB_L2CA_ACL_TRANSFER *) Context; + + NT_ASSERT((brb != NULL)); + + // + // Bytes read/written are contained in Brb->BufferSize + // + information = brb->BufferSize; + + // + // Complete the request + // + WdfRequestCompleteWithInformation( + Request, + Params->IoStatus.Status, + information + ); +} + +VOID +BthEchoCliEvtQueueIoWrite( + _In_ WDFQUEUE Queue, + _In_ WDFREQUEST Request, + _In_ size_t Length + ) +/*++ +Description: + + This routine is invoked by the framework to deliver a + Write request to the driver. + +Arguments: + + Queue - Queue delivering the request + Request - Write request + Length - Length of write + +--*/ +{ + NTSTATUS status; + PBTHECHOSAMPLE_CLIENT_CONTEXT DevCtx; + WDFMEMORY memory; + struct _BRB_L2CA_ACL_TRANSFER * brb = NULL; + PBTHECHO_CONNECTION connection; + + UNREFERENCED_PARAMETER(Length); + + connection = GetFileContext(WdfRequestGetFileObject(Request))->Connection; + + DevCtx = GetClientDeviceContext(WdfIoQueueGetDevice(Queue)); + + status = WdfRequestRetrieveInputMemory( + Request, + &memory + ); + + if (!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, + "WdfRequestRetrieveInputMemory failed, request 0x%p, Status code %!STATUS!\n", + Request, + status); + + goto exit; + } + + // + // Get the BRB from request context and initialize it as + // BRB_L2CA_ACL_TRANSFER BRB + // + brb = (struct _BRB_L2CA_ACL_TRANSFER *)GetRequestContext(Request); + DevCtx->Header.ProfileDrvInterface.BthReuseBrb( + (PBRB)brb, + BRB_L2CA_ACL_TRANSFER + ); + + + // + // Format the Write request for L2Ca OUT transfer + // + // This routine allocates a BRB which is returned to us + // in brb parameter + // + // This BRB is freed by the completion routine is we send the + // request successfully, else it is freed by this routine. + // + status = BthEchoConnectionObjectFormatRequestForL2CaTransfer( + connection, + Request, + &brb, + memory, + ACL_TRANSFER_DIRECTION_OUT + ); + + if (!NT_SUCCESS(status)) + { + goto exit; + } + + // + // Set a CompletionRoutine callback function. + // + + WdfRequestSetCompletionRoutine( + Request, + BthEchoCliReadWriteCompletion, + brb + ); + + // + // Send the request down the stack + // + if (FALSE == WdfRequestSend( + Request, + DevCtx->Header.IoTarget, + NULL + )) + { + status = WdfRequestGetStatus(Request); + + TraceEvents(TRACE_LEVEL_ERROR, DBG_UTIL, + "Request send failed for request 0x%p, Brb 0x%p, Status code %!STATUS!\n", + Request, + brb, + status + ); + + goto exit; + } + +exit: + if (!NT_SUCCESS(status)) + { + WdfRequestComplete(Request, status); + } +} + +VOID +BthEchoCliEvtQueueIoRead ( + _In_ WDFQUEUE Queue, + _In_ WDFREQUEST Request, + _In_ size_t Length + ) +/*++ +Description: + + This routine is invoked by the framework to deliver a + Read request to the driver. + +Arguments: + + Queue - Queue delivering the request + Request - Read request + Length - Length of Read + +--*/ +{ + NTSTATUS status; + PBTHECHOSAMPLE_CLIENT_CONTEXT DevCtx; + WDFMEMORY memory; + struct _BRB_L2CA_ACL_TRANSFER * brb = NULL; + PBTHECHO_CONNECTION connection; + + UNREFERENCED_PARAMETER(Length); + + connection = GetFileContext(WdfRequestGetFileObject(Request))->Connection; + + DevCtx = GetClientDeviceContext(WdfIoQueueGetDevice(Queue)); + + status = WdfRequestRetrieveOutputMemory( + Request, + &memory + ); + + if (!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, + "WdfRequestRetrieveInputMemory failed, request 0x%p, Status code %!STATUS!\n", + Request, + status); + + goto exit; + } + + // + // Get the BRB from request context and initialize it as + // BRB_L2CA_ACL_TRANSFER BRB + // + brb = (struct _BRB_L2CA_ACL_TRANSFER *)GetRequestContext(Request); + DevCtx->Header.ProfileDrvInterface.BthReuseBrb( + (PBRB)brb, + BRB_L2CA_ACL_TRANSFER + ); + + // + // Format the Read request for L2Ca IN transfer + // + // This routine allocates a BRB which is returned to us + // in brb parameter + // + // This BRB is freed by the completion routine is we send the + // request successfully, else it is freed by this routine. + // + status = BthEchoConnectionObjectFormatRequestForL2CaTransfer( + connection, + Request, + &brb, + memory, + ACL_TRANSFER_DIRECTION_IN | ACL_SHORT_TRANSFER_OK + ); + + if (!NT_SUCCESS(status)) + { + goto exit; + } + + // + // Set a CompletionRoutine callback function. + // + + WdfRequestSetCompletionRoutine( + Request, + BthEchoCliReadWriteCompletion, + brb + ); + + // + // Send the request down the stack + // + if (FALSE == WdfRequestSend( + Request, + DevCtx->Header.IoTarget, + NULL + )) + { + status = WdfRequestGetStatus(Request); + + TraceEvents(TRACE_LEVEL_ERROR, DBG_UTIL, + "Request send failed for request 0x%p, Brb 0x%p, Status code %!STATUS!\n", + Request, + brb, + status + ); + + goto exit; + } + +exit: + if (!NT_SUCCESS(status)) + { + WdfRequestComplete(Request, status); + } +} + +VOID +BthEchoCliEvtQueueIoStop( + _In_ WDFQUEUE Queue, + _In_ WDFREQUEST Request, + _In_ ULONG ActionFlags + ) +/*++ +Description: + + This routine is invoked by Framework when Queue is being stopped + + We implement this routine to cancel any requests owned by our driver. + + Without this Queue stop would wait indefinitely for requests to complete + during surprise remove. + +Arguments: + + Queue - Framework queue being stopped + Request - Request owned by the driver + ActionFlags - Action flags + +--*/ +{ + UNREFERENCED_PARAMETER(Queue); + UNREFERENCED_PARAMETER(ActionFlags); + + WdfRequestCancelSentRequest(Request); +} + diff --git a/bluetooth/bthecho/bthcli/sys/queue.h b/bluetooth/bthecho/bthcli/sys/queue.h new file mode 100644 index 00000000..22d00a42 --- /dev/null +++ b/bluetooth/bthecho/bthcli/sys/queue.h @@ -0,0 +1,31 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + Queue.h + +Abstract: + + Queue events for bthecho client + +Environment: + + Kernel mode only + + +--*/ + +EVT_WDF_IO_QUEUE_IO_READ BthEchoCliEvtQueueIoRead ; + +EVT_WDF_IO_QUEUE_IO_WRITE BthEchoCliEvtQueueIoWrite; + +EVT_WDF_IO_QUEUE_IO_STOP BthEchoCliEvtQueueIoStop; + +EVT_WDF_REQUEST_COMPLETION_ROUTINE BthEchoCliReadWriteCompletion; diff --git a/bluetooth/bthecho/bthecho.htm b/bluetooth/bthecho/bthecho.htm new file mode 100644 index 00000000..9ea0ff09 --- /dev/null +++ b/bluetooth/bthecho/bthecho.htm @@ -0,0 +1,2222 @@ + + + + + + + + +BTHECHO + + + + + + + + + + + +
+ +

Bluetooth Echo Sample

+ +

SUMMARY

+ +

This sample demonstrates developing Bluetooth L2CAP +profile drivers using Bluetooth L2CAP DDIs.

+ +

The sample includes two drivers. One for a device that +acts as an L2CAP server and another for the device that acts as an L2CAP +client. Server simply echoes back any data that it receives from client on the +same L2CA channel.

+ +

These drivers can be used with devices that can be +installed with bth.inf. Such devices get installed as ‘Generic Bluetooth +Radio’. Examples of such devices are Bluetooth USB dongles such as (but not +limited to):

+ +

Generic Bluetooth +Radio=                         +BthUsb, USB\Vid_0a12&Pid_0001

+ +

CSR Nanosira=                                    +BthUsb, USB\Vid_0a12&Pid_0003

+ +

CSR Nanosira +WHQL Reference +Radio=               +BthUsb, USB\Vid_0a12&Pid_0004

+ +

CSR Nanosira-Multimedia=                         +BthUsb, USB\Vid_0a12&Pid_0005

+ +

CSR Nanosira-Multimedia +WHQL Reference Radio=    BthUsb, +USB\Vid_0a12&Pid_0006

+ +

Please refer to bth.inf for the complete list of +devices.

+ +

The installation steps below describe how to install +echo server and client with such a device.

+ +

Please note that RFCOMM based profiles must be +developed and accessed using user-mode socket APIs.

+ +

This sample is applicable to Windows® Vista, Windows® +7 and Windows® Developer Preview operating systems.

+ +

BUILDING THE SAMPLE

+ +

To build the sample drivers and exe, you must first +set up the WDK environment on your host machine on your Windows Developer +Preview operating system.

+ +

Run msbuild command +in the bthecho directory as follows

+ +

1.    BthEcho.lib (common library for the +Bluetooth Echo sample)

+ +

cd bthecho\common\lib
+msbuild /t:clean /t:build BthEcho.VcxProj

+ +

2.    BthEchoSampleSrv.sys (driver for +Bluetooth Echo Server device)

+ +

cd ..\..\bthsrv\sys
+msbuild /t:clean +/t:build BthEchoSampleSrv.VcxProj

+ +

3.    BthSrvInst.exe (Bluetooth echo +sever installation utility)

+ +

cd ..\inst
+msbuild /t:clean +/t:build bthsrvinst.VcxProj

+ +

4.    BthEchoSampleCli.sys (driver for +Bluetooth Echo client device)

+ +

cd ..\..\bthcli\ sys
+msbuild /t:clean +/t:build BthEchoSampleCli.VcxProj

+ +

5.    BthEcho.exe (Bluetooth echo +application used to exercise client device)

+ +

cd ..\app
+msbuild /t:clean +/t:build BthEcho.VcxProj

+ +

 

+ +

INSTALLATION

+ +

Note: Bluetooth echo server device and echo client device +must be installed on two different machines.

+ +

 

+ +

Server Installation

+ +

1.    +Copy KMDF coinstaller +(wdfcoinstallerMMmmm.dll, from redist\wdf\ ), BthEchoSampleSrv.Sys, +BthEchoSampleSrv.inf and bthsrvinst.exe on a temporary directory on the +target machine.

+ +

2.    +Run bthsrvinst.exe /i +to install the echo server device. This enables the Bluetooth Enumerator +(BthEnum.sys) to enumerate echo server device and create a PDO for the device +(please refer to the device tree below).

+ +

2.    +Step #2 causes BthEnum.sys to create a PDO. +Consequently hardware installation wizard gets launched. Either go through the UI (Device Manager – Update Driver Software +in Windows® 7, ‘Found New Hardware’ wizard in Windows® Vista) and point it to +the temporary directory where you copied the binaries in step #1, or using +devcon.exe from the tools\devcon folder, run the +following command from the temporary directory:

+ +

devcon.exe update BthEchoSampleSrv.inf +BTHENUM\{c07508f2-b970-43ca-b5dd-cc4f2391bef4}

+ +

If devcon.exe fails +check the error level using:

+ +

echo %errorlevel%

+ +

If errorlevel is 1, you need to reboot the machine for KMDF +update to take effect. If errorlevel is 2, please +make sure that you have the driver files described in #1 available in the +current directory. For more information on installation failure please check +setup logs.

+ +

4.    +Upon successful installation you will see ‘Bluetooth +Echo Sample Server’ in Device Manager under Bluetooth devices.

+ +

5.    +(This steps in needed only on Windows® Vista) Navigate +to the system tray, right click on the Bluetooth icon, and select ‘Open Settings’. +This launches the ‘Bluetooth Settings’ dialog. On the ‘Options’ tab, check +‘Allow Bluetooth devices to find this Computer’. Note that this will make your +computer discoverable to other Bluetooth devices, and should be disabled again +when no longer required.

+ +

 

+ +

Device tree for Echo Server device

+ +

 

+ +

(Drivers for FDOs are shown for each devnode +in the tree.)

+ +

 

+ +
                   ---------------------
                  |                     |
                  |BthEchoSampleSrv.sys |<---------------Function driver for PDO ejected by BthEnum.sys
                  |                     |
                   ---------------------
                            ^
                            |          ---------------------
                            |         |                     |
                            |         |Bluetooth Enumerator |
                            --------- |    (BthEnum.SYS)    | 
                                      |                     |
                                       ---------------------
                                                 ^
                                                 |
                                                 |          ---------------------            ---------------------
                                                 |         |                     |          |                     |
                                                 ----------|     bthport.SYS     |<-------->|     bthusb.SYS      |       
                                                           |                     |          |                     |
                                                            ---------------------            ---------------------
+ +

                                                            +Bth port driver loaded by bthusb.sys +       ^

+ +

                                                                                                        +|

+ +

                                                              +                                          V

+ +

                                                                                               +---------------------

+ +

                                                                                              +|                     +|

+ +

                                                                                              +|      USB Stack      |

+ +

                                                                                              +|                    + |

+ +

                                                                                               +---------------------

+ +

                                                         +                                               ^

+ +

                                                                                                        +|   

+ +

                                                                                                 +       V

+ +

                                                                                               +----------------------

+ +

                                                                                              +| USB Bluetooth Dongle |

+ +

          +                                                                                     ----------------------

+ +

Client Installation

+ +

1.    Important: This must be done on a +separate machine from the one where echo server device was installed.

+ +

2.    Copy KMDF coinstaller +(wdfcoinstallerMMmmm.dll, from redist\wdf\), BthEchoSampleCli.Sys, +BthEchoSampleCli.inf and bthecho.exe on a temporary directory on the target +machine.

+ +

3.    Run bthprops.cpl from a command line or right +click on the Bluetooth icon in the system tray and select ‘Show Devices' to +bring up a list of installed Bluetooth devices.

+ +

4.   Windows® 7:  In the ‘Bluetooth Devices’ window click the ‘Add a +device’ button. Windows® Vista: In the ‘Devices’ tab, click Add button.

+ +

5.    In the Add a Device wizard select the server machine (the machine where +you installed the echo server) as a Bluetooth device. If the server machine +does not appear, please check the echo server installation and make sure that +you have enabled ‘Allow Bluetooth device to find this computer’ on the server +machine as explained above. When the server machine is correctly displayed, +select it and pick ‘Next’.

+ +

6. The wizard should default to a numeric compare +ceremony for pairing the machines. When this happens, ensure the numbers match +on both the client and the server, select ‘Yes’ on both machines to indicate +they match, and click ‘Next’ on both machines to complete the pairing.

+ +

7. The ‘Found New Hardware’ wizard will be launched on +Windows® Vista. On Windows® 7 and Windows® Developer Preview you will need to +go through Device Manager and update driver software for it. Either point the +wizard to the temporary directory created in step #2, or use devcon.exe from +the tools\devcon folder to install the client device:

+ +

Devcon.exe update BthEchoSampleCli.inf BTHENUM\{c07508f2-b970-43ca-b5dd-cc4f2391bef4}

+ +

Check for any error from devcon.exe as described in +server installation.

+ +

If the installation is successful, you will see +‘Bluetooth Echo Sample Client’ in Device Manager under Bluetooth devices.

+ +

 

+ +

The device tree for echo client device is similar to +the one shown for the echo server device, since both client and server are +enumerated by BthEnum.sys (although the installation mechanism and properties +of client and server are different).

+ +

 

+ +

Uninstalling Server

+ +

1.  Uninstall the device and delete driver +software using the Bluetooth Devices window by running bthprops.cpl, +right clicking on the device, and selecting ‘Remove Device’

+ +

2.  Run bthsrvinst.exe /u to +uninstall the echo server. This would make bthenum.sys stop enumerating the +echo server. Without this step ‘Found New Hardware’ wizard will be launched +again when you reconnect the device.

+ +

Uninstalling Client

+ +

1.  Uninstall the device and delete driver +software using the Bluetooth Devices window by running bthprops.cpl, +right clicking on the device, and selecting ‘Remove Device’

+ +

TESTING

+ +

Run BthEcho.exe on the client machine. You should see +client sending data to the server and receiving the same data echoed back. +Press Ctrl+c to terminate the application. You will +see output similar to below:

+ +

D:\bth\wdfcli>BthEcho.exe

+ +

DevicePath: +\\?\bthenum#{c07508f2-b970-43ca-b5dd-cc4f2391bef4}_localmfg&000a#7&3

+ +

62d0a3&0&000c55ff727a_c00000001#{fc71b33d-d528-4763-a86c-78777c7bcd7b}

+ +

Opened device successfully

+ +

Written                 +26 bytes: WDF Bluetooth Sample Echo

+ +

Reply from server       26 bytes: WDF +Bluetooth Sample Echo

+ +

Written                 +26 bytes: WDF Bluetooth Sample Echo

+ +

Reply from server       26 bytes: WDF +Bluetooth Sample Echo

+ +

Written                 +26 bytes: WDF Bluetooth Sample Echo

+ +

Reply from server       26 bytes: WDF +Bluetooth Sample Echo

+ +

Written                 +26 bytes: WDF Bluetooth Sample Echo

+ +

Reply from server       26 bytes: WDF +Bluetooth Sample Echo

+ +

Written                 +26 bytes: WDF Bluetooth Sample Echo

+ +

^C

+ +

You can launch multiple instances of BthEcho.exe. Each +client application would cause echo client device to have an independent +connection to the echo server and thereby have an independent echo session. You +can also have echo client devices and apps installed on multiple machines and +talking to a single echo server.

+ +

DIRECTORY MANIFEST

+ +
File           Description
 
bthcli         contains files for Bluetooth echo sample client
bthcli\sys     contains driver code for echo client (produces BthEchoSampleCli.sys and BthEchoSampleCli.inf)
bthcli\app     contains code for echo test application (produces BthEcho.exe)
bthsrv         contains files for Bluetooth echo sample server
bthsrv\sys     contains driver code for echo server (produces BthEchoSampleSrv.sys and BthEchoSampleSrv.inf)
bthsrv\inst    contains code for server installation utility (produces bthsrvinst.exe)
common         contains headers and code shared by client and server
common\inc     contains common headers
common\lib     contains common code (produces bthecho.lib used while building BthEchoSampleSrv.sys and BthEchoSampleCli.sys)
+ +

FILE MANIFEST

+ +

(build related files and inx files omitted for brevity)

+ +

 

+ +

bthcli\sys

+ +

 

+ +
File           Description
 
driver.*       contains WDF driver functionality
device.*       contains Bluetooth echo client device functionality
client.*       contains reusable code for Bluetooth L2CAP client, this code is used by device.*
queue.*        contains code for WDF queue used for read/write operations
 
+ +

bthcli\app

+ +

 

+ +
File           Description
 
main.cpp       contains code for writing to and reading from Bluetooth echo client
 
bthsrv\sys
 
File           Description
 
driver.*       WDF driver functionality
device.*       contains Bluetooth echo server device functionality
server.*       contains reusable code for Bluetooth L2CAP server, this code is used by device.*
echo.*         contains functionality for sending echo to the client
sdp.*          contains code for building server SDP record
 
bthsrv\inst
 
File           Description
 
main.cpp       contains code for installing and uninstalling echo sample server
 
common\inc
 
File           Description
 
clisrv.h       header for common functions used by both echo client and echo server drivers
connection.h   contains header for connection object used by both echo client and echo server drivers
public.h       definitions used by echo client and server drivers as well as install and echo apps
trace.h        tracing related definitions
 
common\lib
 
File           Description
 
clisrv.c       code for common functions used by both echo client and echo server drivers
connection.c   contains code for connection object used by both echo client and echo server drivers
+ +

CODE TOUR

+ +

Common code

+ +
    +
  • Connection + object: The common code contains implementation of a + connection object (in connection.*) that is utilized by both client and + the server. Client uses this object to maintain the information about + opened connection and the server uses this object to maintain information + about the accepted connection. Connection object also supports continuous + reader which is utilized by server to read the data sent by client. + Connection object is implemented as a WDF user object. Connection details + are maintained in BTHECHO_CONNECTION structure. This structure is used as + the context for WDF user object. Passive dispose is used to make the + connection object cleanup wait for disconnect completion and continuous + reader rundown. Please see WDF documentation for WDF user object and + passive dispose (see WdfObjectCreate).
  • +
+ +

Server

+ +

·         +Startup: Server +registers PSM and L2CA server and published SDP record on startup in BthEchoSrvEvtDeviceSelfManagedIoInit (this callback is +invoked by WDF during device start). While registering the L2CA server it +passes BthEchoSrvIndicationCallback as the callback +for incoming connection notifications.

+ +

·         +Server SDP record creation: The sample uses dynamic creation of server SDP record +using Bluetooth DDIs. Please note that for your particular device you may be +able to use static data for the SDP record.

+ +

·         +Incoming connections: Bluetooth stack invokes BthEchoSrvIndicationCallback +for the incoming connections from clients. In response server accepts the +connection and passes BthEchoSrvConnectionIndicationCallback +callback to Bluetooth stack for disconnect notification. It is possible to use +the same indication callback for server and connection but the sample uses +different callbacks for clarity. Server adds the accepted connection to the +connection list it maintains. Please see below for connection rundown details.

+ +

·         +Connection rundown: Server maintains a list of all the connections it has accepted. This +allows server to properly close down these connections on orderly removal. On +surprise removal bthport.sys itself gets removed and takes care of running down +the connections, but in case of orderly removal driver has to make sure to +rundown the connections.

+ +

·         +Connection state machine:

+ +

                                                                   +                            ConnectFailed

+ +
                                                     ^
                                                     |
                                                     |          
                                                     | (connection failure)
+ +

                         + Uninitialized   ------> Connecting ------> Connected

+ +
                                                     | (disconnect)  /  ^ 
                                                     |              /  /
                                                     |             /  /
                                                     V            V  / (connection complete)
+ +

                                                  +Disconnecting   

+ +
                                                     | (disconnect complete)
                                                     |          
                                                     |             
                                                     V            
+ +

                                                  +Disconnected

+ +

 

+ +

One transition to note here is that if disconnect is +received in the connecting state (i.e. when the connection is not completed) we +wait for connection to completed (transition to connected state) and then +invoke +disconnect.                                         +

+ +

 

+ +

Important: Such state machine is needed only if Disconnect is initiated by +something other than Bluetooth stack (for example device removal in our case). +Bluetooth stack itself would not send disconnect before connect completion. If +you adapt this sample for your device please evaluate whether your driver would +require such state machine. For example, the echo client device does not need +such state machine (although we use common connection code for client and the +server).

+ +

 

+ +
    +
  • Shutdown: + Server + removes the SDP record and unregisters L2CAP server and PSM in BthEchoSrvEvtDeviceSelfManagedIoCleanup (this callback + is invoked by WDF during device removal). It also disconnects any open + connections (see Connection rundown above).
  • +
+ +

Client

+ +
    +
  • Startup: + Client + retrieves local and server Bluetooth address in BthEchoSrvEvtDeviceSelfManagedIoInit + (this callback is invoked by WDF during device start). Please note that + server Bluetooth address would be available regardless of presence of the + server. Thus echo client device start doesn’t fail even if echo server is + not available.
  • +
  • Connecting + to server: Client connects to echo server when application + opens a handle to it (BthEchoCliEvtDeviceFileCreate) + and closes the connection on file close (BthEchoCliEvtFileClose).
  • +
  • Sending + and receiving data from server: When application writes data to + the client, client sends this data to server on the connection opened for + the given handle. Server would echo back this data. This data is retrieved + by the application using a read operation. Echo Sample Client doesn’t do + any draining of echoed data on its own. Application read/write are handled + using a parallel WDF I/O queue.
  • +
  • Shutdown: + Client + doesn’t need any specific shutdown code as connection open/close and + read/write are done within the context of application’s handle open.
  • +
+ +

RESOURCES

+ +

For the latest release of the Windows device Driver +Development Kit, see http://www.microsoft.com/whdc/. +For Bluetooth user mode APIs used in BthSrvInst.exe please see MSDN (http://msdn.microsoft.com).

+ +

Please see the latest WDK release for documentation on +Bluetooth and WDF.

+ +

If you have questions on using or adapting this sample +for your project, you can post your questions in the Microsoft +driver development newsgroup.

+ +

 

+ +

Top of page

+ + + + + +
+ +

© 2009 Microsoft Corporation. All rights reserved.

+ +
+ + + + diff --git a/bluetooth/bthecho/bthecho.sln b/bluetooth/bthecho/bthecho.sln new file mode 100644 index 00000000..3e94270a --- /dev/null +++ b/bluetooth/bthecho/bthecho.sln @@ -0,0 +1,102 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0 +MinimumVisualStudioVersion = 12.0 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Lib", "Lib", "{83E67B5A-A079-4795-BB30-7DF17133F3F2}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Common", "Common", "{5581D7EE-1489-4811-94EE-AA7717B4367A}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "App", "App", "{17CBFF38-C5AD-417C-8CC8-864EE0DDDD4C}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Bthcli", "Bthcli", "{8107A759-05EB-4C85-8E43-21D9C34D8437}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Sys", "Sys", "{7F96521C-27C0-448F-9408-BE90EAEAC221}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Inst", "Inst", "{2E43D7E2-4E3C-490D-951B-4271FB00B68D}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Bthsrv", "Bthsrv", "{2FC6C414-6626-45DC-9519-70E6412A131E}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Sys", "Sys", "{2D8F29A9-064E-4557-BBCB-1A09BCC8CC68}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bthecho", "common\lib\bthecho.vcxproj", "{A2EE1D94-8521-48CE-B925-271ACA5DD459}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BthEcho", "bthcli\app\BthEcho.vcxproj", "{B506A244-2ADC-4C65-85B8-8B19764B4849}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BthEchoSampleCli", "bthcli\sys\BthEchoSampleCli.vcxproj", "{AADDAE40-9C46-4C50-AC5F-FF957C3A6E94}" + ProjectSection(ProjectDependencies) = postProject + {A2EE1D94-8521-48CE-B925-271ACA5DD459} = {A2EE1D94-8521-48CE-B925-271ACA5DD459} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bthsrvinst", "bthsrv\inst\bthsrvinst.vcxproj", "{9DF556F0-A8AB-41C6-A9A4-EEB07CA724A2}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BthEchoSampleSrv", "bthsrv\sys\BthEchoSampleSrv.vcxproj", "{B3D6AD34-E4B4-4C3E-8CD2-583FFE3501E3}" + ProjectSection(ProjectDependencies) = postProject + {A2EE1D94-8521-48CE-B925-271ACA5DD459} = {A2EE1D94-8521-48CE-B925-271ACA5DD459} + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {A2EE1D94-8521-48CE-B925-271ACA5DD459}.Debug|Win32.ActiveCfg = Debug|Win32 + {A2EE1D94-8521-48CE-B925-271ACA5DD459}.Debug|Win32.Build.0 = Debug|Win32 + {A2EE1D94-8521-48CE-B925-271ACA5DD459}.Release|Win32.ActiveCfg = Release|Win32 + {A2EE1D94-8521-48CE-B925-271ACA5DD459}.Release|Win32.Build.0 = Release|Win32 + {A2EE1D94-8521-48CE-B925-271ACA5DD459}.Debug|x64.ActiveCfg = Debug|x64 + {A2EE1D94-8521-48CE-B925-271ACA5DD459}.Debug|x64.Build.0 = Debug|x64 + {A2EE1D94-8521-48CE-B925-271ACA5DD459}.Release|x64.ActiveCfg = Release|x64 + {A2EE1D94-8521-48CE-B925-271ACA5DD459}.Release|x64.Build.0 = Release|x64 + {B506A244-2ADC-4C65-85B8-8B19764B4849}.Debug|Win32.ActiveCfg = Debug|Win32 + {B506A244-2ADC-4C65-85B8-8B19764B4849}.Debug|Win32.Build.0 = Debug|Win32 + {B506A244-2ADC-4C65-85B8-8B19764B4849}.Release|Win32.ActiveCfg = Release|Win32 + {B506A244-2ADC-4C65-85B8-8B19764B4849}.Release|Win32.Build.0 = Release|Win32 + {B506A244-2ADC-4C65-85B8-8B19764B4849}.Debug|x64.ActiveCfg = Debug|x64 + {B506A244-2ADC-4C65-85B8-8B19764B4849}.Debug|x64.Build.0 = Debug|x64 + {B506A244-2ADC-4C65-85B8-8B19764B4849}.Release|x64.ActiveCfg = Release|x64 + {B506A244-2ADC-4C65-85B8-8B19764B4849}.Release|x64.Build.0 = Release|x64 + {AADDAE40-9C46-4C50-AC5F-FF957C3A6E94}.Debug|Win32.ActiveCfg = Debug|Win32 + {AADDAE40-9C46-4C50-AC5F-FF957C3A6E94}.Debug|Win32.Build.0 = Debug|Win32 + {AADDAE40-9C46-4C50-AC5F-FF957C3A6E94}.Release|Win32.ActiveCfg = Release|Win32 + {AADDAE40-9C46-4C50-AC5F-FF957C3A6E94}.Release|Win32.Build.0 = Release|Win32 + {AADDAE40-9C46-4C50-AC5F-FF957C3A6E94}.Debug|x64.ActiveCfg = Debug|x64 + {AADDAE40-9C46-4C50-AC5F-FF957C3A6E94}.Debug|x64.Build.0 = Debug|x64 + {AADDAE40-9C46-4C50-AC5F-FF957C3A6E94}.Release|x64.ActiveCfg = Release|x64 + {AADDAE40-9C46-4C50-AC5F-FF957C3A6E94}.Release|x64.Build.0 = Release|x64 + {9DF556F0-A8AB-41C6-A9A4-EEB07CA724A2}.Debug|Win32.ActiveCfg = Debug|Win32 + {9DF556F0-A8AB-41C6-A9A4-EEB07CA724A2}.Debug|Win32.Build.0 = Debug|Win32 + {9DF556F0-A8AB-41C6-A9A4-EEB07CA724A2}.Release|Win32.ActiveCfg = Release|Win32 + {9DF556F0-A8AB-41C6-A9A4-EEB07CA724A2}.Release|Win32.Build.0 = Release|Win32 + {9DF556F0-A8AB-41C6-A9A4-EEB07CA724A2}.Debug|x64.ActiveCfg = Debug|x64 + {9DF556F0-A8AB-41C6-A9A4-EEB07CA724A2}.Debug|x64.Build.0 = Debug|x64 + {9DF556F0-A8AB-41C6-A9A4-EEB07CA724A2}.Release|x64.ActiveCfg = Release|x64 + {9DF556F0-A8AB-41C6-A9A4-EEB07CA724A2}.Release|x64.Build.0 = Release|x64 + {B3D6AD34-E4B4-4C3E-8CD2-583FFE3501E3}.Debug|Win32.ActiveCfg = Debug|Win32 + {B3D6AD34-E4B4-4C3E-8CD2-583FFE3501E3}.Debug|Win32.Build.0 = Debug|Win32 + {B3D6AD34-E4B4-4C3E-8CD2-583FFE3501E3}.Release|Win32.ActiveCfg = Release|Win32 + {B3D6AD34-E4B4-4C3E-8CD2-583FFE3501E3}.Release|Win32.Build.0 = Release|Win32 + {B3D6AD34-E4B4-4C3E-8CD2-583FFE3501E3}.Debug|x64.ActiveCfg = Debug|x64 + {B3D6AD34-E4B4-4C3E-8CD2-583FFE3501E3}.Debug|x64.Build.0 = Debug|x64 + {B3D6AD34-E4B4-4C3E-8CD2-583FFE3501E3}.Release|x64.ActiveCfg = Release|x64 + {B3D6AD34-E4B4-4C3E-8CD2-583FFE3501E3}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {A2EE1D94-8521-48CE-B925-271ACA5DD459} = {83E67B5A-A079-4795-BB30-7DF17133F3F2} + {B506A244-2ADC-4C65-85B8-8B19764B4849} = {17CBFF38-C5AD-417C-8CC8-864EE0DDDD4C} + {AADDAE40-9C46-4C50-AC5F-FF957C3A6E94} = {7F96521C-27C0-448F-9408-BE90EAEAC221} + {9DF556F0-A8AB-41C6-A9A4-EEB07CA724A2} = {2E43D7E2-4E3C-490D-951B-4271FB00B68D} + {B3D6AD34-E4B4-4C3E-8CD2-583FFE3501E3} = {2D8F29A9-064E-4557-BBCB-1A09BCC8CC68} + {83E67B5A-A079-4795-BB30-7DF17133F3F2} = {5581D7EE-1489-4811-94EE-AA7717B4367A} + {17CBFF38-C5AD-417C-8CC8-864EE0DDDD4C} = {8107A759-05EB-4C85-8E43-21D9C34D8437} + {7F96521C-27C0-448F-9408-BE90EAEAC221} = {8107A759-05EB-4C85-8E43-21D9C34D8437} + {2E43D7E2-4E3C-490D-951B-4271FB00B68D} = {2FC6C414-6626-45DC-9519-70E6412A131E} + {2D8F29A9-064E-4557-BBCB-1A09BCC8CC68} = {2FC6C414-6626-45DC-9519-70E6412A131E} + EndGlobalSection +EndGlobal diff --git a/bluetooth/bthecho/bthsrv/inst/bthsrvinst.vcxproj b/bluetooth/bthecho/bthsrv/inst/bthsrvinst.vcxproj new file mode 100644 index 00000000..612205d0 --- /dev/null +++ b/bluetooth/bthecho/bthsrv/inst/bthsrvinst.vcxproj @@ -0,0 +1,191 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {9DF556F0-A8AB-41C6-A9A4-EEB07CA724A2} + $(MSBuildProjectName) + Debug + Win32 + {6D053B10-3595-40FE-AB0C-0BFF3690D74B} + + + + Windows10 + False + Desktop + + WindowsApplicationForDrivers10.0 + Application + + + Windows10 + True + Desktop + + WindowsApplicationForDrivers10.0 + Application + + + Windows10 + False + Desktop + + WindowsApplicationForDrivers10.0 + Application + + + Windows10 + True + Desktop + + WindowsApplicationForDrivers10.0 + Application + + + + $(IntDir) + + + + + + + + + + + + + + + + bthsrvinst + + + bthsrvinst + + + bthsrvinst + + + bthsrvinst + + + + true + Level4 + %(PreprocessorDefinitions);UNICODE;_UNICODE + %(AdditionalIncludeDirectories);..\..\common\inc + + + + + %(PreprocessorDefinitions);UNICODE;_UNICODE + %(AdditionalIncludeDirectories);..\..\common\inc + + + %(PreprocessorDefinitions);UNICODE;_UNICODE + %(AdditionalIncludeDirectories);..\..\common\inc + + + %(AdditionalDependencies);BluetoothApis.lib + + + + + true + Level4 + %(PreprocessorDefinitions);UNICODE;_UNICODE + %(AdditionalIncludeDirectories);..\..\common\inc + + + + + %(PreprocessorDefinitions);UNICODE;_UNICODE + %(AdditionalIncludeDirectories);..\..\common\inc + + + %(PreprocessorDefinitions);UNICODE;_UNICODE + %(AdditionalIncludeDirectories);..\..\common\inc + + + %(AdditionalDependencies);BluetoothApis.lib + + + + + true + Level4 + %(PreprocessorDefinitions);UNICODE;_UNICODE + %(AdditionalIncludeDirectories);..\..\common\inc + + + + + %(PreprocessorDefinitions);UNICODE;_UNICODE + %(AdditionalIncludeDirectories);..\..\common\inc + + + %(PreprocessorDefinitions);UNICODE;_UNICODE + %(AdditionalIncludeDirectories);..\..\common\inc + + + %(AdditionalDependencies);BluetoothApis.lib + + + + + true + Level4 + %(PreprocessorDefinitions);UNICODE;_UNICODE + %(AdditionalIncludeDirectories);..\..\common\inc + + + + + %(PreprocessorDefinitions);UNICODE;_UNICODE + %(AdditionalIncludeDirectories);..\..\common\inc + + + %(PreprocessorDefinitions);UNICODE;_UNICODE + %(AdditionalIncludeDirectories);..\..\common\inc + + + %(AdditionalDependencies);BluetoothApis.lib + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/bluetooth/bthecho/bthsrv/inst/bthsrvinst.vcxproj.Filters b/bluetooth/bthecho/bthsrv/inst/bthsrvinst.vcxproj.Filters new file mode 100644 index 00000000..d6a736d1 --- /dev/null +++ b/bluetooth/bthecho/bthsrv/inst/bthsrvinst.vcxproj.Filters @@ -0,0 +1,22 @@ + + + + + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* + {269E58B5-F87C-40BF-9AF8-D7A43956F273} + + + h;hpp;hxx;hm;inl;inc;xsd + {C83F223A-D6E4-4CBD-BE8A-F23F9C51CD21} + + + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml + {E0EF99F8-3D01-474D-9924-A4E579A44058} + + + + + Source Files + + + \ No newline at end of file diff --git a/bluetooth/bthecho/bthsrv/inst/main.cpp b/bluetooth/bthecho/bthsrv/inst/main.cpp new file mode 100644 index 00000000..ab555b2b --- /dev/null +++ b/bluetooth/bthecho/bthsrv/inst/main.cpp @@ -0,0 +1,210 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + Main.cpp + +Abstract: + + Utility for installing and uninstalling WdfBthSampleSrv echo bth server. + + bthsrvinst /i (installs bth service) + bthsrvinst /u (uninstalls bth service) + +Environment: + + user mode only + +--*/ + +#include +#include +#include +#include +#include +#include +#include +#include "public.h" + +#define SWITCH_ARG_LEN 2 + +DWORD +ReadSwitch( + _In_ LPCWSTR SwitchArg, + _Out_ WCHAR * Switch + ); + +BOOL +AdjustProcessPrivileges( + ); + +DWORD +SetBthServiceInfo( + BOOLEAN bEnabled + ); + +void +__cdecl +wmain( + _In_ UINT nArgs, + _In_reads_(nArgs) LPCWSTR Args[] + ) +{ + if (nArgs < 2) + { + goto usage; + } + + WCHAR Switch; + + if (ERROR_SUCCESS != ReadSwitch(Args[1], &Switch)) + { + goto exit; + } + + if (FALSE == AdjustProcessPrivileges()) + { + goto exit; + } + + switch(Switch) + { + case L'i': + SetBthServiceInfo(TRUE); + break; + case L'u': + SetBthServiceInfo(FALSE); + break; + default: + goto usage; + } + +exit: + return; + +usage: + printf("Usage: bthsrvinst [/i | /u]\n"); + goto exit; +} + +DWORD SetBthServiceInfo( + BOOLEAN bEnabled + ) +{ + DWORD err = ERROR_SUCCESS; + BLUETOOTH_LOCAL_SERVICE_INFO SvcInfo = {0}; + SvcInfo.Enabled = bEnabled; + + if (FAILED(StringCbCopyW(SvcInfo.szName, sizeof(SvcInfo.szName), BthEchoSampleSvcName))) + { + printf("Copying svc name failed\n"); + goto exit; + } + + if (ERROR_SUCCESS != (err = BluetoothSetLocalServiceInfo( + NULL, //callee would select the first found radio + &BTHECHOSAMPLE_SVC_GUID, + 0, + &SvcInfo + ))) + { + printf("BluetoothSetLocalServiceInfo failed, err = %d\n", err); + goto exit; + } +exit: + return err; +} + +DWORD +ReadSwitch( + _In_ LPCWSTR SwitchArg, + _Out_ WCHAR * Switch + ) +{ + DWORD retval = ERROR_INVALID_PARAMETER; + + if (NULL == Switch) { + printf("Switch should not be null"); + goto exit; + } + *Switch = 0; + + size_t len = 0; + if (FAILED(StringCchLength(SwitchArg, SWITCH_ARG_LEN+1, &len)) || + len != SWITCH_ARG_LEN) + { + printf("Invalid arg %S, expected arg length:0x%x, actual length: 0%Ix\n", SwitchArg, SWITCH_ARG_LEN, len); + goto exit; + } + + if (SwitchArg[0] != L'/' && SwitchArg[0] != L'-') + { + printf("Invalid first character in arg %S\n", SwitchArg); + goto exit; + } + + retval = ERROR_SUCCESS; + *Switch = SwitchArg[1]; +exit: + return retval; +} + +BOOL +AdjustProcessPrivileges( + ) +{ + HANDLE procToken; + LUID luid; + TOKEN_PRIVILEGES tp; + BOOL bRetVal; + DWORD err; + + bRetVal = OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &procToken); + if (!bRetVal) + { + err = GetLastError(); + printf("OpenProcessToken failed, err = %d\n", err); + goto exit; + } + + bRetVal = LookupPrivilegeValue(NULL, SE_LOAD_DRIVER_NAME, &luid); + if (!bRetVal) + { + err = GetLastError(); + printf("LookupPrivilegeValue failed, err = %d\n", err); + goto exit1; + } + + tp.PrivilegeCount = 1; + tp.Privileges[0].Luid = luid; + tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + + // + // AdjustTokenPrivileges can succeed even when privileges are not adjusted. + // In such case GetLastError returns ERROR_NOT_ALL_ASSIGNED. + // + // Hence we check for GetLastError in both success and failure case. + // + + (void) AdjustTokenPrivileges(procToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), (PTOKEN_PRIVILEGES) NULL, (PDWORD)NULL); + err = GetLastError(); + + if (err != ERROR_SUCCESS) + { + bRetVal = FALSE; + printf("AdjustTokenPrivileges failed, err = %d\n", err); + goto exit1; + } + +exit1: + CloseHandle(procToken); +exit: + return bRetVal; +} diff --git a/bluetooth/bthecho/bthsrv/sys/BthEchoSampleSrv.inx b/bluetooth/bthecho/bthsrv/sys/BthEchoSampleSrv.inx new file mode 100644 index 00000000..c414b565 --- /dev/null +++ b/bluetooth/bthecho/bthsrv/sys/BthEchoSampleSrv.inx @@ -0,0 +1,102 @@ +;/*++ +; +;Copyright (c) 1990-2000 Microsoft Corporation +; +; THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY +; KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +; IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR +; PURPOSE. +; +;Module Name: +; BthEchoSampleSrv.inx +; +;Abstract: +; INF file for installing the Bluetooth Echo Sample Server +; +; devcon.exe BthEchoSampleSrv.inf BTHENUM\{c07508f2-b970-43ca-b5dd-cc4f2391bef4} +; +;--*/ + +[Version] +Signature="$WINDOWS NT$" +Class=Sample +ClassGuid={e0cbf06c-cd8b-4647-bb8a-263b43f0f974} +Provider=%MSFTSAMPLE% +DriverVer=06/21/2006,6.0.6001.16625 +CatalogFile=KmdfSamples.cat + +[DestinationDirs] +DefaultDestDir = 12 + +[SourceDisksNames] +1 = %DiskId1%,,,"" + +[SourceDisksFiles] +BthEchoSampleSrv.sys = 1,, + +;***************************************** +; BthEchoSampleSrv Install Section +;***************************************** + +[Manufacturer] +%MSFTSAMPLE%=Microsoft,NTamd64...1 +%MSFTSAMPLE%=Microsoft,NTx86...1 + +[Microsoft.NTamd64...1] +%BthEchoSampleSrv.DeviceDesc% = BthEchoSampleSrv_Inst,BTHENUM\{c07508f2-b970-43ca-b5dd-cc4f2391bef4} + +[Microsoft.NTx86...1] +%BthEchoSampleSrv.DeviceDesc% = BthEchoSampleSrv_Inst,BTHENUM\{c07508f2-b970-43ca-b5dd-cc4f2391bef4} + +[BthEchoSampleSrv_Inst.NT] +CopyFiles=Drivers_Dir + +[Drivers_Dir] +BthEchoSampleSrv.sys + + +;-------------- Service installation +[BthEchoSampleSrv_Inst.NT.Services] +AddService = BthEchoSampleSrv,%SPSVCINST_ASSOCSERVICE%, BthEchoSampleSrv_Service_Inst + +; -------------- BthEchoSampleSrv driver install sections +[BthEchoSampleSrv_Service_Inst] +DisplayName = %BthEchoSampleSrv.SVCDESC% +ServiceType = 1 ; SERVICE_KERNEL_DRIVER +StartType = 3 ; SERVICE_DEMAND_START +ErrorControl = 1 ; SERVICE_ERROR_NORMAL +ServiceBinary = %12%\BthEchoSampleSrv.sys + +; +;--- BthEchoSampleSrv_Inst Coinstaller installation ------ +; + +[DestinationDirs] +BthEchoSampleSrv_Inst_CoInstaller_CopyFiles = 11 + +[BthEchoSampleSrv_Inst.NT.CoInstallers] +AddReg=BthEchoSampleSrv_Inst_CoInstaller_AddReg +CopyFiles=BthEchoSampleSrv_Inst_CoInstaller_CopyFiles + +[BthEchoSampleSrv_Inst_CoInstaller_AddReg] +HKR,,CoInstallers32,0x00010000, "WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll,WdfCoInstaller" + +[BthEchoSampleSrv_Inst_CoInstaller_CopyFiles] +WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll + +[SourceDisksFiles] +WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll=1 ; make sure the number matches with SourceDisksNames + +[BthEchoSampleSrv_Inst.NT.Wdf] +KmdfService = BthEchoSampleSrv, BthEchoSampleSrv_Inst_wdfsect +[BthEchoSampleSrv_Inst_wdfsect] +KmdfLibraryVersion = $KMDFVERSION$ + + +[Strings] +SPSVCINST_ASSOCSERVICE= 0x00000002 +MSFTSAMPLE = "Microsoft Sample" +StdMfg = "(Standard system devices)" +DiskId1 = "BthEchoSampleSrv installation disk" +BthEchoSampleSrv.DeviceDesc = "Bluetooth Echo Sample Server" +BthEchoSampleSrv.SVCDESC = "BthEchoSampleSrv" diff --git a/bluetooth/bthecho/bthsrv/sys/BthEchoSampleSrv.vcxproj b/bluetooth/bthecho/bthsrv/sys/BthEchoSampleSrv.vcxproj new file mode 100644 index 00000000..d175beea --- /dev/null +++ b/bluetooth/bthecho/bthsrv/sys/BthEchoSampleSrv.vcxproj @@ -0,0 +1,201 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {B3D6AD34-E4B4-4C3E-8CD2-583FFE3501E3} + $(MSBuildProjectName) + 1 + Debug + Win32 + {B2ECC080-547B-4E53-90B4-DD7637A509E1} + + + + Windows10 + False + Desktop + KMDF + WindowsKernelModeDriver10.0 + Driver + + + Windows10 + True + Desktop + KMDF + WindowsKernelModeDriver10.0 + Driver + + + Windows10 + False + Desktop + KMDF + WindowsKernelModeDriver10.0 + Driver + + + Windows10 + True + Desktop + KMDF + WindowsKernelModeDriver10.0 + Driver + + + + $(IntDir) + + + + + + + + + + + + + + + + true + true + TraceEvents(LEVEL,FLAGS,MSG,...) + {km-WdfDefault.tpl}*.tmh + + + $(InfArch) + true + .\$(IntDir)\BthEchoSampleSrv.inf + + + + BthEchoSampleSrv + + + BthEchoSampleSrv + + + BthEchoSampleSrv + + + BthEchoSampleSrv + + + + true + Level4 + %(AdditionalIncludeDirectories);..\..\common\inc + %(PreprocessorDefinitions);EVENT_TRACING + + + + + %(AdditionalIncludeDirectories);..\..\common\inc + %(PreprocessorDefinitions);EVENT_TRACING + + + %(AdditionalIncludeDirectories);..\..\common\inc + %(PreprocessorDefinitions);EVENT_TRACING + + + %(AdditionalDependencies);.\..\..\common\lib\$(IntDir)\bthecho.lib + + + + + true + Level4 + %(AdditionalIncludeDirectories);..\..\common\inc + %(PreprocessorDefinitions);EVENT_TRACING + + + + + %(AdditionalIncludeDirectories);..\..\common\inc + %(PreprocessorDefinitions);EVENT_TRACING + + + %(AdditionalIncludeDirectories);..\..\common\inc + %(PreprocessorDefinitions);EVENT_TRACING + + + %(AdditionalDependencies);.\..\..\common\lib\$(IntDir)\bthecho.lib + + + + + true + Level4 + %(AdditionalIncludeDirectories);..\..\common\inc + %(PreprocessorDefinitions);EVENT_TRACING + + + + + %(AdditionalIncludeDirectories);..\..\common\inc + %(PreprocessorDefinitions);EVENT_TRACING + + + %(AdditionalIncludeDirectories);..\..\common\inc + %(PreprocessorDefinitions);EVENT_TRACING + + + %(AdditionalDependencies);.\..\..\common\lib\$(IntDir)\bthecho.lib + + + + + true + Level4 + %(AdditionalIncludeDirectories);..\..\common\inc + %(PreprocessorDefinitions);EVENT_TRACING + + + + + %(AdditionalIncludeDirectories);..\..\common\inc + %(PreprocessorDefinitions);EVENT_TRACING + + + %(AdditionalIncludeDirectories);..\..\common\inc + %(PreprocessorDefinitions);EVENT_TRACING + + + %(AdditionalDependencies);.\..\..\common\lib\$(IntDir)\bthecho.lib + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/bluetooth/bthecho/bthsrv/sys/BthEchoSampleSrv.vcxproj.Filters b/bluetooth/bthecho/bthsrv/sys/BthEchoSampleSrv.vcxproj.Filters new file mode 100644 index 00000000..bcf30fdb --- /dev/null +++ b/bluetooth/bthecho/bthsrv/sys/BthEchoSampleSrv.vcxproj.Filters @@ -0,0 +1,46 @@ + + + + + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* + {AD6BD7F9-8AA3-4C43-80E5-43FAB4855E99} + + + h;hpp;hxx;hm;inl;inc;xsd + {C9966B02-9CF0-4709-81DB-6C07A8C61EA2} + + + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml + {3EB93E42-3C57-45BD-B13C-3BFBBE7327C8} + + + inf;inv;inx;mof;mc; + {1AD1BB40-C641-417E-BEEB-6D99F9B5AF3A} + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Driver Files + + + Driver Files + + + \ No newline at end of file diff --git a/bluetooth/bthecho/bthsrv/sys/device.c b/bluetooth/bthecho/bthsrv/sys/device.c new file mode 100644 index 00000000..f06dc2b7 --- /dev/null +++ b/bluetooth/bthecho/bthsrv/sys/device.c @@ -0,0 +1,422 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + Device.c + +Abstract: + + Device object related functionality for bthecho server device + +Environment: + + Kernel mode only + + +--*/ + +#include "clisrv.h" +#include "device.h" +#include "server.h" +#include "sdp.h" +#include "echo.h" + +#define INITGUID +#include "public.h" + +#if defined(EVENT_TRACING) +#include "device.tmh" +#endif + +#ifdef ALLOC_PRAGMA +#pragma alloc_text (PAGE, BthEchoSrvEvtDriverDeviceAdd) +#pragma alloc_text (PAGE, BthEchoSrvEvtDeviceSelfManagedIoCleanup) +#endif + +NTSTATUS +BthEchoSrvEvtDriverDeviceAdd( + _In_ WDFDRIVER Driver, + _Inout_ PWDFDEVICE_INIT DeviceInit +) +/*++ +Routine Description: + + BthEchoSrvEvtDeviceAdd is called by the framework in response to AddDevice + call from the PnP manager. We create and initialize a device object to + represent a new instance of the device. All the software resources + should be allocated in this callback. + +Arguments: + + Driver - Handle to a framework driver object created in DriverEntry + + DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure. + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status; + WDFDEVICE device; + WDF_OBJECT_ATTRIBUTES attributes; + WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks; + + UNREFERENCED_PARAMETER(Driver); + + PAGED_CODE(); + + // + // Configure Pnp/power callbacks + // + WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks); + pnpPowerCallbacks.EvtDeviceSelfManagedIoInit = BthEchoSrvEvtDeviceSelfManagedIoInit; + pnpPowerCallbacks.EvtDeviceSelfManagedIoCleanup = BthEchoSrvEvtDeviceSelfManagedIoCleanup; + + WdfDeviceInitSetPnpPowerEventCallbacks( + DeviceInit, + &pnpPowerCallbacks + ); + + // + // Create device object with context + // + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, BTHECHOSAMPLE_SERVER_CONTEXT); + + status = WdfDeviceCreate( + &DeviceInit, + &attributes, + &device + ); + + if (!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "WdfDeviceCreate failed with Status code %!STATUS!\n", status); + + goto exit; + } + + status = BthEchoSampleServerContextInit(GetServerDeviceContext(device), device); + + if (!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "Initialization of context failed with Status code %!STATUS!\n", status); + + goto exit; + } + + // + // Query for interfaces and pre-allocate BRBs + // + + status = BthEchoSrvInitialize(GetServerDeviceContext(device)); + if (!NT_SUCCESS(status)) + { + goto exit; + } + + // + // Not creating device interface because we don't expect apps to talk to the + // server. + // + +exit: + return status; +} + +NTSTATUS +BthEchoSrvEvtDeviceSelfManagedIoInit( + _In_ WDFDEVICE Device + ) +/*++ + +Description: + + This routine is called by the framework only once + and hence we use it for our one time initialization. + + In this routine we retrieve local bth address and local stack supported + features. We also register the server and publish SDP record. + +Arguments: + + Device - Framework device object + +Return Value: + + NTSTATUS Status code. + +--*/ +{ + NTSTATUS status; + PBTHECHOSAMPLE_SERVER_CONTEXT devCtx = GetServerDeviceContext(Device); + PUCHAR sdpRecordStream = NULL; + ULONG sdpRecordLength = 0; + BTHDDI_SDP_NODE_INTERFACE sdpNodeInterface; + BTHDDI_SDP_PARSE_INTERFACE sdpParseInterface; + + status = BthEchoSharedRetrieveLocalInfo(&devCtx->Header); + if (!NT_SUCCESS(status)) + { + goto exit; + } + + status = BthEchoSrvRegisterPSM(devCtx); + if (!NT_SUCCESS(status)) + { + goto exit; + } + + status = BthEchoSrvRegisterL2CAPServer(devCtx); + if (!NT_SUCCESS(status)) + { + goto exit; + } + + status = WdfFdoQueryForInterface( + Device, + &GUID_BTHDDI_SDP_PARSE_INTERFACE, + (PINTERFACE) (&sdpParseInterface), + sizeof(sdpParseInterface), + BTHDDI_SDP_PARSE_INTERFACE_VERSION_FOR_QI, + NULL + ); + + if (!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "QueryInterface failed for Interface sdp parse interface, version %d, Status code %!STATUS!\n", + BTHDDI_SDP_PARSE_INTERFACE_VERSION_FOR_QI, + status); + + goto exit; + } + + status = WdfFdoQueryForInterface( + Device, + &GUID_BTHDDI_SDP_NODE_INTERFACE, + (PINTERFACE) (&sdpNodeInterface), + sizeof(sdpNodeInterface), + BTHDDI_SDP_NODE_INTERFACE_VERSION_FOR_QI, + NULL + ); + + if (!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "QueryInterface failed for Interface sdp node interface, version %d, Status code %!STATUS!\n", + BTHDDI_SDP_NODE_INTERFACE_VERSION_FOR_QI, + status); + + goto exit; + } + + status = CreateSdpRecord( + &sdpNodeInterface, + &sdpParseInterface, + &BTHECHOSAMPLE_SVC_GUID, + BthEchoSampleSvcName, + devCtx->Psm, + &sdpRecordStream, + &sdpRecordLength + ); + if (!NT_SUCCESS(status)) + { + goto exit; + } + + status = BthEchoSrvPublishSdpRecord(devCtx, sdpRecordStream, sdpRecordLength); + if (!NT_SUCCESS(status)) + { + goto exit; + } + +exit: + + if (sdpRecordStream) + { + FreeSdpRecord(sdpRecordStream); + } + + return status; +} + +VOID +BthEchoSrvEvtDeviceSelfManagedIoCleanup( + _In_ WDFDEVICE Device + ) +/*++ + +Description: + + This routine is called by the framework only once + and hence we use it for our one time de-initialization. + + In this routine we remove sdp record and unregister server. + + We also disconnect all the outstanding connections. + +Arguments: + + Device - Framework device object + +Return Value: + + NTSTATUS Status code. + +--*/ +{ + PBTHECHOSAMPLE_SERVER_CONTEXT devCtx = GetServerDeviceContext(Device); + + PAGED_CODE(); + + if (HANDLE_SDP_NULL != devCtx->SdpRecordHandle) + { + BthEchoSrvRemoveSdpRecord(devCtx); + } + + if (NULL != devCtx->L2CAPServerHandle) + { + BthEchoSrvUnregisterL2CAPServer(devCtx); + } + + if (0 != devCtx->Psm) + { + BthEchoSrvUnregisterPSM(devCtx); + } + + // + // Disconnect any open connections, after this point no more + // connections can come beacuse we have unregistered server + // + // BthEchoSrvDisconnectConnectionsOnRemove does not wait for disconnect + // to complete. Connection object's cleanup callback waits on that. Since + // connection objects are children of device, they will be cleaned up and + // disconnect would complete before device object is cleaned up. + // + + BthEchoSrvDisconnectConnectionsOnRemove(devCtx); + + return; +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +VOID +BthEchoSrvConnectionObjectContReaderReadCompletedCallback( + _In_ PBTHECHOSAMPLE_DEVICE_CONTEXT_HEADER DevCtxHdr, + _In_ PBTHECHO_CONNECTION Connection, + _In_ PVOID Buffer, + _In_ size_t BufferLength + ) +/*++ +Routine Description: + + This routine is invoked by the continous reader when read completes. + + We in turn call BthEchoSrvSendEcho to perform echo. + +Arguments: + + DevCtxHdr - Device context + Connection - Connection whose continous reader had read completion + Bufer - Buffer which received read + SrcBufferLength - Length of read + +--*/ +{ + BthEchoSrvSendEcho( + DevCtxHdr, + Connection, + Buffer, + BufferLength + ); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +VOID +BthEchoSrvConnectionObjectContReaderFailedCallback( + _In_ PBTHECHOSAMPLE_DEVICE_CONTEXT_HEADER DevCtxHdr, + _In_ PBTHECHO_CONNECTION Connection + ) +/*++ +Routine Description: + + This routine is invoked by the continous reader when there is a failure + in read submission on completion + + In response we disconnect the remote connection + +Arguments: + + DevCtxHdr - Device context + Connection - Connection whose continous reader had read completion + Bufer - Buffer which received read + SrcBufferLength - Length of read + +--*/ +{ + UNREFERENCED_PARAMETER (DevCtxHdr); + + BthEchoSrvDisconnectConnection(Connection); +} + + +_IRQL_requires_max_(DISPATCH_LEVEL) +NTSTATUS +BthEchoSrvConnectionStateConnected( + WDFOBJECT ConnectionObject + ) +/*++ +Routine Description: + + This routine is invoked by BthEchoSrvRemoteConnectResponseCompletion + when connect response is completed. + + We initialize and submit continous readers in this routine. + +Arguments: + + ConnectionObject - Connection object for which connect response completed + +--*/ +{ + PBTHECHO_CONNECTION connection; + NTSTATUS status; + + connection = GetConnectionObjectContext(ConnectionObject); + + status = BthEchoConnectionObjectInitializeContinuousReader( + connection, + BthEchoSrvConnectionObjectContReaderReadCompletedCallback, + BthEchoSrvConnectionObjectContReaderFailedCallback, + BthEchoSampleMaxDataLength + ); + + if (!NT_SUCCESS(status)) + { + goto exit; + } + + status = BthEchoConnectionObjectContinuousReaderSubmitReaders( + connection + ); + + if (!NT_SUCCESS(status)) + { + goto exit; + } + +exit: + return status; +} + diff --git a/bluetooth/bthecho/bthsrv/sys/device.h b/bluetooth/bthecho/bthsrv/sys/device.h new file mode 100644 index 00000000..9fdf54c7 --- /dev/null +++ b/bluetooth/bthecho/bthsrv/sys/device.h @@ -0,0 +1,116 @@ +#include "clisrv.h" + +typedef struct _BTHECHOSAMPLE_SERVER_CONTEXT +{ + // + // Context common to client and server + // + BTHECHOSAMPLE_DEVICE_CONTEXT_HEADER Header; + + // + // Our Data PSM + // + USHORT Psm; + + // + // Handle to published SDP record + // + HANDLE_SDP SdpRecordHandle; + + // + // Handle obtained by registering L2CAP server + // + L2CAP_SERVER_HANDLE L2CAPServerHandle; + + // + // BRB used for server and PSM register and unregister + // + // Server and PSM register and unregister must be done + // sequentially since access to this brb is not + // synchronized. + // + struct _BRB RegisterUnregisterBrb; + + // + // Connection List lock + // + WDFSPINLOCK ConnectionListLock; + + // + // Outstanding open connections + // + LIST_ENTRY ConnectionList; + +} BTHECHOSAMPLE_SERVER_CONTEXT, *PBTHECHOSAMPLE_SERVER_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(BTHECHOSAMPLE_SERVER_CONTEXT, GetServerDeviceContext) + +NTSTATUS +FORCEINLINE +BthEchoSampleServerContextInit( + PBTHECHOSAMPLE_SERVER_CONTEXT Context, + WDFDEVICE Device + ) +{ + NTSTATUS status; + WDF_OBJECT_ATTRIBUTES attributes; + + status = BthEchoSharedDeviceContextHeaderInit(&Context->Header, Device); + if (!NT_SUCCESS(status)) + { + goto exit; + } + + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + attributes.ParentObject = Device; + + status = WdfSpinLockCreate( + &attributes, + &Context->ConnectionListLock + ); + if (!NT_SUCCESS(status)) + { + goto exit; + } + + InitializeListHead(&Context->ConnectionList); + +exit: + return status; +} + +EVT_WDF_DRIVER_DEVICE_ADD BthEchoSrvEvtDriverDeviceAdd; + +EVT_WDF_DEVICE_SELF_MANAGED_IO_INIT BthEchoSrvEvtDeviceSelfManagedIoInit; + +EVT_WDF_DEVICE_SELF_MANAGED_IO_CLEANUP BthEchoSrvEvtDeviceSelfManagedIoCleanup; + +////////////////////////////////////////////////////// +// Device specific functionality invoked by server.c +////////////////////////////////////////////////////// + +_IRQL_requires_max_(DISPATCH_LEVEL) +NTSTATUS +BthEchoSrvConnectionStateConnected( + WDFOBJECT ConnectionObject + ); + +//////////////////////////////////////////////////////////////////// +// Continuous reader callbacks (invoked by common/lib/connection.c) +//////////////////////////////////////////////////////////////////// + +_IRQL_requires_max_(DISPATCH_LEVEL) +VOID +BthEchoSrvConnectionObjectContReaderReadCompletedCallback( + _In_ PBTHECHOSAMPLE_DEVICE_CONTEXT_HEADER DevCtxHdr, + _In_ PBTHECHO_CONNECTION Connection, + _In_ PVOID Buffer, + _In_ size_t BufferLength + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +VOID +BthEchoSrvConnectionObjectContReaderFailedCallback( + _In_ PBTHECHOSAMPLE_DEVICE_CONTEXT_HEADER DevCtxHdr, + _In_ PBTHECHO_CONNECTION Connection + ); diff --git a/bluetooth/bthecho/bthsrv/sys/driver.c b/bluetooth/bthecho/bthsrv/sys/driver.c new file mode 100644 index 00000000..d940d52e --- /dev/null +++ b/bluetooth/bthecho/bthsrv/sys/driver.c @@ -0,0 +1,211 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + Driver.c + +Abstract: + + Driver object related functionality for bthecho server device + +Environment: + + Kernel mode only + + +--*/ + +#include "clisrv.h" +#include "driver.h" + +#if defined(EVENT_TRACING) +// +// The trace message header (.tmh) file must be included in a source file +// before any WPP macro calls and after defining a WPP_CONTROL_GUIDS +// macro (defined in toaster.h). During the compilation, WPP scans the source +// files for DoTraceMessage() calls and builds a .tmh file which stores a unique +// data GUID for each message, the text resource string for each message, +// and the data types of the variables passed in for each message. This file +// is automatically generated and used during post-processing. +// +#include "driver.tmh" +#else +#define _DRIVER_NAME_ "BthEchoSampleSrv" +ULONG DebugLevel = TRACE_LEVEL_INFORMATION; +ULONG DebugFlag = 0xff; +#endif + +#ifdef ALLOC_PRAGMA +#pragma alloc_text (INIT, DriverEntry) +#pragma alloc_text (PAGE, BthEchoSrvEvtDriverCleanup) +#endif + +NTSTATUS +DriverEntry( + _In_ PDRIVER_OBJECT DriverObject, + _In_ PUNICODE_STRING RegistryPath + ) +/*++ + +Routine Description: + DriverEntry initializes the driver and is the first routine called by the + system after the driver is loaded. + +Parameters Description: + + DriverObject - represents the instance of the function driver that is loaded + into memory. DriverEntry must initialize members of DriverObject before it + returns to the caller. DriverObject is allocated by the system before the + driver is loaded, and it is released by the system after the system unloads + the function driver from memory. + + RegistryPath - represents the driver specific path in the Registry. + The function driver can use the path to store driver related data between + reboots. The path does not store hardware instance specific data. + +Return Value: + + STATUS_SUCCESS if successful, + STATUS_UNSUCCESSFUL otherwise. + +--*/ +{ + NTSTATUS status; + WDFDRIVER driver; + WDF_OBJECT_ATTRIBUTES attributes; + + WDF_DRIVER_CONFIG DriverConfig; + WDF_DRIVER_CONFIG_INIT( + &DriverConfig, + BthEchoSrvEvtDriverDeviceAdd + ); + + WPP_INIT_TRACING( DriverObject, RegistryPath ); + + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + attributes.EvtCleanupCallback = BthEchoSrvEvtDriverCleanup; + + status = WdfDriverCreate( + DriverObject, + RegistryPath, + NULL, + &DriverConfig, + &driver + ); + + if(!NT_SUCCESS(status)) + { + WPP_CLEANUP(DriverObject); + } + + return status; +} + +VOID +BthEchoSrvEvtDriverCleanup( + _In_ WDFOBJECT DriverObject + ) +/*++ +Routine Description: + + Free resources allocated in DriverEntry that are automatically + cleaned up framework. + +Arguments: + + DriverObject - handle to a WDF Driver object. + +Return Value: + + VOID. + +--*/ +{ + PAGED_CODE (); + + // + // Driver remains unreferenced if EVENT_TRACING is not defined + // in which case traces are sent to debugger instead of ETW + // + UNREFERENCED_PARAMETER(DriverObject); + + WPP_CLEANUP( WdfDriverWdmGetDriverObject( DriverObject ) ); +} + +#if !defined(EVENT_TRACING) + +VOID +TraceEvents ( + _In_ ULONG DebugPrintLevel, + _In_ ULONG DebugPrintFlag, + _Printf_format_string_ + _In_ PCSTR DebugMessage, + ... + ) + +/*++ + +Routine Description: + + Debug print for the sample driver. + +Arguments: + + TraceEventsLevel - print level between 0 and 3, with 3 the most verbose + +Return Value: + + None. + + --*/ + { +#if DBG +#define TEMP_BUFFER_SIZE 1024 + va_list list; + CHAR debugMessageBuffer[TEMP_BUFFER_SIZE]; + NTSTATUS status; + + va_start(list, DebugMessage); + + if (DebugMessage) { + + // + // Using new safe string functions instead of _vsnprintf. + // This function takes care of NULL terminating if the message + // is longer than the buffer. + // + status = RtlStringCbVPrintfA( debugMessageBuffer, + sizeof(debugMessageBuffer), + DebugMessage, + list ); + if(!NT_SUCCESS(status)) { + + DbgPrint (_DRIVER_NAME_": RtlStringCbVPrintfA failed 0x%x\n", status); + return; + } + if (DebugPrintLevel <= TRACE_LEVEL_ERROR || + (DebugPrintLevel <= DebugLevel && + ((DebugPrintFlag & DebugFlag) == DebugPrintFlag))) { + DbgPrint("%s %s", _DRIVER_NAME_, debugMessageBuffer); + } + } + va_end(list); + + return; +#else + UNREFERENCED_PARAMETER(DebugPrintLevel); + UNREFERENCED_PARAMETER(DebugPrintFlag); + UNREFERENCED_PARAMETER(DebugMessage); +#endif +} + +#endif + + diff --git a/bluetooth/bthecho/bthsrv/sys/driver.h b/bluetooth/bthecho/bthsrv/sys/driver.h new file mode 100644 index 00000000..5885cac5 --- /dev/null +++ b/bluetooth/bthecho/bthsrv/sys/driver.h @@ -0,0 +1,34 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + Driver.c + +Abstract: + + Driver object related declarations for bthecho server device + +Environment: + + Kernel mode only + + +--*/ + +// +// WDFDRIVER Events +// + +DRIVER_INITIALIZE DriverEntry; + +EVT_WDF_DRIVER_DEVICE_ADD BthEchoSrvEvtDriverDeviceAdd; + +EVT_WDF_OBJECT_CONTEXT_CLEANUP BthEchoSrvEvtDriverCleanup; + diff --git a/bluetooth/bthecho/bthsrv/sys/echo.c b/bluetooth/bthecho/bthsrv/sys/echo.c new file mode 100644 index 00000000..8a31d8ee --- /dev/null +++ b/bluetooth/bthecho/bthsrv/sys/echo.c @@ -0,0 +1,227 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + Echo.c + +Abstract: + + Contains echo related functionality + +Environment: + + Kernel mode only + +--*/ + +#include "clisrv.h" +#include "device.h" +#include "server.h" +#include "echo.h" + +#if defined(EVENT_TRACING) +#include "echo.tmh" +#endif + +void +BthEchoSrvWriteCompletion( + _In_ WDFREQUEST Request, + _In_ WDFIOTARGET Target, + _In_ PWDF_REQUEST_COMPLETION_PARAMS Params, + _In_ WDFCONTEXT Context + ) +/*++ +Description: + + Completion routine for echo L2Ca transfer + +Arguments: + + Request - Request that completed + Target - Target to which request was sent + Params - Request completion parameters + Context - We receive connection as the context + +--*/ +{ + NTSTATUS status; + + UNREFERENCED_PARAMETER(Target); + UNREFERENCED_PARAMETER(Context); + + status = Params->IoStatus.Status; + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_CONNECT, + "Write completion, status: %!STATUS!", status); + + WdfObjectDelete(Request); + + // + // We don't attempt to disconnect in case of failure + // here because we expect the failure only be due to + // device/channel disconnect, in which case disconnect + // would happen anyway. + // + // Without taking a reference on the connection object + // while submitting echo write + // we cannot touch connection object here as connection could get + // disconnected and connection object could get freed. + // +} + + +_IRQL_requires_max_(DISPATCH_LEVEL) +VOID +BthEchoSrvSendEcho( + _In_ PBTHECHOSAMPLE_DEVICE_CONTEXT_HEADER DevCtxHdr, + _In_ PBTHECHO_CONNECTION Connection, + _In_ PVOID SrcBuffer, + _In_ size_t SrcBufferLength + ) +/*++ +Routine Description: + + Performs L2Cap transfer to client to do the echo. + + This routine is invoked by continuous reader read completion callback + (BthEchoSrvConnectionObjectContReaderReadCompletedCallback). + +Arguments: + + DevCtxHdr - Device context + Connection - Connection whose continous reader had read completion + SrcBuffer - Source buffer for the echo + SrcBufferLength - Length of the source buffer + +--*/ +{ + NTSTATUS status; + WDF_OBJECT_ATTRIBUTES attributes; + WDFREQUEST request = NULL; + WDFMEMORY memory = NULL; + PVOID dataBuffer = NULL; + struct _BRB_L2CA_ACL_TRANSFER *brb = NULL; + + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + attributes.ParentObject = DevCtxHdr->Device; + + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, BRB); + + status = WdfRequestCreate( + &attributes, + DevCtxHdr->IoTarget, + &request + ); + + if (!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, DBG_CONT_READER, + "Creating request for echo failed, Status code %!STATUS!\n", + status + ); + + goto exit; + } + + if (SrcBufferLength <= 0) + { + TraceEvents(TRACE_LEVEL_ERROR, DBG_CONT_READER, + "SrcBufferLength has an invalid value: %I64d\n", + SrcBufferLength + ); + + status = STATUS_INVALID_PARAMETER; + + goto exit; + } + + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + attributes.ParentObject = request; + + status = WdfMemoryCreate( + &attributes, + NonPagedPoolNx, + POOLTAG_BTHECHOSAMPLE, + SrcBufferLength, + &memory, + &dataBuffer + ); + + if (!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, DBG_CONT_READER, + "Creating memory for pending read failed, Status code %!STATUS!\n", + status + ); + + goto exit; + } + + memcpy(dataBuffer, SrcBuffer, SrcBufferLength); + + brb = (struct _BRB_L2CA_ACL_TRANSFER *)GetEchoRequestContext(request); + + status = BthEchoConnectionObjectFormatRequestForL2CaTransfer( + Connection, + request, + &brb, + memory, + ACL_TRANSFER_DIRECTION_OUT + ); + + if (!NT_SUCCESS(status)) + { + goto exit; + } + + // + // Set a CompletionRoutine callback function. + // + + WdfRequestSetCompletionRoutine( + request, + BthEchoSrvWriteCompletion, + Connection + ); + + if (FALSE == WdfRequestSend( + request, + DevCtxHdr->IoTarget, + NULL + )) + { + status = WdfRequestGetStatus(request); + + TraceEvents(TRACE_LEVEL_ERROR, DBG_CONT_READER, + "Request send failed for request 0x%p, Brb 0x%p, Status code %!STATUS!\n", + request, + brb, + status + ); + + goto exit; + } + +exit: + if (!NT_SUCCESS(status)) + { + if (NULL != request) + { + WdfObjectDelete(request); + } + + // + // If we failed disconnect + // + BthEchoSrvDisconnectConnection(Connection); + } +} + + diff --git a/bluetooth/bthecho/bthsrv/sys/echo.h b/bluetooth/bthecho/bthsrv/sys/echo.h new file mode 100644 index 00000000..7fde0913 --- /dev/null +++ b/bluetooth/bthecho/bthsrv/sys/echo.h @@ -0,0 +1,37 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + Echo.c + +Abstract: + + Contains declaration for echo related functionality + +Environment: + + Kernel mode only + + +--*/ + +_IRQL_requires_max_(DISPATCH_LEVEL) +VOID +BthEchoSrvSendEcho( + _In_ PBTHECHOSAMPLE_DEVICE_CONTEXT_HEADER DevCtxHdr, + _In_ PBTHECHO_CONNECTION Connection, + _In_ PVOID SrcBuffer, + _In_ size_t SrcBufferLength + ); + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(BRB, GetEchoRequestContext) + +EVT_WDF_REQUEST_COMPLETION_ROUTINE BthEchoSrvWriteCompletion; + diff --git a/bluetooth/bthecho/bthsrv/sys/sdp.c b/bluetooth/bthecho/bthsrv/sys/sdp.c new file mode 100644 index 00000000..7466d170 --- /dev/null +++ b/bluetooth/bthecho/bthsrv/sys/sdp.c @@ -0,0 +1,582 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + Sdp.c + +Abstract: + + Contains functionality for publishing and freeing SDP record + +Environment: + + Kernel mode only + + +--*/ + +#include "clisrv.h" +#include "sdp.h" + +#if defined(EVENT_TRACING) +#include "sdp.tmh" +#endif + +NTSTATUS +AddSeqAttribute( + _In_ PBTHDDI_SDP_NODE_INTERFACE SdpNodeInterface, + _In_ PSDP_TREE_ROOT_NODE Tree, + _In_ USHORT AttribId, + _Out_ PSDP_NODE * Seq + ); + +NTSTATUS +AppendSeqNode( + _In_ PBTHDDI_SDP_NODE_INTERFACE SdpNodeInterface, + _In_ PSDP_NODE containerNode, + _Out_ PSDP_NODE * Node + ); + +NTSTATUS +AppendNodeUint16( + _In_ PBTHDDI_SDP_NODE_INTERFACE SdpNodeInterface, + _In_ PSDP_NODE ContainerNode, + _In_ UINT16 Value + ); + +NTSTATUS +AppendNodeUuid128( + _In_ PBTHDDI_SDP_NODE_INTERFACE SdpNodeInterface, + _In_ PSDP_NODE ContainerNode, + _In_ const GUID * Value + ); + +NTSTATUS +AppendNodeUuid16( + _In_ PBTHDDI_SDP_NODE_INTERFACE SdpNodeInterface, + _In_ PSDP_NODE ContainerNode, + _In_ UINT16 Value + ); + + +NTSTATUS +AddSeqAttribute( + _In_ PBTHDDI_SDP_NODE_INTERFACE SdpNodeInterface, + _In_ PSDP_TREE_ROOT_NODE Tree, + _In_ USHORT AttribId, + _Out_ PSDP_NODE * Seq + ) +{ + NTSTATUS status; + PSDP_NODE seq; + + seq = SdpNodeInterface->SdpCreateNodeSequence( + POOLTAG_BTHECHOSAMPLE + ); + + if (NULL == seq) + { + status = STATUS_INSUFFICIENT_RESOURCES; + + TraceEvents(TRACE_LEVEL_ERROR, DBG_SDP, + "Creating sequence failed, returning status code %!STATUS!\n", status); + + goto exit; + } + + status = SdpNodeInterface->SdpAddAttributeToTree(Tree, AttribId, seq, POOLTAG_BTHECHOSAMPLE); + if(!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, DBG_SDP, + "SdpAddAttributeToTree failed, Status code %!STATUS!\n", status); + + // + // If we failed to add attribute to tree use ExFreePool to free it + // + ExFreePool(seq); + + goto exit; + } + + *Seq = seq; +exit: + return status; +} + +NTSTATUS +AppendSeqNode( + _In_ PBTHDDI_SDP_NODE_INTERFACE SdpNodeInterface, + _In_ PSDP_NODE containerNode, + _Out_ PSDP_NODE * Node + ) +{ + NTSTATUS status; + PSDP_NODE node; + + node = SdpNodeInterface->SdpCreateNodeSequence(POOLTAG_BTHECHOSAMPLE); + if(node == NULL) + { + status = STATUS_INSUFFICIENT_RESOURCES; + TraceEvents(TRACE_LEVEL_ERROR, DBG_SDP, + "SdpCreateNodeSequence failed, returning status code %!STATUS!\n", status); + goto exit; + } + + status = SdpNodeInterface->SdpAppendNodeToContainerNode( + containerNode, + node + ); + + // + // SdpAppendNodeToContainerNode doesn't fail due to resource reasons + // Make sure we passed valid parameters and container node + // + + NT_ASSERT(NT_SUCCESS(status)); + + *Node = node; +exit: + return status; +} + +NTSTATUS +AppendNodeUint16( + _In_ PBTHDDI_SDP_NODE_INTERFACE SdpNodeInterface, + _In_ PSDP_NODE ContainerNode, + _In_ UINT16 Value + ) +{ + NTSTATUS status; + PSDP_NODE node; + + node = SdpNodeInterface->SdpCreateNodeUint16(Value, POOLTAG_BTHECHOSAMPLE); + if(node == NULL) + { + status = STATUS_INSUFFICIENT_RESOURCES; + + TraceEvents(TRACE_LEVEL_ERROR, DBG_SDP, + "Creating NodeUint16 failed, returning status code %!STATUS!\n", status); + + goto exit; + } + + status = SdpNodeInterface->SdpAppendNodeToContainerNode( + ContainerNode, + node + ); + + if(!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, DBG_SDP, + "SdpAppendNodeToContainerNode failed, returning status code %!STATUS!\n", status); + ExFreePool(node); + node = NULL; + goto exit; + } + + // + // Make sure we passed valid parameters and container node + // + + NT_ASSERT(NT_SUCCESS(status)); + +exit: + return status; +} + +NTSTATUS +AppendNodeUuid128( + _In_ PBTHDDI_SDP_NODE_INTERFACE SdpNodeInterface, + _In_ PSDP_NODE ContainerNode, + _In_ const GUID * Value + ) +{ + NTSTATUS status; + PSDP_NODE node; + + node = SdpNodeInterface->SdpCreateNodeUuid128(Value, POOLTAG_BTHECHOSAMPLE); + if(node == NULL) + { + status = STATUS_INSUFFICIENT_RESOURCES; + + TraceEvents(TRACE_LEVEL_ERROR, DBG_SDP, + "Creating NodeUuid128 failed, returning status code %!STATUS!\n", status); + + goto exit; + } + + status = SdpNodeInterface->SdpAppendNodeToContainerNode( + ContainerNode, + node + ); + + if(!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, DBG_SDP, + "SdpAppendNodeToContainerNode failed, returning status code %!STATUS!\n", status); + ExFreePool(node); + node = NULL; + goto exit; + } + + // + // Make sure we passed valid parameters and container node + // + + NT_ASSERT(NT_SUCCESS(status)); + +exit: + return status; +} + +NTSTATUS +AppendNodeUuid16( + _In_ PBTHDDI_SDP_NODE_INTERFACE SdpNodeInterface, + _In_ PSDP_NODE ContainerNode, + _In_ UINT16 Value + ) +{ + NTSTATUS status; + PSDP_NODE node; + + node = SdpNodeInterface->SdpCreateNodeUuid16(Value, POOLTAG_BTHECHOSAMPLE); + if(node == NULL) + { + status = STATUS_INSUFFICIENT_RESOURCES; + + TraceEvents(TRACE_LEVEL_ERROR, DBG_SDP, + "Creating NodeUuid16 failed, returning status code %!STATUS!\n", status); + + goto exit; + } + + status = SdpNodeInterface->SdpAppendNodeToContainerNode( + ContainerNode, + node + ); + + if(!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, DBG_SDP, + "SdpAppendNodeToContainerNode failed, returning status code %!STATUS!\n", status); + ExFreePool(node); + node = NULL; + goto exit; + } + + // + // Make sure we passed valid parameters and container node + // + + NT_ASSERT(NT_SUCCESS(status)); + +exit: + return status; +} + +NTSTATUS +CreateSdpRecord( + _In_ PBTHDDI_SDP_NODE_INTERFACE SdpNodeInterface, + _In_ PBTHDDI_SDP_PARSE_INTERFACE SdpParseInterface, + _In_ const GUID * ClassId, + _In_ LPWSTR Name, + _In_ USHORT Psm, + _Out_ PUCHAR * Stream, + _Out_ ULONG * Size + ) +/*++ + +Description: + + Create server SDP record + +Arguments: + + SdpNodeInterface - Node interface that we obtained from bth stack + SdpParseInterface - Parse interface that we obtained from bth stack + ClassId - Service Class ID to publish + Name - Service name to publish + Psm - Server PSM + Stream - receives the sdp record stream + Size - receives size of sdp record stream + +Return Value: + + NTSTATUS Status code. + +--*/ +{ + NTSTATUS status; + PSDP_TREE_ROOT_NODE tree = NULL; + PSDP_NODE seqClsIdList, seqProto, seqLang; + PSDP_NODE nodeName = NULL, nodeDesc = NULL, nodeProto; + UNICODE_STRING unicodeStrName; + ANSI_STRING ansiStrName; + PUCHAR stream = NULL; + ULONG size; + ULONG_PTR errorByte = 0; + + RtlInitUnicodeString(&unicodeStrName, Name); + RtlInitAnsiString(&ansiStrName, NULL); + + status = RtlUnicodeStringToAnsiString(&ansiStrName, &unicodeStrName, TRUE); + if (!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, DBG_SDP, + "Creating ANSI string for service name failed, Status code %!STATUS!\n", status); + + ansiStrName.Length = 0; + goto exit; + } + + tree = SdpNodeInterface->SdpCreateNodeTree( + POOLTAG_BTHECHOSAMPLE + ); + + if (NULL == tree) + { + status = STATUS_INSUFFICIENT_RESOURCES; + + TraceEvents(TRACE_LEVEL_ERROR, DBG_SDP, + "SdpCreateNodeTree failed, returning Status code %!STATUS!\n", status); + + goto exit; + } + + // + // Add ClassIdList attribute + // + + status = AddSeqAttribute(SdpNodeInterface, tree, SDP_ATTRIB_CLASS_ID_LIST, &seqClsIdList); + if (!NT_SUCCESS(status)) + { + goto exit; + } + + status = AppendNodeUuid128(SdpNodeInterface, seqClsIdList, ClassId); + if (!NT_SUCCESS(status)) + { + goto exit; + } + + // + // Add protocols + // + + // + // L2CAP + // + status = AddSeqAttribute(SdpNodeInterface, tree, SDP_ATTRIB_PROTOCOL_DESCRIPTOR_LIST, &seqProto); + if (!NT_SUCCESS(status)) + { + goto exit; + } + + status = AppendSeqNode(SdpNodeInterface, seqProto, &nodeProto); + if (!NT_SUCCESS(status)) + { + goto exit; + } + + status = AppendNodeUuid16(SdpNodeInterface, nodeProto, L2CAP_PROTOCOL_UUID16); + if (!NT_SUCCESS(status)) + { + goto exit; + } + + status = AppendNodeUint16(SdpNodeInterface, nodeProto, Psm); + if (!NT_SUCCESS(status)) + { + goto exit; + } + + // + // SDP + // + + status = AppendSeqNode(SdpNodeInterface, seqProto, &nodeProto); + if (!NT_SUCCESS(status)) + { + goto exit; + } + + status = AppendNodeUuid16(SdpNodeInterface, nodeProto, SDP_PROTOCOL_UUID16); + if (!NT_SUCCESS(status)) + { + goto exit; + } + + // + // Add lang attributes + // + status = AddSeqAttribute(SdpNodeInterface, tree, SDP_ATTRIB_LANG_BASE_ATTRIB_ID_LIST, &seqLang); + if (!NT_SUCCESS(status)) + { + goto exit; + } + + status = AppendNodeUint16(SdpNodeInterface, seqLang, 0x656e); //TODO: find constants for these + if (!NT_SUCCESS(status)) + { + goto exit; + } + + status = AppendNodeUint16(SdpNodeInterface, seqLang, 0x006A); + if (!NT_SUCCESS(status)) + { + goto exit; + } + + status = AppendNodeUint16(SdpNodeInterface, seqLang, 0x0100); + if (!NT_SUCCESS(status)) + { + goto exit; + } + + // + // Add service name + // + + nodeName = SdpNodeInterface->SdpCreateNodeString( + ansiStrName.Buffer, + ansiStrName.Length, + POOLTAG_BTHECHOSAMPLE + ); + if(NULL == nodeName) + { + status = STATUS_INSUFFICIENT_RESOURCES; + + TraceEvents(TRACE_LEVEL_ERROR, DBG_SDP, + "Creating node for service name failed, Status code %!STATUS!\n", status); + + goto exit; + } + + status = SdpNodeInterface->SdpAddAttributeToTree( + tree, + LANG_DEFAULT_ID+STRING_NAME_OFFSET, + nodeName, + POOLTAG_BTHECHOSAMPLE + ); + if(!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, DBG_SDP, + "SdpAddAttributeToTree for service name failed, Status code %!STATUS!\n", status); + + goto exit; + } + + nodeName = NULL; //transferred owenership to tree + + nodeDesc = SdpNodeInterface->SdpCreateNodeString( + ansiStrName.Buffer, + ansiStrName.Length, + POOLTAG_BTHECHOSAMPLE + ); + if(NULL == nodeDesc) + { + status = STATUS_INSUFFICIENT_RESOURCES; + + TraceEvents(TRACE_LEVEL_ERROR, DBG_SDP, + "Creating node for service desc failed, Status code %!STATUS!\n", status); + + goto exit; + } + + status = SdpNodeInterface->SdpAddAttributeToTree( + tree, + LANG_DEFAULT_ID+STRING_DESCRIPTION_OFFSET, + nodeDesc, + POOLTAG_BTHECHOSAMPLE + ); + if(!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, DBG_SDP, + "SdpAddAttributeToTree for service desc failed, Status code %!STATUS!\n", status); + + goto exit; + } + + nodeDesc = NULL; + + // + // Create stream from tree + // + + status = SdpParseInterface->SdpConvertTreeToStream(tree, &stream, &size, POOLTAG_BTHECHOSAMPLE); + if(!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, DBG_SDP, + "Failed to get stream from tree for SDP record, Status code %!STATUS!\n", status); + + goto exit; + } + + status = SdpParseInterface->SdpValidateStream( + stream, + size, + &errorByte + ); + + if(!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, DBG_SDP, + "Validate stream failed for SDP record, first failure at address %p\n", (PVOID)errorByte); + + goto exit; + } + + *Stream = stream; + *Size = size; + +exit: + if (NULL != tree) + { + SdpNodeInterface->SdpFreeTree(tree); + } + + if (NULL != nodeName) + { + // + // If we failed to add attribute to tree use ExFreePool to free it + // + ExFreePool(nodeName); + } + + if (NULL != nodeDesc) + { + // + // If we failed to add attribute to tree use ExFreePool to free it + // + ExFreePool(nodeDesc); + } + + RtlFreeAnsiString(&ansiStrName); + + if (!NT_SUCCESS(status)) + { + if (stream != NULL) + { + ExFreePoolWithTag(stream, POOLTAG_BTHECHOSAMPLE); + } + } + + return status; +} + +VOID +FreeSdpRecord( + PUCHAR SdpRecord + ) +{ + ExFreePoolWithTag(SdpRecord, POOLTAG_BTHECHOSAMPLE); +} + + diff --git a/bluetooth/bthecho/bthsrv/sys/sdp.h b/bluetooth/bthecho/bthsrv/sys/sdp.h new file mode 100644 index 00000000..ecbb0b11 --- /dev/null +++ b/bluetooth/bthecho/bthsrv/sys/sdp.h @@ -0,0 +1,40 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + Sdp.h + +Abstract: + + Contains declarations for Sdp record related functions + +Environment: + + Kernel mode only + + +--*/ + +NTSTATUS +CreateSdpRecord( + _In_ PBTHDDI_SDP_NODE_INTERFACE SdpNodeInterface, + _In_ PBTHDDI_SDP_PARSE_INTERFACE SdpParseInterface, + _In_ const GUID * ClassId, + _In_ LPWSTR Name, + _In_ USHORT Psm, + _Out_ PUCHAR * Stream, + _Out_ ULONG * Size + ); + +VOID +FreeSdpRecord( + PUCHAR SdpRecord + ); + diff --git a/bluetooth/bthecho/bthsrv/sys/server.c b/bluetooth/bthecho/bthsrv/sys/server.c new file mode 100644 index 00000000..b1cee499 --- /dev/null +++ b/bluetooth/bthecho/bthsrv/sys/server.c @@ -0,0 +1,1463 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + Server.c + +Abstract: + + Contains Bluetooth server functionality. + +Environment: + + Kernel mode only + + +--*/ + +#include "clisrv.h" +#include "device.h" +#include "server.h" + +#if defined(EVENT_TRACING) +#include "server.tmh" +#endif + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +BthEchoSrvQueryInterfaces( + _In_ PBTHECHOSAMPLE_SERVER_CONTEXT DevCtx + ); + +#ifdef ALLOC_PRAGMA +#pragma alloc_text (PAGE, BthEchoSrvInitialize) +#pragma alloc_text (PAGE, BthEchoSrvUnregisterPSM) +#pragma alloc_text (PAGE, BthEchoSrvUnregisterL2CAPServer) +#pragma alloc_text (PAGE, BthEchoSrvPublishSdpRecord) +#pragma alloc_text (PAGE, BthEchoSrvRemoveSdpRecord) +#pragma alloc_text (PAGE, BthEchoSrvQueryInterfaces) +#endif + +void +InsertConnectionEntryLocked( + PBTHECHOSAMPLE_SERVER_CONTEXT devCtx, + PLIST_ENTRY ple + ) +{ + WdfSpinLockAcquire(devCtx->ConnectionListLock); + + InsertTailList(&devCtx->ConnectionList, ple); + + WdfSpinLockRelease(devCtx->ConnectionListLock); +} + +void +RemoveConnectionEntryLocked( + PBTHECHOSAMPLE_SERVER_CONTEXT devCtx, + PLIST_ENTRY ple + ) +{ + WdfSpinLockAcquire(devCtx->ConnectionListLock); + + RemoveEntryList(ple); + + WdfSpinLockRelease(devCtx->ConnectionListLock); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +BthEchoSrvQueryInterfaces( + _In_ PBTHECHOSAMPLE_SERVER_CONTEXT DevCtx + ) +/*++ + +Description: + + Query profile driver interface and store it in server context + +Arguments: + + DevCtx - Server device context where to store the queried interface + +Return Value: + + NTSTATUS Status code. + +--*/ +{ + NTSTATUS status; + + PAGED_CODE(); + + status = WdfFdoQueryForInterface( + DevCtx->Header.Device, + &GUID_BTHDDI_PROFILE_DRIVER_INTERFACE, + (PINTERFACE) (&DevCtx->Header.ProfileDrvInterface), + sizeof(DevCtx->Header.ProfileDrvInterface), + BTHDDI_PROFILE_DRIVER_INTERFACE_VERSION_FOR_QI, + NULL + ); + + if (!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "QueryInterface failed for Interface profile driver interface, version %d, Status code %!STATUS!\n", + BTHDDI_PROFILE_DRIVER_INTERFACE_VERSION_FOR_QI, + status); + + goto exit; + } +exit: + return status; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +BthEchoSrvInitialize( + _In_ PBTHECHOSAMPLE_SERVER_CONTEXT DevCtx + ) +{ + NTSTATUS status; + + PAGED_CODE(); + + status = BthEchoSrvQueryInterfaces(DevCtx); + if (!NT_SUCCESS(status)) + { + goto exit; + } + +exit: + return status; +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +void +BthEchoSrvIndicationCallback( + _In_ PVOID Context, + _In_ INDICATION_CODE Indication, + _In_ PINDICATION_PARAMETERS Parameters + ) + +/*++ + +Description: + + Indication callback passed to bth stack while registering server. + Bth stack sends notification related to the server. + We receive connect notifications in this callback. + +Arguments: + + Context - We receive server device context as the context + Indication - Type of indication + Parameters - Parameters of indication + +--*/ + +{ + switch(Indication) + { + case IndicationAddReference: + case IndicationReleaseReference: + break; + case IndicationRemoteConnect: + { + PBTHECHOSAMPLE_SERVER_CONTEXT devCtx = (PBTHECHOSAMPLE_SERVER_CONTEXT) Context; + + BthEchoSrvSendConnectResponse(devCtx, Parameters); + break; + } + case IndicationRemoteDisconnect: + { + // + // We register BthEchoSrvConnectionIndicationCallback for disconnect + // + NT_ASSERT(FALSE); + break; + } + case IndicationRemoteConfigRequest: + case IndicationRemoteConfigResponse: + case IndicationFreeExtraOptions: + break; + } +} + + +#if (NTDDI_VERSION >= NTDDI_WIN8) + +_IRQL_requires_max_(DISPATCH_LEVEL) +void +BthEchoSrvConnectionIndicationCallback( + _In_ PVOID Context, + _In_ INDICATION_CODE Indication, + _In_ PINDICATION_PARAMETERS_ENHANCED Parameters + ) +/*++ + +Description: + + Indication callback passed to bth stack while responding to connect. + Bth stack sends notification related to the connection. + We receive disconnect notifications in this callback + +Arguments: + + Context - We receive connection object as the context + Indication - Type of indication + Parameters - Parameters of indication + +--*/ +{ + UNREFERENCED_PARAMETER(Parameters); + + switch(Indication) + { + case IndicationAddReference: + break; + case IndicationReleaseReference: + break; + case IndicationRemoteConnect: + { + // + // We don't expect connect on this callback + // + NT_ASSERT(FALSE); + break; + } + case IndicationRemoteDisconnect: + { + WDFOBJECT connectionObject = (WDFOBJECT) Context; + PBTHECHO_CONNECTION connection = GetConnectionObjectContext(connectionObject); + + BthEchoSrvDisconnectConnection(connection); + + break; + } + case IndicationRemoteConfigRequest: + case IndicationRemoteConfigResponse: + case IndicationFreeExtraOptions: + break; + default: + // + // We don't expect any other indications on this callback + // + NT_ASSERT(FALSE); + } +} + +#else + + +_IRQL_requires_max_(DISPATCH_LEVEL) +void +BthEchoSrvConnectionIndicationCallback( + _In_ PVOID Context, + _In_ INDICATION_CODE Indication, + _In_ PINDICATION_PARAMETERS Parameters + ) +/*++ + +Description: + + Indication callback passed to bth stack while responding to connect. + Bth stack sends notification related to the connection. + We receive disconnect notifications in this callback + +Arguments: + + Context - We receive connection object as the context + Indication - Type of indication + Parameters - Parameters of indication + +--*/ +{ + UNREFERENCED_PARAMETER(Parameters); + + switch(Indication) + { + case IndicationAddReference: + break; + case IndicationReleaseReference: + break; + case IndicationRemoteConnect: + { + // + // We don't expect connect on this callback + // + NT_ASSERT(FALSE); + break; + } + case IndicationRemoteDisconnect: + { + WDFOBJECT connectionObject = (WDFOBJECT) Context; + PBTHECHO_CONNECTION connection = GetConnectionObjectContext(connectionObject); + + BthEchoSrvDisconnectConnection(connection); + + break; + } + case IndicationRemoteConfigRequest: + case IndicationRemoteConfigResponse: + case IndicationFreeExtraOptions: + break; + default: + // + // We don't expect any other indications on this callback + // + NT_ASSERT(FALSE); + } +} + + +#endif + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +BthEchoSrvRegisterPSM( + _In_ PBTHECHOSAMPLE_SERVER_CONTEXT DevCtx + ) +/*++ + +Description: + + Registers server PSM. + +Arguments: + + DevCtx - Device context of the server + +Return Value: + + NTSTATUS Status code. + +--*/ +{ + NTSTATUS status; + struct _BRB_PSM * brb; + + DevCtx->Header.ProfileDrvInterface.BthReuseBrb( + &(DevCtx->RegisterUnregisterBrb), + BRB_REGISTER_PSM + ); + + brb = (struct _BRB_PSM *) + &(DevCtx->RegisterUnregisterBrb); + + // + // Send in our preferred PSM + // + brb->Psm = DevCtx->Psm; + + status = BthEchoSharedSendBrbSynchronously( + DevCtx->Header.IoTarget, + DevCtx->Header.Request, + (PBRB) brb, + sizeof(*brb) + ); + + if (!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "BRB_REGISTER_PSM failed, Status code %!STATUS!\n", status); + goto exit; + } + + // + // Store PSM obtained + // + DevCtx->Psm = brb->Psm; + +exit: + return status; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +VOID +BthEchoSrvUnregisterPSM( + _In_ PBTHECHOSAMPLE_SERVER_CONTEXT DevCtx + ) +/*++ + +Description: + + Unregisters server PSM. + +Arguments: + + DevCtx - Device context of the server + +Return Value: + + NTSTATUS Status code. + +--*/ +{ + NTSTATUS status; + struct _BRB_PSM * brb; + + PAGED_CODE(); + + if (0 == DevCtx->Psm) + { + return; + } + + DevCtx->Header.ProfileDrvInterface.BthReuseBrb( + &(DevCtx->RegisterUnregisterBrb), + BRB_UNREGISTER_PSM + ); + + brb = (struct _BRB_PSM *) + &(DevCtx->RegisterUnregisterBrb); + + // + // Format Brb + // + + brb->Psm = DevCtx->Psm; + + status = BthEchoSharedSendBrbSynchronously( + DevCtx->Header.IoTarget, + DevCtx->Header.Request, + (PBRB) brb, + sizeof(*(brb)) + ); + + if (!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "BRB_UNREGISTER_PSM failed, Status code %!STATUS!\n", status); + + // + // Send does not fail for resource reasons + // + NT_ASSERT(FALSE); + + goto exit; + } + +exit: + return; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +BthEchoSrvRegisterL2CAPServer( + _In_ PBTHECHOSAMPLE_SERVER_CONTEXT DevCtx + ) +/*++ + +Description: + + Registers L2CAP server. + +Arguments: + + DevCtx - Device context of the server + +Return Value: + + NTSTATUS Status code. + +--*/ +{ + NTSTATUS status; + struct _BRB_L2CA_REGISTER_SERVER *brb; + + DevCtx->Header.ProfileDrvInterface.BthReuseBrb( + &(DevCtx->RegisterUnregisterBrb), + BRB_L2CA_REGISTER_SERVER + ); + + brb = (struct _BRB_L2CA_REGISTER_SERVER *) + &(DevCtx->RegisterUnregisterBrb); + + // + // Format brb + // + brb->BtAddress = BTH_ADDR_NULL; + brb->PSM = 0; //we have already registered the PSM + brb->IndicationCallback = &BthEchoSrvIndicationCallback; + brb->IndicationCallbackContext = DevCtx; + brb->IndicationFlags = 0; + brb->ReferenceObject = WdfDeviceWdmGetDeviceObject(DevCtx->Header.Device); + + status = BthEchoSharedSendBrbSynchronously( + DevCtx->Header.IoTarget, + DevCtx->Header.Request, + (PBRB) brb, + sizeof(*brb) + ); + + if (!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "BRB_REGISTER_PSM failed, Status code %!STATUS!\n", status); + goto exit; + } + + // + // Store server handle + // + DevCtx->L2CAPServerHandle = brb->ServerHandle; + +exit: + return status; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +VOID +BthEchoSrvUnregisterL2CAPServer( + _In_ PBTHECHOSAMPLE_SERVER_CONTEXT DevCtx + ) +/*++ + +Description: + + Unregisters L2CAP server. + +Arguments: + + DevCtx - Device context of the server + +Return Value: + + NTSTATUS Status code. + +--*/ +{ + NTSTATUS status; + struct _BRB_L2CA_UNREGISTER_SERVER *brb; + + PAGED_CODE(); + + if (NULL == DevCtx->L2CAPServerHandle) + { + return; + } + + DevCtx->Header.ProfileDrvInterface.BthReuseBrb( + &(DevCtx->RegisterUnregisterBrb), + BRB_L2CA_UNREGISTER_SERVER + ); + + brb = (struct _BRB_L2CA_UNREGISTER_SERVER *) + &(DevCtx->RegisterUnregisterBrb); + + // + // Format Brb + // + brb->BtAddress = BTH_ADDR_NULL ;//DevCtx->LocalAddress; + brb->Psm = 0; //since we will use unregister PSM to unregister. + brb->ServerHandle = DevCtx->L2CAPServerHandle; + + status = BthEchoSharedSendBrbSynchronously( + DevCtx->Header.IoTarget, + DevCtx->Header.Request, + (PBRB) brb, + sizeof(*(brb)) + ); + + if (!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "BRB_L2CA_UNREGISTER_SERVER failed, Status code %!STATUS!\n", status); + + // + // Send does not fail for resource reasons + // + NT_ASSERT(FALSE); + + goto exit; + } + + DevCtx->L2CAPServerHandle = NULL; + +exit: + return; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +BthEchoSrvPublishSdpRecord( + _In_ PBTHECHOSAMPLE_SERVER_CONTEXT DevCtx, + _In_ PUCHAR SdpRecord, + _In_ ULONG SdpRecordLength + ) +/*++ + +Description: + + Publishes server SDP record. + + We first build SDP record using CreateSdpRecord in sdp.c + and call this function to publish the record. + +Arguments: + + DevCtx - Device context of the server + SdpRecord - Sdp record to publish + SdpRecordLength - Sdp record length + +Return Value: + + NTSTATUS Status code. + +--*/ +{ + NTSTATUS status, statusReuse; + WDF_MEMORY_DESCRIPTOR inMemDesc; + WDF_MEMORY_DESCRIPTOR outMemDesc; + WDF_REQUEST_REUSE_PARAMS ReuseParams; + HANDLE_SDP sdpRecordHandle; + + PAGED_CODE(); + + WDF_REQUEST_REUSE_PARAMS_INIT(&ReuseParams, WDF_REQUEST_REUSE_NO_FLAGS, STATUS_NOT_SUPPORTED); + statusReuse = WdfRequestReuse(DevCtx->Header.Request, &ReuseParams); + NT_ASSERT(NT_SUCCESS(statusReuse)); + UNREFERENCED_PARAMETER(statusReuse); + + WDF_MEMORY_DESCRIPTOR_INIT_BUFFER( + &inMemDesc, + SdpRecord, + SdpRecordLength + ); + + RtlZeroMemory( &sdpRecordHandle, sizeof(HANDLE_SDP) ); + + WDF_MEMORY_DESCRIPTOR_INIT_BUFFER( + &outMemDesc, + &sdpRecordHandle, + sizeof(HANDLE_SDP) + ); + + status = WdfIoTargetSendIoctlSynchronously( + DevCtx->Header.IoTarget, + DevCtx->Header.Request, + IOCTL_BTH_SDP_SUBMIT_RECORD, + &inMemDesc, + &outMemDesc, + NULL, //sendOptions + NULL //bytesReturned + ); + + if (!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "IOCTL_BTH_SDP_SUBMIT_RECORD failed, Status code %!STATUS!\n", status); + + goto exit; + } + + DevCtx->SdpRecordHandle = sdpRecordHandle; + +exit: + return status; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +VOID +BthEchoSrvRemoveSdpRecord( + _In_ PBTHECHOSAMPLE_SERVER_CONTEXT DevCtx + ) +/*++ + +Description: + + Removes Sdp record + +Arguments: + + DevCtx - Device context of the server + +Return Value: + + NTSTATUS Status code. + +--*/ +{ + NTSTATUS status, statusReuse; + WDF_MEMORY_DESCRIPTOR inMemDesc; + WDF_REQUEST_REUSE_PARAMS ReuseParams; + HANDLE_SDP sdpRecordHandle; + + PAGED_CODE(); + + WDF_REQUEST_REUSE_PARAMS_INIT(&ReuseParams, WDF_REQUEST_REUSE_NO_FLAGS, STATUS_NOT_SUPPORTED); + statusReuse = WdfRequestReuse(DevCtx->Header.Request, &ReuseParams); + NT_ASSERT(NT_SUCCESS(statusReuse)); + UNREFERENCED_PARAMETER(statusReuse); + + sdpRecordHandle = DevCtx->SdpRecordHandle; + + WDF_MEMORY_DESCRIPTOR_INIT_BUFFER( + &inMemDesc, + &sdpRecordHandle, + sizeof(HANDLE_SDP) + ); + + status = WdfIoTargetSendIoctlSynchronously( + DevCtx->Header.IoTarget, + DevCtx->Header.Request, + IOCTL_BTH_SDP_REMOVE_RECORD, + &inMemDesc, + NULL, //outMemDesc + NULL, //sendOptions + NULL //bytesReturned + ); + + if (!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "IOCTL_BTH_SDP_REMOVE_RECORD failed, Status code %!STATUS!\n", status); + + // + // Send does not fail for resource reasons + // + NT_ASSERT(FALSE); + + goto exit; + } + + DevCtx->SdpRecordHandle = HANDLE_SDP_NULL; + +exit: + return; +} + +#if (NTDDI_VERSION >= NTDDI_WIN8) + +void +BthEchoSrvRemoteConnectResponseCompletion( + _In_ WDFREQUEST Request, + _In_ WDFIOTARGET Target, + _In_ PWDF_REQUEST_COMPLETION_PARAMS Params, + _In_ WDFCONTEXT Context + ) +/*++ +Description: + + Completion routine for BRB_L2CA_OPEN_CHANNEL_RESPONSE BRB sent in + BthEchoSrvSendConnectResponse. + + If the request completed successfully we call BthEchoSrvConnectionStateConnected + function implemented in device.c. This function initializes and submits + continuous readers to read the data coming from client which then is used + for echo. + +Arguments: + + Request - Request that completed + Target - Target to which request was sent + Params - Request completion parameters + Context - We receive Brb as the context. This Brb is + connection->ConnectDisconnectBrb, and is not allocated separately + hence it is not freed here. + +Return Value: + + NTSTATUS Status code. +--*/ +{ + NTSTATUS status; + struct _BRB_L2CA_OPEN_ENHANCED_CHANNEL *brb; + PBTHECHO_CONNECTION connection; + WDFOBJECT connectionObject; + + + UNREFERENCED_PARAMETER(Target); + UNREFERENCED_PARAMETER(Request); //we reuse the request, hence it is not needed here + + status = Params->IoStatus.Status; + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_CONNECT, + "Connection completion, status: %!STATUS!", status); + + brb = (struct _BRB_L2CA_OPEN_ENHANCED_CHANNEL *) Context; + + // + // We receice connection object as the context in the BRB + // + connectionObject = (WDFOBJECT) brb->Hdr.ClientContext[0]; + connection = GetConnectionObjectContext(connectionObject); + + if(NT_SUCCESS(status)) + { + connection->OutMTU = brb->OutResults.Params.Mtu; + connection->InMTU = brb->InResults.Params.Mtu; + connection->ChannelHandle = brb->ChannelHandle; + connection->RemoteAddress = brb->BtAddress; + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_CONNECT, + "Connection (0x%x) established with client", brb->OutResults.Params.RetransmissionAndFlow.Mode); + + // + // Check if we already received a disconnect request + // and if so disconnect + // + + WdfSpinLockAcquire(connection->ConnectionLock); + + if (connection->ConnectionState == ConnectionStateDisconnecting) + { + // + // We allow transition to disconnected state only from + // connected state + // + // If we are in disconnection state this means that + // we were waiting for connect to complete before we + // can send disconnect down + // + // Set the state to Connected and call BthEchoConnectionObjectRemoteDisconnect + // + connection->ConnectionState = ConnectionStateConnected; + WdfSpinLockRelease(connection->ConnectionLock); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_CONNECT, + "Remote connect response completion: " + "disconnect has been received " + "for connection 0x%p", connection); + + BthEchoConnectionObjectRemoteDisconnect(connection->DevCtxHdr, connection); + } + else + { + connection->ConnectionState = ConnectionStateConnected; + WdfSpinLockRelease(connection->ConnectionLock); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_CONNECT, + "Connection completed, connection: 0x%p", connection); + + // + // Call BthEchoSrvConnectionStateConnected to perform post connect processing + // (namely initializing continuous readers) + // + status = BthEchoSrvConnectionStateConnected(connectionObject); + if (!NT_SUCCESS(status)) + { + // + // If the post connect processing failed, let us disconnect + // + BthEchoConnectionObjectRemoteDisconnect(connection->DevCtxHdr, connection); + } + + } + } + else + { + BOOLEAN setDisconnectEvent = FALSE; + + WdfSpinLockAcquire(connection->ConnectionLock); + if (connection->ConnectionState == ConnectionStateDisconnecting) + { + setDisconnectEvent = TRUE; + } + + connection->ConnectionState = ConnectionStateConnectFailed; + WdfSpinLockRelease(connection->ConnectionLock); + + if (setDisconnectEvent) + { + KeSetEvent(&connection->DisconnectEvent, + 0, + FALSE); + } + + } + + if (!NT_SUCCESS(status)) + { + RemoveConnectionEntryLocked( + (PBTHECHOSAMPLE_SERVER_CONTEXT) connection->DevCtxHdr, + &connection->ConnectionListEntry + ); + + WdfObjectDelete(connectionObject); + } + + return; +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +NTSTATUS +BthEchoSrvSendConnectResponse( + _In_ PBTHECHOSAMPLE_SERVER_CONTEXT DevCtx, + _In_ PINDICATION_PARAMETERS ConnectParams + ) +/*++ +Description: + + Respond to connect indication received. + + This function is invoked by BthEchoSrvIndicationCallback when + connect indication is received. + +Arguments: + + DevCtx - Server device context + ConnectParams - Connect indication parameters + +Return Value: + + NTSTATUS Status code. +--*/ +{ + NTSTATUS status, statusReuse; + WDF_REQUEST_REUSE_PARAMS reuseParams; + struct _BRB_L2CA_OPEN_ENHANCED_CHANNEL *brb = NULL; + WDFOBJECT connectionObject = NULL; + PBTHECHO_CONNECTION connection = NULL; + ULONG modeConfigFlag = CM_BASIC; + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_CONNECT, + "Server receivced connect request"); + + // + // We create the connection object as the first step so that if we receive + // remove before connect response is completed + // we can wait for connection and disconnect. + // + status = BthEchoConnectionObjectCreate( + &DevCtx->Header, + DevCtx->Header.Device, + &connectionObject + ); + + if (!NT_SUCCESS(status)) + { + goto exit; + } + + connection = GetConnectionObjectContext(connectionObject); + + connection->ConnectionState = ConnectionStateConnecting; + + // + // Insert the connection object in the conenction list that we track + // + InsertConnectionEntryLocked(DevCtx, &connection->ConnectionListEntry); + + WDF_REQUEST_REUSE_PARAMS_INIT(&reuseParams, WDF_REQUEST_REUSE_NO_FLAGS, STATUS_NOT_SUPPORTED); + statusReuse = WdfRequestReuse(connection->ConnectDisconnectRequest, &reuseParams); + NT_ASSERT(NT_SUCCESS(statusReuse)); + UNREFERENCED_PARAMETER(statusReuse); + + brb = (struct _BRB_L2CA_OPEN_ENHANCED_CHANNEL*) &(connection->ConnectDisconnectBrb); + DevCtx->Header.ProfileDrvInterface.BthReuseBrb((PBRB)brb, BRB_L2CA_OPEN_ENHANCED_CHANNEL_RESPONSE); + + brb->Hdr.ClientContext[0] = connectionObject; + brb->BtAddress = ConnectParams->BtAddress; + brb->Psm = ConnectParams->Parameters.Connect.Request.PSM; + brb->ChannelHandle = ConnectParams->ConnectionHandle; + brb->Response = CONNECT_RSP_RESULT_SUCCESS; + + brb->ChannelFlags = CF_ROLE_EITHER; + + brb->ConfigOut.Flags = CFG_ENHANCED; + + if (DevCtx->Header.LocalFeatures.Mask & BTH_HOST_FEATURE_ENHANCED_RETRANSMISSION_MODE) + { + modeConfigFlag |= CM_RETRANSMISSION_AND_FLOW; + brb->ConfigOut.ModeConfig.Flags = modeConfigFlag; + + // + // Mode is specified using Flags above and this should be 0. + // + brb->ConfigOut.ModeConfig.RetransmissionAndFlow.Mode = 0; + brb->ConfigOut.ModeConfig.RetransmissionAndFlow.MaxTransmit = L2CAP_RAF_DEFAULT_MAXTRANSMIT; + brb->ConfigOut.ModeConfig.RetransmissionAndFlow.MaxPDUSize = L2CAP_RAF_DEFAULT_MAX_PDU_SIZE; + brb->ConfigOut.ModeConfig.RetransmissionAndFlow.TxWindowSize = L2CAP_RAF_DEFAULT_TX_WINDOW_SIZE; + } + + + brb->ConfigOut.Flags |= CFG_MTU; + brb->ConfigOut.Mtu.Max = L2CAP_DEFAULT_MTU; + brb->ConfigOut.Mtu.Min = L2CAP_MIN_MTU; + brb->ConfigOut.Mtu.Preferred = L2CAP_DEFAULT_MTU; + + brb->ConfigIn.Flags = CFG_MTU; + brb->ConfigIn.Mtu.Max = brb->ConfigOut.Mtu.Max; + brb->ConfigIn.Mtu.Min = brb->ConfigOut.Mtu.Min; + brb->ConfigIn.Mtu.Preferred = brb->ConfigOut.Mtu.Max; + + // + // Get notifications about disconnect + // + brb->CallbackFlags = CALLBACK_DISCONNECT; + brb->Callback = &BthEchoSrvConnectionIndicationCallback; + brb->CallbackContext = connectionObject; + brb->ReferenceObject = (PVOID) WdfDeviceWdmGetDeviceObject(DevCtx->Header.Device); + + status = BthEchoSharedSendBrbAsync( + DevCtx->Header.IoTarget, + connection->ConnectDisconnectRequest, + (PBRB) brb, + sizeof(*brb), + BthEchoSrvRemoteConnectResponseCompletion, + brb + ); + + if (!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, DBG_CONNECT, + "BthEchoSharedSendBrbAsync failed, status = %!STATUS!", status); + } + +exit: + + if(!NT_SUCCESS(status) && connectionObject) + { + // + // If we failed to connect remove connectionfrom list and + // delete the object + // + + // + // connection should not be NULL if connectionObject is not NULL + // since first thing we do after creating connectionObject is to + // get context which gives us connection + // + NT_ASSERT(connection != NULL); + + if (connection != NULL) + { + connection->ConnectionState = ConnectionStateConnectFailed; + + RemoveConnectionEntryLocked( + (PBTHECHOSAMPLE_SERVER_CONTEXT) connection->DevCtxHdr, + &connection->ConnectionListEntry + ); + } + + WdfObjectDelete(connectionObject); + } + + return status; +} + +#else + +void +BthEchoSrvRemoteConnectResponseCompletion( + _In_ WDFREQUEST Request, + _In_ WDFIOTARGET Target, + _In_ PWDF_REQUEST_COMPLETION_PARAMS Params, + _In_ WDFCONTEXT Context + ) +/*++ +Description: + + Completion routine for BRB_L2CA_OPEN_CHANNEL_RESPONSE BRB sent in + BthEchoSrvSendConnectResponse. + + If the request completed successfully we call BthEchoSrvConnectionStateConnected + function implemented in device.c. This function initializes and submits + continuous readers to read the data coming from client which then is used + for echo. + +Arguments: + + Request - Request that completed + Target - Target to which request was sent + Params - Request completion parameters + Context - We receive Brb as the context. This Brb is + connection->ConnectDisconnectBrb, and is not allocated separately + hence it is not freed here. + +Return Value: + + NTSTATUS Status code. +--*/ +{ + NTSTATUS status; + struct _BRB_L2CA_OPEN_CHANNEL *brb; + PBTHECHO_CONNECTION connection; + WDFOBJECT connectionObject; + + + UNREFERENCED_PARAMETER(Target); + UNREFERENCED_PARAMETER(Request); //we reuse the request, hence it is not needed here + + status = Params->IoStatus.Status; + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_CONNECT, + "Connection completion, status: %!STATUS!", status); + + brb = (struct _BRB_L2CA_OPEN_CHANNEL *) Context; + + // + // We receice connection object as the context in the BRB + // + connectionObject = (WDFOBJECT) brb->Hdr.ClientContext[0]; + connection = GetConnectionObjectContext(connectionObject); + + if(NT_SUCCESS(status)) + { + connection->OutMTU = brb->OutResults.Params.Mtu; + connection->InMTU = brb->InResults.Params.Mtu; + connection->ChannelHandle = brb->ChannelHandle; + connection->RemoteAddress = brb->BtAddress; + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_CONNECT, + "Connection established with client"); + + // + // Check if we already received a disconnect request + // and if so disconnect + // + + WdfSpinLockAcquire(connection->ConnectionLock); + + if (connection->ConnectionState == ConnectionStateDisconnecting) + { + // + // We allow transition to disconnected state only from + // connected state + // + // If we are in disconnection state this means that + // we were waiting for connect to complete before we + // can send disconnect down + // + // Set the state to Connected and call BthEchoConnectionObjectRemoteDisconnect + // + connection->ConnectionState = ConnectionStateConnected; + WdfSpinLockRelease(connection->ConnectionLock); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_CONNECT, + "Remote connect response completion: " + "disconnect has been received " + "for connection 0x%p", connection); + + BthEchoConnectionObjectRemoteDisconnect(connection->DevCtxHdr, connection); + } + else + { + connection->ConnectionState = ConnectionStateConnected; + WdfSpinLockRelease(connection->ConnectionLock); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_CONNECT, + "Connection completed, connection: 0x%p", connection); + + // + // Call BthEchoSrvConnectionStateConnected to perform post connect processing + // (namely initializing continuous readers) + // + status = BthEchoSrvConnectionStateConnected(connectionObject); + if (!NT_SUCCESS(status)) + { + // + // If the post connect processing failed, let us disconnect + // + BthEchoConnectionObjectRemoteDisconnect(connection->DevCtxHdr, connection); + } + + } + } + else + { + BOOLEAN setDisconnectEvent = FALSE; + + WdfSpinLockAcquire(connection->ConnectionLock); + if (connection->ConnectionState == ConnectionStateDisconnecting) + { + setDisconnectEvent = TRUE; + } + + connection->ConnectionState = ConnectionStateConnectFailed; + WdfSpinLockRelease(connection->ConnectionLock); + + if (setDisconnectEvent) + { + KeSetEvent(&connection->DisconnectEvent, + 0, + FALSE); + } + + } + + if (!NT_SUCCESS(status)) + { + RemoveConnectionEntryLocked( + (PBTHECHOSAMPLE_SERVER_CONTEXT) connection->DevCtxHdr, + &connection->ConnectionListEntry + ); + + WdfObjectDelete(connectionObject); + } + + return; +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +NTSTATUS +BthEchoSrvSendConnectResponse( + _In_ PBTHECHOSAMPLE_SERVER_CONTEXT DevCtx, + _In_ PINDICATION_PARAMETERS ConnectParams + ) +/*++ +Description: + + Respond to connect indication received. + + This function is invoked by BthEchoSrvIndicationCallback when + connect indication is received. + +Arguments: + + DevCtx - Server device context + ConnectParams - Connect indication parameters + +Return Value: + + NTSTATUS Status code. +--*/ +{ + NTSTATUS status, statusReuse; + WDF_REQUEST_REUSE_PARAMS reuseParams; + struct _BRB_L2CA_OPEN_CHANNEL *brb = NULL; + WDFOBJECT connectionObject = NULL; + PBTHECHO_CONNECTION connection = NULL; + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_CONNECT, + "Server receivced connect request"); + + // + // We create the connection object as the first step so that if we receive + // remove before connect response is completed + // we can wait for connection and disconnect. + // + status = BthEchoConnectionObjectCreate( + &DevCtx->Header, + DevCtx->Header.Device, + &connectionObject + ); + + if (!NT_SUCCESS(status)) + { + goto exit; + } + + connection = GetConnectionObjectContext(connectionObject); + + connection->ConnectionState = ConnectionStateConnecting; + + // + // Insert the connection object in the conenction list that we track + // + InsertConnectionEntryLocked(DevCtx, &connection->ConnectionListEntry); + + WDF_REQUEST_REUSE_PARAMS_INIT(&reuseParams, WDF_REQUEST_REUSE_NO_FLAGS, STATUS_NOT_SUPPORTED); + statusReuse = WdfRequestReuse(connection->ConnectDisconnectRequest, &reuseParams); + NT_ASSERT(NT_SUCCESS(statusReuse)); + UNREFERENCED_PARAMETER(statusReuse); + + brb = (struct _BRB_L2CA_OPEN_CHANNEL*) &(connection->ConnectDisconnectBrb); + DevCtx->Header.ProfileDrvInterface.BthReuseBrb((PBRB)brb, BRB_L2CA_OPEN_CHANNEL_RESPONSE); + + brb->Hdr.ClientContext[0] = connectionObject; + brb->BtAddress = ConnectParams->BtAddress; + brb->Psm = ConnectParams->Parameters.Connect.Request.PSM; + brb->ChannelHandle = ConnectParams->ConnectionHandle; + brb->Response = CONNECT_RSP_RESULT_SUCCESS; + + brb->ChannelFlags = CF_ROLE_EITHER; + + brb->ConfigOut.Flags = 0; + brb->ConfigIn.Flags = 0; + + brb->ConfigOut.Flags |= CFG_MTU; + brb->ConfigOut.Mtu.Max = L2CAP_DEFAULT_MTU; + brb->ConfigOut.Mtu.Min = L2CAP_MIN_MTU; + brb->ConfigOut.Mtu.Preferred = L2CAP_DEFAULT_MTU; + + brb->ConfigIn.Flags = CFG_MTU; + brb->ConfigIn.Mtu.Max = brb->ConfigOut.Mtu.Max; + brb->ConfigIn.Mtu.Min = brb->ConfigOut.Mtu.Min; + brb->ConfigIn.Mtu.Preferred = brb->ConfigOut.Mtu.Max; + + // + // Get notifications about disconnect + // + brb->CallbackFlags = CALLBACK_DISCONNECT; + brb->Callback = &BthEchoSrvConnectionIndicationCallback; + brb->CallbackContext = connectionObject; + brb->ReferenceObject = (PVOID) WdfDeviceWdmGetDeviceObject(DevCtx->Header.Device); + + status = BthEchoSharedSendBrbAsync( + DevCtx->Header.IoTarget, + connection->ConnectDisconnectRequest, + (PBRB) brb, + sizeof(*brb), + BthEchoSrvRemoteConnectResponseCompletion, + brb + ); + + if (!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, DBG_CONNECT, + "BthEchoSharedSendBrbAsync failed, status = %!STATUS!", status); + } + +exit: + + if(!NT_SUCCESS(status) && connectionObject) + { + // + // If we failed to connect remove connectionfrom list and + // delete the object + // + + // + // connection should not be NULL if connectionObject is not NULL + // since first thing we do after creating connectionObject is to + // get context which gives us connection + // + NT_ASSERT(connection != NULL); + + if (connection != NULL) + { + connection->ConnectionState = ConnectionStateConnectFailed; + + RemoveConnectionEntryLocked( + (PBTHECHOSAMPLE_SERVER_CONTEXT) connection->DevCtxHdr, + &connection->ConnectionListEntry + ); + } + + WdfObjectDelete(connectionObject); + } + + return status; +} + + +#endif + +_IRQL_requires_max_(DISPATCH_LEVEL) +VOID +BthEchoSrvDisconnectConnection( + _In_ PBTHECHO_CONNECTION Connection + ) +/*++ +Description: + + Disconnects connection, removes it from the list and deletes the connection + object. + + This helper function can be called for disconnect only after connect is + completed. + +Arguments: + + Connection - Connection to disconnect + +--*/ +{ + WDFOBJECT connectionObject; + + // + // If BthEchoConnectionObjectRemoteDisconnect returns FALSE + // connection is already disconnected + // + if (BthEchoConnectionObjectRemoteDisconnect(Connection->DevCtxHdr, Connection)) + { + RemoveConnectionEntryLocked( + (PBTHECHOSAMPLE_SERVER_CONTEXT) Connection->DevCtxHdr, + &Connection->ConnectionListEntry + ); + + connectionObject = WdfObjectContextGetObject(Connection); + + WdfObjectDelete(connectionObject); + } +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +VOID +BthEchoSrvDisconnectConnectionsOnRemove( + _In_ PBTHECHOSAMPLE_SERVER_CONTEXT DevCtx + ) +/*++ +Description: + + This routine is invoked by BthEchoSrvEvtDeviceSelfManagedIoCleanup + during remove. We disconnect all the outstanding connections + in this routine. + + This routine does not wait for completion of the disconnect. connection object's + cleanup callback waits for that. + +Arguments: + + DevCtx - Server device context + +--*/ +{ + BOOLEAN True = TRUE; + + // + // We will not get any new connections beacuse we have unregistered server + // at this point. + // + // Although it is possible that connections from the current list + // get disconnected. In such case the following things protect us: + // 1. Our reference on connection object keeps connection object alive + // 2. Connection state tracking ensures that disconnect is sent + // only once + // + + while (True) + { + PLIST_ENTRY ple; + PBTHECHO_CONNECTION connection; + + WdfSpinLockAcquire(DevCtx->ConnectionListLock); + + if (IsListEmpty(&DevCtx->ConnectionList)) + { + WdfSpinLockRelease(DevCtx->ConnectionListLock); + break; + } + + ple = DevCtx->ConnectionList.Flink; + + RemoveEntryList(ple); + + connection = CONTAINING_RECORD(ple, BTHECHO_CONNECTION, ConnectionListEntry); + + // + // Add a reference since we will be touching connection object + // outside of the connection list lock + // + WdfObjectReference(WdfObjectContextGetObject(connection)); + + WdfSpinLockRelease(DevCtx->ConnectionListLock); + + // + // Invoke disconnect outside the lock + // If client disconnects in the meantime connection state tracking ensures + // that we send disconnect only once + // + BthEchoConnectionObjectRemoteDisconnect(&DevCtx->Header, connection); + + // + // Release the reference added above + // + WdfObjectDereference(WdfObjectContextGetObject(connection)); + + // + // We don't explicitly delete connection object as it is a child of device object + // which will shortly be deleted. + // + } +} + diff --git a/bluetooth/bthecho/bthsrv/sys/server.h b/bluetooth/bthecho/bthsrv/sys/server.h new file mode 100644 index 00000000..9a181bbc --- /dev/null +++ b/bluetooth/bthecho/bthsrv/sys/server.h @@ -0,0 +1,89 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + Server.h + +Abstract: + + Contains declarations for Bluetooth server functionality. + +Environment: + + Kernel mode only + + +--*/ + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +BthEchoSrvInitialize( + _In_ PBTHECHOSAMPLE_SERVER_CONTEXT DevCtx + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +BthEchoSrvRegisterPSM( + _In_ PBTHECHOSAMPLE_SERVER_CONTEXT DevCtx + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +VOID +BthEchoSrvUnregisterPSM( + _In_ PBTHECHOSAMPLE_SERVER_CONTEXT DevCtx + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +BthEchoSrvRegisterL2CAPServer( + _In_ PBTHECHOSAMPLE_SERVER_CONTEXT DevCtx + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +VOID +BthEchoSrvUnregisterL2CAPServer( + _In_ PBTHECHOSAMPLE_SERVER_CONTEXT DevCtx + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +BthEchoSrvPublishSdpRecord( + _In_ PBTHECHOSAMPLE_SERVER_CONTEXT DevCtx, + _In_ PUCHAR SdpRecord, + _In_ ULONG SdpRecordLength + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +VOID +BthEchoSrvRemoveSdpRecord( + _In_ PBTHECHOSAMPLE_SERVER_CONTEXT DevCtx + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +NTSTATUS +BthEchoSrvSendConnectResponse( + _In_ PBTHECHOSAMPLE_SERVER_CONTEXT DevCtx, + _In_ PINDICATION_PARAMETERS ConnectParams + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +VOID +BthEchoSrvDisconnectConnection( + _In_ PBTHECHO_CONNECTION Connection + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +VOID +BthEchoSrvDisconnectConnectionsOnRemove( + _In_ PBTHECHOSAMPLE_SERVER_CONTEXT devCtx + ); + +EVT_WDF_REQUEST_COMPLETION_ROUTINE BthEchoSrvRemoteConnectResponseCompletion; + diff --git a/bluetooth/bthecho/common/inc/clisrv.h b/bluetooth/bthecho/common/inc/clisrv.h new file mode 100644 index 00000000..0e3f4f8c --- /dev/null +++ b/bluetooth/bthecho/common/inc/clisrv.h @@ -0,0 +1,137 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + CLISRV.h + +Abstract: + + Header file for functions common to bth echo server and client + +Environment: + + Kernel mode + +--*/ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "trace.h" +#include "public.h" + +#define POOLTAG_BTHECHOSAMPLE 'htbw' + + +enum _BTHECHOSAMPLE_MAX_DATA_LENGTH +{ + BthEchoSampleMaxDataLength = 256 +}; + +// +// Device context common to both client and the server +// + +typedef struct _BTHECHOSAMPLE_DEVICE_CONTEXT_HEADER +{ + // + // Framework device this context is associated with + // + WDFDEVICE Device; + + // + // Default I/O target + // + WDFIOTARGET IoTarget; + + // + // Profile driver interface which contains profile driver DDI + // + BTH_PROFILE_DRIVER_INTERFACE ProfileDrvInterface; + + // + // Local Bluetooth Address + // + BTH_ADDR LocalBthAddr; + +#if (NTDDI_VERSION >= NTDDI_WIN8) + + // + // Features supported by the local stack + // + BTH_HOST_FEATURE_MASK LocalFeatures; + +#endif + + // + // Preallocated request to be reused during initialization/deinitialzation phase + // Access to this reqeust is not synchronized + // + WDFREQUEST Request; +} BTHECHOSAMPLE_DEVICE_CONTEXT_HEADER, *PBTHECHOSAMPLE_DEVICE_CONTEXT_HEADER; + +#include "connection.h" + +_IRQL_requires_max_(DISPATCH_LEVEL) +NTSTATUS +BthEchoSharedDeviceContextHeaderInit( + PBTHECHOSAMPLE_DEVICE_CONTEXT_HEADER header, + WDFDEVICE Device + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +BthEchoSharedRetrieveLocalInfo( + _In_ PBTHECHOSAMPLE_DEVICE_CONTEXT_HEADER DevCtxHdr + ); + +#if (NTDDI_VERSION >= NTDDI_WIN8) + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +BthEchoSharedGetHostSupportedFeatures( + _In_ PBTHECHOSAMPLE_DEVICE_CONTEXT_HEADER DevCtxHdr + ); + +#endif + + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +BthEchoSharedSendBrbSynchronously( + _In_ WDFIOTARGET IoTarget, + _In_ WDFREQUEST Request, + _In_ PBRB Brb, + _In_ ULONG BrbSize + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +NTSTATUS +BthEchoSharedSendBrbAsync( + _In_ WDFIOTARGET IoTarget, + _In_ WDFREQUEST Request, + _In_ PBRB Brb, + _In_ size_t BrbSize, + _In_ PFN_WDF_REQUEST_COMPLETION_ROUTINE ComplRoutine, + _In_opt_ WDFCONTEXT Context + ); + diff --git a/bluetooth/bthecho/common/inc/connection.h b/bluetooth/bthecho/common/inc/connection.h new file mode 100644 index 00000000..fd34d26e --- /dev/null +++ b/bluetooth/bthecho/common/inc/connection.h @@ -0,0 +1,217 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + Connection.c + +Abstract: + + Declaration of connection object for L2CA connection + +Environment: + + Kernel mode + +--*/ + +typedef struct _BTHECHO_CONNECTION * PBTHECHO_CONNECTION; + +#define BTHECHOSAMPLE_NUM_CONTINUOUS_READERS 2 + +typedef VOID +(*PFN_BTHECHO_CONNECTION_OBJECT_CONTREADER_READ_COMPLETE) ( + _In_ PBTHECHOSAMPLE_DEVICE_CONTEXT_HEADER DevCtxHdr, + _In_ PBTHECHO_CONNECTION Connection, + _In_ PVOID Buffer, + _In_ size_t BufferSize + ); + +typedef VOID +(*PFN_BTHECHO_CONNECTION_OBJECT_CONTREADER_FAILED) ( + _In_ PBTHECHOSAMPLE_DEVICE_CONTEXT_HEADER DevCtxHdr, + _In_ PBTHECHO_CONNECTION Connection + ); + + +typedef struct _BTHECHO_REPEAT_READER +{ + // + // BRB used for transfer + // + struct _BRB_L2CA_ACL_TRANSFER TransferBrb; + + // + // WDF Request used for pending I/O + // + WDFREQUEST RequestPendingRead; + + // + // Data buffer for pending read + // + WDFMEMORY MemoryPendingRead; + + // + // Dpc for resubmitting pending read + // + KDPC ResubmitDpc; + + // + // Whether the continuous reader is transitioning to stopped state + // + + LONG Stopping; + + // + // Event used to wait for read completion while stopping the continuos reader + // + KEVENT StopEvent; + + // + // Back pointer to connection + // + PBTHECHO_CONNECTION Connection; + +} BTHECHO_REPEAT_READER, *PBTHECHO_REPEAT_READER; + +// +// Connection state +// + +typedef enum _BTHECHO_CONNECTION_STATE { + ConnectionStateUnitialized = 0, + ConnectionStateInitialized, + ConnectionStateConnecting, + ConnectionStateConnected, + ConnectionStateConnectFailed, + ConnectionStateDisconnecting, + ConnectionStateDisconnected + +} BTHECHOSAMPLE_CONNECTION_STATE, *PBTHECHOSAMPLE_CONNECTION_STATE; + +typedef struct _BTHECHO_CONTINUOUS_READER { + + BTHECHO_REPEAT_READER + RepeatReaders[BTHECHOSAMPLE_NUM_CONTINUOUS_READERS]; + + PFN_BTHECHO_CONNECTION_OBJECT_CONTREADER_READ_COMPLETE + BthEchoConnectionObjectContReaderReadCompleteCallback; + + PFN_BTHECHO_CONNECTION_OBJECT_CONTREADER_FAILED + BthEchoConnectionObjectContReaderFailedCallback; + + DWORD InitializedReadersCount; + +} BTHECHO_CONTINUOUS_READER, * PBTHECHO_CONTINUOUS_READER; + +// +// Connection data structure for L2Ca connection +// + +typedef struct _BTHECHO_CONNECTION { + + // + // List entry for connection list maintained at device level + // + LIST_ENTRY ConnectionListEntry; + + PBTHECHOSAMPLE_DEVICE_CONTEXT_HEADER DevCtxHdr; + + BTHECHOSAMPLE_CONNECTION_STATE ConnectionState; + + // + // Connection lock, used to synchronize access to _BTHECHO_CONNECTION data structure + // + WDFSPINLOCK ConnectionLock; + + USHORT OutMTU; + USHORT InMTU; + + L2CAP_CHANNEL_HANDLE ChannelHandle; + BTH_ADDR RemoteAddress; + + // + // Preallocated Brb, Request used for connect/disconnect + // + struct _BRB ConnectDisconnectBrb; + WDFREQUEST ConnectDisconnectRequest; + + // + // Event used to wait for disconnection + // It is non-signaled when connection is in ConnectionStateDisconnecting + // transitionary state and signaled otherwise + // + KEVENT DisconnectEvent; + + // + // Continuous readers (used only by server) + // PLEASE NOTE that KMDF USB Pipe Target uses a single continuous reader + // + BTHECHO_CONTINUOUS_READER ContinuousReader; +} BTHECHO_CONNECTION, *PBTHECHO_CONNECTION; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(BTHECHO_CONNECTION, GetConnectionObjectContext) + +_IRQL_requires_max_(DISPATCH_LEVEL) +NTSTATUS +BthEchoConnectionObjectCreate( + _In_ PBTHECHOSAMPLE_DEVICE_CONTEXT_HEADER DevCtxHdr, + _In_ WDFOBJECT ParentObject, + _Out_ WDFOBJECT* ConnectionObject + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +NTSTATUS +BthEchoConnectionObjectInitializeContinuousReader( + _In_ PBTHECHO_CONNECTION Connection, + _In_ PFN_BTHECHO_CONNECTION_OBJECT_CONTREADER_READ_COMPLETE + BthEchoConnectionObjectContReaderReadCompleteCallback, + _In_ PFN_BTHECHO_CONNECTION_OBJECT_CONTREADER_FAILED + BthEchoConnectionObjectContReaderFailedCallback, + _In_ size_t BufferSize + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +NTSTATUS +BthEchoConnectionObjectContinuousReaderSubmitReaders( + _In_ PBTHECHO_CONNECTION Connection + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +VOID +BthEchoConnectionObjectContinuousReaderCancelReaders( + _In_ PBTHECHO_CONNECTION Connection + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +BOOLEAN +BthEchoConnectionObjectRemoteDisconnect( + _In_ PBTHECHOSAMPLE_DEVICE_CONTEXT_HEADER DevCtxHdr, + _In_ PBTHECHO_CONNECTION Connection + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +VOID +BthEchoConnectionObjectRemoteDisconnectSynchronously( + _In_ PBTHECHOSAMPLE_DEVICE_CONTEXT_HEADER DevCtxHdr, + _In_ PBTHECHO_CONNECTION Connection + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +_When_(return==0, _At_(*Brb, __drv_allocatesMem(Mem))) +NTSTATUS +BthEchoConnectionObjectFormatRequestForL2CaTransfer( + _In_ PBTHECHO_CONNECTION Connection, + _In_ WDFREQUEST Request, + _Inout_ struct _BRB_L2CA_ACL_TRANSFER ** Brb, + _In_ WDFMEMORY Memory, + _In_ ULONG TransferFlags //flags include direction of transfer + ); + +EVT_WDF_OBJECT_CONTEXT_CLEANUP BthEchoEvtConnectionObjectCleanup; diff --git a/bluetooth/bthecho/common/inc/public.h b/bluetooth/bthecho/common/inc/public.h new file mode 100644 index 00000000..825078d5 --- /dev/null +++ b/bluetooth/bthecho/common/inc/public.h @@ -0,0 +1,38 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +ModuleName: + + public.h + +Abstract: + + Contains definitions used both by driver and application + + +--*/ + +#pragma once + +// +// Service GUID and name for the service published by our bth server device +// + +/* c07508f2-b970-43ca-b5dd-cc4f2391bef4 */ +DEFINE_GUID(BTHECHOSAMPLE_SVC_GUID, 0xc07508f2, 0xb970, 0x43ca, 0xb5, 0xdd, 0xcc, 0x4f, 0x23, 0x91, 0xbe, 0xf4); +extern __declspec(selectany) const PWSTR BthEchoSampleSvcName = L"BthEchoSampleSrv"; + +// +// Device interface exposed by our bth client device +// + +/* fc71b33d-d528-4763-a86c-78777c7bcd7b */ +DEFINE_GUID(BTHECHOSAMPLE_DEVICE_INTERFACE, 0xfc71b33d, 0xd528, 0x4763, 0xa8, 0x6c, 0x78, 0x77, 0x7c, 0x7b, 0xcd, 0x7b); + + diff --git a/bluetooth/bthecho/common/inc/trace.h b/bluetooth/bthecho/common/inc/trace.h new file mode 100644 index 00000000..bcff3c46 --- /dev/null +++ b/bluetooth/bthecho/common/inc/trace.h @@ -0,0 +1,117 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + TRACE.h + +Abstract: + + Header file for the debug tracing related function defintions and macros. + +Environment: + + Kernel mode + +--*/ + +#include // For TRACE_LEVEL definitions + +#if !defined(EVENT_TRACING) + +// +// TODO: These defines are missing in evntrace.h +// in some DDK build environments (XP). +// +#if !defined(TRACE_LEVEL_NONE) + #define TRACE_LEVEL_NONE 0 + #define TRACE_LEVEL_CRITICAL 1 + #define TRACE_LEVEL_FATAL 1 + #define TRACE_LEVEL_ERROR 2 + #define TRACE_LEVEL_WARNING 3 + #define TRACE_LEVEL_INFORMATION 4 + #define TRACE_LEVEL_VERBOSE 5 + #define TRACE_LEVEL_RESERVED6 6 + #define TRACE_LEVEL_RESERVED7 7 + #define TRACE_LEVEL_RESERVED8 8 + #define TRACE_LEVEL_RESERVED9 9 +#endif + + +// +// Define Debug Flags +// +#define DBG_INIT 0x00000001 +#define DBG_PNP 0x00000002 +#define DBG_POWER 0x00000004 +#define DBG_WMI 0x00000008 +#define DBG_CREATE_CLOSE 0x00000010 +#define DBG_IOCTL 0x00000020 +#define DBG_WRITE 0x00000040 +#define DBG_READ 0x00000080 +#define DBG_SDP 0x00000100 +#define DBG_CONNECT 0x00000200 +#define DBG_UTIL 0x00000400 +#define DBG_CONT_READER 0x00008000 + + +VOID +TraceEvents ( + _In_ ULONG DebugPrintLevel, + _In_ ULONG DebugPrintFlag, + _Printf_format_string_ + _In_ PCSTR DebugMessage, + ... + ); + +#define WPP_INIT_TRACING(DriverObject, RegistryPath) +#define WPP_CLEANUP(DriverObject) + +#else +// +// If software tracing is defined in the sources file.. +// WPP_DEFINE_CONTROL_GUID specifies the GUID used for this driver. +// *** REPLACE THE GUID WITH YOUR OWN UNIQUE ID *** +// WPP_DEFINE_BIT allows setting debug bit masks to selectively print. +// The names defined in the WPP_DEFINE_BIT call define the actual names +// that are used to control the level of tracing for the control guid +// specified. +// +// NOTE: If you are adopting this sample for your driver, please generate +// a new guid, using tools\other\i386\guidgen.exe present in the +// DDK. +// + +#define WPP_CHECK_FOR_NULL_STRING //to prevent exceptions due to NULL strings + +#define WPP_CONTROL_GUIDS \ + WPP_DEFINE_CONTROL_GUID(BthEchoSampleTraceGuid,(d8694f3b,26cd,48dd,bf36,1adb35192913), \ + WPP_DEFINE_BIT(DBG_INIT) /* bit 0 = 0x00000001 */ \ + WPP_DEFINE_BIT(DBG_PNP) /* bit 1 = 0x00000002 */ \ + WPP_DEFINE_BIT(DBG_POWER) /* bit 2 = 0x00000004 */ \ + WPP_DEFINE_BIT(DBG_WMI) /* bit 3 = 0x00000008 */ \ + WPP_DEFINE_BIT(DBG_CREATE_CLOSE) /* bit 4 = 0x00000010 */ \ + WPP_DEFINE_BIT(DBG_IOCTL) /* bit 5 = 0x00000020 */ \ + WPP_DEFINE_BIT(DBG_WRITE) /* bit 6 = 0x00000040 */ \ + WPP_DEFINE_BIT(DBG_READ) /* bit 7 = 0x00000080 */ \ + WPP_DEFINE_BIT(DBG_SDP) /* bit 8 = 0x00000100 */ \ + WPP_DEFINE_BIT(DBG_CONNECT) /* bit 9 = 0x00000200 */ \ + WPP_DEFINE_BIT(DBG_UTIL) /* bit 9 = 0x00000400 */ \ + WPP_DEFINE_BIT(DBG_CONT_READER) /* bit 9 = 0x00008000 */ \ + /* You can have up to 32 defines. If you want more than that,\ + you have to provide another trace control GUID */\ + ) + + +#define WPP_LEVEL_FLAGS_LOGGER(lvl,flags) WPP_LEVEL_LOGGER(flags) +#define WPP_LEVEL_FLAGS_ENABLED(lvl, flags) (WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level >= lvl) + + +#endif + diff --git a/bluetooth/bthecho/common/lib/bthecho.vcxproj b/bluetooth/bthecho/common/lib/bthecho.vcxproj new file mode 100644 index 00000000..1ff84251 --- /dev/null +++ b/bluetooth/bthecho/common/lib/bthecho.vcxproj @@ -0,0 +1,202 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {A2EE1D94-8521-48CE-B925-271ACA5DD459} + $(MSBuildProjectName) + 1 + Debug + Win32 + {7D08015D-5262-4372-8E97-C25A002DA190} + + + + Windows10 + False + Desktop + KMDF + WindowsKernelModeDriver10.0 + StaticLibrary + + + Windows10 + True + Desktop + KMDF + WindowsKernelModeDriver10.0 + StaticLibrary + + + Windows10 + False + Desktop + KMDF + WindowsKernelModeDriver10.0 + StaticLibrary + + + Windows10 + True + Desktop + KMDF + WindowsKernelModeDriver10.0 + StaticLibrary + + + + $(IntDir) + + + + + + + + + + + + + + + + true + .c.cpp.h.hpp + .h.hpp + true + TraceEvents(LEVEL,FLAGS,MSG,...) + {km-WdfDefault.tpl}*.tmh + + + + bthecho + + + bthecho + + + bthecho + + + bthecho + + + + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc + %(PreprocessorDefinitions);_UNICODE;UNICODE + %(PreprocessorDefinitions);EVENT_TRACING + + + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc + %(PreprocessorDefinitions);_UNICODE;UNICODE + true + Level4 + %(DisableSpecificWarnings);4201 + %(PreprocessorDefinitions);EVENT_TRACING + + + + + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc + %(PreprocessorDefinitions);_UNICODE;UNICODE + %(PreprocessorDefinitions);EVENT_TRACING + + + + + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc + %(PreprocessorDefinitions);_UNICODE;UNICODE + %(PreprocessorDefinitions);EVENT_TRACING + + + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc + %(PreprocessorDefinitions);_UNICODE;UNICODE + true + Level4 + %(DisableSpecificWarnings);4201 + %(PreprocessorDefinitions);EVENT_TRACING + + + + + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc + %(PreprocessorDefinitions);_UNICODE;UNICODE + %(PreprocessorDefinitions);EVENT_TRACING + + + + + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc + %(PreprocessorDefinitions);_UNICODE;UNICODE + %(PreprocessorDefinitions);EVENT_TRACING + + + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc + %(PreprocessorDefinitions);_UNICODE;UNICODE + true + Level4 + %(DisableSpecificWarnings);4201 + %(PreprocessorDefinitions);EVENT_TRACING + + + + + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc + %(PreprocessorDefinitions);_UNICODE;UNICODE + %(PreprocessorDefinitions);EVENT_TRACING + + + + + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc + %(PreprocessorDefinitions);_UNICODE;UNICODE + %(PreprocessorDefinitions);EVENT_TRACING + + + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc + %(PreprocessorDefinitions);_UNICODE;UNICODE + true + Level4 + %(DisableSpecificWarnings);4201 + %(PreprocessorDefinitions);EVENT_TRACING + + + + + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc + %(PreprocessorDefinitions);_UNICODE;UNICODE + %(PreprocessorDefinitions);EVENT_TRACING + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/bluetooth/bthecho/common/lib/bthecho.vcxproj.Filters b/bluetooth/bthecho/common/lib/bthecho.vcxproj.Filters new file mode 100644 index 00000000..70735b7e --- /dev/null +++ b/bluetooth/bthecho/common/lib/bthecho.vcxproj.Filters @@ -0,0 +1,29 @@ + + + + + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* + {2F1B68C0-756D-4458-87A8-8E75D9D889E3} + + + h;hpp;hxx;hm;inl;inc;xsd + {B9556308-CC93-4C4F-A7E2-55F119DCD6DA} + + + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml + {A3F3F256-9D63-4D56-8493-B44D13A67F0A} + + + inf;inv;inx;mof;mc; + {11D85DF8-6812-42E3-A08E-798DE942BED5} + + + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/bluetooth/bthecho/common/lib/clisrv.c b/bluetooth/bthecho/common/lib/clisrv.c new file mode 100644 index 00000000..c5e22414 --- /dev/null +++ b/bluetooth/bthecho/common/lib/clisrv.c @@ -0,0 +1,435 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + clisrv.c + +Abstract: + + Implementation of functions common to bth echo server and client + +Environment: + + Kernel mode + +--*/ + +#include "clisrv.h" + +#if defined(EVENT_TRACING) +#include "clisrv.tmh" +#endif + + +_IRQL_requires_max_(DISPATCH_LEVEL) +NTSTATUS +BthEchoSharedDeviceContextHeaderInit( + PBTHECHOSAMPLE_DEVICE_CONTEXT_HEADER Header, + WDFDEVICE Device + ) +/*++ + +Description: + + Initializes the common context header between server and client + +Arguments: + + Header - Contex header + Device - Framework device object + +Return Value: + + NTSTATUS Status code. + +--*/ +{ + NTSTATUS status; + WDF_OBJECT_ATTRIBUTES attributes; + + Header->Device = Device; + + Header->IoTarget = WdfDeviceGetIoTarget(Device); + + // + // Initialize request object + // + + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + attributes.ParentObject = Device; + + status = WdfRequestCreate( + &attributes, + Header->IoTarget, + &Header->Request + ); + + if (!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "Failed to pre-allocate request in device context, Status code %!STATUS!\n", status); + + goto exit; + } + +exit: + return status; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +BthEchoSharedRetrieveLocalInfo( + _In_ PBTHECHOSAMPLE_DEVICE_CONTEXT_HEADER DevCtxHdr + ) +/*++ + +Description: + + Retrieves the local bth address. + This address is burnt into device hence doesn't change. + + It also retrieves the local host supported features if available. + +Arguments: + + Header - Contex header + +Return Value: + + NTSTATUS Status code. + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + struct _BRB_GET_LOCAL_BD_ADDR * brb = NULL; + + brb = (struct _BRB_GET_LOCAL_BD_ADDR *) + DevCtxHdr->ProfileDrvInterface.BthAllocateBrb( + BRB_HCI_GET_LOCAL_BD_ADDR, + POOLTAG_BTHECHOSAMPLE + ); + + if(brb == NULL) + { + status = STATUS_INSUFFICIENT_RESOURCES; + + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "Failed to allocate brb BRB_HCI_GET_LOCAL_BD_ADDR, returning status code %!STATUS!\n", status); + + goto exit; + } + + status = BthEchoSharedSendBrbSynchronously( + DevCtxHdr->IoTarget, + DevCtxHdr->Request, + (PBRB) brb, + sizeof(*brb) + ); + + if (!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "Retrieving local bth address failed, Status code %!STATUS!\n", status); + + goto exit1; + } + + DevCtxHdr->LocalBthAddr = brb->BtAddress; + +#if (NTDDI_VERSION >= NTDDI_WIN8) + + // + // Now retreive local host supported features + // + status = BthEchoSharedGetHostSupportedFeatures(DevCtxHdr); + + if (!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "Sending IOCTL for reading supported features failed, Status code %!STATUS!\n", status); + + goto exit1; + } + +#endif + +exit1: + DevCtxHdr->ProfileDrvInterface.BthFreeBrb((PBRB)brb); +exit: + return status; +} + + +#if (NTDDI_VERSION >= NTDDI_WIN8) + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +BthEchoSharedGetHostSupportedFeatures( + _In_ PBTHECHOSAMPLE_DEVICE_CONTEXT_HEADER DevCtxHdr + ) +/*++ + +Routine Description: + + This routine synchronously checks the local stack's supported features + +Arguments: + + DevCtxHdr - Information about the local device + +Return Value: + + NTSTATUS Status code. + +--*/ +{ + WDF_MEMORY_DESCRIPTOR outMemDesc = {0}; + BTH_HOST_FEATURE_MASK localFeatures = {0}; + NTSTATUS status = STATUS_SUCCESS; + + DevCtxHdr->LocalFeatures.Mask = 0; + + WDF_MEMORY_DESCRIPTOR_INIT_BUFFER( + &outMemDesc, + &localFeatures, + sizeof(localFeatures) + ); + + status = WdfIoTargetSendIoctlSynchronously( + DevCtxHdr->IoTarget, + NULL, + IOCTL_BTH_GET_HOST_SUPPORTED_FEATURES, + NULL, + &outMemDesc, + NULL, + NULL + ); + + if (!NT_SUCCESS(status)) { + return status; + } + + DevCtxHdr->LocalFeatures = localFeatures; + + return status; +} + +#endif + + +_IRQL_requires_max_(DISPATCH_LEVEL) +NTSTATUS +BthEchoSharedSendBrbAsync( + _In_ WDFIOTARGET IoTarget, + _In_ WDFREQUEST Request, + _In_ PBRB Brb, + _In_ size_t BrbSize, + _In_ PFN_WDF_REQUEST_COMPLETION_ROUTINE ComplRoutine, + _In_opt_ WDFCONTEXT Context + ) +/*++ + +Routine Description: + + This routine formats a request with brb and sends it asynchronously + +Arguments: + + IoTarget - Target to send the brb to + Request - request object to be formatted with brb + Brb - Brb to be sent + BrbSize - size of the Brb data structure + ComplRoutine - WDF completion routine for the request + This must be specified because we are formatting the request + and hence not using SEND_AND_FORGET flag + Context - (optional) context to be passed in to the completion routine + +Return Value: + + Success implies that request was sent correctly and completion routine will be called + for it, + failure implies it was not sent and caller should complete the request + +Notes: + + This routine does not call WdfRequestReuse on the Request passed in. + Caller must do so before passing in the request, if it is reusing the request. + + This routine does not complete the request in case of failure. + Caller must complete the request in case of failure. + +--*/ +{ + NTSTATUS status = BTH_ERROR_SUCCESS; + WDF_OBJECT_ATTRIBUTES attributes; + WDFMEMORY memoryArg1 = NULL; + + if (BrbSize <= 0) + { + TraceEvents(TRACE_LEVEL_ERROR, DBG_CONT_READER, + "BrbSize has invalid value: %I64d\n", + BrbSize + ); + + status = STATUS_INVALID_PARAMETER; + + goto exit; + } + + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + attributes.ParentObject = Request; + + status = WdfMemoryCreatePreallocated( + &attributes, + Brb, + BrbSize, + &memoryArg1 + ); + + if (!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, DBG_UTIL, + "Creating preallocted memory for Brb 0x%p failed, Request to be formatted 0x%p, " + "Status code %!STATUS!\n", + Brb, + Request, + status + ); + + goto exit; + } + + status = WdfIoTargetFormatRequestForInternalIoctlOthers( + IoTarget, + Request, + IOCTL_INTERNAL_BTH_SUBMIT_BRB, + memoryArg1, + NULL, //OtherArg1Offset + NULL, //OtherArg2 + NULL, //OtherArg2Offset + NULL, //OtherArg4 + NULL //OtherArg4Offset + ); + + if (!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, DBG_UTIL, + "Formatting request 0x%p with Brb 0x%p failed, Status code %!STATUS!\n", + Request, + Brb, + status + ); + + goto exit; + } + + // + // Set a CompletionRoutine callback function. + // + WdfRequestSetCompletionRoutine( + Request, + ComplRoutine, + Context + ); + + if (FALSE == WdfRequestSend( + Request, + IoTarget, + NULL + )) + { + status = WdfRequestGetStatus(Request); + + TraceEvents(TRACE_LEVEL_ERROR, DBG_UTIL, + "Request send failed for request 0x%p, Brb 0x%p, Status code %!STATUS!\n", + Request, + Brb, + status + ); + + goto exit; + } + +exit: + return status; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +BthEchoSharedSendBrbSynchronously( + _In_ WDFIOTARGET IoTarget, + _In_ WDFREQUEST Request, + _In_ PBRB Brb, + _In_ ULONG BrbSize + ) +/*++ + +Routine Description: + + This routine formats a request with brb and sends it synchronously + +Arguments: + + IoTarget - Target to send the brb to + Request - request object to be formatted with brb + Brb - Brb to be sent + BrbSize - size of the Brb data structure + +Return Value: + + NTSTATUS Status code. + +Notes: + + This routine does calls WdfRequestReuse on the Request passed in. + Caller need not do so before passing in the request. + + This routine does not complete the request in case of failure. + Caller must complete the request in case of failure. + +--*/ +{ + NTSTATUS status; + WDF_REQUEST_REUSE_PARAMS reuseParams; + WDF_MEMORY_DESCRIPTOR OtherArg1Desc; + + WDF_REQUEST_REUSE_PARAMS_INIT( + &reuseParams, + WDF_REQUEST_REUSE_NO_FLAGS, + STATUS_NOT_SUPPORTED + ); + + status = WdfRequestReuse(Request, &reuseParams); + if (!NT_SUCCESS(status)) + { + goto exit; + } + + WDF_MEMORY_DESCRIPTOR_INIT_BUFFER( + &OtherArg1Desc, + Brb, + BrbSize + ); + + status = WdfIoTargetSendInternalIoctlOthersSynchronously( + IoTarget, + Request, + IOCTL_INTERNAL_BTH_SUBMIT_BRB, + &OtherArg1Desc, + NULL, //OtherArg2 + NULL, //OtherArg4 + NULL, //RequestOptions + NULL //BytesReturned + ); + +exit: + return status; +} + diff --git a/bluetooth/bthecho/common/lib/connection.c b/bluetooth/bthecho/common/lib/connection.c new file mode 100644 index 00000000..36734a06 --- /dev/null +++ b/bluetooth/bthecho/common/lib/connection.c @@ -0,0 +1,1343 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + connection.c + +Abstract: + + Implementation of connection object which represents an L2CA connection + + We create a WDFOBJECT for connection in BthEchoConnectionObjectCreate. + PBTHECHO_CONNECTION is maintained as context of this object. + + We use passive dispose for connection WDFOBJECT. This allows us to wait for + continuous readers to stop and disconnect to complete in the cleanup + callback (BthEchoEvtConnectionObjectCleanup) of connection object. + + Connection object also includes continuous readers which need + to be explicitly initialied and submitted. + + Both client and server utlize connection object although continous reader + functionality is utilized only by server. + +Environment: + + Kernel mode + +--*/ + +#include "clisrv.h" + +#if defined(EVENT_TRACING) +#include "connection.tmh" +#endif + +_IRQL_requires_max_(DISPATCH_LEVEL) +NTSTATUS +BthEchoRepeatReaderSubmit( + _In_ PBTHECHOSAMPLE_DEVICE_CONTEXT_HEADER DevCtx, + _In_ PBTHECHO_REPEAT_READER RepeatReader + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +VOID +BthEchoRepeatReaderWaitForStop( + _In_ PBTHECHO_REPEAT_READER RepeatReader + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +VOID +BthEchoConnectionObjectWaitForAndUninitializeContinuousReader( + _In_ PBTHECHO_CONNECTION Connection + ); + +#ifdef ALLOC_PRAGMA +#pragma alloc_text (PAGE, BthEchoRepeatReaderWaitForStop) +#pragma alloc_text (PAGE, BthEchoConnectionObjectWaitForAndUninitializeContinuousReader) +#pragma alloc_text (PAGE, BthEchoEvtConnectionObjectCleanup) +#pragma alloc_text (PAGE, BthEchoConnectionObjectRemoteDisconnectSynchronously) +#endif + + +KDEFERRED_ROUTINE +BthEchoRepeatReaderResubmitReadDpc; + +VOID +BthEchoRepeatReaderResubmitReadDpc( + _In_ struct _KDPC *Dpc, + _In_opt_ PVOID DeferredContext, + _In_opt_ PVOID SystemArgument1, + _In_opt_ PVOID SystemArgument2 +) +/*++ + +Description: + + Dpc for resubmitting pending read + +Arguments: + + Dpc - Dpc + DeferredContext - We receive device context header as DeferredContext + SystemArgument1 - We receive repeat reader as SystemArgument1 + SystemArgument2 - Unused + +--*/ +{ + PBTHECHO_REPEAT_READER repeatReader; + + UNREFERENCED_PARAMETER(Dpc); + UNREFERENCED_PARAMETER(SystemArgument2); + + repeatReader = + (PBTHECHO_REPEAT_READER) SystemArgument1; + + // + // BthEchoRepeatReaderSubmit will invoke contreader + // failure callback in case of failure + // so we don't check for failure here + // + if ((NULL != DeferredContext) && (NULL != repeatReader)) + { + (void) BthEchoRepeatReaderSubmit( + (PBTHECHOSAMPLE_DEVICE_CONTEXT_HEADER) DeferredContext, + repeatReader + ); + } +} + +EVT_WDF_REQUEST_COMPLETION_ROUTINE +BthEchoRepeatReaderPendingReadCompletion; + +void +BthEchoRepeatReaderPendingReadCompletion( + _In_ WDFREQUEST Request, + _In_ WDFIOTARGET Target, + _In_ PWDF_REQUEST_COMPLETION_PARAMS Params, + _In_ WDFCONTEXT Context + ) +/*++ + +Description: + + Completion routine for pending read request + + In this routine we invoke the read completion callback + in case of success and contreader failure callback + in case of failure. + + These are implemented by server. + +Arguments: + + Request - Request completed + Target - Target to which request was sent + Params - Completion parameters + Context - We receive repeat reader as the context + +--*/ +{ + PBTHECHO_REPEAT_READER repeatReader; + NTSTATUS status; + + UNREFERENCED_PARAMETER(Target); + UNREFERENCED_PARAMETER(Request); + + repeatReader = (PBTHECHO_REPEAT_READER) Context; + + NT_ASSERT((repeatReader != NULL)); + + status = Params->IoStatus.Status; + + if (NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_CONT_READER, + "Pending read completion, RepeatReader: 0x%p, status: %!STATUS!, Buffer: 0x%p, BufferSize: %d", + repeatReader, + Params->IoStatus.Status, + repeatReader->TransferBrb.Buffer, + repeatReader->TransferBrb.BufferSize + ); + + repeatReader->Connection->ContinuousReader.BthEchoConnectionObjectContReaderReadCompleteCallback( + repeatReader->Connection->DevCtxHdr, + repeatReader->Connection, + repeatReader->TransferBrb.Buffer, + repeatReader->TransferBrb.BufferSize + ); + + } + else + { + TraceEvents(TRACE_LEVEL_ERROR, DBG_CONT_READER, + "Pending read completed with failure, RepeatReader: 0x%p, status: %!STATUS!", + repeatReader, + Params->IoStatus.Status + ); + } + + if (!NT_SUCCESS(status)) + { + // + // Invoke reader failed callback only if status is something other + // than cancelled. If the status is STATUS_CANCELLED this is because + // we have cancelled repeat reader. + // + if (STATUS_CANCELLED != status) + { + // + // Invoke reader failed callback before setting the stop event + // to ensure that connection object is alive during this callback + // + repeatReader->Connection->ContinuousReader.BthEchoConnectionObjectContReaderFailedCallback( + repeatReader->Connection->DevCtxHdr, + repeatReader->Connection + ); + } + + // + // Set stop event because we are not resubmitting the reader + // + KeSetEvent(&repeatReader->StopEvent, 0, FALSE); + } + else + { + // + // Resubmit pending read + // We use a Dpc to avoid recursing in this completion routine + // + + BOOLEAN ret = KeInsertQueueDpc(&repeatReader->ResubmitDpc, repeatReader, NULL); + NT_ASSERT (TRUE == ret); //we only expect one outstanding dpc + UNREFERENCED_PARAMETER(ret); //ret remains unused in fre build + } +} + +VOID +BthEchoRepeatReaderUninitialize( + _In_ PBTHECHO_REPEAT_READER RepeatReader + ) +{ + if (NULL != RepeatReader->RequestPendingRead) + { + RepeatReader->RequestPendingRead = NULL; + + RepeatReader->Stopping = 0; + } +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +NTSTATUS +BthEchoRepeatReaderInitialize( + _In_ PBTHECHO_CONNECTION Connection, + _In_ PBTHECHO_REPEAT_READER RepeatReader, + _In_ size_t BufferSize + ) + +/*++ + +Description: + + This routine initializes repeat reader. + +Arguments: + + Connection - Connection with which this repeat reader is associated + RepeatReader - Repeat reader + BufferSize - Buffer size for read + +Return Value: + + NTSTATUS Status code. + +--*/ + +{ + NTSTATUS status; + WDF_OBJECT_ATTRIBUTES attributes; + + // + // Create request object for pending read + // Set connection object as the parent for the request + // + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + attributes.ParentObject = WdfObjectContextGetObject(Connection); + + status = WdfRequestCreate( + &attributes, + Connection->DevCtxHdr->IoTarget, + &RepeatReader->RequestPendingRead + ); + + if (!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, DBG_CONT_READER, + "Creating request for pending read failed, " + "Status code %!STATUS!\n", + status + ); + + goto exit; + } + + if (BufferSize <= 0) + { + TraceEvents(TRACE_LEVEL_ERROR, DBG_CONT_READER, + "BufferSize has an invalid value: %I64d\n", + BufferSize + ); + + status = STATUS_INVALID_PARAMETER; + + goto exit; + } + + // + // Create memory object for the pending read + // + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + attributes.ParentObject = RepeatReader->RequestPendingRead; + + status = WdfMemoryCreate( + &attributes, + NonPagedPoolNx, + POOLTAG_BTHECHOSAMPLE, + BufferSize, + &RepeatReader->MemoryPendingRead, + NULL //buffer + ); + + if (!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, DBG_CONT_READER, + "Creating memory for pending read failed, " + "Status code %!STATUS!\n", + status + ); + + goto exit; + } + + // + // Initialize Dpc that we will use for resubmitting pending read + // + KeInitializeDpc( + &RepeatReader->ResubmitDpc, + BthEchoRepeatReaderResubmitReadDpc, + Connection->DevCtxHdr + ); + + // + // Initialize event used to wait for stop. + // This even is created as signalled. It gets cleared when + // request is submitted. + // + KeInitializeEvent(&RepeatReader->StopEvent, NotificationEvent, TRUE); + + RepeatReader->Connection = Connection; + +exit: + if (!NT_SUCCESS(status)) + { + BthEchoRepeatReaderUninitialize(RepeatReader); + } + + return status; +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +NTSTATUS +BthEchoRepeatReaderSubmit( + _In_ PBTHECHOSAMPLE_DEVICE_CONTEXT_HEADER DevCtxHdr, + _In_ PBTHECHO_REPEAT_READER RepeatReader + ) +/*++ + +Description: + + This routine submits the repeat reader. + + In case of failure it invoked contreader failed callback + +Arguments: + + DevCtxHdr - Device context header + RepeatReader - Repeat reader to submit + +Return Value: + + NTSTATUS Status code. + +--*/ +{ + NTSTATUS status, statusReuse; + WDF_REQUEST_REUSE_PARAMS reuseParams; + struct _BRB_L2CA_ACL_TRANSFER *brb = &RepeatReader->TransferBrb; + + DevCtxHdr->ProfileDrvInterface.BthReuseBrb((PBRB)brb, BRB_L2CA_ACL_TRANSFER); + + WDF_REQUEST_REUSE_PARAMS_INIT(&reuseParams, WDF_REQUEST_REUSE_NO_FLAGS, STATUS_UNSUCCESSFUL); + statusReuse = WdfRequestReuse(RepeatReader->RequestPendingRead, &reuseParams); + NT_ASSERT(NT_SUCCESS(statusReuse)); + UNREFERENCED_PARAMETER(statusReuse); + + // + // Check if we are stopping, if yes set StopEvent and exit. + // + // After this point request is eligible for cancellation, so if this + // flag gets set after we check it, request will be cancelled for stopping + // the repeat reader and next time around we will stop when we are invoked + // again upon completion of cancelled request. + // + if (RepeatReader->Stopping) + { + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_CONT_READER, + "Continuos reader 0x%p stopping", RepeatReader); + + KeSetEvent(&RepeatReader->StopEvent, 0, FALSE); + + status = STATUS_SUCCESS; + + goto exit; + } + + // + // Format request for L2CA IN transfer + // + status = BthEchoConnectionObjectFormatRequestForL2CaTransfer( + RepeatReader->Connection, + RepeatReader->RequestPendingRead, + &brb, + RepeatReader->MemoryPendingRead, + ACL_TRANSFER_DIRECTION_IN | ACL_SHORT_TRANSFER_OK + ); + + if (!NT_SUCCESS(status)) + { + goto exit; + } + + // + // Set a CompletionRoutine callback function. + // + + WdfRequestSetCompletionRoutine( + RepeatReader->RequestPendingRead, + BthEchoRepeatReaderPendingReadCompletion, + RepeatReader + ); + + // + // Clear the stop event before sending the request + // This is relevant only on start of the repeat reader + // (i.e. the first submission) + // this event eventually gets set only when repeat reader stops + // and not on every resubmission. + // + KeClearEvent(&RepeatReader->StopEvent); + + if (FALSE == WdfRequestSend( + RepeatReader->RequestPendingRead, + DevCtxHdr->IoTarget, + NULL + )) + { + status = WdfRequestGetStatus(RepeatReader->RequestPendingRead); + + TraceEvents(TRACE_LEVEL_ERROR, DBG_CONT_READER, + "Request send failed for request 0x%p, Brb 0x%p, Status code %!STATUS!\n", + RepeatReader->RequestPendingRead, + brb, + status + ); + + goto exit; + } + else + { + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_CONT_READER, + "Resubmited pending read with request 0x%p, Brb 0x%p", + RepeatReader->RequestPendingRead, + brb + ); + } + +exit: + if (!NT_SUCCESS(status)) + { + // + // Invoke the reader failed callback before setting the event + // to ensure that the connection object is alive during this callback + // + RepeatReader->Connection->ContinuousReader.BthEchoConnectionObjectContReaderFailedCallback( + RepeatReader->Connection->DevCtxHdr, + RepeatReader->Connection + ); + + // + // If we failed to send pending read, set the event since + // we will not get completion callback + // + + KeSetEvent(&RepeatReader->StopEvent, 0, FALSE); + } + + return status; +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +VOID +BthEchoRepeatReaderCancel( + _In_ PBTHECHO_REPEAT_READER RepeatReader + ) +/*++ + +Description: + + This routine cancels repeat reader + but it does not wait for repeat reader to stop. + + This wait must be performed separately. + +Arguments: + + RepeatReader - Repeat reader to be cancelled + +--*/ +{ + // + // Signal that we are transitioning to stopped state + // so that we don't resubmit pending read + // + + InterlockedIncrement(&RepeatReader->Stopping); + + // + // Cancel the pending read. + // + // If BthEchoRepeatReaderSubmit misses the setting of Stopping + // flag, cancel would cause the request to complete quickly and + // repeat reader will subsequently be stopped. + // + WdfRequestCancelSentRequest(RepeatReader->RequestPendingRead); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +VOID +BthEchoRepeatReaderWaitForStop( + _In_ PBTHECHO_REPEAT_READER RepeatReader + ) +/*++ + +Description: + + This routine waits for repeat reader to stop + +Arguments: + + RepeatReader - Repeat reader to be waited on + +--*/ +{ + PAGED_CODE(); + + // + // Wait for pending read to complete + // + + KeWaitForSingleObject( + &RepeatReader->StopEvent, + Executive, + KernelMode, + FALSE, + NULL + ); +} + +//==================================================================== +//Connection object functions +//==================================================================== + +_IRQL_requires_max_(DISPATCH_LEVEL) +NTSTATUS +BthEchoConnectionObjectInitializeContinuousReader( + _In_ PBTHECHO_CONNECTION Connection, + _In_ PFN_BTHECHO_CONNECTION_OBJECT_CONTREADER_READ_COMPLETE + BthEchoConnectionObjectContReaderReadCompleteCallback, + _In_ PFN_BTHECHO_CONNECTION_OBJECT_CONTREADER_FAILED + BthEchoConnectionObjectContReaderFailedCallback, + _In_ size_t BufferSize + ) +/*++ +Description: + + This routine initializes continuous reader for connection + +Arguments: + + Connection - Connection for which to initialize continuous readers + BthEchoConnectionObjectContReaderReadCompleteCallback - + Pending read completion callback + BthEchoConnectionObjectContReaderFailedCallback - + Repeat reader failed callback + BufferSize - Buffer size for the pending read + +Return Value: + + NTSTATUS Status code. +--*/ + +{ + NTSTATUS status = STATUS_SUCCESS; + UINT i; + + Connection->ContinuousReader.BthEchoConnectionObjectContReaderReadCompleteCallback = + BthEchoConnectionObjectContReaderReadCompleteCallback; + Connection->ContinuousReader.BthEchoConnectionObjectContReaderFailedCallback = + BthEchoConnectionObjectContReaderFailedCallback; + + for (i = 0; i < BTHECHOSAMPLE_NUM_CONTINUOUS_READERS; i++) + { + status = BthEchoRepeatReaderInitialize( + Connection, + &Connection->ContinuousReader.RepeatReaders[i], + BufferSize + ); + + if (!NT_SUCCESS(status)) + { + break; + } + else + { + ++Connection->ContinuousReader.InitializedReadersCount; + } + } + + // + // In case of error (as well as on success) BthEchoEvtConnectionObjectCleanup + // will uninitialize readers + // + + return status; +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +NTSTATUS +BthEchoConnectionObjectContinuousReaderSubmitReaders( + _In_ PBTHECHO_CONNECTION Connection + ) +/*++ + +Description: + + This routine submits all the initialized repeat readers for the + connection + +Arguments: + + Connection - Connection whose repeat readers are to be submitted + +Return Value: + + NTSTATUS Status code. + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + UINT i; + + NT_ASSERT (Connection->ContinuousReader.InitializedReadersCount + <= BTHECHOSAMPLE_NUM_CONTINUOUS_READERS); + + for (i = 0; i < Connection->ContinuousReader.InitializedReadersCount; i++) + { + status = BthEchoRepeatReaderSubmit( + Connection->DevCtxHdr, + &Connection->ContinuousReader.RepeatReaders[i] + ); + + if (!NT_SUCCESS(status)) + { + goto exit; + } + } + +exit: + if (!NT_SUCCESS(status)) + { + // + // Cancel any submitted continuous readers + // We make sure that it is safe to call cancel on unsubmitted readers + // + + BthEchoConnectionObjectContinuousReaderCancelReaders(Connection); + } + + return status; +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +VOID +BthEchoConnectionObjectContinuousReaderCancelReaders( + _In_ PBTHECHO_CONNECTION Connection + ) +/*++ + +Description: + + This routine cancels all the initialized repeat readers for the + connection + +Arguments: + + Connection - Connection whose repeat readers are to be camcelled + +--*/ +{ + UINT i; + + NT_ASSERT (Connection->ContinuousReader.InitializedReadersCount + <= BTHECHOSAMPLE_NUM_CONTINUOUS_READERS); + + for (i = 0; i < Connection->ContinuousReader.InitializedReadersCount; i++) + { + BthEchoRepeatReaderCancel(&Connection->ContinuousReader.RepeatReaders[i]); + } +} + + +_IRQL_requires_max_(PASSIVE_LEVEL) +VOID +BthEchoConnectionObjectWaitForAndUninitializeContinuousReader( + _In_ PBTHECHO_CONNECTION Connection + ) +/*++ + +Description: + + This routine waits for and uninitializes all the initialized + continuous readers for the connection. + +Arguments: + + Connection - Connection whose continuous reader is to be uninitialized + +--*/ +{ + UINT i; + + PAGED_CODE(); + + NT_ASSERT (Connection->ContinuousReader.InitializedReadersCount + <= BTHECHOSAMPLE_NUM_CONTINUOUS_READERS); + + for (i = 0; i < Connection->ContinuousReader.InitializedReadersCount; i++) + { + PBTHECHO_REPEAT_READER repeatReader = &Connection->ContinuousReader.RepeatReaders[i]; + + BthEchoRepeatReaderWaitForStop(repeatReader); //It is OK to wait on unsubmitted readers + BthEchoRepeatReaderUninitialize(repeatReader); + } +} + +#pragma warning(push) +#pragma warning(disable:28118) // this callback will run at IRQL=PASSIVE_LEVEL +_Use_decl_annotations_ +VOID +BthEchoEvtConnectionObjectCleanup( + WDFOBJECT ConnectionObject + ) +/*++ + +Description: + + This routine is invoked by the Framework when connection object + gets deleted (either explicitly or implicitly because of parent + deletion). + + Since we mark ExecutionLevel as passive for connection object we get this + callback at passive level and can wait for stopping of continuous + readers and for disconnect to complete. + +Arguments: + + ConnectionObject - The Connection Object + +Return Value: + + None + +--*/ +{ + PBTHECHO_CONNECTION connection = GetConnectionObjectContext(ConnectionObject); + + PAGED_CODE(); + + BthEchoConnectionObjectWaitForAndUninitializeContinuousReader(connection); + + KeWaitForSingleObject(&connection->DisconnectEvent, + Executive, + KernelMode, + FALSE, + NULL); + + WdfObjectDelete(connection->ConnectDisconnectRequest); +} +#pragma warning(pop) // enable 28118 again + +_IRQL_requires_max_(DISPATCH_LEVEL) +NTSTATUS +BthEchoConnectionObjectInit( + _In_ WDFOBJECT ConnectionObject, + _In_ PBTHECHOSAMPLE_DEVICE_CONTEXT_HEADER DevCtxHdr + ) +/*++ + +Description: + + This routine initializes connection object. + It is invoked by BthEchoConnectionObjectCreate. + +Arguments: + + ConnectionObject - Object to initialize + DevCtxHdr - Device context header + +Return Value: + + NTSTATUS Status code. + +--*/ +{ + NTSTATUS status; + WDF_OBJECT_ATTRIBUTES attributes; + PBTHECHO_CONNECTION connection = GetConnectionObjectContext(ConnectionObject); + + + connection->DevCtxHdr = DevCtxHdr; + + connection->ConnectionState = ConnectionStateInitialized; + + // + // Initialize spinlock + // + + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + attributes.ParentObject = ConnectionObject; + + status = WdfSpinLockCreate( + &attributes, + &connection->ConnectionLock + ); + if (!NT_SUCCESS(status)) + { + goto exit; + } + + // + // Create connect/disconnect request + // + + status = WdfRequestCreate( + &attributes, + DevCtxHdr->IoTarget, + &connection->ConnectDisconnectRequest + ); + + if (!NT_SUCCESS(status)) + { + return status; + } + + // + // Initialize event + // + + KeInitializeEvent(&connection->DisconnectEvent, NotificationEvent, TRUE); + + // + // Initalize list entry + // + + InitializeListHead(&connection->ConnectionListEntry); + + connection->ConnectionState = ConnectionStateInitialized; + +exit: + return status; +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +NTSTATUS +BthEchoConnectionObjectCreate( + _In_ PBTHECHOSAMPLE_DEVICE_CONTEXT_HEADER DevCtxHdr, + _In_ WDFOBJECT ParentObject, + _Out_ WDFOBJECT* ConnectionObject + ) +/*++ + +Description: + + This routine creates a connection object. + This is called by client and server when a remote connection + is made. + +Arguments: + + DevCtxHdr - Device context header + ParentObject - Parent object for connection object + ConnectionObject - receives the created connection object + +Return Value: + + NTSTATUS Status code. + +--*/ +{ + NTSTATUS status; + WDF_OBJECT_ATTRIBUTES attributes; + WDFOBJECT connectionObject = NULL; + + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, BTHECHO_CONNECTION); + attributes.ParentObject = ParentObject; + attributes.EvtCleanupCallback = BthEchoEvtConnectionObjectCleanup; + + // + // We set execution level to passive so that we get cleanup at passive + // level where we can wait for continuous readers to run down + // and for completion of disconnect + // + attributes.ExecutionLevel = WdfExecutionLevelPassive; + + status = WdfObjectCreate( + &attributes, + &connectionObject + ); + + if (!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, DBG_CONNECT, + "WdfObjectCreate for connection object failed, Status code %!STATUS!\n", status); + + goto exit; + } + + status = BthEchoConnectionObjectInit(connectionObject, DevCtxHdr); + + if (!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, DBG_CONNECT, + "Context initialize for connection object failed, ConnectionObject 0x%p, Status code %!STATUS!\n", + connectionObject, + status + ); + + goto exit; + } + + *ConnectionObject = connectionObject; + +exit: + if(!NT_SUCCESS(status) && connectionObject) + { + WdfObjectDelete(connectionObject); + } + + return status; +} + +EVT_WDF_REQUEST_COMPLETION_ROUTINE +BthEchoConnectionObjectDisconnectCompletion; + +void +BthEchoConnectionObjectDisconnectCompletion( + _In_ WDFREQUEST Request, + _In_ WDFIOTARGET Target, + _In_ PWDF_REQUEST_COMPLETION_PARAMS Params, + _In_ WDFCONTEXT Context + ) +/*++ + +Description: + + Completion routine for disconnect BRB completion + + In this routine we set the connection to disconnect + and set the DisconnectEvent. + +Arguments: + + Request - Request completed + Target - Target to which request was sent + Params - Completion parameters + Context - We receive connection as the context + +--*/ +{ + PBTHECHO_CONNECTION connection = (PBTHECHO_CONNECTION) Context; + + UNREFERENCED_PARAMETER(Request); + UNREFERENCED_PARAMETER(Target); + UNREFERENCED_PARAMETER(Params); + + WdfSpinLockAcquire(connection->ConnectionLock); + connection->ConnectionState = ConnectionStateDisconnected; + WdfSpinLockRelease(connection->ConnectionLock); + + // + // Disconnect complete, set the event + // + + KeSetEvent( + &connection->DisconnectEvent, + 0, + FALSE + ); +} + + +_IRQL_requires_max_(DISPATCH_LEVEL) +BOOLEAN +BthEchoConnectionObjectRemoteDisconnect( + _In_ PBTHECHOSAMPLE_DEVICE_CONTEXT_HEADER DevCtxHdr, + _In_ PBTHECHO_CONNECTION Connection + ) +/*++ + +Description: + + This routine sends a disconnect BRB for the connection + +Arguments: + + DevCtxHdr - Device context header + Connection - Connection which is to be disconnected + +Return Value: + + TRUE is this call initiates the disconnect. + FALSE if the connection was already disconnected. + +--*/ +{ + struct _BRB_L2CA_CLOSE_CHANNEL * disconnectBrb; + + // + // Cancel continuous readers for the connection + // + BthEchoConnectionObjectContinuousReaderCancelReaders(Connection); + + WdfSpinLockAcquire(Connection->ConnectionLock); + + if (Connection->ConnectionState == ConnectionStateConnecting) + { + // + // If the connection is not completed yet set the state + // to disconnecting. + // In such case we should send CLOSE_CHANNEL Brb down after + // we receive connect completion. + // + + Connection->ConnectionState = ConnectionStateDisconnecting; + + // + // Clear event to indicate that we are in disconnecting + // state. It will be set when disconnect is completed + // + KeClearEvent(&Connection->DisconnectEvent); + + WdfSpinLockRelease(Connection->ConnectionLock); + return TRUE; + + } + else if (Connection->ConnectionState != ConnectionStateConnected) + { + // + // Do nothing if we are not connected + // + + WdfSpinLockRelease(Connection->ConnectionLock); + return FALSE; + } + + Connection->ConnectionState = ConnectionStateDisconnecting; + WdfSpinLockRelease(Connection->ConnectionLock); + + // + // We are now sending the disconnect, so clear the event. + // + + KeClearEvent(&Connection->DisconnectEvent); + + DevCtxHdr->ProfileDrvInterface.BthReuseBrb(&Connection->ConnectDisconnectBrb, BRB_L2CA_CLOSE_CHANNEL); + + disconnectBrb = (struct _BRB_L2CA_CLOSE_CHANNEL *) &(Connection->ConnectDisconnectBrb); + + disconnectBrb->BtAddress = Connection->RemoteAddress; + disconnectBrb->ChannelHandle = Connection->ChannelHandle; + + // + // The BRB can fail with STATUS_DEVICE_DISCONNECT if the device is already + // disconnected, hence we don't assert for success + // + + (void) BthEchoSharedSendBrbAsync( + DevCtxHdr->IoTarget, + Connection->ConnectDisconnectRequest, + (PBRB) disconnectBrb, + sizeof(*disconnectBrb), + BthEchoConnectionObjectDisconnectCompletion, + Connection + ); + + return TRUE; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +VOID +BthEchoConnectionObjectRemoteDisconnectSynchronously( + _In_ PBTHECHOSAMPLE_DEVICE_CONTEXT_HEADER DevCtxHdr, + _In_ PBTHECHO_CONNECTION Connection + ) +/*++ + +Description: + + This routine disconnects the connection synchronously + +Arguments: + + DevCtxHdr - Device context header + Connection - Connection which is to be disconnected + +--*/ +{ + PAGED_CODE(); + + BthEchoConnectionObjectRemoteDisconnect(DevCtxHdr, Connection); + + KeWaitForSingleObject(&Connection->DisconnectEvent, + Executive, + KernelMode, + FALSE, + NULL + ); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +NTSTATUS +FormatRequestWithBrb( + _In_ WDFIOTARGET IoTarget, + _In_ WDFREQUEST Request, + _In_ PBRB Brb, + _In_ size_t BrbSize + ) +/*++ + +Description: + + This routine formats are WDFREQUEST with the passed in BRB + +Arguments: + + IoTarget - Target to which request will be sent + Request - Request to be formattted + Brb - BRB to format the request with + BrbSize - size of the BRB + +--*/ +{ + NTSTATUS status = BTH_ERROR_SUCCESS; + WDF_OBJECT_ATTRIBUTES attributes; + WDFMEMORY memoryArg1 = NULL; + + if (BrbSize <= 0) + { + TraceEvents(TRACE_LEVEL_ERROR, DBG_UTIL, + "BrbSize has an invalid value: %I64d\n", + BrbSize + ); + + status = STATUS_INVALID_PARAMETER; + + goto exit; + } + + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + attributes.ParentObject = Request; + + status = WdfMemoryCreatePreallocated( + &attributes, + Brb, + BrbSize, + &memoryArg1 + ); + + if (!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, DBG_UTIL, + "Creating preallocted memory for Brb 0x%p failed, Request to be formatted 0x%p, " + "Status code %!STATUS!\n", + Brb, + Request, + status + ); + + goto exit; + } + + status = WdfIoTargetFormatRequestForInternalIoctlOthers( + IoTarget, + Request, + IOCTL_INTERNAL_BTH_SUBMIT_BRB, + memoryArg1, + NULL, //OtherArg1Offset + NULL, //OtherArg2 + NULL, //OtherArg2Offset + NULL, //OtherArg4 + NULL //OtherArg4Offset + ); + + if (!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, DBG_UTIL, + "Formatting request 0x%p with Brb 0x%p failed, Status code %!STATUS!\n", + Request, + Brb, + status + ); + + goto exit; + } +exit: + return status; +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +_When_(return==0, _At_(*Brb, __drv_allocatesMem(Mem))) +NTSTATUS +BthEchoConnectionObjectFormatRequestForL2CaTransfer( + _In_ PBTHECHO_CONNECTION Connection, + _In_ WDFREQUEST Request, + _Inout_ struct _BRB_L2CA_ACL_TRANSFER ** Brb, + _In_ WDFMEMORY Memory, + _In_ ULONG TransferFlags //flags include direction of transfer + ) +/*++ + +Description: + + Formats a request for L2Ca transfer + +Arguments: + + Connection - Connection on which L2Ca transfer will be made + Request - Request to be formatted + Brb - If a Brb is passed in, it will be used, otherwise + this routine will allocate the Brb and return in this parameter + Memory - Memory object which has the buffer for transfer + TransferFlags - Transfer flags which include direction of the transfer + +Return Value: + + NTSTATUS Status code. + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + struct _BRB_L2CA_ACL_TRANSFER *brb = NULL; + size_t bufferSize; + BOOLEAN brbAllocatedLocally = FALSE; //whether this function allocated the BRB + + WdfSpinLockAcquire(Connection->ConnectionLock); + + if(Connection->ConnectionState != ConnectionStateConnected) + { + status = STATUS_CONNECTION_DISCONNECTED; + WdfSpinLockRelease(Connection->ConnectionLock); + goto exit; + } + + WdfSpinLockRelease(Connection->ConnectionLock); + + if (NULL == *Brb) + { + brb= (struct _BRB_L2CA_ACL_TRANSFER *) + Connection->DevCtxHdr->ProfileDrvInterface.BthAllocateBrb( + BRB_L2CA_ACL_TRANSFER, + POOLTAG_BTHECHOSAMPLE + ); + if(!brb) + { + status = STATUS_INSUFFICIENT_RESOURCES; + + TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, + "Failed to allocate BRB_L2CA_ACL_TRANSFER, returning status code %!STATUS!\n", status); + + goto exit; + } + else + { + brbAllocatedLocally = TRUE; + } + } + else + { + brb = *Brb; + Connection->DevCtxHdr->ProfileDrvInterface.BthReuseBrb( + (PBRB)brb, BRB_L2CA_ACL_TRANSFER + ); + } + + brb->BtAddress = Connection->RemoteAddress; + brb->BufferMDL = NULL; + brb->Buffer = WdfMemoryGetBuffer(Memory, &bufferSize); + + __analysis_assume(bufferSize <= (ULONG)(-1)); + if (bufferSize > (ULONG)(-1)) + { + status = STATUS_BUFFER_OVERFLOW; + + TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, + "Buffer passed in longer than max ULONG, returning status code %!STATUS!\n", status); + + goto exit; + } + + brb->BufferSize = (ULONG) bufferSize; + brb->ChannelHandle = Connection->ChannelHandle; + brb->TransferFlags = TransferFlags; + + status = FormatRequestWithBrb( + Connection->DevCtxHdr->IoTarget, + Request, + (PBRB) brb, + sizeof(*brb) + ); + + if (!NT_SUCCESS(status)) + { + goto exit; + } + + if (NULL == *Brb) + { + *Brb = brb; + } +exit: + if (!NT_SUCCESS(status) && brb && brbAllocatedLocally) + { + Connection->DevCtxHdr->ProfileDrvInterface.BthFreeBrb((PBRB)brb); + } + + return status; +} diff --git a/bluetooth/serialhcibus/BluetoothHCISampleBusDriver.htm b/bluetooth/serialhcibus/BluetoothHCISampleBusDriver.htm new file mode 100644 index 00000000..375b609d --- /dev/null +++ b/bluetooth/serialhcibus/BluetoothHCISampleBusDriver.htm @@ -0,0 +1,2333 @@ + + + + + + + + +BluetoothHciSampleBusDriver + + + + + + + + + +
+ +

README—Bluetooth Serial HCI Sample Bus Driver

+ +

 

+ +

VERSION 0.2

+ +

 

+ +

Note: The sample driver & this documentation are +in their pre-release versions, thus they are both subject to change at any time

+ +

 

+ +

6/22/2011

+ +

AUTHOR - Windows Bluetooth

+ +

1       Document purpose

+ +

 

+ +

The purpose of this +sample is to demonstrate how to implement a basic bus driver to support the new +Bluetooth Extensibility transport DDIs over the UART transport. Such a serial +bus driver can support a multi-radio device over the UART transport and utilize +a common Bluetooth HCI packet for communication. The lower edge of this driver +interfaces with a UART controller following the Bluetooth SIG’s UART (H4) +transport protocol.

+ +

 

+ +

Note:

+ +

·         This sample driver is generic—i.e. it is +not designed for a specific device and allows for a vendor to adopt and enhance +it for supporting Bluetooth

+ +

·         This sample driver, as is, may not +properly function for a device until all vendor-specific device requirements +(e.g. device initialization) have been incorporated

+ +

·         It is recommended to use WDK whose +version matches the target Windows build version or newer for the development +of the serial bus driver

+ +

 

+ +

2       Building the sample

+ +

 

+ +

1.       Open the project file (SerialHciBus\WDK\SerialBusWDK VC++ +project) from Visual Studio Dev11 to build this project.

+ +

2.       After rebuilding the driver, you can +find SerialBusWDK.sys/pdb/inf +files.

+ +

 

+ +

3       Directory Manifest

+ +

 

+ +

File Description

+ +

SerialHciBus – contains files for the Bluetooth +serial HCI bus driver

+ +

SerialHciBus\Wdk – +contains driver code for device specific functions (produces SerialBusWdk.sys +and SerialBusWdk.inf)

+ +

 

+ +

4       File Manifest

+ +

4.1        WDK header file

+ +

·         BthXDDI.h – this has the constants, +struct, and IOCTL definitions for the Bluetooth extensibility transport. This +header file is included in WDK.

+ +

4.2        Common code section

+ +
    +
  1. driver.c – driver initialization
  2. +
  3. driver.h – common header file for driver.c and includes other header files
  4. +
  5. Fdo.c – functions for function + device object (FDO) and BTHX DDI processing
  6. +
  7. io.c – functions that perform IO + read pump via UART controller
  8. +
  9. Io.h – header for io.c
  10. +
  11. pdo.c – PDO (Bluetooth function) + enumeration and IOCTL processing
  12. +
  13. public.h – header to share with + application to support Radio On/Off (“Airplane mode”)
  14. +
+ +

 

+ +

Note: The goal is to +keep the common code section the same, so the vendor will only need to update +those code sections in the device specific directory.

+ +

4.3        Device-specific code section

+ +
    +
  1. Debugdef.h – WPP trace GUID; user should + use a new GUID (unique per driver)
  2. +
  3. device.c – device specific functions to + implement
  4. +
      +
    1. DeviceInitialize() + – to perform UART and Bluetooth device initialization;
    2. +
    3. DeviceEnable() + – (optional) to bring serial bus device out of disable/reset state.
    4. +
    5. DevicePowerOn() + – (optional) to power on the device.
    6. +
    7. DeviceEnableWakeControl() – (optional) to arm for device wake signal
    8. +
    9. DeviceDisableWakeControl() – (optional) to disarm for device wake signal
    10. +
    +
  5. device.h – header file for device.c
  6. +
  7. driver.rc – driver version and name
  8. +
  9. SerialBusWdk.inx – device specific INF file to + install this driver. The vendor will need to add the hardware ID to match + the “_HID” for the Serial Bus Device (Bluetooth) in the DSDT.asl file. For example, in SerialBusWDK.inx, + the hardware ID is “ACPI\<Vendor>_BTH0” where “<vendor>” could + be a 4 digit vendor name
  10. +
+ +

 

+ +

5       Installation

+ +

 

+ +

The vendor can adopt +this driver to add device specific functions, e.g. vendor-specific device +initialization. After this is completed, the following steps can be followed to +perform device installation in order to test the driver:

+ +

·         Copy driver and inf file to a directory on the test system

+ +

·         Perform “Update Driver” on the devnode corresponding to the hardware ID in the DSDT.asl file for this multifunction serial bus driver

+ +

·         Point the installation to the +directory to find the INF and sys files

+ +

·         Upon successful installation, you will +see “Serial Bus Driver over UART Bus Enumerator" in Device Manager under +the Ports device class

+ +

·         Upon successful installation of the +serial bus driver, a PDO will be created with a compat ID of “MS_BTHX_BTHMINI.” +This will cause PnP to find the match in bth.inf to perform the installation of +the Bluetooth core components with its extensibility transport

+ +

 

+ +

Pre-requisite: +DSDT.ASL

+ +

A multifunction serial +bus device is a peripheral device on a SoC platform. Its configuration is often +defined in the DSDT.asl (Differentiated System +Description Table) file to reflect its configuration and interconnection with a +UART controller and other optional dependent controllers, e.g. I2C, GPIO, etc. +for additional control.

+ +

Here is an +(incomplete) sample system bus device section of a DSDT.ASL file for a UART +controller and a multifunction serial bus device that supports Bluetooth. For +details, please reference the document “Minimum WOA ACPI Requirements.docx” +from Microsoft.

+ +

 

+ +

//

+ +

// +UART where a serial bus device is connected to

+ +

//

+ +

Device +(UAR1)

+ +

{

+ +

    +Name (_HID, "ABCD_UART")      // where +“ABCD” is vendor name;

+ +

    +// …

+ +

 

+ +

    +Name (_CID, "ACPI\ABCD_UART")

+ +

    +Name (_UID, 6)

+ +

 

+ +

    +Method (_CRS, 0x0, NotSerialized) {

+ +

        +Name (RBUF, ResourceTemplate ()

+ +

        +{

+ +

                     +…

+ +

        +})

+ +

        +Return (RBUF)

+ +

    +}

+ +

}

+ +

 

+ +

//

+ +

// +Multifunction serial bus device to support Bluetooth function

+ +

//

+ +

Device(BTH0)

+ +

{

+ +

    +// ACPI enumerate will generate a hardware ID “ACPI\ABCD_BTH0”

+ +

    +Name (_HID, "ABCD_BTH0") // where “ABCD” is vendor name; 

+ +

       + 

+ +

    +Method(_CRS, 0x0, NotSerialized)

+ +

    +{

+ +

        +Name (RBUF, ResourceTemplate ()

+ +

        +{

+ +

        +// GPIO Descriptor

+ +

        +// (optional)

+ +

 

+ +

        +// I2C Serial Bus Descriptor

+ +

        +// (optional)

+ +

 

+ +

        +// UART Serial Bus Descriptor

+ +

        +UARTSerialBus (

+ +

      0xC0, // RTS | +CTS

+ +

      LittleEndian,

+ +

      DataBitsEight,

+ +

      StopBitsOne,

+ +

      FlowControlHardware,

+ +

      115200, // +Initial Baudrate

+ +

      480, // Rx FIFO +size

+ +

      32, // Tx FIFO size

+ +

      ParityTypeNone,

+ +

      +"\\_SB.UAR1", , )

+ +

        +})

+ +

        +Return +(RBUF)            

+ +

    +}

+ +

}

+ +

 

+ +

6       Resources

+ +

 

+ +

For the latest release +of the Windows device Driver Development Kit, see http://www.microsoft.com/whdc/. +

+ +

 

+ +

Please see the latest +WDK release for documentation on Bluetooth and WDF.

+ +

 

+ +

Bus Driver Development +Based on KMDF http://msdn.microsoft.com/en-us/windows/hardware/gg463281.aspx

+ +
+ + + + diff --git a/bluetooth/serialhcibus/WDK/SerialBusWdk.vcxproj b/bluetooth/serialhcibus/WDK/SerialBusWdk.vcxproj index 770cb2e7..1b1088b1 100644 --- a/bluetooth/serialhcibus/WDK/SerialBusWdk.vcxproj +++ b/bluetooth/serialhcibus/WDK/SerialBusWdk.vcxproj @@ -19,12 +19,12 @@
- {B126E3A5-91B5-41B5-9B40-719D474AA513} + {186E63FF-9F2F-4FF6-82CB-FBAD7BA24089} $(MSBuildProjectName) 1 Debug Win32 - {0929A3E4-68D7-482B-93C5-539571CF51D7} + {B81CFC73-D7CD-484D-B134-1D6AC0106514} diff --git a/bluetooth/serialhcibus/WDK/SerialBusWdk.vcxproj.Filters b/bluetooth/serialhcibus/WDK/SerialBusWdk.vcxproj.Filters index 83b788e4..90e9b2a7 100644 --- a/bluetooth/serialhcibus/WDK/SerialBusWdk.vcxproj.Filters +++ b/bluetooth/serialhcibus/WDK/SerialBusWdk.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {4614A6EB-0DDA-4E7D-B6B7-1AC9BF5F6AAA} + {201450EB-D675-4E41-BAAC-8BF2E93F8BA4} h;hpp;hxx;hm;inl;inc;xsd - {A95E3765-07D5-45E1-B82E-8D9EF61CD4BC} + {28214B85-07EC-4DAA-9EE8-7ECB4867524B} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {4E3D8A20-8B42-428D-AAEB-A5BA3C5C33C5} + {CCE43425-7067-4FF7-A1FA-B55E892E4CF6} inf;inv;inx;mof;mc; - {C6A2211E-78CA-4EFF-85FD-A921F4F8EB29} + {678E1E03-C75C-4BFD-A872-84A5F2191188} diff --git a/bluetooth/serialhcibus/serialhcibus.sln b/bluetooth/serialhcibus/serialhcibus.sln index 06bf3320..f299309d 100644 --- a/bluetooth/serialhcibus/serialhcibus.sln +++ b/bluetooth/serialhcibus/serialhcibus.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SerialBusWdk", "WDK\SerialBusWdk.vcxproj", "{B126E3A5-91B5-41B5-9B40-719D474AA513}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SerialBusWdk", "WDK\SerialBusWdk.vcxproj", "{186E63FF-9F2F-4FF6-82CB-FBAD7BA24089}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +13,14 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {B126E3A5-91B5-41B5-9B40-719D474AA513}.Debug|Win32.ActiveCfg = Debug|Win32 - {B126E3A5-91B5-41B5-9B40-719D474AA513}.Debug|Win32.Build.0 = Debug|Win32 - {B126E3A5-91B5-41B5-9B40-719D474AA513}.Release|Win32.ActiveCfg = Release|Win32 - {B126E3A5-91B5-41B5-9B40-719D474AA513}.Release|Win32.Build.0 = Release|Win32 - {B126E3A5-91B5-41B5-9B40-719D474AA513}.Debug|x64.ActiveCfg = Debug|x64 - {B126E3A5-91B5-41B5-9B40-719D474AA513}.Debug|x64.Build.0 = Debug|x64 - {B126E3A5-91B5-41B5-9B40-719D474AA513}.Release|x64.ActiveCfg = Release|x64 - {B126E3A5-91B5-41B5-9B40-719D474AA513}.Release|x64.Build.0 = Release|x64 + {186E63FF-9F2F-4FF6-82CB-FBAD7BA24089}.Debug|Win32.ActiveCfg = Debug|Win32 + {186E63FF-9F2F-4FF6-82CB-FBAD7BA24089}.Debug|Win32.Build.0 = Debug|Win32 + {186E63FF-9F2F-4FF6-82CB-FBAD7BA24089}.Release|Win32.ActiveCfg = Release|Win32 + {186E63FF-9F2F-4FF6-82CB-FBAD7BA24089}.Release|Win32.Build.0 = Release|Win32 + {186E63FF-9F2F-4FF6-82CB-FBAD7BA24089}.Debug|x64.ActiveCfg = Debug|x64 + {186E63FF-9F2F-4FF6-82CB-FBAD7BA24089}.Debug|x64.Build.0 = Debug|x64 + {186E63FF-9F2F-4FF6-82CB-FBAD7BA24089}.Release|x64.ActiveCfg = Release|x64 + {186E63FF-9F2F-4FF6-82CB-FBAD7BA24089}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/filesys/cdfs/cddata.c b/filesys/cdfs/cddata.c index 19648e36..15cfe2d5 100644 --- a/filesys/cdfs/cddata.c +++ b/filesys/cdfs/cddata.c @@ -194,7 +194,22 @@ CDFS_TELEMETRY_DATA_CONTEXT CdTelemetryData; #pragma alloc_text(PAGE, CdSetThreadContext) #endif - +_IRQL_requires_max_(APC_LEVEL) +__drv_dispatchType(DRIVER_DISPATCH) +__drv_dispatchType(IRP_MJ_CREATE) +__drv_dispatchType(IRP_MJ_CLOSE) +__drv_dispatchType(IRP_MJ_READ) +__drv_dispatchType(IRP_MJ_WRITE) +__drv_dispatchType(IRP_MJ_QUERY_INFORMATION) +__drv_dispatchType(IRP_MJ_SET_INFORMATION) +__drv_dispatchType(IRP_MJ_QUERY_VOLUME_INFORMATION) +__drv_dispatchType(IRP_MJ_DIRECTORY_CONTROL) +__drv_dispatchType(IRP_MJ_FILE_SYSTEM_CONTROL) +__drv_dispatchType(IRP_MJ_DEVICE_CONTROL) +__drv_dispatchType(IRP_MJ_LOCK_CONTROL) +__drv_dispatchType(IRP_MJ_CLEANUP) +__drv_dispatchType(IRP_MJ_PNP) +__drv_dispatchType(IRP_MJ_SHUTDOWN) NTSTATUS CdFsdDispatch ( _In_ PDEVICE_OBJECT DeviceObject, diff --git a/filesys/cdfs/cdfs.sln b/filesys/cdfs/cdfs.sln index 1dbf3f5c..b45ac8df 100644 --- a/filesys/cdfs/cdfs.sln +++ b/filesys/cdfs/cdfs.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cdfs", "cdfs.vcxproj", "{CF3DA8BB-C366-42EF-B62B-F3D799F94B72}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cdfs", "cdfs.vcxproj", "{6E1BC036-32B6-4CDA-A44E-13471EF68E06}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +13,14 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {CF3DA8BB-C366-42EF-B62B-F3D799F94B72}.Debug|Win32.ActiveCfg = Debug|Win32 - {CF3DA8BB-C366-42EF-B62B-F3D799F94B72}.Debug|Win32.Build.0 = Debug|Win32 - {CF3DA8BB-C366-42EF-B62B-F3D799F94B72}.Release|Win32.ActiveCfg = Release|Win32 - {CF3DA8BB-C366-42EF-B62B-F3D799F94B72}.Release|Win32.Build.0 = Release|Win32 - {CF3DA8BB-C366-42EF-B62B-F3D799F94B72}.Debug|x64.ActiveCfg = Debug|x64 - {CF3DA8BB-C366-42EF-B62B-F3D799F94B72}.Debug|x64.Build.0 = Debug|x64 - {CF3DA8BB-C366-42EF-B62B-F3D799F94B72}.Release|x64.ActiveCfg = Release|x64 - {CF3DA8BB-C366-42EF-B62B-F3D799F94B72}.Release|x64.Build.0 = Release|x64 + {6E1BC036-32B6-4CDA-A44E-13471EF68E06}.Debug|Win32.ActiveCfg = Debug|Win32 + {6E1BC036-32B6-4CDA-A44E-13471EF68E06}.Debug|Win32.Build.0 = Debug|Win32 + {6E1BC036-32B6-4CDA-A44E-13471EF68E06}.Release|Win32.ActiveCfg = Release|Win32 + {6E1BC036-32B6-4CDA-A44E-13471EF68E06}.Release|Win32.Build.0 = Release|Win32 + {6E1BC036-32B6-4CDA-A44E-13471EF68E06}.Debug|x64.ActiveCfg = Debug|x64 + {6E1BC036-32B6-4CDA-A44E-13471EF68E06}.Debug|x64.Build.0 = Debug|x64 + {6E1BC036-32B6-4CDA-A44E-13471EF68E06}.Release|x64.ActiveCfg = Release|x64 + {6E1BC036-32B6-4CDA-A44E-13471EF68E06}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/filesys/cdfs/cdfs.vcxproj b/filesys/cdfs/cdfs.vcxproj index 8e87f675..4c0cae16 100644 --- a/filesys/cdfs/cdfs.vcxproj +++ b/filesys/cdfs/cdfs.vcxproj @@ -19,12 +19,12 @@ - {CF3DA8BB-C366-42EF-B62B-F3D799F94B72} + {6E1BC036-32B6-4CDA-A44E-13471EF68E06} $(MSBuildProjectName) false Debug Win32 - {1340E057-CDDF-46D6-B5D9-394AF1B2CA07} + {B7974984-CC80-44F6-A5FF-3450139B650B} diff --git a/filesys/cdfs/cdfs.vcxproj.Filters b/filesys/cdfs/cdfs.vcxproj.Filters index e5978b9a..f9071fe0 100644 --- a/filesys/cdfs/cdfs.vcxproj.Filters +++ b/filesys/cdfs/cdfs.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {6041F7C5-67BE-4EBD-A1B8-53A22C207899} + {DDD1C6BA-4FDB-4B31-8CA1-A98A3B87BCAD} h;hpp;hxx;hm;inl;inc;xsd - {7B185A7C-1201-4E8B-80F4-79EC615CB7F0} + {6330F9B6-65BA-4A38-955C-1968DCB91EDE} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {2979BE05-350C-4B63-96FF-B319CCBD776F} + {D575D231-5B8E-4A00-BBEF-7105E4F2B0FB} inf;inv;inx;mof;mc; - {217A878D-9867-4135-9B60-4809FBE6E1CE} + {B1FE81D8-D0AC-4BB6-B311-CF9DA3709742} diff --git a/filesys/cdfs/cdprocs.h b/filesys/cdfs/cdprocs.h index 6645e539..d2f7db0b 100644 --- a/filesys/cdfs/cdprocs.h +++ b/filesys/cdfs/cdprocs.h @@ -1707,13 +1707,29 @@ CdLbnToMmSsFf ( // contained in CdData.c // -// NTSTATUS -// CdFsdDispatch ( -// _In_ PDEVICE_OBJECT DeviceObject, -// _Inout_ PIRP Irp -// ); +_IRQL_requires_max_(APC_LEVEL) +__drv_dispatchType(DRIVER_DISPATCH) +__drv_dispatchType(IRP_MJ_CREATE) +__drv_dispatchType(IRP_MJ_CLOSE) +__drv_dispatchType(IRP_MJ_READ) +__drv_dispatchType(IRP_MJ_WRITE) +__drv_dispatchType(IRP_MJ_QUERY_INFORMATION) +__drv_dispatchType(IRP_MJ_SET_INFORMATION) +__drv_dispatchType(IRP_MJ_QUERY_VOLUME_INFORMATION) +__drv_dispatchType(IRP_MJ_DIRECTORY_CONTROL) +__drv_dispatchType(IRP_MJ_FILE_SYSTEM_CONTROL) +__drv_dispatchType(IRP_MJ_DEVICE_CONTROL) +__drv_dispatchType(IRP_MJ_LOCK_CONTROL) +__drv_dispatchType(IRP_MJ_CLEANUP) +__drv_dispatchType(IRP_MJ_PNP) +__drv_dispatchType(IRP_MJ_SHUTDOWN) +NTSTATUS +CdFsdDispatch ( + _In_ PDEVICE_OBJECT DeviceObject, + _Inout_ PIRP Irp + ); -DRIVER_DISPATCH CdFsdDispatch; +// DRIVER_DISPATCH CdFsdDispatch; LONG CdExceptionFilter ( diff --git a/filesys/cdfs/deviosup.c b/filesys/cdfs/deviosup.c index a6a69c64..b2f9467b 100644 --- a/filesys/cdfs/deviosup.c +++ b/filesys/cdfs/deviosup.c @@ -3544,7 +3544,9 @@ Return Value: PCD_IO_CONTEXT IoContext = Context; _Analysis_assume_(Context != NULL); AssertVerifyDeviceIrp( Irp ); - + + UNREFERENCED_PARAMETER( DeviceObject ); + // // If we got an error (or verify required), remember it in the Irp // @@ -3614,7 +3616,6 @@ Return Value: return STATUS_MORE_PROCESSING_REQUIRED; } - UNREFERENCED_PARAMETER( DeviceObject ); } @@ -3718,6 +3719,8 @@ Return Value: { PCD_IO_CONTEXT IoContext = Context; + UNREFERENCED_PARAMETER( DeviceObject ); + _Analysis_assume_(IoContext != NULL); AssertVerifyDeviceIrp( Irp ); @@ -3742,6 +3745,7 @@ Return Value: // Now release the resource // + _Analysis_assume_lock_held_(*IoContext->Resource); ExReleaseResourceForThreadLite( IoContext->Resource, IoContext->ResourceThreadId ); // @@ -3751,7 +3755,6 @@ Return Value: CdFreeIoContext( IoContext ); return STATUS_SUCCESS; - UNREFERENCED_PARAMETER( DeviceObject ); } diff --git a/filesys/miniFilter/MetadataManager/MetadataManager.sln b/filesys/miniFilter/MetadataManager/MetadataManager.sln index 9af2fc43..6f4e3cb4 100644 --- a/filesys/miniFilter/MetadataManager/MetadataManager.sln +++ b/filesys/miniFilter/MetadataManager/MetadataManager.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fmm", "fmm.vcxproj", "{A95B7D4F-B926-4E1F-A051-E66091E08D3A}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fmm", "fmm.vcxproj", "{D7BF32EC-9C86-43C5-B512-9D40E9617518}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +13,14 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {A95B7D4F-B926-4E1F-A051-E66091E08D3A}.Debug|Win32.ActiveCfg = Debug|Win32 - {A95B7D4F-B926-4E1F-A051-E66091E08D3A}.Debug|Win32.Build.0 = Debug|Win32 - {A95B7D4F-B926-4E1F-A051-E66091E08D3A}.Release|Win32.ActiveCfg = Release|Win32 - {A95B7D4F-B926-4E1F-A051-E66091E08D3A}.Release|Win32.Build.0 = Release|Win32 - {A95B7D4F-B926-4E1F-A051-E66091E08D3A}.Debug|x64.ActiveCfg = Debug|x64 - {A95B7D4F-B926-4E1F-A051-E66091E08D3A}.Debug|x64.Build.0 = Debug|x64 - {A95B7D4F-B926-4E1F-A051-E66091E08D3A}.Release|x64.ActiveCfg = Release|x64 - {A95B7D4F-B926-4E1F-A051-E66091E08D3A}.Release|x64.Build.0 = Release|x64 + {D7BF32EC-9C86-43C5-B512-9D40E9617518}.Debug|Win32.ActiveCfg = Debug|Win32 + {D7BF32EC-9C86-43C5-B512-9D40E9617518}.Debug|Win32.Build.0 = Debug|Win32 + {D7BF32EC-9C86-43C5-B512-9D40E9617518}.Release|Win32.ActiveCfg = Release|Win32 + {D7BF32EC-9C86-43C5-B512-9D40E9617518}.Release|Win32.Build.0 = Release|Win32 + {D7BF32EC-9C86-43C5-B512-9D40E9617518}.Debug|x64.ActiveCfg = Debug|x64 + {D7BF32EC-9C86-43C5-B512-9D40E9617518}.Debug|x64.Build.0 = Debug|x64 + {D7BF32EC-9C86-43C5-B512-9D40E9617518}.Release|x64.ActiveCfg = Release|x64 + {D7BF32EC-9C86-43C5-B512-9D40E9617518}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/filesys/miniFilter/MetadataManager/fmm.vcxproj b/filesys/miniFilter/MetadataManager/fmm.vcxproj index c2da0192..08369fc5 100644 --- a/filesys/miniFilter/MetadataManager/fmm.vcxproj +++ b/filesys/miniFilter/MetadataManager/fmm.vcxproj @@ -19,11 +19,11 @@ - {A95B7D4F-B926-4E1F-A051-E66091E08D3A} + {D7BF32EC-9C86-43C5-B512-9D40E9617518} $(MSBuildProjectName) Debug Win32 - {DD166882-E368-4576-B537-05B15D55B977} + {7C86E1A6-1B03-4023-BC29-22867C198C7F} diff --git a/filesys/miniFilter/MetadataManager/fmm.vcxproj.Filters b/filesys/miniFilter/MetadataManager/fmm.vcxproj.Filters index b76f8eb2..49f80878 100644 --- a/filesys/miniFilter/MetadataManager/fmm.vcxproj.Filters +++ b/filesys/miniFilter/MetadataManager/fmm.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {3AEFB0E9-101A-43AB-8E44-D384CB8D17F8} + {50875A86-C80E-4F00-B5E6-F8750B4A63D5} h;hpp;hxx;hm;inl;inc;xsd - {58BAA0C3-0CF4-438F-A011-53C6310A7E5E} + {47046E6F-7445-430F-9F9F-33D5F2C15DDA} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {168C91BC-EA8F-4E36-9315-77ACF64E6FA7} + {392DBF7C-4449-4E3A-9354-2F7AC7DCDE78} inf;inv;inx;mof;mc; - {95E307D5-2257-4A2D-AA47-58C291F7AF68} + {E94FBEAE-1CA4-4F77-93A5-934B5212B838} diff --git a/filesys/miniFilter/NameChanger/NameChanger.inf b/filesys/miniFilter/NameChanger/NameChanger.inf new file mode 100644 index 00000000..a79016a6 --- /dev/null +++ b/filesys/miniFilter/NameChanger/NameChanger.inf @@ -0,0 +1,105 @@ +;;; +;;; NameChanger +;;; +;;; +;;; Copyright (c) 1999 - 2001, Microsoft Corporation +;;; + +[Version] +Signature = "$Windows NT$" +Class = "ActivityMonitor" ;This is determined by the work this filter driver does +ClassGuid = {b86dff51-a31e-4bac-b3cf-e8cfe75c9fc2} ;This value is determined by the Class +Provider = %Msft% +DriverVer = 06/05/2009,1.0.0.1 +CatalogFile = NameChanger.cat + +[SourceDisksNames] +12=%ServiceDescription%,,, + +[SourceDisksFiles] +NameChanger.sys = 12 + + +[DestinationDirs] +DefaultDestDir = 12 +NameChanger.DriverFiles = 12 ;%windir%\system32\drivers + +;; +;; Default install sections +;; + +[DefaultInstall] +OptionDesc = %ServiceDescription% +CopyFiles = NameChanger.DriverFiles + +[DefaultInstall.Services] +AddService = %ServiceName%,,NameChanger.Service + +;; +;; Default uninstall sections +;; + +[DefaultUninstall] +DelFiles = NameChanger.DriverFiles + +[DefaultUninstall.Services] +DelService = %ServiceName%,0x200 ;Ensure service is stopped before deleting + +; +; Services Section +; + +[NameChanger.Service] +DisplayName = %ServiceName% +Description = %ServiceDescription% +ServiceBinary = %12%\%DriverName%.sys ;%windir%\system32\drivers\ +Dependencies = "FltMgr" +ServiceType = 2 ;SERVICE_FILE_SYSTEM_DRIVER +StartType = 3 ;SERVICE_DEMAND_START +ErrorControl = 1 ;SERVICE_ERROR_NORMAL +LoadOrderGroup = "FSFilter Activity Monitor" +AddReg = NameChanger.AddRegistry + +; +; Registry Modifications +; + +[NameChanger.AddRegistry] +HKR,,"DebugFlags",0x00010001 ,0x0 +HKR,,"SupportedFeatures",0x00010001,0x3 +HKR,"Instances","DefaultInstance",0x00000000,%DefaultInstance% +HKR,"Instances\"%Instance1.Name%,"Altitude",0x00000000,%Instance1.Altitude% +HKR,"Instances\"%Instance1.Name%,"Flags",0x00010001,%Instance1.Flags% +HKR,,"UserMapping",0x00000000,%UserMapping% +HKR,,"UserMappingFinalComponentShort",0x00000000,%UserMappingFinalComponentShort% +HKR,,"RealMapping",0x00000000,%RealMapping% + +; +; Copy Files +; + +[NameChanger.DriverFiles] +%DriverName%.sys + + +;; +;; String Section +;; + +[Strings] +Msft = "Microsoft Corporation" +ServiceDescription = "NameChanger Mini-Filter Driver Sample" +ServiceName = "NameChanger" +DriverName = "NameChanger" + +;Instances specific information. +DefaultInstance = "NameChanger Instance" +Instance1.Name = "NameChanger Instance" +Instance1.Altitude = "370120" +Instance1.Flags = 0x0 ; Allow all attachments + +;Default settings +UserMapping = "\X\Y" +UserMappingFinalComponentShort = "Y" +RealMapping = "\A\B" + diff --git a/filesys/miniFilter/NameChanger/NameChanger.sln b/filesys/miniFilter/NameChanger/NameChanger.sln new file mode 100644 index 00000000..f4ae9420 --- /dev/null +++ b/filesys/miniFilter/NameChanger/NameChanger.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0 +MinimumVisualStudioVersion = 12.0 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NameChanger", "NameChanger.vcxproj", "{5CA32B6F-182F-4028-837A-041E30696D95}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {5CA32B6F-182F-4028-837A-041E30696D95}.Debug|Win32.ActiveCfg = Debug|Win32 + {5CA32B6F-182F-4028-837A-041E30696D95}.Debug|Win32.Build.0 = Debug|Win32 + {5CA32B6F-182F-4028-837A-041E30696D95}.Release|Win32.ActiveCfg = Release|Win32 + {5CA32B6F-182F-4028-837A-041E30696D95}.Release|Win32.Build.0 = Release|Win32 + {5CA32B6F-182F-4028-837A-041E30696D95}.Debug|x64.ActiveCfg = Debug|x64 + {5CA32B6F-182F-4028-837A-041E30696D95}.Debug|x64.Build.0 = Debug|x64 + {5CA32B6F-182F-4028-837A-041E30696D95}.Release|x64.ActiveCfg = Release|x64 + {5CA32B6F-182F-4028-837A-041E30696D95}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/filesys/miniFilter/NameChanger/NameChanger.vcxproj b/filesys/miniFilter/NameChanger/NameChanger.vcxproj new file mode 100644 index 00000000..5b088fcb --- /dev/null +++ b/filesys/miniFilter/NameChanger/NameChanger.vcxproj @@ -0,0 +1,205 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {5CA32B6F-182F-4028-837A-041E30696D95} + $(MSBuildProjectName) + Debug + Win32 + {505C6DEB-79DC-43DC-AE00-5A573EF44152} + + + + Windows10 + False + Universal + WDM + WindowsKernelModeDriver10.0 + Driver + + + Windows10 + True + Universal + WDM + WindowsKernelModeDriver10.0 + Driver + + + Windows10 + False + Universal + WDM + WindowsKernelModeDriver10.0 + Driver + + + Windows10 + True + Universal + WDM + WindowsKernelModeDriver10.0 + Driver + + + + $(IntDir) + + + + + + + + + + + + + + + + NameChanger + + + NameChanger + + + NameChanger + + + NameChanger + + + + true + Level4 + %(AdditionalIncludeDirectories);. + %(PreprocessorDefinitions);POOL_NX_OPTIN=1 + + + + + %(AdditionalIncludeDirectories);. + %(PreprocessorDefinitions);POOL_NX_OPTIN=1 + + + %(AdditionalIncludeDirectories);. + %(PreprocessorDefinitions);POOL_NX_OPTIN=1 + + + %(AdditionalDependencies);$(DDK_LIB_PATH)\fltMgr.lib + + + + + true + Level4 + %(AdditionalIncludeDirectories);. + %(PreprocessorDefinitions);POOL_NX_OPTIN=1 + + + + + %(AdditionalIncludeDirectories);. + %(PreprocessorDefinitions);POOL_NX_OPTIN=1 + + + %(AdditionalIncludeDirectories);. + %(PreprocessorDefinitions);POOL_NX_OPTIN=1 + + + %(AdditionalDependencies);$(DDK_LIB_PATH)\fltMgr.lib + + + + + true + Level4 + %(AdditionalIncludeDirectories);. + %(PreprocessorDefinitions);POOL_NX_OPTIN=1 + + + + + %(AdditionalIncludeDirectories);. + %(PreprocessorDefinitions);POOL_NX_OPTIN=1 + + + %(AdditionalIncludeDirectories);. + %(PreprocessorDefinitions);POOL_NX_OPTIN=1 + + + %(AdditionalDependencies);$(DDK_LIB_PATH)\fltMgr.lib + + + + + true + Level4 + %(AdditionalIncludeDirectories);. + %(PreprocessorDefinitions);POOL_NX_OPTIN=1 + + + + + %(AdditionalIncludeDirectories);. + %(PreprocessorDefinitions);POOL_NX_OPTIN=1 + + + %(AdditionalIncludeDirectories);. + %(PreprocessorDefinitions);POOL_NX_OPTIN=1 + + + %(AdditionalDependencies);$(DDK_LIB_PATH)\fltMgr.lib + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/filesys/miniFilter/NameChanger/NameChanger.vcxproj.Filters b/filesys/miniFilter/NameChanger/NameChanger.vcxproj.Filters new file mode 100644 index 00000000..6520d305 --- /dev/null +++ b/filesys/miniFilter/NameChanger/NameChanger.vcxproj.Filters @@ -0,0 +1,70 @@ + + + + + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* + {817F7394-22D9-49B6-A7EE-2CC524F1CBF2} + + + h;hpp;hxx;hm;inl;inc;xsd + {DF2CCD0F-541A-4EFC-AA37-579066F38CD0} + + + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml + {86478AE0-8DEC-4E96-924F-3D6DA78E254F} + + + inf;inv;inx;mof;mc; + {D01D724E-D3A3-464D-8307-CE7E057FA327} + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Resource Files + + + \ No newline at end of file diff --git a/filesys/miniFilter/NameChanger/ReadMe.md b/filesys/miniFilter/NameChanger/ReadMe.md new file mode 100644 index 00000000..9846414b --- /dev/null +++ b/filesys/miniFilter/NameChanger/ReadMe.md @@ -0,0 +1,116 @@ +NameChanger File System Minifilter Driver +========================================= + +The *NameChanger* minifilter grafts a directory from one part of a volume's namespace to another part using a mapping. The minifilter maintains this illusion by acting as a name provider, injecting entries into directory enumerations and forwarding directory change notifications. + + +Build the sample +---------------- + +You can build the sample in two ways: using Microsoft Visual Studio or the command line (*MSBuild*). + +Building a Driver Using Visual Studio +------------------------------------- + +You build a driver the same way you build any project or solution in Visual Studio. When you create a new driver project using a Windows driver template, the template defines a default (active) project configuration and a default (active) solution build configuration. When you create a project from existing driver sources or convert existing driver code that was built with previous versions of the WDK, the conversion process preserves the target version information (operating systems and platform). + +The default Solution build configuration is Windows 8.1 Debug and Win32. + +### To select a configuration and build a driver + +1. Open the driver project or solution in Visual Studio (find *filtername*.sln or *filtername*.vcxproj). +2. Right-click the solution in the **Solutions Explorer** and select **Configuration Manager**. +3. From the **Configuration Manager**, select the **Active Solution Configuration** (for example, Windows 8.1 Debug or Windows 8.1 Release) and the **Active Solution Platform** (for example, Win32) that correspond to the type of build you are interested in. +4. From the Build menu, click **Build Solution** (Ctrl+Shift+B). + +Building a Driver Using the Command Line (MSBuild) +-------------------------------------------------- + +You can build a driver from the command line using the Visual Studio Command Prompt window and the Microsoft Build Engine (MSBuild.exe) Previous versions of the WDK used the Windows Build utility (Build.exe) and provided separate build environment windows for each of the supported build configurations. You can now use the Visual Studio Command Prompt window for all build configurations. + +### To select a configuration and build a driver + +1. Open a Visual Studio Command Prompt window at the **Start** screen. From this window you can use MsBuild.exe to build any Visual Studio project by specifying the project (.VcxProj) or solutions (.Sln) file. +2. Navigate to the project directory and enter the **MSbuild** command for your target. For example, to perform a clean build of a Visual Studio driver project called *filtername*.vcxproj, navigate to the project directory and enter the following MSBuild command: **msbuild /t:clean /t:build .\\***filtername***.vcxproj**. + +Run the sample +-------------- + +Installation +------------ + +The minifilter samples come with an INF file that will install the minifilter. To install the minifilter, do the following: + +1. Make sure that *filtername*.sys and *filtername*.inf are in the same directory. + + **Note**  This installation will make the necessary registry updates to register the minifilter service and place *filtername*.sys in the %SystemRoot%\\system32\\drivers directory. + +2. In Windows Explorer, right-click *filtername*.inf, and click **Install**. + +3. To load the minifilter, run **fltmc load** *filtername* or **net start** *filtername*. + +Design and Operation +-------------------- + +The *NameChanger* minifilter illustrates how to make one part of a volume's namespace appear as though it belongs to part of another namespace. It accomplishes this by altering the names of files that reside beneath a particular path (called the "real mapping") to appear as though they actually reside beneath a different path (called the "user mapping"). The .inf file supplied with the sample defines the real and user mappings in the *[Strings]* section. The three strings used for the mappings are: + + ++++ + + + + + + + + + + + +
String +Description

UserMapping

+

The location where files will appear to be in when the filter is attached

UserMappingFinalComponentShort

+

The"short" (e.g. DOS-compliant 8.3-format) name for the final component of the UserMapping path.

+ +Before attaching the minifilter to a volume, you must set up the user and real paths. By default the .inf defines the mapping paths like in the following manner: + + ++++ + + + + + + + + + + + +
String +Mapping

UserMapping

+

"\X\Y"

UserMappingFinalComponentShort

+

"Y"

+ +To successfully attach the filter to a volume you must first create a couple of directories. For example, to attach the *NameChanger* minifilter to the F: volume, first create the RealMapping directory (the F:\\A\\B directory). Next, create the parent of the UserMapping path (the F:\\X directory). The following directories are be created: + +F:\\A\\B + +F:\\X + +Once this is done the *NameChanger* filter should successfully attach to F:. It will change the directories you created to appear like the following: + +F:\\A + +F:\\X\\Y + +After the minifilter attaches, the "B" subdirectory of F:\\A is no longer visible. Its contents now appear under the "Y" subdirectory of F:\\X. + +For more information on file system minifilter design, start with the [File System Minifilter Drivers](http://msdn.microsoft.com/en-us/library/windows/hardware/ff540402) section in the Installable File Systems Design Guide. + diff --git a/filesys/miniFilter/NameChanger/nc.c b/filesys/miniFilter/NameChanger/nc.c new file mode 100644 index 00000000..05431407 --- /dev/null +++ b/filesys/miniFilter/NameChanger/nc.c @@ -0,0 +1,2017 @@ +/*++ + +Copyright (c) 1999 - 2002 Microsoft Corporation + +Module Name: + + nc.c + +Abstract: + + This is the main module of the NameChanger MiniFilter driver. + This filter grafts a directory from one part of a volume's namespace + to another part using a mapping. The filter then maintains the illusion + by acting as a name provider, injecting entries into directory enumerations + and forwarding directory change notifications. + +Environment: + + Kernel mode + +--*/ + +#include +#include + +#include "nc.h" + + +// +// Prototypes +// + +DRIVER_INITIALIZE DriverEntry; +NTSTATUS +DriverEntry ( + _In_ PDRIVER_OBJECT DriverObject, + _In_ PUNICODE_STRING RegistryPath + ); + +NTSTATUS +NcInstanceSetup ( + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _In_ FLT_INSTANCE_SETUP_FLAGS Flags, + _In_ DEVICE_TYPE VolumeDeviceType, + _In_ FLT_FILESYSTEM_TYPE VolumeFilesystemType + ); + +VOID +NcInstanceTeardownStart ( + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _In_ FLT_INSTANCE_TEARDOWN_FLAGS Flags + ); + +NTSTATUS +NcUnload ( + _In_ FLT_FILTER_UNLOAD_FLAGS Flags + ); + +NTSTATUS +NcInstanceQueryTeardown ( + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _In_ FLT_INSTANCE_QUERY_TEARDOWN_FLAGS Flags + ); + + +// +// Assign sections for each routine. +// + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(INIT, DriverEntry) +#pragma alloc_text(PAGE, NcInstanceSetup) +#pragma alloc_text(PAGE, NcInstanceTeardownStart) +#pragma alloc_text(PAGE, NcUnload) +#pragma alloc_text(PAGE, NcInstanceQueryTeardown) +#endif + +// +// IRP Callback Prototypes +// + +FLT_PREOP_CALLBACK_STATUS +NcPreCreateCallback ( + _Inout_ PFLT_CALLBACK_DATA Data, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _Flt_CompletionContext_Outptr_ PVOID *CompletionContext + ); + +FLT_PREOP_CALLBACK_STATUS +NcPreCleanupCallback ( + _Unreferenced_parameter_ PFLT_CALLBACK_DATA Data, + _Unreferenced_parameter_ PCFLT_RELATED_OBJECTS FltObjects, + _Flt_CompletionContext_Outptr_ PVOID *CompletionContext + ); + +FLT_POSTOP_CALLBACK_STATUS +NcPostCleanupCallback ( + _Inout_ PFLT_CALLBACK_DATA Data, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _In_opt_ PVOID CompletionContext, + _In_ FLT_POST_OPERATION_FLAGS Flags + ); + +FLT_PREOP_CALLBACK_STATUS +NcPreFsctlCallback ( + _Inout_ PFLT_CALLBACK_DATA Data, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _Flt_CompletionContext_Outptr_ PVOID *CompletionContext + ); + +FLT_POSTOP_CALLBACK_STATUS +NcPostFsctlCallback ( + _Inout_ PFLT_CALLBACK_DATA Data, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _When_(Data->Iopb->Parameters.FileSystemControl.Common.FsControlCode==FSCTL_FIND_FILES_BY_SID, _In_) + _When_(Data->Iopb->Parameters.FileSystemControl.Common.FsControlCode!=FSCTL_FIND_FILES_BY_SID, _In_opt_) + PVOID CompletionContext, + _In_ FLT_POST_OPERATION_FLAGS Flags + ); + +FLT_PREOP_CALLBACK_STATUS +NcPreQueryInformationCallback ( + _Inout_ PFLT_CALLBACK_DATA Data, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _Flt_CompletionContext_Outptr_ PVOID *CompletionContext + ); + +FLT_POSTOP_CALLBACK_STATUS +NcPostQueryInformationCallback ( + _Inout_ PFLT_CALLBACK_DATA Data, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _In_opt_ PVOID CompletionContext, + _In_ FLT_POST_OPERATION_FLAGS Flags + ); + +FLT_PREOP_CALLBACK_STATUS +NcPreSetInformationCallback ( + _Inout_ PFLT_CALLBACK_DATA Data, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _Flt_CompletionContext_Outptr_ PVOID *CompletionContext + ); + +FLT_PREOP_CALLBACK_STATUS +NcPreDirectoryControlCallback ( + _Inout_ PFLT_CALLBACK_DATA Data, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _Flt_CompletionContext_Outptr_ PVOID *CompletionContext + ); + +FLT_POSTOP_CALLBACK_STATUS +NcPostDirectoryControlCallback ( + _Inout_ PFLT_CALLBACK_DATA Data, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _In_ PVOID CompletionContext, + _In_ FLT_POST_OPERATION_FLAGS Flags + ); + +FLT_PREOP_CALLBACK_STATUS +NcPreNetworkQueryCallback ( + _Inout_ PFLT_CALLBACK_DATA Data, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _Flt_CompletionContext_Outptr_ PVOID *CompletionContext + ); + +// +// Assign text sections for each routine. +// + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE, NcPreCreateCallback) +#pragma alloc_text(PAGE, NcPreCleanupCallback) +#pragma alloc_text(PAGE, NcPostCleanupCallback) +#pragma alloc_text(PAGE, NcPreFsctlCallback) +#pragma alloc_text(PAGE, NcPreQueryInformationCallback) +#pragma alloc_text(PAGE, NcPostQueryInformationCallback) +#pragma alloc_text(PAGE, NcPreSetInformationCallback) +#pragma alloc_text(PAGE, NcPreDirectoryControlCallback) +#pragma alloc_text(PAGE, NcPreNetworkQueryCallback) +#endif + +// +// Name Callback Prototypes +// + +NTSTATUS +NcGenerateFileNameCallback ( + _In_ PFLT_INSTANCE Instance, + _In_ PFILE_OBJECT FileObject, + _In_opt_ PFLT_CALLBACK_DATA Data, + _In_ FLT_FILE_NAME_OPTIONS NameOptions, + _Out_ PBOOLEAN CacheFileNameInformation, + _Inout_ PFLT_NAME_CONTROL FileName + ); + +NTSTATUS +NcNormalizeNameComponentExCallback ( + _In_ PFLT_INSTANCE Instance, + _In_opt_ PFILE_OBJECT FileObject, + _In_ PCUNICODE_STRING ParentDirectory, + _In_ USHORT DeviceNameLength, + _In_ PCUNICODE_STRING Component, + _Out_writes_bytes_(ExpandComponentNameLength) PFILE_NAMES_INFORMATION ExpandComponentName, + _In_ ULONG ExpandComponentNameLength, + _In_ FLT_NORMALIZE_NAME_FLAGS Flags, + _Inout_ PVOID *NormalizationContext + ); + +NTSTATUS +NcNormalizeNameComponentCallback ( + _In_ PFLT_INSTANCE Instance, + _In_ PCUNICODE_STRING ParentDirectory, + _In_ USHORT DeviceNameLength, + _In_ PCUNICODE_STRING Component, + _Out_writes_bytes_(ExpandComponentNameLength) PFILE_NAMES_INFORMATION ExpandComponentName, + _In_ ULONG ExpandComponentNameLength, + _In_ FLT_NORMALIZE_NAME_FLAGS Flags, + _Inout_ PVOID *NormalizationContext + ); + +// +// Assign text sections for each routine. +// + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE, NcGenerateFileNameCallback) +#pragma alloc_text(PAGE, NcNormalizeNameComponentCallback) +#pragma alloc_text(PAGE, NcNormalizeNameComponentExCallback) +#endif + +// +// operation registration +// + +CONST FLT_OPERATION_REGISTRATION Callbacks[] = { + { IRP_MJ_CREATE, + 0, + NcPreCreateCallback, + NULL }, + + { IRP_MJ_CLEANUP, + 0, + NcPreCleanupCallback, + NcPostCleanupCallback }, + + { IRP_MJ_QUERY_INFORMATION, + 0, + NcPreQueryInformationCallback, + NcPostQueryInformationCallback }, + + { IRP_MJ_SET_INFORMATION, + 0, + NcPreSetInformationCallback, + NULL }, + + { IRP_MJ_DIRECTORY_CONTROL, + 0, + NcPreDirectoryControlCallback, + NcPostDirectoryControlCallback }, + + { IRP_MJ_NETWORK_QUERY_OPEN, + 0, + NcPreNetworkQueryCallback, + NULL }, + + { IRP_MJ_FILE_SYSTEM_CONTROL, + 0, + NcPreFsctlCallback, + NcPostFsctlCallback }, + + { IRP_MJ_OPERATION_END } +}; + +// +// Context Registration +// + +const FLT_CONTEXT_REGISTRATION contextRegistration[] = { + + { FLT_INSTANCE_CONTEXT, + 0, + NcInstanceContextClose, + sizeof(NC_INSTANCE_CONTEXT), + NC_INSTANCE_CONTEXT_TAG, + NULL, + NULL, + NULL }, + + { FLT_STREAMHANDLE_CONTEXT, + 0, + NcStreamHandleContextClose, + sizeof(NC_STREAM_HANDLE_CONTEXT), + NC_STREAM_HANDLE__CONTEXT_TAG, + NULL, + NULL, + NULL }, + + { FLT_CONTEXT_END } +}; + +// +// This defines what we want to filter with FltMgr +// + +CONST FLT_REGISTRATION FilterRegistration = { + + sizeof( FLT_REGISTRATION ), // Size + FLT_REGISTRATION_VERSION, // Version + 0, // Flags + + contextRegistration, // Context + Callbacks, // Operation callbacks + + NcUnload, // MiniFilterUnload + + NcInstanceSetup, // InstanceSetup + NcInstanceQueryTeardown, // InstanceQueryTeardown + NcInstanceTeardownStart, // InstanceTeardownStart + NULL, // InstanceTeardownComplete + + NcGenerateFileNameCallback, // GenerateFileName + NcNormalizeNameComponentCallback, // Normalize Component + NULL, // NormalizeContextCleanupCallback + +#if FLT_MGR_LONGHORN + NULL, // Transaction Notification Callback. + NcNormalizeNameComponentExCallback // Normalize Name Component with transaction handle. +#endif + +}; + +// +// Constants +// + +NC_GLOBAL_DATA NcGlobalData; + +// +// Function Definitions +// + + +NTSTATUS +NcInstanceSetup ( + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _In_ FLT_INSTANCE_SETUP_FLAGS Flags, + _In_ DEVICE_TYPE VolumeDeviceType, + _In_ FLT_FILESYSTEM_TYPE VolumeFilesystemType + ) +/*++ + +Routine Description: + + This routine is called whenever a new instance is created on a volume. This + gives us a chance to decide if we need to attach to this volume or not. + + We attach to the volume if: + The User mapping parent exists. + The User mapping does not exist + The Real mapping parent exists + +Arguments: + + FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing + opaque handles to this filter, instance and its associated volume. + + Flags - Flags describing the reason for this attach request. + +Return Value: + + STATUS_SUCCESS - attach + STATUS_FLT_DO_NOT_ATTACH - do not attach + Other Errorcode - Percolate errors up. (do not attach). + +Logic: + A) Validate that we should attach. + 1) Construct UserMappingPath + 2) Open User Parent (validate it exists) + 3) Query Final component (validate it does not exist) + 4) Construct RealMappingPath + 5) Open Real Parent (validate it exists) + B) Now we know that we should attach. We need to get + short and normalized names for the paths and then + construct our mapping and instance context. +--*/ +{ + + // + // Status Tracking Vars. + // + + NTSTATUS Status; + NTSTATUS ReturnValue = STATUS_SUCCESS; + + // + // User mapping vars + // + + NC_MAPPING_PATH UserPath; + HANDLE UserParentHandle = 0; + PFILE_OBJECT UserParentFileObj = NULL; + OBJECT_ATTRIBUTES UserParentAttributes; + IO_STATUS_BLOCK UserParentStatusBlock; + PFILE_NAMES_INFORMATION FinalComponentQueryBuffer = NULL; + ULONG FinalComponentQueryLength; + + // + // Real Mapping vars + // + + NC_MAPPING_PATH RealPath; + HANDLE RealParentHandle = 0; + PFILE_OBJECT RealParentFileObj = NULL; + OBJECT_ATTRIBUTES RealParentAttributes; + IO_STATUS_BLOCK RealParentStatusBlock; + + // + // Context Vars + // + + PNC_INSTANCE_CONTEXT InstanceContext = NULL; + + // + // Temp vars + // + + ULONG DataRead; + NC_PATH_OVERLAP Overlap; + + + PAGED_CODE(); + + UNREFERENCED_PARAMETER( VolumeDeviceType ); + + // + // Although this filter goes to great lengths to be filesystem-agnostic, + // it is not yet able to handle the V3 USN records supported by ReFS. + // + + if (VolumeFilesystemType == FLT_FSTYPE_REFS) { + + return STATUS_FLT_DO_NOT_ATTACH; + } + + // + // Prevent the filter from auto attaching. + // + + if (FlagOn( Flags, FLTFL_INSTANCE_SETUP_AUTOMATIC_ATTACHMENT )) { + + // + // We actually return here, rather than goto cleanup, because + // we have not yet zeroed out the buffers in the mappings. + // + + return STATUS_FLT_DO_NOT_ATTACH; + } + + // + // We should not be attaching before our driver initialization + // has completed, which should load and sanity check these + // values. If this hasn't happened, fail attachment. + // + + if (NcGlobalData.UserMappingPath.Length == 0 || + NcGlobalData.UserMappingFinalComponentShort.Length == 0 || + NcGlobalData.UserMappingFinalComponentLong.Length == 0 || + NcGlobalData.RealMappingPath.Length == 0 || + NcGlobalData.RealMappingFinalComponent.Length == 0) { + + FLT_ASSERT( FALSE ); + return STATUS_FLT_DO_NOT_ATTACH; + } + + // + // Zero Out structures. (Now we can cleanup) + // + + NcInitMappingPath( &UserPath ); + NcInitMappingPath( &RealPath ); + + // + // Build the mapping strings for this instance from our global + // registry state. + // + + Status = NcBuildMappingPathFromVolume( FltObjects->Volume, + &NcGlobalData.UserMappingPath, + &NcGlobalData.UserMappingFinalComponentShort, + &UserPath ); + + if (!NT_SUCCESS( Status )) { + + ReturnValue = Status; + goto NcInstanceSetupCleanup; + } + + Status = NcBuildMappingPathFromVolume( FltObjects->Volume, + &NcGlobalData.RealMappingPath, + &NcGlobalData.RealMappingFinalComponent, + &RealPath ); + + if (!NT_SUCCESS( Status )) { + + ReturnValue = Status; + goto NcInstanceSetupCleanup; + } + + // + // Allocate the buffer to store the directory lookup. We + // reuse the buffer for long and short names, so it must + // be large enough to handle either. + // + + FinalComponentQueryLength = sizeof(FILE_NAMES_INFORMATION) + + AlignToSize( max( NcGlobalData.UserMappingFinalComponentLong.Length, NcGlobalData.UserMappingFinalComponentShort.Length ), 8 ); + FinalComponentQueryBuffer = ExAllocatePoolWithTag( PagedPool, + FinalComponentQueryLength, + NC_NORMALIZE_NAME_TAG ); + + if (FinalComponentQueryBuffer == NULL) { + + ReturnValue = STATUS_INSUFFICIENT_RESOURCES; + goto NcInstanceSetupCleanup; + } + + + // + // Open Parent of user mapping, and validate that it exists. + // Note that we do have a race here; a user may have this object + // opened with FILE_DELETE_ON_CLOSE. Under these semantics, our + // create will succeed, but when their handle is closed our + // mapping parent will go away, which this filter cannot deal + // with. + // + + InitializeObjectAttributes( &UserParentAttributes, + &UserPath.ParentPath, + OBJ_KERNEL_HANDLE, + NULL, + NULL ); + + Status = NcCreateFileEx2( NcGlobalData.FilterHandle, // Filter + FltObjects->Instance, // Instance + &UserParentHandle, // Returned Handle + &UserParentFileObj, // Returned FileObject + FILE_LIST_DIRECTORY|FILE_TRAVERSE, // Desired Access + &UserParentAttributes, // object attributes + &UserParentStatusBlock, // Returned IOStatusBlock + 0, // Allocation Size + FILE_ATTRIBUTE_NORMAL, // File Attributes + 0, // Share Access + FILE_OPEN, // Create Disposition + FILE_DIRECTORY_FILE, // Create Options + NULL, // Ea Buffer + 0, // EA Length + IO_IGNORE_SHARE_ACCESS_CHECK, // Flags + NULL ); // Transaction/ECP + + if (!NT_SUCCESS( Status )) { + + // + // We could not open the parent path, fail attachment. + // + + ReturnValue = STATUS_FLT_DO_NOT_ATTACH; + goto NcInstanceSetupCleanup; + } + + // + // Make sure that the User mapping's short final component does not exist. + // + + Status = NcQueryDirectoryFile( FltObjects->Instance, + UserParentFileObj, + FinalComponentQueryBuffer, + FinalComponentQueryLength, + FileNamesInformation, + TRUE,//Return single entry + &NcGlobalData.UserMappingFinalComponentShort, + TRUE,//restart scan + &DataRead); + + if (Status != STATUS_NO_SUCH_FILE) { + + if (!NT_SUCCESS( Status )) { + + // + // An unexpected error occurred, return code. + // + + ReturnValue = Status; + goto NcInstanceSetupCleanup; + + } else { + + // + // The query worked, but the file exists. + // The volume does not meet our constraints, + // so abort attachment. + // + + ReturnValue = STATUS_FLT_DO_NOT_ATTACH; + goto NcInstanceSetupCleanup; + } + } + + // + // Now we have established that the short name does not exist, + // we must search again for the long name. Since the search + // string for a directory enumeration is cached by the filesystem + // and cannot be changed, we have to close and re-open the file + // in order to do the second enumeration. + // + + FltClose( UserParentHandle ); + UserParentHandle = NULL; + + ObDereferenceObject( UserParentFileObj ); + UserParentFileObj = NULL; + + Status = NcCreateFileEx2( NcGlobalData.FilterHandle, // Filter + FltObjects->Instance, // Instance + &UserParentHandle, // Returned Handle + &UserParentFileObj, // Returned FileObject + FILE_LIST_DIRECTORY|FILE_TRAVERSE, // Desired Access + &UserParentAttributes, // object attributes + &UserParentStatusBlock, // Returned IOStatusBlock + 0, // Allocation Size + FILE_ATTRIBUTE_NORMAL, // File Attributes + 0, // Share Access + FILE_OPEN, // Create Disposition + FILE_DIRECTORY_FILE, // Create Options + NULL, // Ea Buffer + 0, // EA Length + IO_IGNORE_SHARE_ACCESS_CHECK, // Flags + NULL ); // Transaction/ECP + + if (!NT_SUCCESS( Status )) { + + ReturnValue = Status; + goto NcInstanceSetupCleanup; + } + + // + // Make sure that the User mapping's long final component does not exist. + // + + Status = NcQueryDirectoryFile( FltObjects->Instance, + UserParentFileObj, + FinalComponentQueryBuffer, + FinalComponentQueryLength, + FileNamesInformation, + TRUE,//Return single entry + &NcGlobalData.UserMappingFinalComponentLong, + TRUE,//restart scan + &DataRead ); + + if (Status != STATUS_NO_SUCH_FILE) { + + if (!NT_SUCCESS( Status )) { + + // + // An unexpected error occurred, return code. + // + + ReturnValue = Status; + goto NcInstanceSetupCleanup; + + } else { + + // + // The query worked, but the file exists. + // The volume does not meet our constraints, + // so abort attachment. + // + + ReturnValue = STATUS_FLT_DO_NOT_ATTACH; + goto NcInstanceSetupCleanup; + } + } + + // + // Open parent of real mapping. + // Note that we do have a race here; a user may have this object + // opened with FILE_DELETE_ON_CLOSE. Under these semantics, our + // create will succeed, but when their handle is closed our + // mapping parent will go away, which this filter cannot deal + // with. + // + + InitializeObjectAttributes( &RealParentAttributes, + &RealPath.ParentPath, + OBJ_KERNEL_HANDLE, + NULL, + NULL ); + + Status = NcCreateFileEx2( NcGlobalData.FilterHandle, // Filter + FltObjects->Instance, // Instance + &RealParentHandle, // Returned Handle + &RealParentFileObj, // Returned FileObject + FILE_LIST_DIRECTORY|FILE_TRAVERSE, // Desired Access + &RealParentAttributes, // object attributes + &RealParentStatusBlock, // Returned IOStatusBlock + 0, // Allocation Size + FILE_ATTRIBUTE_NORMAL, // File Attributes + 0, // Share Access + FILE_OPEN, // Create Disposition + FILE_DIRECTORY_FILE, // Create Options + NULL, // Ea Buffer + 0, // EA Length + IO_IGNORE_SHARE_ACCESS_CHECK, // Flags + NULL ); // Transaction/ECP + + FLT_ASSERT( Status != STATUS_INVALID_PARAMETER ); + + if (!NT_SUCCESS( Status )) { + + // + // We could not open the parent path, fail attachment. + // + + ReturnValue = STATUS_FLT_DO_NOT_ATTACH; + goto NcInstanceSetupCleanup; + } + + // + // We have validated that we should attach. + // + + + // + // Allocate context + // + + Status = FltAllocateContext( FltObjects->Filter, + FLT_INSTANCE_CONTEXT, + sizeof(NC_INSTANCE_CONTEXT), + NonPagedPool, + &InstanceContext ); + + if (!NT_SUCCESS( Status )) { + + ReturnValue = Status; + goto NcInstanceSetupCleanup; + } + + // + // We have allocated an instance context. Now initialize it. + // + + // + // Now that we have a context, + // we need to generate the mapping + // + + NcInitMapping( &InstanceContext->Mapping ); + + + Status = NcBuildMapping( UserParentFileObj, + RealParentFileObj, + &NcGlobalData.UserMappingFinalComponentShort, + &NcGlobalData.UserMappingFinalComponentLong, + &NcGlobalData.RealMappingFinalComponent, + FltObjects->Instance, + &InstanceContext->Mapping ); + + if (!NT_SUCCESS( Status )) { + + ReturnValue = Status; + goto NcInstanceSetupCleanup; + } + + // + // Sanity check the relation between the mappings. Force case insensitive + // to TRUE here, since we may be evaluating this relationship in response + // to case insensitive user requests in the future. + // + + NcComparePath( &RealPath.FullPath, + &InstanceContext->Mapping.UserMapping, + NULL, + TRUE, + TRUE, + &Overlap ); + + if (Overlap.InMapping || Overlap.Ancestor) { + + ReturnValue = STATUS_FLT_DO_NOT_ATTACH; + goto NcInstanceSetupCleanup; + } + + NcComparePath( &UserPath.FullPath, + &InstanceContext->Mapping.RealMapping, + NULL, + TRUE, + TRUE, + &Overlap ); + + if (Overlap.InMapping || Overlap.Ancestor) { + + ReturnValue = STATUS_FLT_DO_NOT_ATTACH; + goto NcInstanceSetupCleanup; + } + + // + // Remember what file system we're attached to. + // + + InstanceContext->VolumeFilesystemType = VolumeFilesystemType; + + // + // Register the instance context. + // + + Status = FltSetInstanceContext( FltObjects->Instance, + FLT_SET_CONTEXT_REPLACE_IF_EXISTS, + InstanceContext, + NULL); + + if (!NT_SUCCESS( Status )) { + + ReturnValue = Status; + goto NcInstanceSetupCleanup; + } + + +NcInstanceSetupCleanup: + + if (InstanceContext != NULL ) { + + FltReleaseContext( InstanceContext ); + } + + NcTeardownMappingPath( &UserPath ); + + if (UserParentHandle != 0) { + + FltClose( UserParentHandle ); + } + + if (UserParentFileObj != NULL) { + + ObDereferenceObject( UserParentFileObj ); + } + + NcTeardownMappingPath( &RealPath ); + + if (RealParentHandle != 0) { + + FltClose( RealParentHandle ); + } + + if (RealParentFileObj != NULL) { + + ObDereferenceObject( RealParentFileObj ); + } + + if (FinalComponentQueryBuffer != NULL) { + + ExFreePool( FinalComponentQueryBuffer ); + } + + return ReturnValue; +} + + +NTSTATUS +NcInstanceQueryTeardown ( + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _In_ FLT_INSTANCE_QUERY_TEARDOWN_FLAGS Flags + ) +/*++ + +Routine Description: + + This is called when an instance is being manually deleted by a + call to FltDetachVolume or FilterDetach thereby giving us a + chance to fail that detach request. + + If this routine is not defined in the registration structure, explicit + detach requests via FltDetachVolume or FilterDetach will always be + failed. + +Arguments: + + FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing + opaque handles to this filter, instance and its associated volume. + + Flags - Indicating where this detach request came from. + +Return Value: + + Returns the Status of this operation. + +--*/ +{ + UNREFERENCED_PARAMETER( FltObjects ); + UNREFERENCED_PARAMETER( Flags ); + + PAGED_CODE(); + + return STATUS_SUCCESS; +} + + +VOID +NcInstanceTeardownStart ( + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _In_ FLT_INSTANCE_TEARDOWN_FLAGS Flags + ) +/*++ + +Routine Description: + + This routine is called at the start of instance teardown. + +Arguments: + + FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing + opaque handles to this filter, instance and its associated volume. + + Flags - Reason why this instance is been deleted. + +Return Value: + + None. + +--*/ +{ + NTSTATUS Status; + PNC_INSTANCE_CONTEXT InstanceContext = NULL; + + PAGED_CODE(); + UNREFERENCED_PARAMETER( Flags ); + + Status = FltGetInstanceContext( FltObjects->Instance, + &InstanceContext ); + + if (!NT_SUCCESS( Status )) { + + goto NcInstanceTeardownStartCleanup; + } + +NcInstanceTeardownStartCleanup: + + if (InstanceContext) { + + FltReleaseContext( InstanceContext ); + } + +} + +// +// MiniFilter initialization and unload routines. +// + +NTSTATUS +DriverEntry ( + _In_ PDRIVER_OBJECT DriverObject, + _In_ PUNICODE_STRING RegistryPath + ) +/*++ + +Routine Description: + + This is the initialization routine for this miniFilter driver. This + registers with FltMgr and initializes all global data structures. + +Arguments: + + DriverObject - Pointer to driver object created by the system to + represent this driver. + + RegistryPath - Unicode string identifying where the parameters for this + driver are located in the registry. + +Return Value: + + Returns STATUS_SUCCESS. + +--*/ +{ + NTSTATUS Status; + + // + // Import routines + // + + NcCompatInit( ); + + Status = NcInitializeMapping( RegistryPath ); + if (!NT_SUCCESS( Status )) { + return Status; + } + + // + // Register with FltMgr to tell it our callback routines + // + + Status = FltRegisterFilter( DriverObject, + &FilterRegistration, + &NcGlobalData.FilterHandle ); + + FLT_ASSERT( NT_SUCCESS( Status ) ); + + if (NT_SUCCESS( Status )) { + + // + // Start filtering i/o + // + + Status = FltStartFiltering( NcGlobalData.FilterHandle ); + + if (!NT_SUCCESS( Status )) { + + FltUnregisterFilter( NcGlobalData.FilterHandle ); + } + } + + return Status; +} + +NTSTATUS +NcUnload ( + _In_ FLT_FILTER_UNLOAD_FLAGS Flags + ) +/*++ + +Routine Description: + + This is the unload routine for this miniFilter driver. This is called + when the minifilter is about to be unloaded. We can fail this unload + request if this is not a mandatory unloaded indicated by the Flags + parameter. + +Arguments: + + Flags - Indicating if this is a mandatory unload. + +Return Value: + + Returns the final Status of this operation. + +--*/ +{ + UNREFERENCED_PARAMETER( Flags ); + + PAGED_CODE(); + + FltUnregisterFilter( NcGlobalData.FilterHandle ); + + if (NcGlobalData.UserMappingPath.Buffer != NULL) { + NcFreeUnicodeString( &NcGlobalData.UserMappingPath ); + } + + if (NcGlobalData.UserMappingFinalComponentShort.Buffer != NULL) { + NcFreeUnicodeString( &NcGlobalData.UserMappingFinalComponentShort ); + } + + if (NcGlobalData.UserMappingFinalComponentLong.Buffer != NULL) { + NcFreeUnicodeString( &NcGlobalData.UserMappingFinalComponentLong ); + } + + if (NcGlobalData.RealMappingPath.Buffer != NULL) { + NcFreeUnicodeString( &NcGlobalData.RealMappingPath ); + } + + if (NcGlobalData.RealMappingFinalComponent.Buffer != NULL) { + NcFreeUnicodeString( &NcGlobalData.RealMappingFinalComponent ); + } + + return STATUS_SUCCESS; +} + +// +// MiniFilter callback routines. +// + +FLT_PREOP_CALLBACK_STATUS +NcPreCreateCallback ( + _Inout_ PFLT_CALLBACK_DATA Data, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _Flt_CompletionContext_Outptr_ PVOID *CompletionContext + ) +/*++ + +Routine Description: + + Routine is invoked when a create is issued by a user. + + +Arguments: + + Data - Pointer to the filter CallbackData that is passed to us. + + FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing + opaque handles to this filter, instance, its associated volume and + file object. + + CompletionContext - The context for the completion routine for this + operation. + +Return Value: + + The return value is the Status of the operation. + +Logic: + + 1) If file is opened by ID or is a Paging File, etc. + A) return PASSTHROUGH_NO_CALLBACK + 2) Get the opened name and calculate overlap + 3) If File is Delete On close + A) If the file is an ancestor of either mapping + a) Fail Open + 4) If the path is in the real mapping + A) Fail the Open + 5) If the path is in user mapping + A) Recalculate the full name (without SL_TARGET_PARENT_DIRECTORY) + B) Munge Name to Real Mapping + C) Switch name + D) Passthrough with callback. + 6) Else + A) Return Passthrough No callback +--*/ +{ + PAGED_CODE(); + + return NcPreCreate( Data, + FltObjects, + CompletionContext ); +} + +FLT_PREOP_CALLBACK_STATUS +NcPreCleanupCallback ( + _Unreferenced_parameter_ PFLT_CALLBACK_DATA Data, + _Unreferenced_parameter_ PCFLT_RELATED_OBJECTS FltObjects, + _Flt_CompletionContext_Outptr_ PVOID *CompletionContext + ) +/*++ + +Routine Description: + + This is the pre cleanup callback. It is called for every handle cleanup + operation. The role of this callback is merely to ensure that we + also receive every post handle cleanup operation, and that it is safe + to issue filesystem calls when we do. We do this via + FLT_PREOP_SYNCHRONIZE for simplicity. + parameter. + +Arguments: + + Data - Pointer to the filter CallbackData that is passed to us. + + FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing + opaque handles to this filter, instance, its associated volume and + file object. + + CompletionContext - The context for the completion routine for this + operation. Not used in this function. + +Return Value: + + Returns the final status of this operation. Always FLT_PREOP_SYNCHRONIZE + in this routine. + +--*/ +{ + PAGED_CODE(); + + UNREFERENCED_PARAMETER( Data ); + UNREFERENCED_PARAMETER( FltObjects ); + UNREFERENCED_PARAMETER( CompletionContext ); + + // + // Synchronize all cleanup requests. This enables us to ensure + // that any state is torn down correctly even if a request is + // issued between pre cleanup and post cleanup. + // + + return FLT_PREOP_SYNCHRONIZE; +} + +FLT_POSTOP_CALLBACK_STATUS +NcPostCleanupCallback ( + _Inout_ PFLT_CALLBACK_DATA Data, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _In_opt_ PVOID CompletionContext, + _In_ FLT_POST_OPERATION_FLAGS Flags + ) +/*++ + +Routine Description: + + This is the post cleanup callback. It is called for every handle cleanup + operation. The role of this callback is to tear down any pending + directory change notification state attached to this handle. + +Arguments: + + Data - Pointer to the filter CallbackData that is passed to us. + + FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing + opaque handles to this filter, instance, its associated volume and + file object. + + CompletionContext - The context for the completion routine for this + operation. Not used in this function. + + Flags - The flags for this operation. + +Return Value: + + Returns the final status of this operation. Always + FLT_POSTOP_FINISHED_PROCESSING in this routine. Note that cleanup + operations should never fail. + +--*/ +{ + NTSTATUS Status; + PNC_STREAM_HANDLE_CONTEXT HandleContext = NULL; + + UNREFERENCED_PARAMETER( Data ); + UNREFERENCED_PARAMETER( CompletionContext ); + + PAGED_CODE(); + + if (!FlagOn( Flags, FLTFL_POST_OPERATION_DRAINING )) { + + // + // Obtain our handle context. We should only be called here + // if we really have one. + // + + Status = FltGetStreamHandleContext( FltObjects->Instance, + FltObjects->FileObject, + &HandleContext ); + + if (!NT_SUCCESS( Status )) { + + goto NcPostCleanupCallbackCleanup; + + } + + FLT_ASSERT( HandleContext != NULL ); + + NcStreamHandleContextNotCleanup( HandleContext ); + } + + +NcPostCleanupCallbackCleanup: + + if (HandleContext != NULL) { + + FltReleaseContext( HandleContext ); + + } + + // + // We don't want to fail cleanup no matter what goes wrong. + // + + return FLT_POSTOP_FINISHED_PROCESSING; +} + + +FLT_PREOP_CALLBACK_STATUS +NcPreFsctlCallback ( + _Inout_ PFLT_CALLBACK_DATA Data, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _Flt_CompletionContext_Outptr_ PVOID *CompletionContext + ) +/*++ + +Routine Description: + + This is the pre FSCTL callback. It is called for every FSCTL + operation. This allows us to intercept and process FSCTLs which + either consume or return names which may be affected by the namespace + redirection performed by this filter. + + Currently we munge: + FSCTL_ENUM_USN_DATA + FSCTL_FIND_FILES_BY_SID + FSCTL_LOOKUP_STREAM_FROM_CLUSTER + FSCTL_READ_FILE_USN_DATA + FSCTL_READ_USN_JOURNAL + + We also need to munge: + FSCTL_TXFS_LIST_TRANSACTION_LOCKED_FILES + +Arguments: + + Data - Pointer to the filter CallbackData that is passed to us. + + FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing + opaque handles to this filter, instance, its associated volume and + file object. + + CompletionContext - The context for the completion routine for this + operation. Not used in this function. + +Return Value: + + Returns the final status of this operation. + +--*/ +{ + PAGED_CODE(); + + // + // TODO: + // FSCTL_TXFS_LIST_TRANSACTION_LOCKED_FILES + // + // The following take paths and work without any explicit change. + // Since Txf sends its creates to the top of the filter stack, we + // munge these paths on create (both for the RM and the logs.) Thus + // Txf believes its logs are in the user mapping, when they are not; + // subsequent queries return the user mapping correctly. + // + // FSCTL_TXFS_QUERY_RM_INFORMATION + // FSCTL_TXFS_START_RM + // + + switch (Data->Iopb->Parameters.FileSystemControl.Common.FsControlCode) { + case FSCTL_ENUM_USN_DATA: + return FLT_PREOP_SYNCHRONIZE; + break; + case FSCTL_FIND_FILES_BY_SID: + return NcPreFindFilesBySid( Data, + FltObjects, + CompletionContext ); + break; +#if FLT_MGR_WIN7 + case FSCTL_LOOKUP_STREAM_FROM_CLUSTER: + return FLT_PREOP_SYNCHRONIZE; + break; +#endif + case FSCTL_READ_FILE_USN_DATA: + return FLT_PREOP_SYNCHRONIZE; + break; + case FSCTL_READ_USN_JOURNAL: + return FLT_PREOP_SUCCESS_WITH_CALLBACK; + break; + default: + + // + // We're not processing this. Let the filesystem handle it + // normally. + // + + return FLT_PREOP_SUCCESS_NO_CALLBACK; + break; + + } +} + +FLT_POSTOP_CALLBACK_STATUS +NcPostFsctlCallback ( + _Inout_ PFLT_CALLBACK_DATA Data, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _When_(Data->Iopb->Parameters.FileSystemControl.Common.FsControlCode==FSCTL_FIND_FILES_BY_SID, _In_) + _When_(Data->Iopb->Parameters.FileSystemControl.Common.FsControlCode!=FSCTL_FIND_FILES_BY_SID, _In_opt_) + PVOID CompletionContext, + _In_ FLT_POST_OPERATION_FLAGS Flags + ) +/*++ + +Routine Description: + + This is the post FSCTL callback. It is called for every FSCTL + which we need to munge, including USN, find files by SID, and lookup + stream from cluster. This allows us to process these FSCTLs which + either consume or return names which may be affected by the namespace + redirection performed by this filter. + +Arguments: + + Data - Pointer to the filter CallbackData that is passed to us. + + FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing + opaque handles to this filter, instance, its associated volume and + file object. + + CompletionContext - The context for the completion routine for this + operation. Not used in this function. + + Flags - The flags for this operation. + +Return Value: + + Returns the final status of this operation. + +--*/ +{ + FLT_POSTOP_CALLBACK_STATUS Status = FLT_POSTOP_FINISHED_PROCESSING; + + if (!FlagOn( Flags, FLTFL_POST_OPERATION_DRAINING )) { + + switch (Data->Iopb->Parameters.FileSystemControl.Common.FsControlCode) { + + case FSCTL_ENUM_USN_DATA: + + Status = NcPostEnumUsnData( Data, + FltObjects, + CompletionContext, + Flags ); + break; + + case FSCTL_FIND_FILES_BY_SID: + + Status = NcPostFindFilesBySid( Data, + FltObjects, + CompletionContext, + Flags ); + + break; +#if FLT_MGR_WIN7 + case FSCTL_LOOKUP_STREAM_FROM_CLUSTER: + + Status = NcPostLookupStreamFromCluster( Data, + FltObjects, + CompletionContext, + Flags ); + + break; +#endif + + case FSCTL_READ_FILE_USN_DATA: + + Status = NcPostReadFileUsnData( Data, + FltObjects, + CompletionContext, + Flags ); + break; + + case FSCTL_READ_USN_JOURNAL: + + Status = NcPostReadUsnJournal( Data, + FltObjects, + CompletionContext, + Flags ); + break; + + default: + break; + } + } + + return Status; +} + +FLT_PREOP_CALLBACK_STATUS +NcPreQueryInformationCallback ( + _Inout_ PFLT_CALLBACK_DATA Data, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _Flt_CompletionContext_Outptr_ PVOID *CompletionContext + ) +/*++ + +Routine Description: + + This callback is invoked when the user queries a file's information. + +Arguments: + + Data - Pointer to the filter CallbackData that is passed to us. + Currently we munge: + FileAllInformation + FileAlternateNameInformation + FileHardLinkInformation + FileNameInformation + FileNormalizedNameInformation + + FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing + opaque handles to this filter, instance, its associated volume and + file object. + + CompletionContext - The context for the completion routine for this + operation. + +Return Value: + + The return value is the Status of the operation. + +--*/ +{ + FLT_PREOP_CALLBACK_STATUS result; + + PAGED_CODE(); + + // + // We only have to munge for name sensitive operations. + // + + switch( Data->Iopb->Parameters.QueryFileInformation.FileInformationClass ) { + + case FileAllInformation: + case FileNameInformation: + case FileNormalizedNameInformation: + + result = FLT_PREOP_SYNCHRONIZE; + break; + + case FileAlternateNameInformation: + result = NcPreQueryAlternateName( Data, + FltObjects, + CompletionContext ); + break; + + case FileHardLinkInformation: + + result = FLT_PREOP_SYNCHRONIZE; + break; + + default: + result = FLT_PREOP_SUCCESS_NO_CALLBACK; + break; + } + + return result; +} + +FLT_POSTOP_CALLBACK_STATUS +NcPostQueryInformationCallback ( + _Inout_ PFLT_CALLBACK_DATA Data, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _In_opt_ PVOID CompletionContext, + _In_ FLT_POST_OPERATION_FLAGS Flags + ) +/*++ + +Routine Description: + + This is the post query file information callback. It is called for + every information class we need to process. This allows us to fixup + names returned that would otherwise contain real mapping paths. + +Arguments: + + Data - Pointer to the filter CallbackData that is passed to us. + + FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing + opaque handles to this filter, instance, its associated volume and + file object. + + CompletionContext - The context for the completion routine for this + operation. Not used in this function. + + Flags - The flags for this operation. + +Return Value: + + Returns the final status of this operation. + +--*/ +{ + FLT_POSTOP_CALLBACK_STATUS Status = FLT_POSTOP_FINISHED_PROCESSING; + + PAGED_CODE(); + + if (!FlagOn( Flags, FLTFL_POST_OPERATION_DRAINING )) { + + switch( Data->Iopb->Parameters.SetFileInformation.FileInformationClass ) { + + case FileNameInformation: + case FileNormalizedNameInformation: + case FileAllInformation: + + Status = NcPostQueryName( Data, + FltObjects, + CompletionContext, + Flags ); + break; + + case FileHardLinkInformation: + Status = NcPostQueryHardLinks( Data, + FltObjects, + CompletionContext, + Flags ); + break; + } + } + return Status; +} + +FLT_PREOP_CALLBACK_STATUS +NcPreSetInformationCallback ( + _Inout_ PFLT_CALLBACK_DATA Data, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _Flt_CompletionContext_Outptr_ PVOID *CompletionContext + ) +/*++ + +Routine Description: + + This is the pre set file information callback. It is called for every + set file information operation. This allows us to intercept and process + those which either consume or return names, as well as those which would + violate the constraints imposed by this filter. + + Currently we munge: + FileDispositionInformation + FileLinkInformation + FileRenameInformation + FileShortNameInformation + +Arguments: + + Data - Pointer to the filter CallbackData that is passed to us. + + FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing + opaque handles to this filter, instance, its associated volume and + file object. + + CompletionContext - The context for the completion routine for this + operation. + +Return Value: + + The return value is the Status of the operation. + +--*/ +{ + + FLT_PREOP_CALLBACK_STATUS result; + + PAGED_CODE(); + + switch( Data->Iopb->Parameters.SetFileInformation.FileInformationClass ) { + + case FileDispositionInformation: + + result = NcPreSetDisposition( Data, + FltObjects, + CompletionContext ); + + break; + + case FileLinkInformation: + + result = NcPreSetLinkInformation( Data, + FltObjects, + CompletionContext ); + + break; + + case FileRenameInformation: + + result = NcPreRename( Data, + FltObjects, + CompletionContext ); + + break; + + case FileShortNameInformation: + + result = NcPreSetShortName( Data, + FltObjects, + CompletionContext ); + + break; + + default: + result = FLT_PREOP_SUCCESS_NO_CALLBACK; + break; + } + + return result; +} + +FLT_PREOP_CALLBACK_STATUS +NcPreDirectoryControlCallback ( + _Inout_ PFLT_CALLBACK_DATA Data, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _Flt_CompletionContext_Outptr_ PVOID *CompletionContext + ) +/*++ + +Routine Description: + + This callback is invoked when the user tries to enumerate a directory + or get change notifications. + +Arguments: + + Data - Pointer to the filter CallbackData that is passed to us. + + FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing + opaque handles to this filter, instance, its associated volume and + file object. + + CompletionContext - The context for the completion routine for this + operation. + +Return Value: + + The return value is the Status of the operation. + +--*/ +{ + FLT_PREOP_CALLBACK_STATUS Status; + + PAGED_CODE(); + + switch( Data->Iopb->MinorFunction ) { + + case IRP_MN_QUERY_DIRECTORY: + Status = NcEnumerateDirectory( Data, FltObjects, CompletionContext ); + break; + + case IRP_MN_NOTIFY_CHANGE_DIRECTORY: + Status = NcPreNotifyDirectory( Data, FltObjects, CompletionContext ); + break; + + default: + FLT_ASSERT( FALSE ); + Status = FLT_PREOP_SUCCESS_NO_CALLBACK; + + } + + return Status; +} + +FLT_POSTOP_CALLBACK_STATUS +NcPostDirectoryControlCallback ( + _Inout_ PFLT_CALLBACK_DATA Data, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _In_ PVOID CompletionContext, + _In_ FLT_POST_OPERATION_FLAGS Flags + ) +/*++ + +Routine Description: + + This callback is invoked after the user tries to enumerate a directory + or get change notifications. + +Arguments: + + Data - Pointer to the filter CallbackData that is passed to us. + + FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing + opaque handles to this filter, instance, its associated volume and + file object. + + CompletionContext - The context for the completion routine for this + operation. + +Return Value: + + The return value is the Status of the operation. + +--*/ +{ + FLT_POSTOP_CALLBACK_STATUS Status; + + // + // Note this routine must be nonpaged. It is called within completion + // routines. + // + + switch( Data->Iopb->MinorFunction ) { + + case IRP_MN_QUERY_DIRECTORY: + + // + // Currently we don't process post directory enumeration + // requests. We really should. + // + + Status = FLT_POSTOP_FINISHED_PROCESSING; + break; + + case IRP_MN_NOTIFY_CHANGE_DIRECTORY: + + Status = NcPostNotifyDirectory( Data, FltObjects, CompletionContext, Flags ); + break; + + default: + FLT_ASSERT( FALSE ); + Status = FLT_POSTOP_FINISHED_PROCESSING; + + } + + return Status; +} + +FLT_PREOP_CALLBACK_STATUS +NcPreNetworkQueryCallback ( + _Inout_ PFLT_CALLBACK_DATA Data, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _Flt_CompletionContext_Outptr_ PVOID *CompletionContext + ) +/*++ + +Routine Description: + + This callback is invoked when the user tries to do a network query open. + +Arguments: + + Data - Pointer to the filter CallbackData that is passed to us. + + FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing + opaque handles to this filter, instance, its associated volume and + file object. + + CompletionContext - The context for the completion routine for this + operation. + +Return Value: + + The return value is the Status of the operation. + +--*/ +{ + UNREFERENCED_PARAMETER( Data ); + UNREFERENCED_PARAMETER( FltObjects ); + UNREFERENCED_PARAMETER( CompletionContext ); + + PAGED_CODE(); + + // + // TODO We need to pipe these through the existing create path if + // possible. + // + + return FLT_PREOP_DISALLOW_FASTIO; +} + +NTSTATUS +NcGenerateFileNameCallback ( + _In_ PFLT_INSTANCE Instance, + _In_ PFILE_OBJECT FileObject, + _In_opt_ PFLT_CALLBACK_DATA Data, + _In_ FLT_FILE_NAME_OPTIONS NameOptions, + _Out_ PBOOLEAN CacheFileNameInformation, + _Inout_ PFLT_NAME_CONTROL OutputNameControl + ) +/*++ + +Routine Description: + + This callback is invoked to maintain FltMgr's name cache coherency + when this filter munges names. + +Arguments: + + Instance - Instance pointer for the minifilter instance that this + callback routine is registered for. + + FileObject - Pointer to a file object for the file whose name is being + requested. + + Data - Pointer to the callback data structure for the operation during + which this name is being requested. + + NameOptions - FLT_FILE_NAME_OPTIONS value that specifies the name format, + query method, and flags for this file name information query. + + CacheFileNameInformation - Pointer to a Boolean value specifying whether + this name can be cached. Set to TRUE on output if the name can be + cached; set to FALSE otherwise. + + OutputNameControl - Pointer to a Filter Manager-allocated FLT_NAME_CONTROL + structure to receive the file name on output. + +Return Value: + + The return value is the Status of the operation. + +--*/ +{ + + PAGED_CODE(); + + return NcGenerateFileName( Instance, + FileObject, + Data, + NameOptions, + CacheFileNameInformation, + OutputNameControl ); +} + +NTSTATUS +NcNormalizeNameComponentExCallback ( + _In_ PFLT_INSTANCE Instance, + _In_opt_ PFILE_OBJECT FileObject, + _In_ PCUNICODE_STRING ParentDirectory, + _In_ USHORT DeviceNameLength, + _In_ PCUNICODE_STRING Component, + _Out_writes_bytes_(ExpandComponentNameLength) PFILE_NAMES_INFORMATION ExpandComponentName, + _In_ ULONG ExpandComponentNameLength, + _In_ FLT_NORMALIZE_NAME_FLAGS Flags, + _Inout_ PVOID *NormalizationContext + ) +/*++ + +Routine Description: + + This callback is invoked to maintain FltMgr's name cache coherency + when this filter munges names. + +Arguments: + + Instance - Instance pointer for the minifilter instance that this callback + routine is registered for. + + FileObject - Optionally points to a file object that the name query is + taking place on. We can use this to flow transaction information + to any recursive requests. + + ParentDirectory - Pointer to a UNICODE_STRING structure that contains the + name of the parent directory for this name component. + + DeviceNameLength - Length, in bytes, of the parent directory name stored + in the structure that the ParentDirectory parameter points to. + + Component - Pointer to a UNICODE_STRING structure that contains the name + component to be expanded. + + ExpandComponentName - Pointer to a FILE_NAMES_INFORMATION structure that + receives the expanded (normalized) file name information for the name + component. + + ExpandComponentNameLength - Length, in bytes, of the buffer that the + ExpandComponentName parameter points to. + + NormalizationContext - Pointer to minifilter-provided context information + to be passed in any subsequent calls to this callback routine that are + made to normalize the remaining components in the same file name path. + +Return Value: + + The return value is the Status of the operation. + +--*/ +{ + PAGED_CODE(); + + return NcNormalizeNameComponentEx( Instance, + FileObject, + ParentDirectory, + DeviceNameLength, + Component, + ExpandComponentName, + ExpandComponentNameLength, + Flags, + NormalizationContext ); + +} + +NTSTATUS +NcNormalizeNameComponentCallback ( + _In_ PFLT_INSTANCE Instance, + _In_ PCUNICODE_STRING ParentDirectory, + _In_ USHORT DeviceNameLength, + _In_ PCUNICODE_STRING Component, + _Out_writes_bytes_(ExpandComponentNameLength) PFILE_NAMES_INFORMATION ExpandComponentName, + _In_ ULONG ExpandComponentNameLength, + _In_ FLT_NORMALIZE_NAME_FLAGS Flags, + _Inout_ PVOID *NormalizationContext + ) +/*++ + +Routine Description: + + This callback is invoked to maintain FltMgr's name cache coherency + when this filter munges names. + +Arguments: + + Instance - Instance pointer for the minifilter instance that this callback + routine is registered for. + + ParentDirectory - Pointer to a UNICODE_STRING structure that contains the + name of the parent directory for this name component. + + DeviceNameLength - Length, in bytes, of the parent directory name stored + in the structure that the ParentDirectory parameter points to. + + Component - Pointer to a UNICODE_STRING structure that contains the name + component to be expanded. + + ExpandComponentName - Pointer to a FILE_NAMES_INFORMATION structure that + receives the expanded (normalized) file name information for the name + component. + + ExpandComponentNameLength - Length, in bytes, of the buffer that the + ExpandComponentName parameter points to. + + NormalizationContext - Pointer to minifilter-provided context information + to be passed in any subsequent calls to this callback routine that are + made to normalize the remaining components in the same file name path. + +Return Value: + + The return value is the Status of the operation. + +--*/ +{ + + PAGED_CODE(); + + return NcNormalizeNameComponentEx( Instance, + NULL, + ParentDirectory, + DeviceNameLength, + Component, + ExpandComponentName, + ExpandComponentNameLength, + Flags, + NormalizationContext ); +} + + + diff --git a/filesys/miniFilter/NameChanger/nc.h b/filesys/miniFilter/NameChanger/nc.h new file mode 100644 index 00000000..c2509faa --- /dev/null +++ b/filesys/miniFilter/NameChanger/nc.h @@ -0,0 +1,1040 @@ +#ifndef __NC_H__ +#define __NC_H__ + +#pragma warning( disable: 4701 ) // 'Potentially' uninitialized local variable. + // Hopefully one day the compiler will be a little + // more factual about this and we can use it. It + // would make a great warning. + +// +// Allocation Tags +// + +#define NC_TAG 'NC__' // Generic NameChanger Tag +#define NC_MAPPING_TAG 'NCMP' // Mapping Buffer Tag +#define NC_INSTANCE_CONTEXT_TAG 'NCin' // Instance Context Tag +#define NC_LOCK_TAG 'NClk' // Tag for nonpaged locks +#define NC_GENERATE_NAME_TAG 'NCgn' // Tag for strings which are allocated for name generation +#define NC_NORMALIZE_NAME_TAG 'NCnn' // Tag for strings which are allocated for name normalization +#define NC_FILE_NAME_TAG 'NCfn' // Tag for strings which are allocated for file names in file objects +#define NC_DIR_QRY_CACHE_TAG 'NCqc' // Tag for buffers which are allocated for directory enumeration cache and injection entries +#define NC_DIR_QRY_SEARCH_STRING 'NCqs' // Tag for strings which are allocated for directory search strings +#define NC_SET_LINK_BUFFER_TAG 'NCsl' // Tag for munge buffer in Set Link operations +#define NC_RENAME_BUFFER_TAG 'NCrn' // Tag for munge buffer in Rename operations + + +#define NC_STREAM_HANDLE__CONTEXT_TAG 'NCsh' + +// +// Macros to make math easier. +// + +#define NC_SEPARATOR ((WCHAR) L'\\') +#define EMPTY_UNICODE_STRING {0, 0, NULL} + +#define AlignToSize(_length, _alignment) \ + (((_length) + ((_alignment) - 1)) & ~((_alignment) - 1)) + +#define Max(a,b) ((a) >= (b) ? (a) : (b)) + +#define NcFreeUnicodeString( UCS ) \ + ExFreePoolWithTag( (UCS)->Buffer, NC_TAG ); \ + (UCS)->Buffer = NULL; \ + (UCS)->MaximumLength = \ + (UCS)->Length = 0; + +// +// We need to supress a few warnings in order to enable compilation with +// the 2003 IFS Kit. WDK does not require this. +// + +#pragma warning( push ) +#pragma warning( disable: 4201 4214 ) +#include +#pragma warning( pop ) + +#include + +#define INVALID_HANDLE_VALUE ((HANDLE) -1) + +// +// Typedefs for dynamically imported routines +// + +typedef +NTSTATUS +(* NC_REPLACE_FILEOBJECT_NAME_TYPE) ( + _In_ PFILE_OBJECT FileObject, + _In_reads_bytes_(FileNameLength) PWSTR NewFileName, + _In_ USHORT FileNameLength + ); + +typedef +NTSTATUS +( * NC_QUERY_DIRECTORY_FILE_TYPE) ( + _In_ PFLT_INSTANCE Instance, + _In_ PFILE_OBJECT FileObject, + _Out_writes_bytes_(Length) PVOID FileInformation, + _In_ ULONG Length, + _In_ FILE_INFORMATION_CLASS FileInformationClass, + _In_ BOOLEAN ReturnSingleEntry, + _In_opt_ PUNICODE_STRING FileName, + _In_ BOOLEAN RestartScan, + _Out_opt_ PULONG LengthReturned + ); + +typedef +NTSTATUS +( * NC_CREATE_FILE_EX_TYPE) ( + _In_ PFLT_FILTER Filter, + _In_opt_ PFLT_INSTANCE Instance, + _Out_ PHANDLE FileHandle, + _Outptr_opt_ PFILE_OBJECT *FileObject, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _In_opt_ PLARGE_INTEGER AllocationSize, + _In_ ULONG FileAttributes, + _In_ ULONG ShareAccess, + _In_ ULONG CreateDisposition, + _In_ ULONG CreateOptions, + _In_reads_bytes_opt_(EaLength) PVOID EaBuffer, + _In_ ULONG EaLength, + _In_ ULONG Flags + ); + +typedef +NTSTATUS +( * NC_CREATE_FILE_EX2_TYPE) ( + _In_ PFLT_FILTER Filter, + _In_opt_ PFLT_INSTANCE Instance, + _Out_ PHANDLE FileHandle, + _Outptr_opt_ PFILE_OBJECT *FileObject, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _In_opt_ PLARGE_INTEGER AllocationSize, + _In_ ULONG FileAttributes, + _In_ ULONG ShareAccess, + _In_ ULONG CreateDisposition, + _In_ ULONG CreateOptions, + _In_reads_bytes_opt_(EaLength) PVOID EaBuffer, + _In_ ULONG EaLength, + _In_ ULONG Flags, + _In_opt_ PIO_DRIVER_CREATE_CONTEXT DriverContext + ); + +typedef +PVOID +( * NC_GET_NEW_SYSTEM_BUFFER_ADDRESS ) ( + _In_ PFLT_CALLBACK_DATA Data + ); + +// +// Common Structures +// + +// +// Struct which provides a single buffer and offset for data caching. +// + +typedef struct __NC_CACHE_ENTRY { + + char *Buffer; + ULONG CurrentOffset; + +} NC_CACHE_ENTRY, *PNC_CACHE_ENTRY; + +// +// Structure which manages a single path. These are used to precompute +// various paths for the mapping for easy comparison. We do not use +// this structure for user-supplied paths (eg. on open.) +// + +typedef struct _NC_MAPPING_PATH { + + UNICODE_STRING FullPath; // \volume_name\parent_path\final_component + UNICODE_STRING VolumePath; // \volume_name + UNICODE_STRING ParentPath; // \volume_name\parent_name + UNICODE_STRING FinalComponentName; // final_component or \ (for volume root open) + UNICODE_STRING VolumelessName; // \parent_name\final_component + USHORT NumberComponentsInFullPath; // \volume_name\parent_name\final_component == 3 + USHORT NumberComponentsInVolumePath; // \volume_name == 1 + +} NC_MAPPING_PATH, *PNC_MAPPING_PATH; + +// +// Structure which manages a long and short name pairing. +// + +typedef struct _NC_MAPPING_ENTRY { + + //Strings which manage the long name. + NC_MAPPING_PATH LongNamePath; + + //Strings which manage the short name. + NC_MAPPING_PATH ShortNamePath; + +} NC_MAPPING_ENTRY, *PNC_MAPPING_ENTRY; + +// +// Structure which manages with user and real mapping. +// + +typedef struct _NC_MAPPING { + + NC_MAPPING_ENTRY RealMapping; + NC_MAPPING_ENTRY UserMapping; + +} NC_MAPPING, *PNC_MAPPING; + +// +// NC_PATH_OVERLAP is a series of flags which determine a name's relation to a mapping. +// +// Ancestor means that the path is a directory along the mapping path. +// For example \a\b is an ancestor of \a\b\c, but \a\b\x is not an ancestor of \a\b\c. +// +// Parent means that the path is the parent directory of the mapping path. +// +// Match means that the path and the mapping are equal. +// +// InMapping means that the path is either the mapping itself, or a decendent of the mapping. +// +// Peer means that the object is directly next to the mapping (a\b\x is a peer of a\b\y.) +// +// If no flags are set, the path is entirely outside the mapping. +// + +// +// TODO: Should we use a different representation of this structure which +// does not require warning suppressions? +// +#pragma warning( push ) +#pragma warning( disable: 4201 ) +typedef union { + ULONG EntireFlags; + struct { + int Ancestor:1; + int Parent:1; + int Match:1; + int InMapping:1; + int Peer:1; + }; +} NC_PATH_OVERLAP, *PNC_PATH_OVERLAP; +#pragma warning( pop ) + +// +// Instance Context Defines +// + +typedef struct _NC_INSTANCE_CONTEXT { + + // The mapping is defined as a property of the instance. + NC_MAPPING Mapping; + + // The file system we're attached to + FLT_FILESYSTEM_TYPE VolumeFilesystemType; + +} NC_INSTANCE_CONTEXT, *PNC_INSTANCE_CONTEXT; + + +// +// This context is used when a file is enumerating +// a directory and we need to cache entries in our context. +// + +typedef struct _NC_DIR_QRY_CONTEXT { + + BOOLEAN EnumerationOutstanding; + + // Determines if the structure is in use. If it is, + // then there is no need to initialize the cache or injection entry. + BOOLEAN InUse; + + // Pointer to list of entries which we must drain from. + NC_CACHE_ENTRY Cache; + + // Pointer to entry which we want to inject. + NC_CACHE_ENTRY InjectionEntry; + + // The user provided search string which can only be set up on + // the first query. + UNICODE_STRING SearchString; + + // The information class which the user requested. + FILE_INFORMATION_CLASS InformationClass; + +} NC_DIR_QRY_CONTEXT, *PNC_DIR_QRY_CONTEXT; + +// +// This context is used when a file is being used for +// directory notification forwarding. +// + +typedef struct _NC_DIR_NOT_IO_CACHE { + + // + // Stores the state of the cache. + // If the pointer is NULL, there is nothing in cache. + // + + NC_CACHE_ENTRY Cache; + + // + // If ReadyToIssue is TRUE, then its safe to fire off the request. + // + + BOOLEAN ReadyToIssue; + + // + // Io is a pointer to the callback data. + // When ReadyToUse new io can be issued. + // + + PFLT_CALLBACK_DATA Io; + + // + // SystemBuffer is a pointer to a system buffer which will + // be used to issue the IO. + // + + char * SystemBuffer; + ULONG SystemBufferLength; + +} NC_DIR_NOT_IO_CACHE, * PNC_DIR_NOT_IO_CACHE; + +typedef struct _NC_DIR_NOT_CONTEXT { + + // + // We save off some parameters used to send down the user + // request so we can look them up in our completion callback. + // In some cases, this is an optimization. In others, it's + // because we need access to state when the user request may + // be completed. + // + + enum { + Uninitialized, + Filter, + Munge, + Merge + } Mode; + BOOLEAN CancelSeen; + BOOLEAN CleanupSeen; + BOOLEAN IgnoreCase; + BOOLEAN InsufficientBufferSeen; + BOOLEAN WatchTree; + UCHAR OperationFlags; + ULONG CompletionFilter; + + // + // These names allow us to re-build full path names for each + // notification. We need two strings to represent paths to + // the handle the user opened, or the handle we opened to + // the mapping parent when merging notifications. After + // building the full name, we'll need to re-translate back + // to the user's path for returning. These names are saved + // so we don't need to construct them again in our completion + // routine. + // + + UNICODE_STRING UserRequestName; + UNICODE_STRING MappingParentName; + + // + // Our three potential requests. + // + // UserRequest - the request the user sent to us on this handle. + // We may have sent this to the filesystem (Munge case), or we + // may hang on to it ourselves (Filter and Merge cases.) + // + // ShadowRequest - the request sent to the filesystem on the + // user's handle. This is used in the Filter and Merge cases. + // In the Filter case, we do this to allow us to reissue + // the IO if we have filtered out all events so have nothing + // to return to the user. In the merge case, we require two + // requests that we control, and will complete the user's + // request when either of our requests complete. + // + // MappingRequest - the request sent to the filesystem on the + // handle we opened to the parent of the mapping. Only valid + // when in Merge mode. We use the parent so as to capture + // notifications about changes to the mapping itself. + // + + PFLT_CALLBACK_DATA UserRequest; + PFLT_CALLBACK_DATA ShadowRequest; + PFLT_CALLBACK_DATA MappingRequest; + + PNC_INSTANCE_CONTEXT InstanceContext; + + // + // Specifies a handle to the parent of the real mapping. + // This can be NULL, and is only used if Mode == Merge. + // This occurs when we are watching the parent of the + // mapping, or if we are watching the subtree of the user + // mapping but not the subtree of the real mapping. Keep + // a workitem so that we can reliably clean up this object, + // which we can't do inline at APC level. + // + + HANDLE RealParentHandle; + PFILE_OBJECT RealParentFileObject; + PFLT_GENERIC_WORKITEM RealParentCloseWorkItem; + + PFILE_NOTIFY_INFORMATION BufferToFree; + ULONG BufferLength; + +} NC_DIR_NOT_CONTEXT, *PNC_DIR_NOT_CONTEXT; + +typedef struct _NC_FIND_BY_SID_CONTEXT { + + // + // Specifies a handle to the real mapping. This can + // be NULL, and is only required if finding objects + // under an ancestor of the user mapping which is not + // an ancestor of the real mapping (so we need to + // inject entries.) + // + + HANDLE RealHandle; + PFILE_OBJECT RealFileObject; + + // + // If the filesystem returns more results than can + // be returned in the current call, we need to buffer + // them and return them on a subsequent call. + // BufferToFree refers to the beginning of the allocation, + // which we can tear down when all entries are consumed. + // BufferSize is the size of this buffer, in bytes. + // CurrentEntry is the offset into this buffer where + // we should begin returning result on the subsequent + // call. + // + + PFILE_NAME_INFORMATION BufferToFree; + ULONG BufferSize; + ULONG CurrentEntry; + + // + // Count of the number of outstanding requests. We need + // to know this to ensure we only tear down state when + // a) holding the lock and b) no other requests are + // outstanding. + // + + ULONG OutstandingRequests; + +} NC_FIND_BY_SID_CONTEXT, *PNC_FIND_BY_SID_CONTEXT; + +// +// Stream Handle Context +// + +typedef struct _NC_STREAM_HANDLE_CONTEXT { + + PERESOURCE Lock; + + NC_DIR_NOT_CONTEXT DirectoryNotificationContext; + NC_DIR_QRY_CONTEXT DirectoryQueryContext; + NC_FIND_BY_SID_CONTEXT FindBySidContext; + +} NC_STREAM_HANDLE_CONTEXT, *PNC_STREAM_HANDLE_CONTEXT; + +#define NcLockStreamHandleContext( C ) \ + FltAcquireResourceExclusive( (C)->Lock ); + +#define NcUnlockStreamHandleContext( C ) \ + FltReleaseResource( (C)->Lock ); + +// +// Structure which gives us offsets to find values within directory +// query buffers. +// + +typedef struct _DIRECTORY_CONTROL_OFFSETS { + + ULONG NextEntryOffsetDist; + ULONG FileNameLengthDist; + ULONG FileNameDist; + + BOOLEAN ShortNamePresent; + ULONG ShortNameLengthDist; + ULONG ShortNameDist; + +} DIRECTORY_CONTROL_OFFSETS, *PDIRECTORY_CONTROL_OFFSETS; + +typedef struct _NC_GLOBAL_DATA { + UNICODE_STRING UserMappingPath; + UNICODE_STRING UserMappingFinalComponentShort; + UNICODE_STRING UserMappingFinalComponentLong; + + UNICODE_STRING RealMappingPath; + UNICODE_STRING RealMappingFinalComponent; + + PFLT_FILTER FilterHandle; +} NC_GLOBAL_DATA, *PNC_GLOBAL_DATA; + +extern NC_GLOBAL_DATA NcGlobalData; + +// +// Function declarations +// + +// +// The following functions exist in nchelper.c +// + +_When_(Data == NULL, _Pre_satisfies_(FileObject != NULL && Instance != NULL)) +_When_(FileObject == NULL || Instance == NULL, _Pre_satisfies_(Data != NULL)) +NTSTATUS +NcGetFileNameInformation( + _In_opt_ PFLT_CALLBACK_DATA Data, + _In_opt_ PFILE_OBJECT FileObject, + _In_opt_ PFLT_INSTANCE Instance, + _In_ FLT_FILE_NAME_OPTIONS NameOptions, + _Outptr_ PFLT_FILE_NAME_INFORMATION *FileNameInformation + ); + +NTSTATUS +NcAllocateEResource( + _Out_ PERESOURCE * OutputLock + ); + +VOID +NcFreeEResource( + _In_ PERESOURCE Lock + ); + +NTSTATUS +NcCreateFileHelper ( + _In_ PFLT_FILTER Filter, + _In_opt_ PFLT_INSTANCE Instance, + _Out_ PHANDLE FileHandle, + _Outptr_opt_ PFILE_OBJECT *FileObject, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _In_opt_ PLARGE_INTEGER AllocationSize, + _In_ ULONG FileAttributes, + _In_ ULONG ShareAccess, + _In_ ULONG CreateDisposition, + _In_ ULONG CreateOptions, + _In_reads_bytes_opt_(EaLength) PVOID EaBuffer, + _In_ ULONG EaLength, + _In_ ULONG Flags, + _In_opt_ PFILE_OBJECT ParentFileObject + ); + +NTSTATUS +NcSetCancelCompletion ( + _In_ PFLT_CALLBACK_DATA Data, + _In_ PFLT_COMPLETE_CANCELED_CALLBACK CanceledCallback + ); + +LONG +NcExceptionFilter ( + _In_ PEXCEPTION_POINTERS ExceptionPointer, + _In_ BOOLEAN AccessingUserBuffer + ); + +// +// The following functions exist in ncmapping.c +// + +VOID +NcInitMappingPath ( + _Out_ PNC_MAPPING_PATH Path + ); + +VOID +NcTeardownMappingPath ( + _Inout_ PNC_MAPPING_PATH Path + ); + +NTSTATUS +NcBuildMappingPathFromVolume ( + _In_ PFLT_VOLUME CONST Volume, + _In_ PUNICODE_STRING ParentPath, + _In_ PUNICODE_STRING FinalComponentName, + _Inout_ PNC_MAPPING_PATH Entry + ); + +BOOLEAN +NcIsMappingZeroed ( + PNC_MAPPING Mapping + ); + +VOID +NcInitMapping ( + PNC_MAPPING Mapping + ); + +BOOLEAN +NcIsMappingZeroed ( + PNC_MAPPING Mapping + ); + +VOID +NcInitMapping ( + PNC_MAPPING Mapping + ); + +VOID +NcTeardownMapping ( + _Inout_ PNC_MAPPING Mapping + ); + +NTSTATUS +NcBuildMapping ( + _In_ PFILE_OBJECT UserParent, + _In_ PFILE_OBJECT RealParent, + _In_ PUNICODE_STRING UserFinalComponentShortName, + _In_ PUNICODE_STRING UserFinalComponentLongName, + _In_ PUNICODE_STRING RealFinalComponentName, + _In_ PFLT_INSTANCE Instance, + _Out_ PNC_MAPPING Mapping + ); + +// +// The following functions exist in ncinit.c +// + +NTSTATUS +NcInitializeMapping( + _In_ PUNICODE_STRING RegistryPath + ); + +// +// The following functions exist in ncpath.c +// + +BOOLEAN +NcComparePath ( + _In_ PCUNICODE_STRING Name, + _In_ PNC_MAPPING_ENTRY Mapping, + _Out_opt_ PUNICODE_STRING Remainder, + _In_ BOOLEAN IgnoreCase, + _In_ BOOLEAN ContainsDevice, + _Out_ PNC_PATH_OVERLAP Overlap + ); + +_Post_satisfies_(NewName->MaximumLength < MAXUSHORT) +_Post_satisfies_(NewName->Length <= NewName->MaximumLength) +_Must_inspect_result_ +NTSTATUS +NcConstructPath ( + _In_ PNC_MAPPING_ENTRY RealPath, + _In_ PUNICODE_STRING Remainder, + _In_ BOOLEAN IncludeVolume, + _Out_ _At_(NewName->Buffer, __drv_allocatesMem(Mem)) PUNICODE_STRING NewName + ); + +NTSTATUS +NcParseFinalComponent ( + _In_ PUNICODE_STRING EntirePath, + _Out_ PUNICODE_STRING ParentPath, + _Out_ PUNICODE_STRING FinalComponent + ); + +// +// The following functions exist in nccontext.c +// + +NTSTATUS +NcStreamHandleContextAllocAndAttach( + _In_ PFLT_FILTER Filter, + _In_ PFLT_INSTANCE Instance, + _In_ PFILE_OBJECT FileObject, + _Out_ PNC_STREAM_HANDLE_CONTEXT * Context + ); + +VOID +NcInstanceContextClose ( + _In_ PFLT_CONTEXT Context, + _In_ FLT_CONTEXT_TYPE ContextType + ); + +VOID +NcStreamHandleContextClose ( + _In_ PFLT_CONTEXT Context, + _In_ FLT_CONTEXT_TYPE ContextType + ); + +// +// The following functions exist in nccreate.c +// + +FLT_PREOP_CALLBACK_STATUS +NcPreCreate ( + _Inout_ PFLT_CALLBACK_DATA Data, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _Flt_CompletionContext_Outptr_ PVOID *CompletionContext + ); + +// +// The following functions exist in ncnameprov.c +// + +NTSTATUS +NcGenerateFileName ( + _In_ PFLT_INSTANCE Instance, + _In_ PFILE_OBJECT FileObject, + _In_opt_ PFLT_CALLBACK_DATA Data, + _In_ FLT_FILE_NAME_OPTIONS NameOptions, + _Out_ PBOOLEAN CacheFileNameInformation, + _Inout_ PFLT_NAME_CONTROL FileName + ); + +NTSTATUS +NcNormalizeNameComponentEx ( + _In_ PFLT_INSTANCE Instance, + _In_opt_ PFILE_OBJECT FileObject, + _In_ PCUNICODE_STRING ParentDirectory, + _In_ USHORT DeviceNameLength, + _In_ PCUNICODE_STRING Component, + _Out_writes_bytes_(ExpandComponentNameLength) PFILE_NAMES_INFORMATION ExpandComponentName, + _In_ ULONG ExpandComponentNameLength, + _In_ FLT_NORMALIZE_NAME_FLAGS Flags, + _Inout_ PVOID *NormalizationContext + ); + +// +// The following functions exist in ncoffsets.c +// + +BOOLEAN +NcDetermineStructureOffsets ( + _Out_ PDIRECTORY_CONTROL_OFFSETS Offsets, + _In_ FILE_INFORMATION_CLASS Information + ); + +VOID +NcCalculateDirectoryNotificationOffsets ( + PDIRECTORY_CONTROL_OFFSETS Offsets + ); + +ULONG +NcGetNextEntryOffset ( + _In_ CONST PVOID Buffer, + _In_ CONST PDIRECTORY_CONTROL_OFFSETS Offsets + ); + +PVOID +NcGetNextEntry ( + _In_ CONST PVOID Buffer, + _In_ CONST PDIRECTORY_CONTROL_OFFSETS Offsets + ); + +ULONG +NcGetFileNameLength ( + _In_ CONST PVOID Buffer, + _In_ CONST PDIRECTORY_CONTROL_OFFSETS Offsets + ); + +ULONG +NcGetEntrySize ( + _In_ CONST PVOID Buffer, + _In_ CONST PDIRECTORY_CONTROL_OFFSETS Offsets + ); + +PWSTR +NcGetFileName ( + _In_ CONST PVOID Buffer, + _In_ CONST PDIRECTORY_CONTROL_OFFSETS Offsets + ); + +PWSTR +NcGetShortName ( + _In_ CONST PVOID Buffer, + _In_ CONST PDIRECTORY_CONTROL_OFFSETS Offsets + ); + +CCHAR +NcGetShortNameLength ( + _In_ CONST PVOID Buffer, + _In_ CONST PDIRECTORY_CONTROL_OFFSETS Offsets + ); + +VOID +NcSetNextEntryOffset ( + _Inout_ PVOID Buffer, + _In_ CONST PDIRECTORY_CONTROL_OFFSETS Offsets, + _In_ BOOLEAN ForceLast); + +VOID +NcSetFileName ( + _In_ PVOID Entry, + _In_ PWSTR NewName, + _In_ ULONG Length, + _In_ CONST PDIRECTORY_CONTROL_OFFSETS Offsets, + _In_ BOOLEAN ForceLast + ); + +VOID +NcSetShortName ( + _In_ PVOID Entry, + _In_ PWSTR NewShortName, + _In_ USHORT Length, + _In_ CONST PDIRECTORY_CONTROL_OFFSETS Offsets + ); + +// +// The following functions exist in ncdirenum.c +// + +FLT_PREOP_CALLBACK_STATUS +NcEnumerateDirectory ( + _Inout_ PFLT_CALLBACK_DATA Data, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _Flt_CompletionContext_Outptr_ PVOID *CompletionContext + ); + +NTSTATUS +NcEnumerateDirectorySetupInjection ( + _Inout_ PNC_DIR_QRY_CONTEXT DirQryCtx, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _In_ PNC_INSTANCE_CONTEXT InstanceContext, + _In_ PDIRECTORY_CONTROL_OFFSETS Offsets, + _In_ FILE_INFORMATION_CLASS InformationClass + ); + +VOID +NcEnumerateDirectoryReset ( + _Inout_ PNC_DIR_QRY_CONTEXT dirCtx + ); + +NTSTATUS +NcPerformEnumeration(); + +NTSTATUS +NcPopulateCacheEntry ( + _In_ PFLT_INSTANCE Instance, + _In_ PFILE_OBJECT FileObject, + _In_ ULONG BufferLength, + _In_ FILE_INFORMATION_CLASS FileInfoClass, + _In_ PUNICODE_STRING SearchString, + _In_ BOOLEAN RestartScan, + _Out_ PNC_CACHE_ENTRY Cache + ); + +PNC_CACHE_ENTRY +NcDirEnumSelectNextEntry ( + _Inout_ PNC_DIR_QRY_CONTEXT Context, + _In_ PDIRECTORY_CONTROL_OFFSETS Offsets, + _In_ BOOLEAN IgnoreCase + ); + +BOOLEAN +NcSkipName ( + _In_ PDIRECTORY_CONTROL_OFFSETS Offsets, + _In_ PNC_DIR_QRY_CONTEXT Context, + _In_ NC_PATH_OVERLAP RealOverlap, + _In_ PNC_MAPPING Mapping, + _In_ BOOLEAN IgnoreCase + ); + +_Success_(*Copied) +ULONG +NcCopyDirEnumEntry ( + _Out_ PVOID UserBuffer, + _In_ ULONG UserOffset, + _In_ ULONG UserSize, + _Inout_ PNC_CACHE_ENTRY Entry, + _In_ PDIRECTORY_CONTROL_OFFSETS Offsets, + _Out_ PBOOLEAN Copied + ); + +NTSTATUS +NcStreamHandleContextDirEnumCreate ( + _Out_ PNC_DIR_QRY_CONTEXT Context + ); + +NTSTATUS +NcStreamHandleContextEnumSetup ( + _Inout_ PNC_DIR_QRY_CONTEXT DirContext, + _In_ PNC_INSTANCE_CONTEXT InstanceContext, + _In_ PDIRECTORY_CONTROL_OFFSETS Offsets, + _In_ PFLT_CALLBACK_DATA Data, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _In_ NC_PATH_OVERLAP UserMappingOverlap, + _Out_ PBOOLEAN FirstUsage + ); + +VOID +NcStreamHandleContextEnumClose ( + _In_ PNC_DIR_QRY_CONTEXT DirContext + ); + +// +// The following functions exist in ncdirnotify.c +// + +FLT_PREOP_CALLBACK_STATUS +NcPreNotifyDirectory ( + _Inout_ PFLT_CALLBACK_DATA Data, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _Flt_CompletionContext_Outptr_ PVOID *CompletionContext + ); + +FLT_POSTOP_CALLBACK_STATUS +NcPostNotifyDirectory ( + _Inout_ PFLT_CALLBACK_DATA Data, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _In_ PVOID CompletionContext, + _In_ FLT_POST_OPERATION_FLAGS Flags + ); + +NTSTATUS +NcStreamHandleContextNotCreate ( + _Out_ PNC_DIR_NOT_CONTEXT Context + ); + +VOID +NcStreamHandleContextNotCleanup( + _In_ PNC_STREAM_HANDLE_CONTEXT HandleContext + ); + +VOID +NcStreamHandleContextNotClose ( + _In_ PNC_DIR_NOT_CONTEXT DirContext + ); + +// +// The following functions exist in ncfileinfo.c +// + +FLT_PREOP_CALLBACK_STATUS +NcPreQueryAlternateName ( + _Inout_ PFLT_CALLBACK_DATA Data, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _Flt_CompletionContext_Outptr_ PVOID *CompletionContext + ); + +FLT_POSTOP_CALLBACK_STATUS +NcPostQueryHardLinks ( + _Inout_ PFLT_CALLBACK_DATA Data, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _In_opt_ PVOID CompletionContext, + _In_ FLT_POST_OPERATION_FLAGS Flags + ); + +FLT_POSTOP_CALLBACK_STATUS +NcPostQueryName ( + _Inout_ PFLT_CALLBACK_DATA Data, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _In_opt_ PVOID CompletionContext, + _In_ FLT_POST_OPERATION_FLAGS Flags + ); + +FLT_PREOP_CALLBACK_STATUS +NcPreRename ( + _Inout_ PFLT_CALLBACK_DATA Data, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _Flt_CompletionContext_Outptr_ PVOID *CompletionContext + ); + +FLT_PREOP_CALLBACK_STATUS +NcPreSetDisposition ( + _Inout_ PFLT_CALLBACK_DATA Data, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _Flt_CompletionContext_Outptr_ PVOID *CompletionContext + ); + +FLT_PREOP_CALLBACK_STATUS +NcPreSetLinkInformation ( + _Inout_ PFLT_CALLBACK_DATA Data, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _Flt_CompletionContext_Outptr_ PVOID *CompletionContext + ); + +FLT_PREOP_CALLBACK_STATUS +NcPreSetShortName ( + _Inout_ PFLT_CALLBACK_DATA Data, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _Flt_CompletionContext_Outptr_ PVOID *CompletionContext + ); + +// +// The following functions exist in ncfsctrl.c +// + + +FLT_POSTOP_CALLBACK_STATUS +NcPostEnumUsnData ( + _Inout_ PFLT_CALLBACK_DATA Data, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _In_opt_ PVOID CompletionContext, + _In_ FLT_POST_OPERATION_FLAGS Flags + ); + +NTSTATUS +NcStreamHandleContextFindBySidCreate ( + _Out_ PNC_FIND_BY_SID_CONTEXT Context + ); + +VOID +NcStreamHandleContextFindBySidClose ( + _In_ PNC_FIND_BY_SID_CONTEXT Context + ); + +FLT_PREOP_CALLBACK_STATUS +NcPreFindFilesBySid ( + _Inout_ PFLT_CALLBACK_DATA Data, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _Flt_CompletionContext_Outptr_ PVOID *CompletionContext + ); + +FLT_POSTOP_CALLBACK_STATUS +NcPostFindFilesBySid ( + _Inout_ PFLT_CALLBACK_DATA Data, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _In_ PVOID CompletionContext, + _In_ FLT_POST_OPERATION_FLAGS Flags + ); + +#ifdef FLT_MGR_WIN7 +FLT_POSTOP_CALLBACK_STATUS +NcPostLookupStreamFromCluster ( + _Inout_ PFLT_CALLBACK_DATA Data, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _In_opt_ PVOID CompletionContext, + _In_ FLT_POST_OPERATION_FLAGS Flags + ); +#endif + +FLT_POSTOP_CALLBACK_STATUS +NcPostReadFileUsnData ( + _Inout_ PFLT_CALLBACK_DATA Data, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _In_opt_ PVOID CompletionContext, + _In_ FLT_POST_OPERATION_FLAGS Flags + ); + +FLT_POSTOP_CALLBACK_STATUS +NcPostReadUsnJournal ( + _Inout_ PFLT_CALLBACK_DATA Data, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _In_opt_ PVOID CompletionContext, + _In_ FLT_POST_OPERATION_FLAGS Flags + ); + +// +// The following functions exist in nccompat.c +// + +VOID +NcCompatInit(); + +// +// Global variables +// + +extern PFLT_FILTER gFilterHandle; +extern NC_REPLACE_FILEOBJECT_NAME_TYPE NcReplaceFileObjectName; +extern NC_QUERY_DIRECTORY_FILE_TYPE NcQueryDirectoryFile; +extern NC_CREATE_FILE_EX2_TYPE NcCreateFileEx2; +extern NC_GET_NEW_SYSTEM_BUFFER_ADDRESS NcGetNewSystemBufferAddress; + +#endif /* __NC_H__ */ + diff --git a/filesys/miniFilter/NameChanger/nc.rc b/filesys/miniFilter/NameChanger/nc.rc new file mode 100644 index 00000000..490b44cb --- /dev/null +++ b/filesys/miniFilter/NameChanger/nc.rc @@ -0,0 +1,10 @@ +#include + +#include + +#define VER_FILETYPE VFT_DRV +#define VER_FILESUBTYPE VFT2_DRV_SYSTEM +#define VER_FILEDESCRIPTION_STR "Name Changer Filter Driver" +#define VER_INTERNALNAME_STR "nc.sys" + +#include "common.ver" diff --git a/filesys/miniFilter/NameChanger/nccompat.c b/filesys/miniFilter/NameChanger/nccompat.c new file mode 100644 index 00000000..204b10fe --- /dev/null +++ b/filesys/miniFilter/NameChanger/nccompat.c @@ -0,0 +1,468 @@ +/*++ + +Copyright (c) 1999 - 2002 Microsoft Corporation + +Module Name: + + nccompat.c + +Abstract: + + Contains compatibility routines so that name changer works on + all OSes. Functions not available on older OSes are emulated here. + We try, wherever possible, to call into newer routines directly and + only fall back to emulation if required. + +Environment: + + Kernel mode + +--*/ + +#include "nc.h" + +// +// Prototypes for alternates. +// + +NTSTATUS +NcReplaceFileObjectNameAlternate ( + _In_ PFILE_OBJECT FileObject, + _In_reads_bytes_(FileNameLength) PWSTR NewFileName, + _In_ USHORT FileNameLength + ); + +NTSTATUS +NcQueryDirectoryFileAlternate ( + _In_ PFLT_INSTANCE Instance, + _In_ PFILE_OBJECT FileObject, + _In_reads_bytes_(Length) PVOID FileInformation, + _In_ ULONG Length, + _In_ FILE_INFORMATION_CLASS FileInformationClass, + _In_ BOOLEAN ReturnSingleEntry, + _In_opt_ PUNICODE_STRING FileName, + _In_ BOOLEAN RestartScan, + _Out_opt_ PULONG LengthReturned + ); + +NTSTATUS +FLTAPI +NcCreateFileEx2Alternate ( + _In_ PFLT_FILTER Filter, + _In_opt_ PFLT_INSTANCE Instance, + _Out_ PHANDLE FileHandle, + _Outptr_opt_ PFILE_OBJECT *FileObject, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _In_opt_ PLARGE_INTEGER AllocationSize, + _In_ ULONG FileAttributes, + _In_ ULONG ShareAccess, + _In_ ULONG CreateDisposition, + _In_ ULONG CreateOptions, + _In_reads_bytes_opt_(EaLength) PVOID EaBuffer, + _In_ ULONG EaLength, + _In_ ULONG Flags, + _In_opt_ PIO_DRIVER_CREATE_CONTEXT DriverContext + ); + +#pragma alloc_text(PAGE, NcCompatInit) +#pragma alloc_text(PAGE, NcCreateFileEx2Alternate) +#pragma alloc_text(PAGE, NcQueryDirectoryFileAlternate) +#pragma alloc_text(PAGE, NcReplaceFileObjectNameAlternate) + +// +// Global variables which hold pointers to the functions we will call. +// + +NC_REPLACE_FILEOBJECT_NAME_TYPE NcReplaceFileObjectName; +NC_QUERY_DIRECTORY_FILE_TYPE NcQueryDirectoryFile; +NC_CREATE_FILE_EX2_TYPE NcCreateFileEx2; +NC_GET_NEW_SYSTEM_BUFFER_ADDRESS NcGetNewSystemBufferAddress; + +// +// Holder for FltCreateFileEx, if it exists and we need to call it. +// + +NC_CREATE_FILE_EX_TYPE NcCreateFileEx; + +// +// Alternative routines which are used when on downlevel os'es. +// + +NTSTATUS +NcReplaceFileObjectNameAlternate ( + _In_ PFILE_OBJECT FileObject, + _In_reads_bytes_(FileNameLength) PWSTR NewFileName, + _In_ USHORT FileNameLength + ) +/*++ + +Routine Description: + + This routine is used to replace a file object's name with a provided + name. On Win7 and forward IoReplaceFileObjectName will be used. + If this function is used and verifier is enabled on pre Win7 machines + the filter will fail to unload due to a false positive on the leaked + pool test. + +Arguments: + + FileObject - Pointer to file object whose name is to be replaced. + + NewFileName - Pointer to buffer containing the new name. + + FileNameLength - Length of the new name in bytes. + +Return Value: + + STATUS_INSUFFICIENT_RESOURCES - No memory to allocate the new buffer. + + STATUS_SUCCESS otherwise. + +--*/ +{ + PWSTR Buffer; + PUNICODE_STRING FileName; + USHORT NewMaxLength; + + PAGED_CODE(); + + FileName = &FileObject->FileName; + + // + // If the new name fits inside the current buffer we simply copy it over + // instead of allocating a new buffer (and keep the MaximumLength value + // the same). + // + + if (FileNameLength <= FileName->MaximumLength) { + + goto CopyAndReturn; + } + + NewMaxLength = FileNameLength; + + Buffer = ExAllocatePoolWithTag( PagedPool, + NewMaxLength, + NC_FILE_NAME_TAG ); + + if (!Buffer) { + + return STATUS_INSUFFICIENT_RESOURCES; + } + + if (FileName->Buffer != NULL) { + + ExFreePool(FileName->Buffer); + } + + FileName->Buffer = Buffer; + FileName->MaximumLength = NewMaxLength; + +CopyAndReturn: + + RtlZeroMemory(FileName->Buffer, FileName->MaximumLength); + + FileName->Length = FileNameLength; + RtlCopyMemory(FileName->Buffer, NewFileName, FileNameLength); + + return STATUS_SUCCESS; +} + +NTSTATUS +NcQueryDirectoryFileAlternate ( + _In_ PFLT_INSTANCE Instance, + _In_ PFILE_OBJECT FileObject, + _In_reads_bytes_(Length) PVOID FileInformation, + _In_ ULONG Length, + _In_ FILE_INFORMATION_CLASS FileInformationClass, + _In_ BOOLEAN ReturnSingleEntry, + _In_opt_ PUNICODE_STRING FileName, + _In_ BOOLEAN RestartScan, + _Out_opt_ PULONG LengthReturned + ) +/*++ + +Routine Description: + + This function issues a directory control operation to the filesystem + +Arguments: + + + Instance - Supplies the Instance initiating this IO. + + FileObject - Supplies the file object about which the requested + Information should be queried. + + FileInformation - Supplies a buffer to hold the directory control + results. + + Length - Supplies the length, in bytes, of the FileInformation buffer. + + FileInformationClass - Specifies the file Information class requested. + + ReturnSingleEntry - Retrieve only one file at a time. + + FileName - This is the pattern to search for. + + RestartScan - Restart the directory enumeration from the start. + + LengthReturned - On success, this is how much Information was placed + into the FileInformation buffer. + +Return Value: + + The status returned is the final completion Status of the operation. + +--*/ +{ + PFLT_CALLBACK_DATA Info; + NTSTATUS Status; + + PAGED_CODE(); + + Status = FltAllocateCallbackData( Instance, FileObject, &Info ); + + if (!NT_SUCCESS( Status )) { + + return Status; + } + + Info->Iopb->MajorFunction = IRP_MJ_DIRECTORY_CONTROL; + Info->Iopb->MinorFunction = IRP_MN_QUERY_DIRECTORY; + + Info->Iopb->Parameters.DirectoryControl.QueryDirectory.Length = Length; + Info->Iopb->Parameters.DirectoryControl.QueryDirectory.FileName = FileName; + Info->Iopb->Parameters.DirectoryControl.QueryDirectory.FileInformationClass = FileInformationClass; + Info->Iopb->Parameters.DirectoryControl.QueryDirectory.FileIndex = 0; + + Info->Iopb->Parameters.DirectoryControl.QueryDirectory.DirectoryBuffer = FileInformation; + Info->Iopb->Parameters.DirectoryControl.QueryDirectory.MdlAddress = NULL; + + if (RestartScan) { + + Info->Iopb->OperationFlags |= SL_RESTART_SCAN; + } + + if (ReturnSingleEntry) { + + Info->Iopb->OperationFlags |= SL_RETURN_SINGLE_ENTRY; + } + + // + // Perform the operation + // + + FltPerformSynchronousIo( Info ); + + Status = Info->IoStatus.Status; + + if (ARGUMENT_PRESENT(LengthReturned) && + NT_SUCCESS( Status )) { + + *LengthReturned = (ULONG) Info->IoStatus.Information; + } + + FltFreeCallbackData( Info ); + + return Status; +} + +NTSTATUS +FLTAPI +NcCreateFileEx2Alternate ( + _In_ PFLT_FILTER Filter, + _In_opt_ PFLT_INSTANCE Instance, + _Out_ PHANDLE FileHandle, + _Outptr_opt_ PFILE_OBJECT *FileObject, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _In_opt_ PLARGE_INTEGER AllocationSize, + _In_ ULONG FileAttributes, + _In_ ULONG ShareAccess, + _In_ ULONG CreateDisposition, + _In_ ULONG CreateOptions, + _In_reads_bytes_opt_(EaLength) PVOID EaBuffer, + _In_ ULONG EaLength, + _In_ ULONG Flags, + _In_opt_ PIO_DRIVER_CREATE_CONTEXT DriverContext + ) +{ + NTSTATUS Status; + + PAGED_CODE(); + + // + // If we are here, FltCreateFileEx2 does not exist. We + // cannot open files within the context of a transaction + // from here. If Txf exists, so should FltCreateFileEx2. + // + + UNREFERENCED_PARAMETER( DriverContext ); + FLT_ASSERT( DriverContext == NULL ); + + // + // Zero out output parameters. + // + + *FileHandle = INVALID_HANDLE_VALUE; + + if (ARGUMENT_PRESENT( FileObject )) { + + *FileObject = NULL; + } + + if (NcCreateFileEx) { + + // + // If the system has FltCreateFileEx, we call that. + // + + Status = NcCreateFileEx( Filter, + Instance, + FileHandle, + FileObject, + DesiredAccess, + ObjectAttributes, + IoStatusBlock, + AllocationSize, + FileAttributes, + ShareAccess, + CreateDisposition, + CreateOptions, + EaBuffer, + EaLength, + Flags ); + } else { + + // + // Attempt the open. + // + + Status = FltCreateFile( Filter, + Instance, + FileHandle, + DesiredAccess, + ObjectAttributes, + IoStatusBlock, + AllocationSize, + FileAttributes, + ShareAccess, + CreateDisposition, + CreateOptions, + EaBuffer, + EaLength, + Flags ); + + if(!NT_SUCCESS( Status )) { + + goto NcCreateFileEx2Cleanup; + } + + FLT_ASSERT( *FileHandle != INVALID_HANDLE_VALUE && *FileHandle != NULL ); + + if(ARGUMENT_PRESENT( FileObject )) { + + // + // If the user provided an output FileObject parameter, + // then we need to get a reference to the fileobject and return it. + // + + Status = ObReferenceObjectByHandle( *FileHandle, + DesiredAccess, + *IoFileObjectType, + KernelMode, + FileObject, + NULL ); + + if(!NT_SUCCESS( Status )) { + + goto NcCreateFileEx2Cleanup; + } + } + } + +NcCreateFileEx2Cleanup: + + if (!NT_SUCCESS( Status )) { + + if (*FileHandle != INVALID_HANDLE_VALUE) { + + FltClose( *FileHandle ); + } + + if (ARGUMENT_PRESENT( FileObject )) { + + if (*FileObject != NULL) { + + ObDereferenceObject( *FileObject ); + } + } + } + + return Status; +} + +// +// Helper routines which manage importing the functions. +// + +VOID +NcCompatInit( ) +{ + UNICODE_STRING FuncName; + PAGED_CODE(); + + // + // Default to NonPagedPoolNx for non paged pool allocations where supported. + // + + ExInitializeDriverRuntime( DrvRtPoolNxOptIn ); + + // + // Cast from data pointer to function pointer. This is + // somewhat unavoidable when calling MmGetSystemRoutineAddress/ + // FltGetRoutineAddress etc. + // + +#pragma warning( push ) +#pragma warning( disable: 4055 ) + + RtlInitUnicodeString( &FuncName, L"IoReplaceFileObjectName" ); + + NcReplaceFileObjectName = (NC_REPLACE_FILEOBJECT_NAME_TYPE) + MmGetSystemRoutineAddress( &FuncName ); + + if (NcReplaceFileObjectName == NULL) { + + NcReplaceFileObjectName = NcReplaceFileObjectNameAlternate; + } + + NcQueryDirectoryFile = (NC_QUERY_DIRECTORY_FILE_TYPE) + FltGetRoutineAddress( "FltQueryDirectoryFile" ); + + if (NcQueryDirectoryFile == NULL) { + + NcQueryDirectoryFile = NcQueryDirectoryFileAlternate; + } + + NcCreateFileEx2 = (NC_CREATE_FILE_EX2_TYPE) + FltGetRoutineAddress( "FltCreateFileEx2" ); + + if (NcCreateFileEx2 == NULL) { + + NcCreateFileEx = (NC_CREATE_FILE_EX_TYPE) + FltGetRoutineAddress( "FltCreateFileEx" ); + NcCreateFileEx2 = NcCreateFileEx2Alternate; + } + + NcGetNewSystemBufferAddress = (NC_GET_NEW_SYSTEM_BUFFER_ADDRESS) + FltGetRoutineAddress( "FltGetNewSystemBufferAddress" ); + +#pragma warning( pop ) +} + + diff --git a/filesys/miniFilter/NameChanger/nccontext.c b/filesys/miniFilter/NameChanger/nccontext.c new file mode 100644 index 00000000..43592ecb --- /dev/null +++ b/filesys/miniFilter/NameChanger/nccontext.c @@ -0,0 +1,304 @@ +/*++ + +Copyright (c) 1999 - 2002 Microsoft Corporation + +Module Name: + + nccontext.c + +Abstract: + + Contains routines to manage the lifetime of instance contexts and + stream handle contexts. This file performs context-wide setup + and teardown, with callouts for specific functions to perform their + own setup and teardown. + +Environment: + + Kernel mode + +--*/ + +#include "nc.h" + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE, NcInstanceContextClose) +#pragma alloc_text(PAGE, NcStreamHandleContextAllocAndAttach) +#pragma alloc_text(PAGE, NcStreamHandleContextClose) +#endif + +VOID +NcInstanceContextClose ( + _In_ PFLT_CONTEXT Context, + _In_ FLT_CONTEXT_TYPE ContextType + ) +/*++ + +Routine Description: + + This routine is used to tear down and remove an instance context. + +Arguments: + + Context - The context to destroy. + + ContextType - The type of the context. Since this function is specific + to instance contexts, we expect this to always be the instance + context type. + +Return Value: + + None. + +--*/ +{ + PNC_INSTANCE_CONTEXT InstanceContext = (PNC_INSTANCE_CONTEXT) Context; + PAGED_CODE(); + + UNREFERENCED_PARAMETER( ContextType ); + FLT_ASSERT( ContextType == FLT_INSTANCE_CONTEXT ); + + NcTeardownMapping( &InstanceContext->Mapping ); +} + +VOID +NcStreamHandleContextClose ( + _In_ PFLT_CONTEXT Context, + _In_ FLT_CONTEXT_TYPE ContextType + ) +/*++ + +Routine Description: + + This routine is used to tear down and remove a stream handle context. + +Arguments: + + Context - The context to destroy. + + ContextType - The type of the context. Since this function is specific + to stream handle contexts, we expect this to always be the stream + handle context type. + +Return Value: + + None. + +--*/ +{ + PNC_STREAM_HANDLE_CONTEXT StreamContext = (PNC_STREAM_HANDLE_CONTEXT) Context; + + PAGED_CODE(); + + UNREFERENCED_PARAMETER( ContextType ); + FLT_ASSERT( ContextType == FLT_STREAMHANDLE_CONTEXT ); + + // + // Clean up notification context + // + + NcStreamHandleContextEnumClose( &StreamContext->DirectoryQueryContext ); + + // + // Clean up enumeration context + // + + NcStreamHandleContextNotClose( &StreamContext->DirectoryNotificationContext ); + + // + // Clean up find by SID context + // + + NcStreamHandleContextFindBySidClose( &StreamContext->FindBySidContext ); + + // + // Clean up shared context information + // + + if (StreamContext->Lock != NULL) { + + NcFreeEResource( StreamContext->Lock ); + StreamContext->Lock = NULL; + } +} + +NTSTATUS +NcStreamHandleContextAllocAndAttach ( + _In_ PFLT_FILTER Filter, + _In_ PFLT_INSTANCE Instance, + _In_ PFILE_OBJECT FileObject, + _Out_ PNC_STREAM_HANDLE_CONTEXT * Context + ) +/*++ + +Routine Description: + + Allocates and initializes an empty stream handle context. + +Arguments: + + Filter - The filter we are going to attach with. + + Instance - The instance we are going to attach with. + + FileObject - File object we are going to attach to. + + Context - Pointer to a user allocated PNC_STREAM_HANDLE_CONTEXT. + +Return Value: + + On success, returns STATUS_SUCCESS and a pointer to the context in *Context. + Otherwise returns an error and NULL in *Context. + + The user must call FltReleaseContext to balance ref count. + +--*/ +{ + PNC_STREAM_HANDLE_CONTEXT OurContext = NULL; + PNC_STREAM_HANDLE_CONTEXT TheirContext = NULL; + + NTSTATUS Status; + + PAGED_CODE(); + + // + // Default to no return context. + // + + *Context = NULL; + + // + // Check if a context already exists. If so, return it. + // + + Status = FltGetStreamHandleContext( Instance, + FileObject, + &TheirContext ); + + if (NT_SUCCESS( Status )) { + + *Context = TheirContext; + return Status; + } + + // + // Allocate a new context. + // + + Status = FltAllocateContext( Filter, + FLT_STREAMHANDLE_CONTEXT, + sizeof(NC_STREAM_HANDLE_CONTEXT), + PagedPool, + &OurContext ); + + if (!NT_SUCCESS( Status )) { + + goto NcStreamHandleContextAllocAndAttachClose; + } + + // + // Zero out the buffer so we can unwind on failure. + // + + RtlZeroMemory( OurContext, sizeof(NC_STREAM_HANDLE_CONTEXT)); + + // + // Initialize shared context information. + // + + Status = NcAllocateEResource( &OurContext->Lock ); + + if (!NT_SUCCESS( Status )) { + + goto NcStreamHandleContextAllocAndAttachClose; + } + + // + // Initialize the Directory Notification Structure. + // + + Status = NcStreamHandleContextNotCreate( &OurContext->DirectoryNotificationContext ); + + if (!NT_SUCCESS( Status )) { + + goto NcStreamHandleContextAllocAndAttachClose; + } + + // + // Initialize the Directory Enumeration Structure + // + + Status = NcStreamHandleContextDirEnumCreate( &OurContext->DirectoryQueryContext ); + + if (!NT_SUCCESS( Status )) { + + goto NcStreamHandleContextAllocAndAttachClose; + } + + // + // Initialize the Find by SID Structure + // + + Status = NcStreamHandleContextFindBySidCreate( &OurContext->FindBySidContext ); + + if (!NT_SUCCESS( Status )) { + + goto NcStreamHandleContextAllocAndAttachClose; + } + + // + // Now we have a new context, but we could be racing with another thread + // attaching a context to this stream. We will now try to attach, but + // keep the existing context if it is there. If there is an existing + // context, then we return the pre-existing context and free ours. + // + + Status = FltSetStreamHandleContext( Instance, + FileObject, + FLT_SET_CONTEXT_KEEP_IF_EXISTS, + OurContext, + &TheirContext ); + + if (Status == STATUS_FLT_CONTEXT_ALREADY_DEFINED) { + + Status = STATUS_SUCCESS; + + } else if (!NT_SUCCESS( Status )) { + + goto NcStreamHandleContextAllocAndAttachClose; + } + + // + // We need to keep 1 ref count on the context we are sticking with. + // However, if there are two contexts we need to free one of them. + // We therefore NULL out the context that is being returned so as + // to only clean up the other (if it exists.) + // + + if (TheirContext != NULL) { + + *Context = TheirContext; + TheirContext = NULL; + + } else { + + *Context = OurContext; + OurContext = NULL; + } + +NcStreamHandleContextAllocAndAttachClose: + + if (OurContext != NULL) { + + FltReleaseContext( OurContext ); + } + + if (TheirContext != NULL) { + + FltReleaseContext( TheirContext ); + } + + return Status; +} + + diff --git a/filesys/miniFilter/NameChanger/nccreate.c b/filesys/miniFilter/NameChanger/nccreate.c new file mode 100644 index 00000000..574d64c7 --- /dev/null +++ b/filesys/miniFilter/NameChanger/nccreate.c @@ -0,0 +1,451 @@ +/*++ + +Copyright (c) 1999 - 2002 Microsoft Corporation + +Module Name: + + nccreate.c + +Abstract: + + Contains routines to process user-initiated creates. We need to + detect if these need to be redirected to a new physical location, + and redirect as appropriate. + +Environment: + + Kernel mode + +--*/ + +#include "nc.h" + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE, NcPreCreate) +#endif + + +FLT_PREOP_CALLBACK_STATUS +NcPreCreate ( + _Inout_ PFLT_CALLBACK_DATA Data, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _Flt_CompletionContext_Outptr_ PVOID *CompletionContext + ) +/*++ + +Routine Description: + + Routine is invoked when a create is issued by a user. + + +Arguments: + + Data - Pointer to the filter CallbackData that is passed to us. + + FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing + opaque handles to this filter, instance, its associated volume and + file object. + + CompletionContext - The context for the completion routine for this + operation. + +Return Value: + + The return value is the Status of the operation. + +Logic: + + 1) If file is opened by ID or is a Paging File, etc. + A) return FLT_PREOP_SUCCESS_NO_CALLBACK + 2) Get the opened name and calculate overlap + 3) If File is Delete On close + A) If the file is an ancestor of either mapping + a) Fail Open + 4) If the path is in the real mapping + A) Fail the Open + 5) If the path is in user mapping + A) Recalculate the full name (without SL_OPEN_TARGET_DIRECTORY) + B) Munge Name to Real Mapping + C) Switch name + D) Passthrough with callback. + 6) Else + A) Return Passthrough No callback +--*/ +{ + + + NTSTATUS Status; + FLT_PREOP_CALLBACK_STATUS ReturnValue = FLT_PREOP_SUCCESS_NO_CALLBACK; + PFLT_FILE_NAME_INFORMATION FileNameInformation = NULL; + PFLT_FILE_NAME_INFORMATION FullFileNameInformation = NULL; + PNC_INSTANCE_CONTEXT InstanceContext = NULL; + NC_PATH_OVERLAP RealOverlap, UserOverlap, FullOverlap; + UNICODE_STRING Remainder; + UNICODE_STRING MungedName = EMPTY_UNICODE_STRING; + BOOLEAN IgnoreCase = !BooleanFlagOn( Data->Iopb->OperationFlags, SL_CASE_SENSITIVE ); + UCHAR CreateDisposition = (UCHAR)(Data->Iopb->Parameters.Create.Options >> 24); + + PAGED_CODE(); + + UNREFERENCED_PARAMETER( CompletionContext ); + + FLT_ASSERT( IoGetTopLevelIrp() == NULL ); + + // + // Check if this open is to the paging file. + // We are not going to handle munging the namespace for paging files. + // + + if (FlagOn( Data->Iopb->OperationFlags, SL_OPEN_PAGING_FILE )) { + + ReturnValue = FLT_PREOP_SUCCESS_NO_CALLBACK; + goto NcPreCreateCleanup; + } + + // + // Check if this is a volume open. + // Volume opens do not affect the namespace of the volume so we don't care. + // + + if (FlagOn( Data->Iopb->TargetFileObject->Flags, FO_VOLUME_OPEN )) { + + ReturnValue = FLT_PREOP_SUCCESS_NO_CALLBACK; + goto NcPreCreateCleanup; + } + + // + // Check if this open is by ID. + // Opens by file ID are name agnostic. Thus we do not care about this open. + // + + if (FlagOn( Data->Iopb->Parameters.Create.Options, FILE_OPEN_BY_FILE_ID )) { + + ReturnValue = FLT_PREOP_SUCCESS_NO_CALLBACK; + goto NcPreCreateCleanup; + } + + // + // Get opened name. + // This is pre-create so this is the name which will be opened if allowed + // to continue. Note that unlike most other paths, we do not call + // ourselves here; doing so would munge the "real" name into the "user" + // name, which would prevent us from detecting access via the "real" + // name. Because this request is not being sent to us, we need to ensure + // we don't poison the cache of below filters (allowing the user visible + // mapping to be cached beneath us.) + // + + Status = NcGetFileNameInformation( Data, + NULL, + NULL, + FLT_FILE_NAME_OPENED | + FLT_FILE_NAME_QUERY_DEFAULT | + FLT_FILE_NAME_DO_NOT_CACHE, + &FileNameInformation ); + + if (!NT_SUCCESS( Status )) { + + ReturnValue = FLT_PREOP_COMPLETE; + goto NcPreCreateCleanup; + } + + Status = FltParseFileNameInformation( FileNameInformation ); + + if (!NT_SUCCESS( Status )) { + + ReturnValue = FLT_PREOP_COMPLETE; + goto NcPreCreateCleanup; + } + + // + // Get the instance context. + // + + Status = FltGetInstanceContext( FltObjects->Instance, + &InstanceContext ); + + if (!NT_SUCCESS( Status )) { + + ReturnValue = FLT_PREOP_COMPLETE; + goto NcPreCreateCleanup; + } + + FLT_ASSERT( InstanceContext != NULL ); + + // + // Get the open path's relation to the mapping paths. + // + + NcComparePath( &FileNameInformation->Name, + &InstanceContext->Mapping.RealMapping, + NULL, + IgnoreCase, + TRUE, + &RealOverlap ); + + NcComparePath( &FileNameInformation->Name, + &InstanceContext->Mapping.UserMapping, + &Remainder, + IgnoreCase, + TRUE, + &UserOverlap ); + + // + // Name changer uses the opened name of a file as an indicator that the + // file has been munged. Because of this we have to deny opens down the + // real mapping in order to disambiguate whether it was opened via the + // munging operation. We thus disallow opens down the real mapping path. + // + + if (RealOverlap.Match) { + + // + // When opening the mapping itself, we have virtualized its + // nonexistence to the caller. Therefore, any attempt to open + // should return a not found code, and any conditional open/create + // is effectively a create and should be failed with a code + // appropriate for that. + // + + ReturnValue = FLT_PREOP_COMPLETE; + switch (CreateDisposition) { + case FILE_OPEN: + case FILE_OVERWRITE: + Status = STATUS_OBJECT_NAME_NOT_FOUND; + goto NcPreCreateCleanup; + case FILE_CREATE: + case FILE_OPEN_IF: + case FILE_OVERWRITE_IF: + case FILE_SUPERSEDE: + Status = STATUS_ACCESS_DENIED; + goto NcPreCreateCleanup; + } + + FLT_ASSERT( FALSE ); + Status = STATUS_ACCESS_DENIED; + goto NcPreCreateCleanup; + + } else if (RealOverlap.InMapping) { + + Status = STATUS_OBJECT_PATH_NOT_FOUND; + ReturnValue = FLT_PREOP_COMPLETE; + goto NcPreCreateCleanup; + } + + // + // Short names around the mapping cause a problem for namechanger. + // This is because the filesystem will generate new shortnames which are + // not told to fltmgr. Finding out the names accurately is not reliable + // because the name can change while fltmgr is querying the name. + // + // One solution to this problem is to protect the mapping. We prevent + // users from renaming or deleting the mapping paths so that we know the + // short names do not change. + // + // In create we need to make sure that the FILE_DELETE_ON_CLOSE flag is + // not set if the user is opening the real mapping or an ancestor of it. + // + + if (FlagOn( Data->Iopb->Parameters.Create.Options, FILE_DELETE_ON_CLOSE )) { + + if (RealOverlap.Ancestor || UserOverlap.Ancestor) { + + Status = STATUS_ACCESS_DENIED; + ReturnValue = FLT_PREOP_COMPLETE; + goto NcPreCreateCleanup; + } + } + + // + // Name changer munges opens which occur down the user mapping path. + // Here we check to see if this is a name we want to change. + // + + if (UserOverlap.InMapping) { + + // + // This open is targeted inside the user mapping. + // This means that we need to munge the open name + // to the real mapping. + // + + // + // Constructing a new path for the file has a quirk because of + // SL_OPEN_TARGET_DIRECTORY. If it is set, then the name has the + // following components: /device/ancestors/parent/final_component. + // If the flag is set, then fltmgr stripped of the final component + // (leaving /device/ancestors/parent) when we called + // FltGetFileNameInformation. + // + // File systems assume that file objects for use as a target directory + // in rename operations are opened with SL_OPEN_TARGET_DIRECTORY. + // This means that unlike the related file object, which can be just + // cleared, opens with SL_OPEN_TARGET_DIRECTORY need to be propogated + // with the flag always. + // + // This means that opens which get munged and have + // SL_OPEN_TARGET_DIRECTORY need to be calculated with the final + // component in the name string. + // + + if (FlagOn( Data->Iopb->OperationFlags, SL_OPEN_TARGET_DIRECTORY )) { + + // + // Clear the flag so we can get the full name. + // + + ClearFlag( Data->Iopb->OperationFlags, SL_OPEN_TARGET_DIRECTORY ); + + // + // Get the name with the final component. + // + + Status = NcGetFileNameInformation( Data, + NULL, + NULL, + FLT_FILE_NAME_OPENED | FLT_FILE_NAME_QUERY_FILESYSTEM_ONLY, + &FullFileNameInformation ); + + if (!NT_SUCCESS( Status )) { + + ReturnValue = FLT_PREOP_COMPLETE; + goto NcPreCreateCleanup; + } + + Status = FltParseFileNameInformation( FullFileNameInformation ); + + if (!NT_SUCCESS( Status )) { + + ReturnValue = FLT_PREOP_COMPLETE; + goto NcPreCreateCleanup; + } + + FLT_ASSERT( FullFileNameInformation != NULL ); + + // + // Now that we have the full path, lets put the + // flag back on the file object. + // + + SetFlag( Data->Iopb->OperationFlags, SL_OPEN_TARGET_DIRECTORY ); + + // + // We need to re-calculate the Remainder so we can + // construct the new name. + // + + NcComparePath( &FullFileNameInformation->Name, + &InstanceContext->Mapping.UserMapping, + &Remainder, + IgnoreCase, + TRUE, + &FullOverlap ); + + // + // Since we were dealing with a path further down + // the mapping, lets make sure that we are now + // even further down the mapping. + // + + FLT_ASSERT( FullOverlap.InMapping ); + + } + + // + // Generate new name + // + + Status = NcConstructPath( &InstanceContext->Mapping.RealMapping, + &Remainder, + FALSE, + &MungedName ); + + if (!NT_SUCCESS( Status )) { + + ReturnValue = FLT_PREOP_COMPLETE; + goto NcPreCreateCleanup; + } + + // + // Replace open name in the file object. + // + + Status = NcReplaceFileObjectName( Data->Iopb->TargetFileObject, + MungedName.Buffer, + MungedName.Length ); + + if (!NT_SUCCESS(Status)) { + + ReturnValue = FLT_PREOP_COMPLETE; + goto NcPreCreateCleanup; + } + + // + // Because we calculate our own full path, the + // RelatedFileObject is not needed on munged creates. + // Make sure that we don't send it below us. + // + + FltObjects->FileObject->RelatedFileObject = NULL; + + // + // Pass the create below us. + // + + ReturnValue = FLT_PREOP_SUCCESS_NO_CALLBACK; + goto NcPreCreateCleanup; + + } //end if for in mapping + + // + // If we got here then we are not interested in this open. + // Passthrough no callback. + // + + ReturnValue = FLT_PREOP_SUCCESS_NO_CALLBACK; + goto NcPreCreateCleanup; + +NcPreCreateCleanup: + + // + // Check if we care going to fail the open. + // + + if (ReturnValue == FLT_PREOP_COMPLETE) { + + // + // If we get here, then Status must be a failure code. + // + + FLT_ASSERT( !NT_SUCCESS( Status ) ); + + Data->IoStatus.Status = Status; + } + + // + // Clean up variables + // + + if (FileNameInformation != NULL) { + + FltReleaseFileNameInformation( FileNameInformation ); + } + + if (FullFileNameInformation != NULL) { + + FltReleaseFileNameInformation( FullFileNameInformation ); + } + + if (MungedName.Buffer != NULL) { + + ExFreePoolWithTag( MungedName.Buffer, NC_TAG ); + } + + if (InstanceContext != NULL) { + + FltReleaseContext( InstanceContext ); + } + + return ReturnValue; +} + diff --git a/filesys/miniFilter/NameChanger/ncdirenum.c b/filesys/miniFilter/NameChanger/ncdirenum.c new file mode 100644 index 00000000..7594894f --- /dev/null +++ b/filesys/miniFilter/NameChanger/ncdirenum.c @@ -0,0 +1,1420 @@ +/*++ + +Copyright (c) 1999 - 2002 Microsoft Corporation + +Module Name: + + ncdirenum.c + +Abstract: + + Contains routines to process user-initiated directory enumerations. + Depending on path, we may need to suppress the real mapping from + being visible to the user, or "inject" the user mapping for the + user. We must take care to do so having regard for the pattern + matching and case sensitivity dictated by the caller. + +Environment: + + Kernel mode + +--*/ + +#include "nc.h" + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE, NcCopyDirEnumEntry) +#pragma alloc_text(PAGE, NcDirEnumSelectNextEntry) +#pragma alloc_text(PAGE, NcEnumerateDirectory) +#pragma alloc_text(PAGE, NcEnumerateDirectorySetupInjection) +#pragma alloc_text(PAGE, NcEnumerateDirectoryReset) +#pragma alloc_text(PAGE, NcPopulateCacheEntry) +#pragma alloc_text(PAGE, NcSkipName) +#pragma alloc_text(PAGE, NcStreamHandleContextEnumClose) +#pragma alloc_text(PAGE, NcStreamHandleContextEnumSetup) +#pragma alloc_text(PAGE, NcStreamHandleContextDirEnumCreate) +#endif + +FLT_PREOP_CALLBACK_STATUS +NcEnumerateDirectory ( + _Inout_ PFLT_CALLBACK_DATA Data, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _Flt_CompletionContext_Outptr_ PVOID *CompletionContext + ) +/*++ + +Routine Description: + + Routine is invoked when a directory enumeration is issued by the + user. + +Arguments: + + Data - Pointer to the filter CallbackData that is passed to us. + + FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing + opaque handles to this filter, instance, its associated volume and + file object. + + CompletionContext - The context for the completion routine for this + operation. + +Return Value: + + The return value is the Status of the operation. + +--*/ +{ + //TODO WE SHOULD CONSIDER MOVING THIS TO POST BECAUSE NTFS WILL TAKE CARE + // OF SYNC. + FLT_PREOP_CALLBACK_STATUS ReturnValue; + NTSTATUS Status; + + PNC_INSTANCE_CONTEXT InstanceContext = NULL; + PNC_STREAM_HANDLE_CONTEXT HandleContext = NULL; + PNC_DIR_QRY_CONTEXT DirCtx = NULL; + + PFLT_FILE_NAME_INFORMATION FileNameInformation = NULL; + + NC_PATH_OVERLAP RealOverlap; + NC_PATH_OVERLAP UserOverlap; + + BOOLEAN Reset = BooleanFlagOn( Data->Iopb->OperationFlags, SL_RESTART_SCAN ); + BOOLEAN FirstQuery; + BOOLEAN Single = BooleanFlagOn( Data->Iopb->OperationFlags, SL_RETURN_SINGLE_ENTRY ); + BOOLEAN IgnoreCase = !BooleanFlagOn( FltObjects->FileObject->Flags, + FO_OPENED_CASE_SENSITIVE ); + + FILE_INFORMATION_CLASS InformationClass = + Data->Iopb->Parameters.DirectoryControl.QueryDirectory.FileInformationClass; + + PVOID UserBuffer; + ULONG BufferSize; //size for user and system buffers. + + BOOLEAN Unlock = FALSE; + + //Vars for moving data into user buffer. + ULONG NumEntriesCopied; + ULONG UserBufferOffset; + ULONG LastEntryStart; + BOOLEAN MoreRoom; + PNC_CACHE_ENTRY NextEntry; + + DIRECTORY_CONTROL_OFFSETS Offsets; + + BOOLEAN FoundStructureOffsets; + + UNREFERENCED_PARAMETER( CompletionContext ); + + PAGED_CODE(); + + FLT_ASSERT( IoGetTopLevelIrp() == NULL ); + + FoundStructureOffsets = NcDetermineStructureOffsets( &Offsets, + InformationClass ); + + if (!FoundStructureOffsets) { + + Status = STATUS_INVALID_PARAMETER; + ReturnValue = FLT_PREOP_COMPLETE; + goto NcEnumerateDirectoryCleanup; + } + + // + // Get our instance context. + // + + Status = FltGetInstanceContext( FltObjects->Instance, + &InstanceContext ); + + if (!NT_SUCCESS( Status )) { + + ReturnValue = FLT_PREOP_COMPLETE; + goto NcEnumerateDirectoryCleanup; + } + + // + // Get the directory's name. + // + + Status = NcGetFileNameInformation( Data, + NULL, + NULL, + FLT_FILE_NAME_OPENED | FLT_FILE_NAME_QUERY_DEFAULT, + &FileNameInformation ); + + if (!NT_SUCCESS( Status )) { + + ReturnValue = FLT_PREOP_COMPLETE; + goto NcEnumerateDirectoryCleanup; + } + + Status = FltParseFileNameInformation( FileNameInformation ); + + if (!NT_SUCCESS( Status )) { + + ReturnValue = FLT_PREOP_COMPLETE; + goto NcEnumerateDirectoryCleanup; + } + + // + // See if the directory is parent of either mapping. + // + + NcComparePath( &FileNameInformation->Name, + &InstanceContext->Mapping.UserMapping, + NULL, + IgnoreCase, + TRUE, + &UserOverlap ); + + NcComparePath( &FileNameInformation->Name, + &InstanceContext->Mapping.RealMapping, + NULL, + IgnoreCase, + TRUE, + &RealOverlap ); + + if (!(UserOverlap.Parent || RealOverlap.Parent )) { + + // + // We are not interested in this directory + // because it is not the parent of either + // mapping. This means we can just passthrough. + // + + Status = STATUS_SUCCESS; + ReturnValue = FLT_PREOP_SUCCESS_NO_CALLBACK; + goto NcEnumerateDirectoryCleanup; + } + + Status = NcStreamHandleContextAllocAndAttach( FltObjects->Filter, + FltObjects->Instance, + FltObjects->FileObject, + &HandleContext ); + + if (!NT_SUCCESS( Status )) { + + ReturnValue = FLT_PREOP_COMPLETE; + goto NcEnumerateDirectoryCleanup; + } + + FLT_ASSERT( HandleContext != NULL ); + + DirCtx = &HandleContext->DirectoryQueryContext; + _Analysis_assume_( DirCtx != NULL ); + + // + // Before looking at the context, we have to acquire the lock. + // + + NcLockStreamHandleContext( HandleContext ); + Unlock = TRUE; + + // + // We don't allow multiple outstanding enumeration requests on + // a single handle. + // + // TODO: This needs to change. + // + + if (DirCtx->EnumerationOutstanding) { + + Status = STATUS_UNSUCCESSFUL; + ReturnValue = FLT_PREOP_COMPLETE; + goto NcEnumerateDirectoryCleanup; + + } + + DirCtx->EnumerationOutstanding = TRUE; + + // + // Now drop the lock. We're protected by the EnumerationOutstanding + // flag; nobody else can muck with the enumeration context structure. + // + + NcUnlockStreamHandleContext( HandleContext ); + Unlock = FALSE; + + // + // Now we need to initialize or clear the cache and query options. + // + + Status = NcStreamHandleContextEnumSetup( DirCtx, + InstanceContext, + &Offsets, + Data, + FltObjects, + UserOverlap, + &FirstQuery ); + + if (!NT_SUCCESS( Status )) { + + ReturnValue = FLT_PREOP_COMPLETE; + goto NcEnumerateDirectoryCleanup; + } + + // + // Prepare to populate the user buffer. + // + + UserBuffer = Data->Iopb->Parameters.DirectoryControl.QueryDirectory.DirectoryBuffer; + + BufferSize = Data->Iopb->Parameters.DirectoryControl.QueryDirectory.Length; + + // + // Lets copy data into the user buffer. + // + + NumEntriesCopied = 0; + UserBufferOffset = 0; + + do { + + // + // If there is no cache entry, populate it. + // + + if (DirCtx->Cache.Buffer == NULL) { + + Status = NcPopulateCacheEntry( FltObjects->Instance, + FltObjects->FileObject, + Data->Iopb->Parameters.DirectoryControl.QueryDirectory.Length, + Data->Iopb->Parameters.DirectoryControl.QueryDirectory.FileInformationClass, + Data->Iopb->Parameters.DirectoryControl.QueryDirectory.FileName, + Reset, + &DirCtx->Cache); + + // + // We only want to reset the cache once. + // + + Reset = FALSE; + + // + // There was a problem populating cache, pass up to user. + // + + if (!NT_SUCCESS( Status )) { + + ReturnValue = FLT_PREOP_COMPLETE; + goto NcEnumerateDirectoryCleanup; + } + + } + + NextEntry = NcDirEnumSelectNextEntry( DirCtx, &Offsets, IgnoreCase ); + + if (NextEntry == NULL) { + + // + // There are no more entries. + // + + break; + } + + if (NcSkipName( &Offsets, + DirCtx, + RealOverlap, + &InstanceContext->Mapping, + IgnoreCase )) { + + // + // This entry is the real mapping path. That means we have to mask it... + // We will say there is more room and continue. + // + + MoreRoom = TRUE; + + } else { + + // + // We are keeping this entry! + // + + try { + + LastEntryStart = UserBufferOffset; + UserBufferOffset = NcCopyDirEnumEntry( UserBuffer, + UserBufferOffset, + BufferSize, + NextEntry, + &Offsets, + &MoreRoom ); + + } except (NcExceptionFilter( GetExceptionInformation(), TRUE )) { + + Status = STATUS_INVALID_USER_BUFFER; + ReturnValue = FLT_PREOP_COMPLETE; + goto NcEnumerateDirectoryCleanup; + } + + if (MoreRoom) { + + NumEntriesCopied++; + } + + }// end of "we are copying entry" + + } while (MoreRoom && + (Single ? (NumEntriesCopied < 1) : TRUE)); + + if (NumEntriesCopied > 0) { + + // + // Now we know what the last entry in the user buffer is going to be. + // Set its NextEntryOffset to 0, so that the user knows its the last element. + // + + try { + + NcSetNextEntryOffset( Add2Ptr(UserBuffer, LastEntryStart), + &Offsets, + TRUE ); + + } except (NcExceptionFilter( GetExceptionInformation(), TRUE )) { + + Status = STATUS_INVALID_USER_BUFFER; + ReturnValue = FLT_PREOP_COMPLETE; + goto NcEnumerateDirectoryCleanup; + } + } + + // + // We finished copying data. + // + + ReturnValue = FLT_PREOP_COMPLETE; + + if (NumEntriesCopied == 0) { + + if (FirstQuery) { + + Status = STATUS_NO_SUCH_FILE; + + } else { + + Status = STATUS_NO_MORE_FILES; + } + + } else { + + Status = STATUS_SUCCESS; + } + + ReturnValue = FLT_PREOP_COMPLETE; + goto NcEnumerateDirectoryCleanup; + +NcEnumerateDirectoryCleanup: + + if (ReturnValue == FLT_PREOP_COMPLETE) { + + // + // We need to write back results of query. + // + + Data->IoStatus.Status = Status; + + if (NT_SUCCESS( Status )) { + + //success + Data->IoStatus.Information = UserBufferOffset; + + } else { + + //failure + Data->IoStatus.Information = 0; + } + } + + if (InstanceContext != NULL) { + + FltReleaseContext( InstanceContext ); + } + + if (DirCtx != NULL) { + + if (!Unlock) { + NcLockStreamHandleContext( HandleContext ); + Unlock = TRUE; + } + + FLT_ASSERT( DirCtx->EnumerationOutstanding ); + DirCtx->EnumerationOutstanding = FALSE; + + NcUnlockStreamHandleContext( HandleContext ); + Unlock = FALSE; + + FltReleaseContext( HandleContext ); + } + + FLT_ASSERT( !Unlock ); + + if (FileNameInformation != NULL) { + + FltReleaseFileNameInformation( FileNameInformation ); + } + + return ReturnValue; +} + +NTSTATUS +NcEnumerateDirectorySetupInjection ( + _Inout_ PNC_DIR_QRY_CONTEXT DirQryCtx, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _In_ PNC_INSTANCE_CONTEXT InstanceContext, + _In_ PDIRECTORY_CONTROL_OFFSETS Offsets, + _In_ FILE_INFORMATION_CLASS InformationClass + ) +/*++ + +Routine Description: + + Sets up directory enumeration context cache so that we are ready to + perform injection. + +Arguments: + + DirQryCtx - Pointer to directory query context (on the stream handle.) + + FltObjects - FltObjects structure for this operation. + + InstanceContext - Instance Context for this operation. + + Offsets - Offsets structure for this information class. + + InformationClass - The information class for this operation. + +Return Value: + + Returns STATUS_SUCCESS on success, otherwise an appropriate error code. + +--*/ +{ + NTSTATUS Status; + + OBJECT_ATTRIBUTES RealParentAttributes; + HANDLE RealParentHandle = 0; //close always + PFILE_OBJECT RealParentFileObj = NULL; + IO_STATUS_BLOCK RealParentStatusBlock; + char * QueryBuffer = NULL; //free on error, when no injection + ULONG QueryBufferLength = 0; + USHORT NameLength; + ULONG QueryBufferLengthRead; + BOOLEAN IgnoreCase = !BooleanFlagOn( FltObjects->FileObject->Flags, + FO_OPENED_CASE_SENSITIVE ); + + PAGED_CODE(); + + + // + // If the user has specified a search string, and if our user mapping + // should not be returned in this search string, return success. We + // don't need to inject anything. + // + + if (DirQryCtx->SearchString.Length > 0 && + !FsRtlIsNameInExpression( &DirQryCtx->SearchString, + &InstanceContext->Mapping.UserMapping.LongNamePath.FinalComponentName, + IgnoreCase, + NULL ) && + !FsRtlIsNameInExpression( &DirQryCtx->SearchString, + &InstanceContext->Mapping.UserMapping.ShortNamePath.FinalComponentName, + IgnoreCase, + NULL )) { + + Status = STATUS_SUCCESS; + goto NcEnumerateDirectorySetupCleanup; + } + + // + // Initialize insertion info. + // + // We have to insert the final component of the real mapping + // as the final component of the user mapping. To do this we + // will open the parent of the real mapping, and query the real + // mapping. + // Then we will overwrite the real mapping's name with + // the final component of the user mapping. This data will be + // stored in the DirQryCtx for later injection. + // + + // + // Open parent of real mapping. + // + + InitializeObjectAttributes( &RealParentAttributes, + &InstanceContext->Mapping.RealMapping.LongNamePath.ParentPath, + OBJ_KERNEL_HANDLE, + NULL, + NULL); + + Status = NcCreateFileHelper( NcGlobalData.FilterHandle, // Filter + FltObjects->Instance, // InstanceOffsets + &RealParentHandle, // Returned Handle + &RealParentFileObj, // Returned FileObject + FILE_LIST_DIRECTORY|FILE_TRAVERSE, // Desired Access + &RealParentAttributes, // object attributes + &RealParentStatusBlock, // Returned IOStatusBlock + 0, // Allocation Size + FILE_ATTRIBUTE_NORMAL, // File Attributes + 0, // Share Access + FILE_OPEN, // Create Disposition + FILE_DIRECTORY_FILE, // Create Options + NULL, // Ea Buffer + 0, // EA Length + IO_IGNORE_SHARE_ACCESS_CHECK, // Flags + FltObjects->FileObject ); // Transaction state + + if (!NT_SUCCESS( Status )) { + + goto NcEnumerateDirectorySetupCleanup; + } + + // + // Allocate Buffer to store mapping data. + // + + NameLength = Max( InstanceContext->Mapping.RealMapping.LongNamePath.FinalComponentName.Length, + InstanceContext->Mapping.UserMapping.LongNamePath.FinalComponentName.Length ); + + QueryBufferLength = Offsets->FileNameDist + NameLength; + + QueryBuffer = ExAllocatePoolWithTag( PagedPool, QueryBufferLength, NC_DIR_QRY_CACHE_TAG ); + + if (QueryBuffer == NULL) { + + Status = STATUS_INSUFFICIENT_RESOURCES; + goto NcEnumerateDirectorySetupCleanup; + } + + // + // Query the information from the parent of the real mapping. + // + + Status = NcQueryDirectoryFile( FltObjects->Instance, + RealParentFileObj, + QueryBuffer, + QueryBufferLength, + InformationClass, + TRUE,//Return single entry + &InstanceContext->Mapping.RealMapping.LongNamePath.FinalComponentName, + FALSE,//restart scan + &QueryBufferLengthRead); + + if (Status == STATUS_NO_SUCH_FILE) { + + // + // The user mapping does not exist, this is allowed. It means we + // have nothing to inject. + // + + DirQryCtx->InjectionEntry.Buffer = NULL; + DirQryCtx->InjectionEntry.CurrentOffset = 0; + + ExFreePoolWithTag( QueryBuffer, NC_DIR_QRY_CACHE_TAG ); + QueryBuffer = NULL; + + Status = STATUS_SUCCESS; + + } else if (!NT_SUCCESS( Status )) { + + // + // An unexpected error occurred, return code. + // + + goto NcEnumerateDirectorySetupCleanup; + + } else { + + // + // Now we have to munge the real mapping directory entry into a + // user mapping directory entry. + // + + NcSetFileName( QueryBuffer, + InstanceContext->Mapping.UserMapping.LongNamePath.FinalComponentName.Buffer, + InstanceContext->Mapping.UserMapping.LongNamePath.FinalComponentName.Length, + Offsets, + TRUE ); + + NcSetShortName( QueryBuffer, + InstanceContext->Mapping.UserMapping.ShortNamePath.FinalComponentName.Buffer, + InstanceContext->Mapping.UserMapping.ShortNamePath.FinalComponentName.Length, + Offsets ); + + FLT_ASSERT( DirQryCtx->InjectionEntry.Buffer == NULL ); + + // + // Set the injection entry up in the cache. + // + + DirQryCtx->InjectionEntry.Buffer = QueryBuffer; + DirQryCtx->InjectionEntry.CurrentOffset = 0; + } + +NcEnumerateDirectorySetupCleanup: + + if (!NT_SUCCESS( Status )) { + + if(QueryBuffer != NULL) { + + ExFreePoolWithTag( QueryBuffer, NC_DIR_QRY_CACHE_TAG ); + } + + } + + if (RealParentHandle != NULL) { + + FltClose( RealParentHandle ); + } + + if (RealParentFileObj != NULL) { + + ObDereferenceObject( RealParentFileObj ); + } + + return Status; +} + +VOID +NcEnumerateDirectoryReset ( + _Inout_ PNC_DIR_QRY_CONTEXT DirCtx + ) +/*++ + +Routine Description: + + Tears down any stream handle context related to enumeration and prepares + the stream handle context for reuse. + +Arguments: + + DirQryCtx - Pointer to directory query context (on the stream handle.) + +Return Value: + + None. + +--*/ +{ + PAGED_CODE(); + + ExFreePoolWithTag( DirCtx->Cache.Buffer, NC_DIR_QRY_CACHE_TAG ); + DirCtx->Cache.Buffer = NULL; + DirCtx->Cache.CurrentOffset = 0; + + ExFreePoolWithTag( DirCtx->InjectionEntry.Buffer, NC_DIR_QRY_CACHE_TAG ); + DirCtx->InjectionEntry.Buffer = NULL; + DirCtx->InjectionEntry.CurrentOffset = 0; +} + +BOOLEAN +NcSkipName ( + _In_ PDIRECTORY_CONTROL_OFFSETS Offsets, + _In_ PNC_DIR_QRY_CONTEXT Context, + _In_ NC_PATH_OVERLAP RealOverlap, + _In_ PNC_MAPPING Mapping, + _In_ BOOLEAN IgnoreCase + ) +/*++ + +Routine Description: + + Determines if the next entry is for the real mapping. If it is, we want + to "skip" returning this entry and proceed to the next. + +Arguments: + + Offsets - Offset information for this enumeration class. + + Context - Pointer to directory query context (on the stream handle.) + This is used to obtain the entry we are contemplating returning. + + RealOverlap - Relationship of the object that enumeration is being + requested on to the real mapping. This routine will only skip + entries if we are enumerating the parent of the real mapping. + +Return Value: + + TRUE if this entry should be skipped/suppressed; FALSE if it should be + returned to the user. + +--*/ +{ + BOOLEAN Result = FALSE; + PVOID CacheEntry; + UNICODE_STRING CacheString; + PUNICODE_STRING IgnoreString = &Mapping->RealMapping.LongNamePath.FinalComponentName; + ULONG ElementSize; + BOOLEAN LastElement; + + PAGED_CODE(); + + if (RealOverlap.Parent) { + + // + // We have to check for a match. + // + + CacheEntry = Add2Ptr( Context->Cache.Buffer, Context->Cache.CurrentOffset); + ElementSize = NcGetEntrySize( CacheEntry, Offsets ); + LastElement = (BOOLEAN)(NcGetNextEntryOffset( CacheEntry, Offsets ) == 0); + + CacheString.Buffer = NcGetFileName( CacheEntry, Offsets ); + CacheString.Length = (USHORT) NcGetFileNameLength( CacheEntry, Offsets ); + CacheString.MaximumLength = CacheString.Length; + + + if (RtlCompareUnicodeString( &CacheString, + IgnoreString, + IgnoreCase ) == 0) { + + // + // We need to ignore this name. + // + + Result = TRUE; + + // + // skip + // + + if (LastElement) { + + // + // This was the last element in the entry, so we should clean the entry. + // + + ExFreePoolWithTag(Context->Cache.Buffer, NC_DIR_QRY_CACHE_TAG); + Context->Cache.Buffer = NULL; + Context->Cache.CurrentOffset = 0; + + } else { + + // + // Entry has more elements, update offset counter. + // + + Context->Cache.CurrentOffset += ElementSize; + } + } + } + + return Result; +} + +NTSTATUS +NcPopulateCacheEntry ( + _In_ PFLT_INSTANCE Instance, + _In_ PFILE_OBJECT FileObject, + _In_ ULONG BufferLength, + _In_ FILE_INFORMATION_CLASS FileInfoClass, + _In_ PUNICODE_STRING SearchString, + _In_ BOOLEAN RestartScan, + _Out_ PNC_CACHE_ENTRY Cache + ) +/*++ + +Routine Description: + + Obtains the next entry from the filesystem. By always reading ahead, we + can determine when to return the injected entry (if one exists) while + attempting to preserve directory sort order. + +Arguments: + + Instance - Instance of this filter in the filter stack. + + FileObject - Directory that we are enumerating. + + BufferLength - Size, in bytes, of the buffer to allocate within this + routine. + + FileInfoClass - Directory enumeration class that we are using. + + SearchString - Pointer to the string containing the enumeration criteria. + Will be empty if enumerating all objects in a directory. + + RestartScan - Boolean value set to TRUE if we should start enumeration from + the beginning. Set to FALSE to continue from the previous point. + + Cache - Pointer to our structure for receiving the cached entry. + +Return Value: + + The return value is the Status of the operation. + +--*/ +{ + + NTSTATUS Status; + PVOID Buffer; + + PAGED_CODE(); + + if (SearchString != NULL && SearchString->Buffer == NULL) { + + // + // In the case there is no search string provided, + // don't pass one to the filesystem. + // + + SearchString = NULL; + } + + Buffer = ExAllocatePoolWithTag( PagedPool, BufferLength, NC_DIR_QRY_CACHE_TAG ); + + if (Buffer == NULL) { + + Status = STATUS_INSUFFICIENT_RESOURCES; + return Status; + } + + Status = NcQueryDirectoryFile( Instance, + FileObject, + Buffer, + BufferLength, + FileInfoClass, + FALSE, + SearchString, + RestartScan, + NULL); + + if (Status == STATUS_NO_MORE_FILES || Status == STATUS_NO_SUCH_FILE) { + + // + // There are no more files. Keep cache empty. + // + + Cache->Buffer = NULL; + Cache->CurrentOffset = 0; + + ExFreePoolWithTag( Buffer, NC_DIR_QRY_CACHE_TAG ); + + Status = STATUS_SUCCESS; + + } else if (NT_SUCCESS( Status )) { + + // + // There were entries, populate. + // + + Cache->Buffer = Buffer; + Cache->CurrentOffset = 0; + + } else { + + // + // An unspecified error occurred, return it. + // + + ExFreePoolWithTag( Buffer, NC_DIR_QRY_CACHE_TAG ); + } + + return Status; +} + +PNC_CACHE_ENTRY +NcDirEnumSelectNextEntry( + _Inout_ PNC_DIR_QRY_CONTEXT Context, + _In_ PDIRECTORY_CONTROL_OFFSETS Offsets, + _In_ BOOLEAN IgnoreCase + ) +/*++ + +Routine Description: + + This routine determines whether the cached entry (returned from the + filesystem) should be returned now or whether the injected entry (as a + result of our mapping) should be returned now. + +Arguments: + + Context - The enumeration context of this handle. + + Offsets - Information describing the offsets for this enumeration class. + + IgnoreCase - TRUE if we are case insensitive, FALSE if case sensitive. + +Return Value: + + A pointer to the entry we should return, or NULL if there is nothing + remaining to return. + +--*/ +{ + PNC_CACHE_ENTRY NextEntry; + UNICODE_STRING CacheString; + UNICODE_STRING InsertString; + PVOID CacheEntry; + PVOID InjectEntry; + + PAGED_CODE(); + + // + // Figure out which name comes first + // + + if ((Context->Cache.Buffer == NULL) && + (Context->InjectionEntry.Buffer == NULL)) { + + // + // There are no names left, return STATUS_NO_MORE_FILES + // + + NextEntry = NULL; + + } else if (Context->Cache.Buffer == NULL) { + + // + // The cache is empty, so inject. + // + + NextEntry = &Context->InjectionEntry; + + } else if (Context->InjectionEntry.Buffer == NULL) { + + // + // The injection entry is empty, drain the cache. + // + + NextEntry = &Context->Cache; + + } else { + + // + // We have to seek in the entry buffer to the current entry within the buffer. + // + + CacheEntry = Add2Ptr( Context->Cache.Buffer, Context->Cache.CurrentOffset ); + InjectEntry = Add2Ptr( Context->InjectionEntry.Buffer, Context->InjectionEntry.CurrentOffset ); + + // + // Find names within the entries. + // + + CacheString.Buffer = NcGetFileName( CacheEntry, Offsets ); + CacheString.Length = (USHORT) NcGetFileNameLength( CacheEntry, Offsets ); + CacheString.MaximumLength = CacheString.Length; + + InsertString.Buffer = NcGetFileName( InjectEntry, Offsets ); + InsertString.Length = (USHORT) NcGetFileNameLength( InjectEntry, Offsets ); + InsertString.MaximumLength = InsertString.Length; + + // + // Compare the names + // + + if (RtlCompareUnicodeString( &CacheString, + &InsertString, + IgnoreCase ) < 0) { + + // + // Cache string comes first + // + + NextEntry = &Context->Cache; + + } else { + + // + // insert string comes first + // + + NextEntry = &Context->InjectionEntry; + } + } + return NextEntry; +} + +_Success_(*Copied) +ULONG +NcCopyDirEnumEntry ( + _Out_ PVOID UserBuffer, + _In_ ULONG UserOffset, + _In_ ULONG UserSize, + _Inout_ PNC_CACHE_ENTRY Entry, + _In_ PDIRECTORY_CONTROL_OFFSETS Offsets, + _Out_ PBOOLEAN Copied + ) +/*++ + +Routine Description: + + This routine copies a single enumeration result into the caller's + buffer. + +Arguments: + + UserBuffer - Pointer to the caller's buffer. + + UserOffset - Offset within the caller's buffer that we intend to write new + results. + + UserSize - Size of the caller's buffer, in bytes. + + Entry - Pointer to the directory entry that we intend to return. + + Offsets - Information describing the offsets for this enumeration class. + + Copied - Pointer to a boolean value indicating whether this routine copied + a new entry or not. + +Return Value: + + The new offset in the user buffer that any future copies should use. + +--*/ +{ + PVOID Element = Add2Ptr( Entry->Buffer, Entry->CurrentOffset ); + PVOID Dest = Add2Ptr( UserBuffer, UserOffset ); + ULONG ElementSize = NcGetEntrySize( Element, Offsets ); + BOOLEAN LastElement = (BOOLEAN)(NcGetNextEntryOffset( Element, Offsets ) == 0); + + PAGED_CODE(); + + if (UserSize - UserOffset >= ElementSize) { + + // + // There is enough room for this element, so copy it. + // + + RtlCopyMemory( Dest, Element, ElementSize ); + UserOffset += ElementSize; + *Copied = TRUE; + + // + // Update Entry's Offset + // + + if (LastElement) { + + // + // This was the last element in the entry, so we should clean the + // entry. + // + + ExFreePoolWithTag( Entry->Buffer, NC_TAG ); + Entry->Buffer = NULL; + Entry->CurrentOffset = 0; + + // + // The last element in cached entries have a NextEntryOffset of 0, + // make sure that we report the actual next entry offset. + // + + NcSetNextEntryOffset( Dest, Offsets, FALSE ); + + } else { + + // + // Entry has more elements, update offset counter. + // + + Entry->CurrentOffset += ElementSize; + } + + } else { + + // + // User buffer does not have enough space. + // + + *Copied = FALSE; + } + + return UserOffset; +} + +NTSTATUS +NcStreamHandleContextDirEnumCreate ( + _Out_ PNC_DIR_QRY_CONTEXT Context + ) +/*++ + +Routine Description: + + Initializes the stream handle context ready for directory enumeration + requests. + +Arguments: + + Context - Pointer to the directory context. + +Return Value: + + The return value is the Status of the operation. Currently this operation + cannot fail, so this function always returns STATUS_SUCCESS. + +--*/ +{ + NTSTATUS Status = STATUS_SUCCESS; + + PAGED_CODE(); + + Context->EnumerationOutstanding = FALSE; + Context->InUse = FALSE; + Context->Cache.Buffer = NULL; + Context->Cache.CurrentOffset = 0; + Context->InjectionEntry.Buffer = NULL; + Context->InjectionEntry.CurrentOffset = 0; + Context->SearchString.Length = 0; + Context->SearchString.MaximumLength = 0; + Context->SearchString.Buffer = NULL; + + return Status; +} + + +NTSTATUS +NcStreamHandleContextEnumSetup ( + _Inout_ PNC_DIR_QRY_CONTEXT DirContext, + _In_ PNC_INSTANCE_CONTEXT InstanceContext, + _In_ PDIRECTORY_CONTROL_OFFSETS Offsets, + _In_ PFLT_CALLBACK_DATA Data, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _In_ NC_PATH_OVERLAP UserMappingOverlap, + _Out_ PBOOLEAN FirstUsage + ) +/*++ + +Routine Description: + + Acquires the stream handle context and initializes it for a directory + enumeration. + +Arguments: + + DirContext - Pointer to the directory context. + + InstanceContext - Pointer to this instance's context. + + Offsets - Offsets structure for this enumeration class. + + Data - Callback data for this operation. + + FltObjects - FltObjects structure for this operation. + + UserMappingOverlap - The overlap between the user mapping and this file + object. + + FirstUsage - Weather or not this is the first usage of this handle in a + directory enumeration. + +Return Value: + + The return value is the Status of the operation. + +--*/ +{ + NTSTATUS Status = STATUS_SUCCESS; + + PUNICODE_STRING SearchString = Data->Iopb->Parameters.DirectoryControl.QueryDirectory.FileName; + FILE_INFORMATION_CLASS InformationClass = Data->Iopb->Parameters.DirectoryControl.QueryDirectory.FileInformationClass; + BOOLEAN ResetSearch = BooleanFlagOn( Data->Iopb->OperationFlags, SL_RESTART_SCAN ); + BOOLEAN IgnoreCase = !BooleanFlagOn( FltObjects->FileObject->Flags, + FO_OPENED_CASE_SENSITIVE ); + + PAGED_CODE(); + + // + // This context could be in its first use. If it is, then we need to + // setup the search string and information class. + // + + if (DirContext->InUse == FALSE) { + + // + // This was the first usage of the context. + // We should set up the search string. + // + + if (SearchString != NULL) { + + DirContext->SearchString.Buffer = ExAllocatePoolWithTag( PagedPool, + SearchString->Length, + NC_DIR_QRY_SEARCH_STRING ); + + if (DirContext->SearchString.Buffer == NULL) { + + Status = STATUS_INSUFFICIENT_RESOURCES; + goto NcStreamHandleContextEnumSetupCleanup; + } + + DirContext->SearchString.MaximumLength = SearchString->Length; + + if (IgnoreCase) { + + RtlUpcaseUnicodeString( &DirContext->SearchString, SearchString, FALSE ); + + } else { + + RtlCopyUnicodeString( &DirContext->SearchString, SearchString ); + } + + DirContext->SearchString.Length = SearchString->Length; + + } else { + + RtlInitEmptyUnicodeString( &DirContext->SearchString, + NULL, + 0 ); + } + + DirContext->InformationClass = InformationClass; + + // + // We should write back to the caller so they know its the first usage. + // + + *FirstUsage = TRUE; + + } else { + + // + // This is not the fist usage, so write back to user. + // + + *FirstUsage = FALSE; + + // + // This is not the first query. Lets make sure that our data + // is consistent. If the information classes don't line up + // then our cache might be inconsistant. We should fail this + // operation. + // + // TODO: Is this correct? + // + + if (DirContext->InformationClass != InformationClass) { + + Status = STATUS_INVALID_PARAMETER; + goto NcStreamHandleContextEnumSetupCleanup; + } + } + + if (!DirContext->InUse || ResetSearch) { + + // + // Either this is the first use of the context, + // or they are reseting the enumeration. We + // should clear the cache either way. + // + + if (DirContext->Cache.Buffer != NULL) { + + ExFreePoolWithTag( DirContext->Cache.Buffer, NC_TAG ); + DirContext->Cache.Buffer = NULL; + DirContext->Cache.CurrentOffset = 0; + } + + if (DirContext->InjectionEntry.Buffer != NULL) { + + ExFreePoolWithTag( DirContext->InjectionEntry.Buffer, NC_TAG ); + DirContext->InjectionEntry.Buffer = NULL; + DirContext->InjectionEntry.CurrentOffset = 0; + } + + // + // Now that the cache is clear we can set up the injection entry. + // The injection entry is the user mapping itself. Thus it only needs + // to be injected if the directory being enumerated is the parent of + // the user mapping. + // + + if (UserMappingOverlap.Parent) { + + Status = NcEnumerateDirectorySetupInjection( DirContext, + FltObjects, + InstanceContext, + Offsets, + InformationClass ); + if (!NT_SUCCESS( Status )) { + + goto NcStreamHandleContextEnumSetupCleanup; + } + } + } + + // + // Now we know that the entry is setup. + // Mark it as in use. + // + + DirContext->InUse = TRUE; + Status = STATUS_SUCCESS; + +NcStreamHandleContextEnumSetupCleanup: + + if (!NT_SUCCESS( Status )) { + + if (!DirContext->InUse) { + + // + // We failed to set up the context for first use. + // We should free our buffer we allocated. + // + + if (DirContext->SearchString.Buffer != NULL) { + + ExFreePoolWithTag( DirContext->SearchString.Buffer, NC_TAG ); + DirContext->SearchString.Buffer = NULL; + DirContext->SearchString.Length = 0; + DirContext->SearchString.MaximumLength = 0; + } + } + } + + return Status; +} + +VOID +NcStreamHandleContextEnumClose ( + _In_ PNC_DIR_QRY_CONTEXT DirContext + ) +/*++ + +Routine Description: + + Tears down any remaining state associated with a directory enumeration. + +Arguments: + + DirContext - Pointer to the directory context. + +Return Value: + + None. + +--*/ +{ + PAGED_CODE(); + + if (DirContext->Cache.Buffer != NULL) { + + ExFreePoolWithTag( DirContext->Cache.Buffer, + NC_DIR_QRY_CACHE_TAG ); + + DirContext->Cache.Buffer = NULL; + } + + if (DirContext->InjectionEntry.Buffer != NULL) { + + ExFreePoolWithTag( DirContext->InjectionEntry.Buffer, + NC_DIR_QRY_CACHE_TAG ); + + DirContext->InjectionEntry.Buffer = NULL; + } + + if (DirContext->SearchString.Buffer != NULL) { + + ExFreePoolWithTag( DirContext->SearchString.Buffer, + NC_DIR_QRY_SEARCH_STRING ); + + DirContext->SearchString.Buffer = NULL; + } +} + + diff --git a/filesys/miniFilter/NameChanger/ncdirnotify.c b/filesys/miniFilter/NameChanger/ncdirnotify.c new file mode 100644 index 00000000..480f647f --- /dev/null +++ b/filesys/miniFilter/NameChanger/ncdirnotify.c @@ -0,0 +1,3526 @@ +/*++ + +Copyright (c) 2009 Microsoft Corporation + +Module Name: + + ncdirnotify.c + +Abstract: + + Contains routines to process user-initiated directory change notifications. + Depending on path, we may need to suppress the real mapping and its + children from generating notifications to the user, or inject changes from + the user mapping to the user. In some cases we can optimize this merely + by transforming the real mapping to user mapping (if we are watching an + ancestor of both paths.) + +Environment: + + Kernel mode + +--*/ + +#include "nc.h" + +// +// The following structures define a context which is allocated per sub-request. +// We record the type of the subrequest, and any state that is subrequest +// specific. +// +typedef enum _NC_NOTIFY_REQUEST_TYPE { + NotifyUserRequest = 0, + NotifyShadowRequest, + NotifyMappingRequest +} NC_NOTIFY_REQUEST_TYPE; + +typedef struct _NC_NOTIFY_REQUEST_CONTEXT { + PNC_STREAM_HANDLE_CONTEXT UserHandleContext; + PFILE_OBJECT FileObjectToDereference; + NC_NOTIFY_REQUEST_TYPE RequestType; + PFLT_CALLBACK_DATA Request; +} NC_NOTIFY_REQUEST_CONTEXT, *PNC_NOTIFY_REQUEST_CONTEXT; + +NTSTATUS +NcAllocateNotifyRequestContext ( + _In_ PNC_STREAM_HANDLE_CONTEXT HandleContext, + _In_ PFILE_OBJECT FileObject, + _In_ NC_NOTIFY_REQUEST_TYPE RequestType, + _In_ PFLT_CALLBACK_DATA Request, + _Out_ PNC_NOTIFY_REQUEST_CONTEXT * NotifyRequestContext + ); + +VOID +NcFreeNotifyRequestContext ( + _In_ PNC_NOTIFY_REQUEST_CONTEXT NotifyRequestContext + ); + +FLT_POSTOP_CALLBACK_STATUS +NcPostNotifyDirectorySafe ( + _Inout_ PFLT_CALLBACK_DATA Data, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _In_ PVOID CompletionContext, + _In_ FLT_POST_OPERATION_FLAGS Flags + ); + +VOID +NcPostNotifyDirectoryReal ( + _Inout_ PFLT_CALLBACK_DATA Data, + _In_ PVOID CompletionContext + ); + +NTSTATUS +NcDirNotifyTranslateBuffers ( + _In_ PNC_INSTANCE_CONTEXT InstanceContext, + _In_ BOOLEAN IgnoreCase, + _In_ PUNICODE_STRING UserRequestName, + _In_ PUNICODE_STRING OpenedName, + _In_reads_bytes_(InputBufferLength) PFILE_NOTIFY_INFORMATION InputSystemBuffer, + _Out_writes_bytes_to_(OutputBufferLength, *OutputBufferWritten) PFILE_NOTIFY_INFORMATION OutputUserBuffer, + _In_ ULONG InputBufferLength, + _In_ ULONG OutputBufferLength, + _Out_ PULONG InputBufferConsumed, + _Out_ PULONG OutputBufferWritten, + _In_ BOOLEAN ReturnRealMappingPaths, + _In_ BOOLEAN ReturnInMappingOnly + ); + + + +NTSTATUS +NcBuildSubNotifyRequest ( + _In_ PFLT_CALLBACK_DATA PrimaryRequest, + _In_ PFLT_INSTANCE Instance, + _In_ PFILE_OBJECT FileObject, + _In_ PNC_STREAM_HANDLE_CONTEXT HandleContext, + _In_ NC_NOTIFY_REQUEST_TYPE RequestType, + _Out_ PFLT_CALLBACK_DATA * SubRequest, + _Out_ PNC_NOTIFY_REQUEST_CONTEXT * NotifyRequestContext + ); + +VOID +NcCleanupSubNotifyRequest ( + _In_ PFLT_CALLBACK_DATA SubRequest + ); + +NTSTATUS +NcGetDestinationNotifyBuffer ( + _Inout_ PFLT_CALLBACK_DATA Data, + _Outptr_result_bytebuffer_maybenull_(*BufferSize) PVOID * DestBuffer, + _Out_ PULONG BufferSize + ); + +_Pre_satisfies_(*LockHeld) +_Requires_lock_held_(_Global_critical_region_) +_Requires_lock_held_(*HandleContext->Lock) +_When_(*LockHeld == FALSE, _Releases_lock_(_Global_critical_region_)) +_When_(*LockHeld == FALSE, _Releases_lock_(*HandleContext->Lock)) +VOID +NcNotifyAbort( + _In_ PNC_STREAM_HANDLE_CONTEXT HandleContext, + _In_ NTSTATUS Status, + _Inout_ PBOOLEAN LockHeld + ); + +VOID +NcNotifyCancelCallback( + _In_ PFLT_CALLBACK_DATA Data + ); + +VOID +NcCloseHandleWorkerRoutine ( + _In_ PFLT_GENERIC_WORKITEM WorkItem, + _In_ PFLT_FILTER Filter, + _In_ PVOID HandlePtr + ); + +VOID +NcReissueNotifyRequestWorkerRoutine ( + _In_ PFLT_GENERIC_WORKITEM WorkItem, + _In_ PFLT_FILTER Filter, + _In_ PVOID RequestPtr + ); + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE, NcAllocateNotifyRequestContext) +#pragma alloc_text(PAGE, NcBuildSubNotifyRequest) +#pragma alloc_text(PAGE, NcCleanupSubNotifyRequest) +#pragma alloc_text(PAGE, NcCloseHandleWorkerRoutine) +#pragma alloc_text(PAGE, NcDirNotifyTranslateBuffers) +#pragma alloc_text(PAGE, NcFreeNotifyRequestContext) +#pragma alloc_text(PAGE, NcGetDestinationNotifyBuffer) +#pragma alloc_text(PAGE, NcNotifyAbort) +#pragma alloc_text(PAGE, NcNotifyCancelCallback) +#pragma alloc_text(PAGE, NcPreNotifyDirectory) +#pragma alloc_text(PAGE, NcPostNotifyDirectorySafe) +#pragma alloc_text(PAGE, NcPostNotifyDirectoryReal) +#pragma alloc_text(PAGE, NcReissueNotifyRequestWorkerRoutine) +#pragma alloc_text(PAGE, NcStreamHandleContextNotCleanup) +#pragma alloc_text(PAGE, NcStreamHandleContextNotCreate) +#pragma alloc_text(PAGE, NcStreamHandleContextNotClose) +#endif + +#define NcRemoveTrailingSlashIfPresent( US ) \ + FLT_ASSERT( (US)->Length > 0 ); \ + if ( (US)->Buffer[(US)->Length/sizeof(WCHAR) - 1] == NC_SEPARATOR) { \ + (US)->Length -= sizeof(WCHAR); \ + } + + +NTSTATUS +NcDirNotifyTranslateBuffers ( + _In_ PNC_INSTANCE_CONTEXT InstanceContext, + _In_ BOOLEAN IgnoreCase, + _In_ PUNICODE_STRING UserRequestName, + _In_ PUNICODE_STRING OpenedName, + _In_reads_bytes_(InputBufferLength) PFILE_NOTIFY_INFORMATION InputSystemBuffer, + _Out_writes_bytes_to_(OutputBufferLength, *OutputBufferWritten) PFILE_NOTIFY_INFORMATION OutputUserBuffer, + _In_ ULONG InputBufferLength, + _In_ ULONG OutputBufferLength, + _Out_ PULONG InputBufferConsumed, + _Out_ PULONG OutputBufferWritten, + _In_ BOOLEAN ReturnRealMappingPaths, + _In_ BOOLEAN ReturnInMappingOnly + ) +/*++ + +Routine Description: + + This routine is used to transform buffers from a filesystem view to the + user view. Depending on flags we either replace references to the real + mapping with the user mapping, suppress all entries from the real mapping, + or only return results from inside the real mapping. + +Arguments: + + InstanceContext - Pointer to the context describing this instance of the + filter. + + IgnoreCase - TRUE if comparisons should be case insensitive, FALSE if + comparisons should be case sensitive. + + UserRequestName - The string for the path that the user opened and is + requesting notifications on. + + OpenedName - The string for the path that we are processing notifications + on. "Typically" the same as UserRequestName, but may be different if + we are merging notifications from the user's handle and combining + from the real mapping. In this case, OpenedName may refer to the + path to the real mapping. + + InputSystemBuffer - The buffer we are processing from. Note that this + routine assumes the buffer is not volatile (cannot be externally + modified.) For this reason, the buffer is expected to be system + buffered by the caller if it is not already. + + Note however that the contents of the buffer may have originated from + a user buffer (via a memcpy), so although the contents are non-volatile, + they are not to be trusted. + + OutputUserBuffer - The buffer we are returning munged results into. + This buffer is expected to have been probed, and this function will + catch and return any invalid buffer exceptions. + + InputBufferLength - Size, in bytes, of the input buffer. + + OutputBufferLength - Size, in bytes, of the output buffer. + + InputBufferConsumed - Pointer to a ULONG which will contain, on output, + the number of bytes processed from the input buffer. This may be + zero, the length of the input buffer, or any value in between. + This value is undefined on failure. + + OutputBufferWritten - Pointer to a ULONG which will contain, on output, + the number of bytes written into the output buffer. This may be + zero, the length of the output buffer, or any value in between. + This value is undefined on failure. + + ReturnRealMappingPaths - TRUE if this function should transform and + return any paths that are within the real mapping. If FALSE, we + omit these entries. + + ReturnInMappingOnly - TRUE if this function should transform and return + paths from within the real mapping only, and omit all other paths. + FALSE if it should return all paths. Only meaningful if + ReturnRealMappingPaths is TRUE. + +Return Value: + + The return value is the Status of the operation. + +--*/ +{ + NTSTATUS Status = STATUS_SUCCESS; + NC_PATH_OVERLAP RealOverlap; + + // + // Pointers into the above buffers used as we read entries from + // one buffer and write them to the other. We keep a pointer to + // the previous destination entry to allow us to terminate the + // list when done. + // + + PFILE_NOTIFY_INFORMATION SourceEntry = NULL; + PFILE_NOTIFY_INFORMATION DestEntry = NULL; + PFILE_NOTIFY_INFORMATION PrevDestEntry = NULL; + + // + // A full path to the path returned from the filesystem that we are + // currently examining; the Remainder of that path if it turns out + // to be in a mapping; the transformed name if one is required. + // + + UNICODE_STRING NameString = EMPTY_UNICODE_STRING; + UNICODE_STRING Remainder; + UNICODE_STRING MungedName = EMPTY_UNICODE_STRING; + + // + // A pointer to one of the above buffers that we intend on returning to + // the application. Note that this may be NULL if an entry is being + // suppressed. + // + + PUNICODE_STRING ReturnName; + ULONG EntryLength; + + ULONG UlongResult; + PVOID PointerResult; + + PAGED_CODE(); + + SourceEntry = InputSystemBuffer; + DestEntry = OutputUserBuffer; + *InputBufferConsumed = 0; + *OutputBufferWritten = 0; + + // + // This routine assumes it will only be called if there is work to do. + // + + FLT_ASSERT( InputBufferLength && OutputBufferLength ); + + try { + + while (SourceEntry) { + + // + // The path returned is relative to the handle used to request + // the service. We now allocate and construct a full path name. + // Use safe math routines when consulting the buffer, since it is + // possible that the buffer contents were modified by malicious + // code before getting here. + // + + EntryLength = OpenedName->Length + + sizeof(WCHAR); + + if (EntryLength >= MAXUSHORT) { + + Status = STATUS_OBJECT_PATH_INVALID; + goto NcDirNotifyTranslateBuffersCleanup; + } + + Status = RtlULongAdd( EntryLength, + SourceEntry->FileNameLength, + &EntryLength ); + + if (!NT_SUCCESS( Status ) || + (EntryLength >= MAXUSHORT)) { + + Status = STATUS_OBJECT_PATH_INVALID; + goto NcDirNotifyTranslateBuffersCleanup; + } + + // + // Now check whether this entry walks off the end of the input buffer. + // + + Status = RtlULongAdd( *InputBufferConsumed, + FIELD_OFFSET(FILE_NOTIFY_INFORMATION, FileName), + &UlongResult ); + + if (NT_SUCCESS( Status )) { + + Status = RtlULongAdd( UlongResult, + SourceEntry->FileNameLength, + &UlongResult ); + } + + if (!NT_SUCCESS( Status ) || + (UlongResult > InputBufferLength)) { + + // + // We have an entry that walks off the end of the buffer. + // Since the buffer that we get from the filesystem is not + // system buffered, we cannot guarantee that a caller is + // not corrupting it in an in-flight request. This + // condition should never occur without aforementioned + // corruption. + // + + FLT_ASSERT( FALSE ); + Status = STATUS_INVALID_USER_BUFFER; + goto NcDirNotifyTranslateBuffersCleanup; + } + + if (EntryLength > NameString.MaximumLength) { + + if (NameString.Buffer != NULL) { + NcFreeUnicodeString( &NameString ); + } + + NameString.Buffer = ExAllocatePoolWithTag( PagedPool, + EntryLength, + NC_TAG ); + + if (NameString.Buffer == NULL) { + + Status = STATUS_INSUFFICIENT_RESOURCES; + goto NcDirNotifyTranslateBuffersCleanup; + } + + NameString.MaximumLength = (USHORT)EntryLength; + } + + _Analysis_assume_(NameString.Buffer != NULL); + RtlCopyMemory( NameString.Buffer, + OpenedName->Buffer, + OpenedName->Length ); + + NameString.Buffer[OpenedName->Length / sizeof(WCHAR)] = NC_SEPARATOR; + + RtlCopyMemory( Add2Ptr( NameString.Buffer, OpenedName->Length + sizeof(WCHAR) ), + SourceEntry->FileName, + SourceEntry->FileNameLength ); + + NameString.Length = (USHORT)EntryLength; + + // + // Now see if this name needs to be munged. + // + + NcComparePath( &NameString, + &InstanceContext->Mapping.RealMapping, + &Remainder, + IgnoreCase, + TRUE, + &RealOverlap ); + + if (RealOverlap.InMapping && ReturnRealMappingPaths) { + + // + // If the name is under the real mapping and we're returning + // paths under the real mapping, the query is a common + // ancestor of both real and user mappings. In this case, + // we need to translate real mapping paths to user mapping + // paths. + // + + Status = NcConstructPath( &InstanceContext->Mapping.UserMapping, + &Remainder, + TRUE, + &MungedName ); + + if (!NT_SUCCESS( Status )) { + goto NcDirNotifyTranslateBuffersCleanup; + } + + ReturnName = &MungedName; + + } else if (ReturnInMappingOnly || RealOverlap.InMapping) { + + // + // If the name is in the real mapping but the caller is asking + // for a tree which is not an ancestor of the user mapping, + // then this name should not be visible under this tree. If + // the name is an ancestor of the real mapping, but the caller + // only requires children, this name should not be visible + // under this tree either. + // + + ReturnName = NULL; + + } else { + + ReturnName = &NameString; + + } + + if (ReturnName != NULL) { + + ULONG EntryLengthExact; + + // + // Since this API returns paths under the one the query was + // issued on, the path we have now had better be longer than + // that path length. Even if we refer to the same object, + // our path includes a trailing slash. + // + + FLT_ASSERT( ReturnName->Length > UserRequestName->Length ); + _Analysis_assume_( ReturnName->Length > UserRequestName->Length ); + + // + // We take care not to copy the leading slash. If we have + // a trailing slash as well as a leading slash, truncate the + // string. This can occur when we're injecting an entry for + // the mapping. + // + + if (ReturnName->Length - UserRequestName->Length > sizeof(WCHAR) && + ReturnName->Buffer[ReturnName->Length/sizeof(WCHAR) - 1] == NC_SEPARATOR) { + + ReturnName->Length -= sizeof(WCHAR); + } + + EntryLengthExact = FIELD_OFFSET( FILE_NOTIFY_INFORMATION, FileName ); + EntryLengthExact += (ReturnName->Length - UserRequestName->Length - sizeof(WCHAR)); + + EntryLength = AlignToSize( EntryLengthExact, 8); + + // + // We've done all we can. Return now to let our caller deal + // with the remaining buffer. + // + + Status = RtlULongAdd( EntryLength, + *OutputBufferWritten, + &UlongResult ); + + if (!NT_SUCCESS( Status ) || + (UlongResult > OutputBufferLength)) { + + if (PrevDestEntry != NULL) { + PrevDestEntry->NextEntryOffset = 0; + } + + SourceEntry = NULL; + DestEntry = NULL; + break; + } + + // + // Copy the relative path name, taking care to exclude the + // initial slash. + // + + DestEntry->FileNameLength = ReturnName->Length - + UserRequestName->Length - + sizeof(WCHAR); + + RtlCopyMemory( DestEntry->FileName, + Add2Ptr( ReturnName->Buffer, UserRequestName->Length + sizeof(WCHAR)), + ReturnName->Length - UserRequestName->Length - sizeof(WCHAR)); + DestEntry->Action = SourceEntry->Action; + DestEntry->NextEntryOffset = EntryLength; + + // + // Advance the destination that we're writing new entries by + // however much we just consumed. + // + + PrevDestEntry = DestEntry; + *OutputBufferWritten += EntryLength; + DestEntry = Add2Ptr( DestEntry, EntryLength ); + + if (MungedName.Buffer != NULL) { + ExFreePoolWithTag( MungedName.Buffer, NC_GENERATE_NAME_TAG ); + MungedName.Buffer = NULL; + MungedName.MaximumLength = MungedName.Length = 0; + } + } + + // + // Now calculate and advance the location we're reading and + // processing from. If we're have no more buffer left, we're + // done. + // + + // + // SourceEntry->NextEntryOffset is untrusted, since it may have been + // copied from a user-provided buffer. + // + + EntryLength = SourceEntry->NextEntryOffset; + + PointerResult = Add2Ptr( SourceEntry, EntryLength ); + + Status = RtlULongAdd( *InputBufferConsumed, + EntryLength, + InputBufferConsumed ); + + // + // There's a problem if one of the following happened: + // + // 1) We overflowed when accounting for for consumed input buffer + // 2) We wrapped when advancing SourceEntry + // 3) PointerResult is not within InputSystemBuffer + // + + if (!NT_SUCCESS( Status ) || + (PointerResult < (PVOID)SourceEntry) || + (PointerResult < Add2Ptr( InputSystemBuffer, sizeof(FILE_NOTIFY_INFORMATION) ))) { + + FLT_ASSERT( FALSE ); + + Status = STATUS_INVALID_USER_BUFFER; + goto NcDirNotifyTranslateBuffersCleanup; + } + + SourceEntry = (PFILE_NOTIFY_INFORMATION)PointerResult; + + if ((EntryLength == 0)) { + + if (PrevDestEntry != NULL) { + PrevDestEntry->NextEntryOffset = 0; + } + + *InputBufferConsumed = InputBufferLength; + SourceEntry = NULL; + } + + // + // If we've just advanced our next location beyond the end of the + // input buffer, or there isn't enough room in it for even a FILE_NOTIFY_INFORMATION + // structure, terminate the loop by setting SourceEntry to NULL so + // we can at least return the valid entries we have. + // + + FLT_ASSERT( *InputBufferConsumed <= InputBufferLength ); + + if ((SourceEntry != NULL) && + ((*InputBufferConsumed >= InputBufferLength) || + (*InputBufferConsumed + FIELD_OFFSET( FILE_NOTIFY_INFORMATION, FileName ) > InputBufferLength))) { + + // + // Indicate to the caller that we consumed exactly the input buffer. + // Otherwise it may hold the possibly small remnant and come back + // in to this routine later with that remnant, causing us to overread + // the buffer. + // + + *InputBufferConsumed = InputBufferLength; + SourceEntry = NULL; + } + } + + } except (NcExceptionFilter( GetExceptionInformation(), TRUE )) { + + Status = STATUS_INVALID_USER_BUFFER; + } + + // + // If we're succeeding, our list should be terminated. + // + + FLT_ASSERT( PrevDestEntry == NULL || + !NT_SUCCESS( Status ) || + PrevDestEntry->NextEntryOffset == 0); + +NcDirNotifyTranslateBuffersCleanup: + + if (MungedName.Buffer != NULL) { + + ExFreePoolWithTag( MungedName.Buffer, NC_GENERATE_NAME_TAG ); + MungedName.Buffer = NULL; + MungedName.MaximumLength = MungedName.Length = 0; + + } + + if (NameString.Buffer != NULL) { + + NcFreeUnicodeString( &NameString ); + } + + return Status; +} + +NTSTATUS +NcAllocateNotifyRequestContext ( + _In_ PNC_STREAM_HANDLE_CONTEXT HandleContext, + _In_ PFILE_OBJECT FileObject, + _In_ NC_NOTIFY_REQUEST_TYPE RequestType, + _In_ PFLT_CALLBACK_DATA Request, + _Out_ PNC_NOTIFY_REQUEST_CONTEXT * NotifyRequestContext + ) +/*++ + +Routine Description: + + This function allocates a new request context with the specified + properties. It references objects passed into it. + +Arguments: + + HandleContext - Pointer to the handle context attached to the + user's handle. + + FileObject - The file that this request is being sent to. This + will be different to the user's file object for + mapping requests. + + RequestType - Specifies which class of subrequest this context + is for. + + Request - Pointer to Fltmgr's notion of this request. + + NotifyRequestContext - On output, points to the newly allocated + context. On failure, this value is + undefined. + +Return Value: + + Status of the operation. + +--*/ +{ + PNC_NOTIFY_REQUEST_CONTEXT RequestContext; + + PAGED_CODE(); + + RequestContext = ExAllocatePoolWithTag( PagedPool, + sizeof(NC_NOTIFY_REQUEST_CONTEXT), + NC_TAG ); + + if (RequestContext == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + FltReferenceContext( HandleContext ); + RequestContext->UserHandleContext = HandleContext; + + if (ARGUMENT_PRESENT( FileObject )) { + + ObReferenceObject( FileObject ); + RequestContext->FileObjectToDereference = FileObject; + } + + RequestContext->RequestType = RequestType; + RequestContext->Request = Request; + + *NotifyRequestContext = RequestContext; + + return STATUS_SUCCESS; +} + +VOID +NcFreeNotifyRequestContext ( + _In_ PNC_NOTIFY_REQUEST_CONTEXT NotifyRequestContext + ) +/*++ + +Routine Description: + + This function frees a request context previously allocated with + NcAllocateNotifyRequestContext. Since it dereferences objects + referenced at allocate time, it must be called without locks + held. + +Arguments: + + NotifyRequestContext - The request context to tear down. + +Return Value: + + None. + +--*/ +{ + PAGED_CODE(); + + FLT_ASSERT( ExIsResourceAcquiredSharedLite( NotifyRequestContext->UserHandleContext->Lock ) == 0 ); + + if (NotifyRequestContext->FileObjectToDereference) { + ObDereferenceObject( NotifyRequestContext->FileObjectToDereference ); + } + + FltReleaseContext( NotifyRequestContext->UserHandleContext ); + + ExFreePoolWithTag( NotifyRequestContext, NC_TAG ); + +} + +NTSTATUS +NcBuildSubNotifyRequest ( + _In_ PFLT_CALLBACK_DATA PrimaryRequest, + _In_ PFLT_INSTANCE Instance, + _In_ PFILE_OBJECT FileObject, + _In_ PNC_STREAM_HANDLE_CONTEXT HandleContext, + _In_ NC_NOTIFY_REQUEST_TYPE RequestType, + _Out_ PFLT_CALLBACK_DATA * SubRequest, + _Out_ PNC_NOTIFY_REQUEST_CONTEXT * NotifyRequestContext + ) +/*++ + +Routine Description: + + This routine is used to create and initialize a new subrequest for + directory change notifications. We need to create a new subrequest + when requests are being shadowed or when merging from multiple locations. + For change notifications unrelated to the mapping or spanning both + mapping locations, we can send the user's request to the filesystem and + not create any subrequests. + +Arguments: + + PrimaryRequest - Pointer to the user's request. We use this to propagate + settings into the sub request. + + Instance - Pointer to the instance of this filter. + + FileObject - Pointer to the file object for the subrequest. This may be + the same as the user's file object, or may be a file object to the + parent of the real mapping. + + HandleContext - Pointer to the handle context attached to the + user's handle. + + RequestType - Specifies which class of subrequest this context + is for. + + SubRequest - Pointer to a location to contain the new request created by + this routine. This value is undefined on failure. + + NotifyRequestContext - On output, points to the newly allocated + context. On failure, this value is undefined. + +Return Value: + + The return value is the Status of the operation. + +--*/ +{ + PVOID MyBuffer; + ULONG BufferLength = PrimaryRequest->Iopb->Parameters.DirectoryControl.NotifyDirectory.Length; + NTSTATUS Status; + PFLT_CALLBACK_DATA NewRequest; + + PAGED_CODE(); + + if (BufferLength > 0) { + + // + // Since this request isn't being sent to the filesystem and + // we'll complete it in arbitary context, we need to build a + // MDL now so we can copy to system address space rather than + // back to the originating usermode process. + // + + Status = FltLockUserBuffer( PrimaryRequest ); + + if (!NT_SUCCESS( Status )) { + + return Status; + } + + // + // The #pragma is a notation to the static code analyzer to not worry + // that we're apparently leaking MyBuffer. It goes in to the subrequest + // we are building and will be cleaned up by NcCleanupSubNotifyRequest. + // That routine gets called on error in this routine, and from + // NcPostNotifyDirectoryReal, which is the completion routine that will + // be called once the subrequest we are building is finished executing. + // + +#pragma warning(suppress: 6014) + MyBuffer = ExAllocatePoolWithTag( PagedPool, + BufferLength, + NC_TAG ); + + if (MyBuffer == NULL) { + + Status = STATUS_INSUFFICIENT_RESOURCES; + return Status; + } + + } else { + + MyBuffer = NULL; + } + + Status = FltAllocateCallbackData( Instance, + FileObject, + &NewRequest ); + + if (!NT_SUCCESS( Status )) { + + if (MyBuffer != NULL) { + ExFreePoolWithTag( MyBuffer, NC_TAG ); + } + + return Status; + } + + NewRequest->Iopb->MajorFunction = IRP_MJ_DIRECTORY_CONTROL; + NewRequest->Iopb->MinorFunction = IRP_MN_NOTIFY_CHANGE_DIRECTORY; + NewRequest->Iopb->OperationFlags = PrimaryRequest->Iopb->OperationFlags; + NewRequest->Iopb->Parameters.DirectoryControl.NotifyDirectory.Length = BufferLength; + NewRequest->Iopb->Parameters.DirectoryControl.NotifyDirectory.DirectoryBuffer = MyBuffer; + NewRequest->Iopb->Parameters.DirectoryControl.NotifyDirectory.CompletionFilter = + PrimaryRequest->Iopb->Parameters.DirectoryControl.NotifyDirectory.CompletionFilter; + NewRequest->Iopb->Parameters.DirectoryControl.NotifyDirectory.Spare1 = 0; + NewRequest->Iopb->Parameters.DirectoryControl.NotifyDirectory.Spare2 = 0; + NewRequest->Iopb->Parameters.DirectoryControl.NotifyDirectory.MdlAddress = NULL; + + if (BufferLength > 0) { + + NewRequest->Flags |= FLTFL_CALLBACK_DATA_SYSTEM_BUFFER; + } + + // + // Allocate the request context. We do this last because we + // cannot safely drop references if we fail after this point. + // + + Status = NcAllocateNotifyRequestContext( HandleContext, + FileObject, + RequestType, + NewRequest, + NotifyRequestContext ); + + if (!NT_SUCCESS( Status )) { + + NcCleanupSubNotifyRequest( NewRequest ); + return Status; + } + + *SubRequest = NewRequest; + return STATUS_SUCCESS; +} + +VOID +NcCleanupSubNotifyRequest ( + _In_ PFLT_CALLBACK_DATA SubRequest + ) +/*++ + +Routine Description: + + This routine is used to tear down a subrequest once we are done with it. + +Arguments: + + SubRequest - Pointer to the request to tear down. + +Return Value: + + None. + +--*/ +{ + PAGED_CODE(); + + if (SubRequest->Iopb->Parameters.DirectoryControl.NotifyDirectory.DirectoryBuffer != NULL) { + + ExFreePoolWithTag( SubRequest->Iopb->Parameters.DirectoryControl.NotifyDirectory.DirectoryBuffer, + NC_TAG ); + } + + FltFreeCallbackData( SubRequest ); +} + +NTSTATUS +NcGetDestinationNotifyBuffer ( + _Inout_ PFLT_CALLBACK_DATA Data, + _Outptr_result_bytebuffer_maybenull_(*BufferSize) PVOID * DestBuffer, + _Out_ PULONG BufferSize + ) +/*++ + +Routine Description: + + This routine is used to obtain the virtual address that we should use + to access a particular request's buffer. Depending on the request, + this may be system buffered, system mapped but user exposed, or user + VA. + +Arguments: + + Data - The request whose VA we are trying to obtain/map. + + DestBuffer - Pointer to a pointer which will, on output, point to the + buffer associated with this request. On failure, this value is + undefined. + + BufferSize - Pointer to a location which will, on output, contain the + length of the user's buffer. On failure, this value is undefined. + +Return Value: + + The return value is the Status of the operation. + +--*/ +{ + NTSTATUS Status = STATUS_SUCCESS; + PAGED_CODE(); + + *BufferSize = Data->Iopb->Parameters.DirectoryControl.NotifyDirectory.Length; + + *DestBuffer = NULL; + + // + // FltLockUserBuffer doesn't like being called with zero length buffers. + // If we have one of those, end now. + // + + if (Data->Iopb->Parameters.DirectoryControl.NotifyDirectory.Length == 0) { + + Status = STATUS_SUCCESS; + goto NcGetDestinationNotifyBufferCleanup; + } + + // + // If we are in our post routine, we expect the buffer to have already + // been locked if FltGetNewSystemBufferAddress does not exist. If it + // does exist, we may have a MDL, or we may be obtaining the system + // buffer supplied by the filesystem. + // + // If we are issuing our own requests, we can also consume the user + // buffer directly, since it will always be system mapped (it's a pool + // allocation.) + // + + if (Data->Iopb->Parameters.DirectoryControl.NotifyDirectory.MdlAddress) { + + Status = FltLockUserBuffer( Data ); + + if (!NT_SUCCESS( Status )) { + + goto NcGetDestinationNotifyBufferCleanup; + } + + *DestBuffer = MmGetSystemAddressForMdlSafe( Data->Iopb->Parameters.DirectoryControl.NotifyDirectory.MdlAddress, + NormalPagePriority | MdlMappingNoExecute ); + if (*DestBuffer == NULL) { + + // + // If this fails, we have the pages locked in RAM but don't + // have VA to map them to. STATUS_NO_MEMORY is usually used to + // indicate VA exhaustion. + // + + Status = STATUS_NO_MEMORY; + goto NcGetDestinationNotifyBufferCleanup; + } + } else { + + if (NcGetNewSystemBufferAddress) { + *DestBuffer = NcGetNewSystemBufferAddress( Data ); + } else { + *DestBuffer = NULL; + } + + // + // If we have no MDL, and the filesystem hasn't allocated a system + // buffer, there are two possibilities: + // + // 1. This is a request we created ourselves and was already system + // buffered. + // + // 2. We are returning within the original thread context (ie., + // buffered results being returned to the caller instantly.) + // In this case, we can use the user's VA. + // + + if (*DestBuffer == NULL) { + + *DestBuffer = Data->Iopb->Parameters.DirectoryControl.NotifyDirectory.DirectoryBuffer; + + if (NcGetNewSystemBufferAddress == NULL) { + + // + // On Win7 where we have FltGetNewSystemBufferAddress, we + // can grab the system buffer from the Irp. Pre-Win7 we + // must lock the user's buffer, thereby ending up in the + // above code block. If we roll our own, the buffers we + // use are in kernel space. The rule here is, no user VA + // can be sent down without being locked first. + // + + FLT_ASSERT( *DestBuffer > (PVOID)0x80000000 ); + + } else { + + try { + + if (Data->RequestorMode != KernelMode) { + ProbeForWrite( *DestBuffer, *BufferSize, sizeof( UCHAR )); + } + + } except (NcExceptionFilter( GetExceptionInformation(), TRUE )) { + + Status = STATUS_INVALID_USER_BUFFER; + } + + } + } + + } + +NcGetDestinationNotifyBufferCleanup: + + return Status; +} + + +FLT_PREOP_CALLBACK_STATUS +NcPreNotifyDirectory( + _Inout_ PFLT_CALLBACK_DATA Data, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _Flt_CompletionContext_Outptr_ PVOID *CompletionContext + ) +/*++ + +Routine Description: + + Routine is invoked when the user wants to modify a directory for + changes. The user can specify to monitor any directory, and can + opt to monitor an entire subtree. + + We can approach this problem in one of four ways: + + 1. If the directory being monitored has no relation to either + mapping, we can send it straight to the filesystem. + + 2. If the directory being monitored is an ancestor of the real + mapping but not the user mapping, we must suppress entries + from the mapping. + + 3. If the directory being monitored is an ancestor of both + mappings, we can change the contents of the buffer from real + to user to reflect the change. + + 4. If the directory being monitored is an ancestor of the user + mapping but not the real mapping, we must send down two + requests, one for the mapping parent and one for the user's + handle, and combine the results back to the user. + +Arguments: + + Data - Pointer to the filter CallbackData that is passed to us. + + FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure + containing opaque handles to this filter, instance, its + associated volume and file object. + + CompletionContext - The context for the completion routine for + this operation. We set this to the handle context for + directory change notifications. + +Return Value: + + The return value is the Status of the operation. + +--*/ +{ + FLT_PREOP_CALLBACK_STATUS ReturnValue; + NTSTATUS Status; + + PNC_INSTANCE_CONTEXT InstanceContext = NULL; + PNC_STREAM_HANDLE_CONTEXT HandleContext = NULL; + PNC_DIR_NOT_CONTEXT NotCtx = NULL; + + PFLT_FILE_NAME_INFORMATION FileNameInformation = NULL; + + NC_PATH_OVERLAP RealOverlap; + NC_PATH_OVERLAP UserOverlap; + + BOOLEAN WatchTree = BooleanFlagOn( Data->Iopb->OperationFlags, SL_WATCH_TREE ); + BOOLEAN IgnoreCase = !BooleanFlagOn( FltObjects->FileObject->Flags, + FO_OPENED_CASE_SENSITIVE ); + BOOLEAN UnlockContext = FALSE; + ULONG SizeWeReturn = 0; + PNC_NOTIFY_REQUEST_CONTEXT ShadowRequestContext = NULL; + PNC_NOTIFY_REQUEST_CONTEXT MappingParentRequestContext = NULL; + PFLT_CALLBACK_DATA NewShadowRequest = NULL; + PFLT_CALLBACK_DATA NewMappingParentRequest = NULL; + + PAGED_CODE(); + + FLT_ASSERT( IoGetTopLevelIrp() == NULL ); + + // + // If the FileObject has been through cleanup, fail now. This check + // is to catch where a file was cleaned up, then a notification was + // called on it for the first time. We don't want to start + // initializing our structures now if we don't have to. + // + + if (FlagOn( FltObjects->FileObject->Flags, FO_CLEANUP_COMPLETE )) { + + ReturnValue = FLT_PREOP_COMPLETE; + Status = STATUS_NOTIFY_CLEANUP; + SizeWeReturn = 0; + + goto NcPreNotifyDirectoryCleanup; + } + + // + // Get our instance context. + // + + Status = FltGetInstanceContext( FltObjects->Instance, + &InstanceContext ); + + if (!NT_SUCCESS( Status )) { + + ReturnValue = FLT_PREOP_COMPLETE; + goto NcPreNotifyDirectoryCleanup; + } + + // + // Get the directory's name. + // + + Status = NcGetFileNameInformation( Data, + NULL, + NULL, + FLT_FILE_NAME_OPENED | FLT_FILE_NAME_QUERY_DEFAULT, + &FileNameInformation ); + + if (!NT_SUCCESS( Status )) { + + ReturnValue = FLT_PREOP_COMPLETE; + goto NcPreNotifyDirectoryCleanup; + } + + Status = FltParseFileNameInformation( FileNameInformation ); + + if (!NT_SUCCESS( Status )) { + + ReturnValue = FLT_PREOP_COMPLETE; + goto NcPreNotifyDirectoryCleanup; + } + + // + // See if the directory is parent of either mapping. + // + + NcComparePath( &FileNameInformation->Name, + &InstanceContext->Mapping.UserMapping, + NULL, + IgnoreCase, + TRUE, + &UserOverlap ); + + NcComparePath( &FileNameInformation->Name, + &InstanceContext->Mapping.RealMapping, + NULL, + IgnoreCase, + TRUE, + &RealOverlap ); + + // + // If we are watching within the mapping, we have no + // work to do. Strings returned are relative to the + // handle used to query for this operation. + // + + if (UserOverlap.InMapping || RealOverlap.InMapping) { + + Status = STATUS_SUCCESS; + ReturnValue = FLT_PREOP_SUCCESS_NO_CALLBACK; + goto NcPreNotifyDirectoryCleanup; + } + + // + // If this object has no relation to either mapping, + // we have nothing to do. + // + + if (!UserOverlap.Ancestor && !RealOverlap.Ancestor) { + + Status = STATUS_SUCCESS; + ReturnValue = FLT_PREOP_SUCCESS_NO_CALLBACK; + goto NcPreNotifyDirectoryCleanup; + } + + // + // If we are not monitoring recursively, and this is a + // non-parent ancestor, we have no work to do. + // + + if (!WatchTree && + (!UserOverlap.Parent && !RealOverlap.Parent)) { + + Status = STATUS_SUCCESS; + ReturnValue = FLT_PREOP_SUCCESS_NO_CALLBACK; + goto NcPreNotifyDirectoryCleanup; + } + + // + // Attach our handle context. We use this to record + // state about which object we're monitoring, how we're + // monitoring it, and our outstanding subrequests. + // + + Status = NcStreamHandleContextAllocAndAttach( FltObjects->Filter, + FltObjects->Instance, + FltObjects->FileObject, + &HandleContext ); + + if (!NT_SUCCESS( Status )) { + + ReturnValue = FLT_PREOP_COMPLETE; + goto NcPreNotifyDirectoryCleanup; + } + + FLT_ASSERT( HandleContext != NULL ); + + NotCtx = &HandleContext->DirectoryNotificationContext; + + // + // Before looking at the context, we have to acquire the lock. + // + + NcLockStreamHandleContext( HandleContext ); + UnlockContext = TRUE; + + // + // If the user's handle has gone through cleanup, don't allow this + // request. We're not synchronized with the FO_CLEANUP_COMPLETE + // flag, but we are synchronized with the CleanupSeen flag, so we + // need to do this check now after acquiring the lock. + // + + if (NotCtx->CleanupSeen || + FlagOn( FltObjects->FileObject->Flags, FO_CLEANUP_COMPLETE )) { + + ReturnValue = FLT_PREOP_COMPLETE; + Status = STATUS_NOTIFY_CLEANUP; + SizeWeReturn = 0; + + goto NcPreNotifyDirectoryCleanup; + } + + // + // Save away the path used on this handle, if we haven't already. + // This is done to avoid having to re-request it in post. + // + // Note that NameChanger will not allow renames of ancestor + // components, which are also the only paths it intercepts + // directory change notifications on. Accordingly, the path we + // capture here should not change for the lifetime of the + // notification. + // + + if (NotCtx->UserRequestName.Buffer == NULL) { + + NotCtx->UserRequestName.Buffer = ExAllocatePoolWithTag( PagedPool, + FileNameInformation->Name.Length, + NC_TAG ); + + if (NotCtx->UserRequestName.Buffer == NULL) { + + ReturnValue = FLT_PREOP_COMPLETE; + Status = STATUS_INSUFFICIENT_RESOURCES; + goto NcPreNotifyDirectoryCleanup; + + } + + RtlCopyMemory( NotCtx->UserRequestName.Buffer, + FileNameInformation->Name.Buffer, + FileNameInformation->Name.Length ); + + NotCtx->UserRequestName.MaximumLength = + NotCtx->UserRequestName.Length = + FileNameInformation->Name.Length; + + NcRemoveTrailingSlashIfPresent( &NotCtx->UserRequestName ); + + NotCtx->IgnoreCase = IgnoreCase; + + FltReferenceContext( InstanceContext ); + NotCtx->InstanceContext = InstanceContext; + NotCtx->CompletionFilter = Data->Iopb->Parameters.DirectoryControl.NotifyDirectory.CompletionFilter; + NotCtx->OperationFlags = Data->Iopb->OperationFlags; + + } + + // + // If the user had previously cancelled a request on this handle, + // clear that now. We want to process all results from this + // point. + // + + NotCtx->CancelSeen = FALSE; + + // + // TODO: The notify package can record a number of Irps for the + // same directory (with the same settings for all.) To preserve + // this semantic, we need to save off whether we're watching the + // entire tree or not in our handle context, then keep a list + // of outstanding requests. These will be completed by the + // filesystem on a first in, first out basis. Or perhaps, we + // maintain the list and only send the filesystem a "representative" + // query, but maintain our own list and re-send to the filesystem + // if further user requests exist. + // + // Bah. + // + + // Check if this ever occurs in practice + FLT_ASSERT( NotCtx->UserRequest == NULL ); + if (NotCtx->UserRequest != NULL) { + + Status = STATUS_UNSUCCESSFUL; + ReturnValue = FLT_PREOP_COMPLETE; + goto NcPreNotifyDirectoryCleanup; + } + + // + // If we previously saw the filesystem indicate that the buffer was + // not large enough to return all results, but we did not have a user + // request to complete to that effect, let the user know now. + // + + if (NotCtx->InsufficientBufferSeen) { + + NotCtx->InsufficientBufferSeen = FALSE; + Status = STATUS_NOTIFY_ENUM_DIR; + ReturnValue = FLT_PREOP_COMPLETE; + goto NcPreNotifyDirectoryCleanup; + } + + // + // If we still have leftover changes from a previous call, + // return them now. Note that we do not want to set this + // request as being the user's request in this case. + // + + if (NotCtx->BufferToFree != NULL) { + + PVOID Buffer; + ULONG BufferSize; + + FLT_ASSERT( NotCtx->BufferLength != 0 ); + + Status = NcGetDestinationNotifyBuffer( Data, &Buffer, &BufferSize ); + + // + // We were unable to lock/map the user's buffer, or the buffer + // was invalid. + // + + if (!NT_SUCCESS( Status )) { + + ReturnValue = FLT_PREOP_COMPLETE; + goto NcPreNotifyDirectoryCleanup; + } + + // + // If the user's buffer isn't big enough, tell them to rescan. + // Since we're telling them to rescan, tear down the buffer. + // + + if (BufferSize < NotCtx->BufferLength) { + + ExFreePoolWithTag( NotCtx->BufferToFree, NC_TAG ); + NotCtx->BufferToFree = NULL; + NotCtx->BufferLength = 0; + + ReturnValue = FLT_PREOP_COMPLETE; + Status = STATUS_NOTIFY_ENUM_DIR; + goto NcPreNotifyDirectoryCleanup; + + } else { + + try { + + RtlCopyMemory( Buffer, + NotCtx->BufferToFree, + NotCtx->BufferLength ); + + } except (NcExceptionFilter( GetExceptionInformation(), TRUE )) { + + Status = STATUS_INVALID_USER_BUFFER; + goto NcPreNotifyDirectoryCleanup; + } + + SizeWeReturn = NotCtx->BufferLength; + + ExFreePoolWithTag( NotCtx->BufferToFree, NC_TAG ); + NotCtx->BufferToFree = NULL; + NotCtx->BufferLength = 0; + + ReturnValue = FLT_PREOP_COMPLETE; + Status = STATUS_SUCCESS; + + goto NcPreNotifyDirectoryCleanup; + } + } + + NotCtx->UserRequest = Data; + + // + // If we are watching the parent of the real mapping, + // or an ancestor of it including subtree, but not + // an ancestor of the user mapping, we'll need to "filter" + // out notifications that a caller should not see. + // + + if ((WatchTree && RealOverlap.Ancestor && !UserOverlap.Ancestor) || + (!WatchTree && RealOverlap.Parent && !UserOverlap.Parent)) { + + NotCtx->Mode = Filter; + + // + // TODO: Currently the lifetime of requests in filter mode is + // lock-step. If we get here when the Irp is already sent to + // the filesystem, that implies that we have multiple async + // notify irps sent to us, and we either support having + // multiple notify irps sent to the filesystem, or we queue + // them here. + // + + FLT_ASSERT( NotCtx->ShadowRequest == NULL ); + if (NotCtx->ShadowRequest == NULL) { + + Status = NcBuildSubNotifyRequest( Data, + FltObjects->Instance, + FltObjects->FileObject, + HandleContext, + NotifyShadowRequest, + &NewShadowRequest, + &ShadowRequestContext ); + + if (!NT_SUCCESS( Status )) { + + ReturnValue = FLT_PREOP_COMPLETE; + goto NcPreNotifyDirectoryCleanup; + } + + } + + // + // To synchronize this, we set the request in the context under + // cover of the context lock. We then drop the lock to issue the + // IO. The rule here is that IO should only be sent by its + // creator or its completor. + // + + if (NewShadowRequest) { + + FLT_ASSERT( ShadowRequestContext ); + FLT_ASSERT( UnlockContext ); + + // + // Set up the subrequest. This is done before we set up a + // cancel callback to ensure that the cancel can do + // something meaningful if it's invoked. + // + + NotCtx->ShadowRequest = NewShadowRequest; + + // + // Set a cancel routine on the user's request (which we intend + // on hanging on to.) If the request is already cancelled, + // cancel our new request. + // + + Status = NcSetCancelCompletion( Data, NcNotifyCancelCallback ); + + if (!NT_SUCCESS( Status )) { + + NotCtx->ShadowRequest = NULL; + + ReturnValue = FLT_PREOP_COMPLETE; + goto NcPreNotifyDirectoryCleanup; + } + + FLT_ASSERT( HandleContext != NULL ); + NcUnlockStreamHandleContext( HandleContext ); + UnlockContext = FALSE; + + // + // As soon as we send this, Data/NotCtx->UserRequest is + // no longer guaranteed to be valid. Fltmgr will call + // our completion routine even on failure. Regardless + // of what happens here, we do not need to worry about + // cleaning things up. + // + + Status = FltPerformAsynchronousIo( NotCtx->ShadowRequest, + NcPostNotifyDirectoryReal, + ShadowRequestContext ); + + } + + // + // Don't free the request or its context. These belong to the + // request now. + // + + ShadowRequestContext = NULL; + NewShadowRequest = NULL; + + // + // We return pending here in all cases. Either the filesystem + // pended the request (and we should too), or the filesystem + // completed it inline, in which case our completion routine has + // already completed our 'pending' request, so we'd better pend it. + // + // If our request failed, Fltmgr will call our completion routine + // which will also propagate the failure to the user request and + // complete it. + // + + ReturnValue = FLT_PREOP_PENDING; + + } else + + // + // If we are watching the tree of a mutual ancestor, + // or just the directory of a mutal parent, or within + // the mapping itself, we'll need to transform names. + // + + if ((WatchTree && RealOverlap.Ancestor && UserOverlap.Ancestor) || + (RealOverlap.Parent && UserOverlap.Parent)) { + + // + // Filesystems may switch a directory change notify request + // to system buffered. On Win7, we can obtain the resulting + // system buffer from FltGetNewSystemBufferAddress. Prior + // to this we can't obtain it, so we must lock the user + // buffer now so the filesystem can obtain kernel VA and will + // not attempt to system buffer the request. + // + + if (NcGetNewSystemBufferAddress == NULL) { + + Status = FltLockUserBuffer( Data ); + if (!NT_SUCCESS( Status )) { + + ReturnValue = FLT_PREOP_COMPLETE; + goto NcPreNotifyDirectoryCleanup; + } + + if (MmGetSystemAddressForMdlSafe( Data->Iopb->Parameters.DirectoryControl.NotifyDirectory.MdlAddress, + NormalPagePriority | MdlMappingNoExecute ) == NULL) { + + Status = STATUS_NO_MEMORY; + ReturnValue = FLT_PREOP_COMPLETE; + goto NcPreNotifyDirectoryCleanup; + } + } + + // + // Allocate a context that describes this subrequest. + // + + Status = NcAllocateNotifyRequestContext( HandleContext, + FltObjects->FileObject, + NotifyUserRequest, + Data, + &ShadowRequestContext ); + + if (!NT_SUCCESS( Status )) { + + ReturnValue = FLT_PREOP_COMPLETE; + goto NcPreNotifyDirectoryCleanup; + } + + *CompletionContext = ShadowRequestContext; + ShadowRequestContext = NULL; + + // + // We have to do something with this call, so tell + // fltmgr to call us back. + // + + ReturnValue = FLT_PREOP_SUCCESS_WITH_CALLBACK; + + NotCtx->Mode = Munge; + + } else + + // + // If we are watching the tree of an ancestor of the + // user mapping or just the directory of the parent + // of the user mapping, which is not an ancestor of + // the real mapping, we need to merge two different + // notifications into one. + // + + if ((WatchTree && UserOverlap.Ancestor && !RealOverlap.Ancestor) || + (!WatchTree && UserOverlap.Parent && !RealOverlap.Parent)) { + + // + // If we already have a handle to the mapping parent, use it. + // If we don't have one, drop our lock and proceed to open it. + // + + if (NotCtx->RealParentHandle == NULL) { + + OBJECT_ATTRIBUTES MappingParentAttributes; + HANDLE MappingParentHandle = NULL; + PFILE_OBJECT MappingParentFileObject = NULL; + PWSTR MappingParentName; + IO_STATUS_BLOCK MappingParentStatusBlock; + PFLT_FILE_NAME_INFORMATION FileInfoInternalHandle = NULL; + PFLT_GENERIC_WORKITEM MappingParentWorkItem = NULL; + + // + // Since we haven't opened a handle yet, we assume no requests + // can be outstanding which could race with us. Even if the + // directory being used has been renamed so we're going into + // this path after being through one of the other paths, we + // should be in lock-step until we enter Merge mode, so no + // requests should exist. + // + + FLT_ASSERT( NotCtx->ShadowRequest == NULL && + NotCtx->MappingRequest == NULL ); + + FLT_ASSERT( UnlockContext ); + NcUnlockStreamHandleContext( HandleContext ); + UnlockContext = FALSE; + + // + // Open the parent of the mapping. We'll need to return results + // from both the user's handle and our own. Note that we open + // the parent specifically so that a caller can monitor changes + // to the mapping itself. + // + + InitializeObjectAttributes( &MappingParentAttributes, + &InstanceContext->Mapping.RealMapping.LongNamePath.ParentPath, + OBJ_KERNEL_HANDLE | (IgnoreCase?OBJ_CASE_INSENSITIVE:0), + NULL, + NULL); + + Status = NcCreateFileHelper( NcGlobalData.FilterHandle, // Filter + FltObjects->Instance, // InstanceOffsets + &MappingParentHandle, // Returned Handle + &MappingParentFileObject, // Returned FileObject + FILE_READ_ATTRIBUTES|FILE_TRAVERSE, // Desired Access + &MappingParentAttributes, // object attributes + &MappingParentStatusBlock, // Returned IOStatusBlock + 0, // Allocation Size + FILE_ATTRIBUTE_NORMAL, // File Attributes + 0, // Share Access + FILE_OPEN, // Create Disposition + FILE_DIRECTORY_FILE, // Create Options + NULL, // Ea Buffer + 0, // EA Length + IO_IGNORE_SHARE_ACCESS_CHECK, // Flags + FltObjects->FileObject ); // Transaction info + + if (!NT_SUCCESS( Status )) { + + // + // This filter enforces the existence of mapping parents + // at attach time, and will prevent them being deleted or + // renamed. + // + + FLT_ASSERT( Status != STATUS_OBJECT_PATH_NOT_FOUND && + Status != STATUS_OBJECT_NAME_NOT_FOUND ); + + ReturnValue = FLT_PREOP_COMPLETE; + goto NcPreNotifyDirectoryCleanup; + + } + + Status = NcGetFileNameInformation( NULL, + MappingParentFileObject, + FltObjects->Instance, + FLT_FILE_NAME_OPENED | + FLT_FILE_NAME_QUERY_DEFAULT | + FLT_FILE_NAME_REQUEST_FROM_CURRENT_PROVIDER, + &FileInfoInternalHandle ); + if (!NT_SUCCESS( Status )) { + + FltClose( MappingParentHandle ); + ObDereferenceObject( MappingParentFileObject ); + + ReturnValue = FLT_PREOP_COMPLETE; + goto NcPreNotifyDirectoryCleanup; + } + + Status = FltParseFileNameInformation( FileInfoInternalHandle ); + if (!NT_SUCCESS( Status )) { + + FltClose( MappingParentHandle ); + ObDereferenceObject( MappingParentFileObject ); + FltReleaseFileNameInformation( FileInfoInternalHandle ); + + ReturnValue = FLT_PREOP_COMPLETE; + goto NcPreNotifyDirectoryCleanup; + } + + MappingParentName = ExAllocatePoolWithTag( PagedPool, + FileInfoInternalHandle->Name.Length, + NC_TAG ); + + if (MappingParentName == NULL) { + + Status = STATUS_INSUFFICIENT_RESOURCES; + + FltClose( MappingParentHandle ); + ObDereferenceObject( MappingParentFileObject ); + FltReleaseFileNameInformation( FileInfoInternalHandle ); + + ReturnValue = FLT_PREOP_COMPLETE; + goto NcPreNotifyDirectoryCleanup; + } + + MappingParentWorkItem = FltAllocateGenericWorkItem(); + if (MappingParentWorkItem == NULL) { + + Status = STATUS_INSUFFICIENT_RESOURCES; + + FltClose( MappingParentHandle ); + ObDereferenceObject( MappingParentFileObject ); + FltReleaseFileNameInformation( FileInfoInternalHandle ); + ExFreePoolWithTag( MappingParentName, NC_TAG ); + + ReturnValue = FLT_PREOP_COMPLETE; + goto NcPreNotifyDirectoryCleanup; + } + + + NcLockStreamHandleContext( HandleContext ); + UnlockContext = TRUE; + + // + // We could be racing with another thread attempting to open the + // mapping. If, after having reacquired the lock we still see + // no mapping handle, use ours. If another thread beat us to it, + // tear down ours and use theirs. + // + + if (NotCtx->RealParentHandle == NULL && + !NotCtx->CleanupSeen) { + + // + // Store our object into the context. + // + + FLT_ASSERT( NotCtx->RealParentFileObject == NULL && + NotCtx->RealParentCloseWorkItem == NULL && + NotCtx->MappingParentName.Buffer == NULL ); + + NotCtx->RealParentHandle = MappingParentHandle; + NotCtx->RealParentFileObject = MappingParentFileObject; + NotCtx->RealParentCloseWorkItem = MappingParentWorkItem; + + NotCtx->MappingParentName.Buffer = MappingParentName; + NotCtx->MappingParentName.MaximumLength = FileInfoInternalHandle->Name.Length; + + RtlCopyMemory( NotCtx->MappingParentName.Buffer, + FileInfoInternalHandle->Name.Buffer, + FileInfoInternalHandle->Name.Length ); + + NotCtx->MappingParentName.Length = FileInfoInternalHandle->Name.Length; + + NcRemoveTrailingSlashIfPresent( &NotCtx->MappingParentName ); + + FltReleaseFileNameInformation( FileInfoInternalHandle ); + + } else { + + // + // Another thread beat us to the punch, or our services are + // no longer required. Tear down our state and reload from + // theirs. + // + // Really, we can't race here (currently) because: + // + // 1. We do not support multiple outstanding requests on one + // handle (if attempted, we already failed.) + // + // 2. This must be the first request on this handle, or else + // our mapping parent handle already existed. + // + // 3. We have not yet set up cancellation on this request. + // + // The only way to be here is if a cleanup request has + // occurred and we're aborting. + // + + FLT_ASSERT( NotCtx->CleanupSeen ); + + NcUnlockStreamHandleContext( HandleContext ); + UnlockContext = FALSE; + + FltClose( MappingParentHandle ); + ObDereferenceObject( MappingParentFileObject ); + ExFreePoolWithTag( MappingParentName, NC_TAG ); + FltReleaseFileNameInformation( FileInfoInternalHandle ); + FltFreeGenericWorkItem( MappingParentWorkItem ); + + NcLockStreamHandleContext( HandleContext ); + UnlockContext = TRUE; + + // + // Another thread beat us to creating the file object, but + // it was subsequently torn down while we dropped our lock. + // This can happen if the user handle is closed, in which + // case we expect CleanupSeen to be set and we can safely + // leave. Return pending because the cleanup completed our + // request. + // + + if (NotCtx->RealParentHandle == NULL) { + + FLT_ASSERT( NotCtx->CleanupSeen ); + + ReturnValue = FLT_PREOP_PENDING; + goto NcPreNotifyDirectoryCleanup; + } + } + + MappingParentHandle = NULL; + MappingParentFileObject = NULL; + MappingParentName = NULL; + + // + // This relationship may have changed while we dropped the + // lock, but this can't happen in practice today: + // + // 1. We do not support multiple outstanding requests on one + // handle (if attempted, we already failed.) + // + // 2. This must be the first request on this handle, or else + // our mapping parent handle already existed. + // + // 3. We have not yet set up cancellation on this request. + // + // 4. If the user handle were closed, we failed out above. + // + // If these change and we need to revalidate state, we may + // need to clear cancel state, return insufficient buffer, + // or return buffered data here. + // + + FLT_ASSERT( NotCtx->UserRequest == Data ); + + FLT_ASSERT( NotCtx->ShadowRequest == NULL && + NotCtx->MappingRequest == NULL && + !NotCtx->CleanupSeen && + !NotCtx->CancelSeen && + !NotCtx->InsufficientBufferSeen && + NotCtx->BufferToFree == NULL && + NotCtx->BufferLength == 0 ); + + } + + FLT_ASSERT( UnlockContext ); + FLT_ASSERT( NotCtx->RealParentHandle != NULL && + NotCtx->RealParentFileObject != NULL && + NotCtx->RealParentCloseWorkItem != NULL ); + + NotCtx->Mode = Merge; + + // + // Now create our child requests. We need to watch for changes on + // both the user's handle and on the mapping parent handle. While + // this process is ongoing, we're trying to drop/reacquire the lock + // as few times as possible, so we set up both requests at once, + // then issue them together. + // + // If this is the second (or subsequent) time notifications are + // being requested, we may already have subrequests issued to the + // filesystem. In that case, we leave the existing requests in + // place. Any request not already in place we create ourselves + // now. + // + + if (NotCtx->ShadowRequest == NULL) { + + Status = NcBuildSubNotifyRequest( Data, + FltObjects->Instance, + FltObjects->FileObject, + HandleContext, + NotifyShadowRequest, + &NewShadowRequest, + &ShadowRequestContext ); + + if (!NT_SUCCESS( Status )) { + + ReturnValue = FLT_PREOP_COMPLETE; + goto NcPreNotifyDirectoryCleanup; + } + + } + + if (NotCtx->MappingRequest == NULL) { + + Status = NcBuildSubNotifyRequest( Data, + FltObjects->Instance, + NotCtx->RealParentFileObject, + HandleContext, + NotifyMappingRequest, + &NewMappingParentRequest, + &MappingParentRequestContext ); + + if (!NT_SUCCESS( Status )) { + + ReturnValue = FLT_PREOP_COMPLETE; + goto NcPreNotifyDirectoryCleanup; + } + } + + // + // To synchronize this, we set the request in the context under cover + // of the context lock. We then drop the lock to issue the IO. + // The rule here is that IO should only be sent by its creator or its + // completor. + // + + if (NewShadowRequest || NewMappingParentRequest) { + + FLT_ASSERT( UnlockContext ); + + if (NewShadowRequest) { + NotCtx->ShadowRequest = NewShadowRequest; + } + + if (NewMappingParentRequest) { + NotCtx->MappingRequest = NewMappingParentRequest; + } + + // + // Set a cancel routine on the user's request (which we intend on + // hanging on to.) + // + + Status = NcSetCancelCompletion( Data, NcNotifyCancelCallback ); + + if (!NT_SUCCESS( Status )) { + + ReturnValue = FLT_PREOP_COMPLETE; + goto NcPreNotifyDirectoryCleanup; + } + + FLT_ASSERT( HandleContext != NULL ); + NcUnlockStreamHandleContext( HandleContext ); + UnlockContext = FALSE; + + // + // Note that as soon as we drop the lock, the user's request is + // no longer guaranteed to be valid. Any previously outstanding + // IO may complete and take it away from us. + // + + if (NewShadowRequest) { + + Status = FltPerformAsynchronousIo( NotCtx->ShadowRequest, + NcPostNotifyDirectoryReal, + ShadowRequestContext ); + + ShadowRequestContext = NULL; + NewShadowRequest = NULL; + + + // + // If we failed and have a second request, grab the lock + // again to enable our cleanup code to tear it down. + // + + if (!NT_SUCCESS( Status ) && NewMappingParentRequest) { + + NcLockStreamHandleContext( HandleContext ); + UnlockContext = TRUE; + + ReturnValue = FLT_PREOP_PENDING; + goto NcPreNotifyDirectoryCleanup; + + } + } + + if (NewMappingParentRequest) { + + Status = FltPerformAsynchronousIo( NotCtx->MappingRequest, + NcPostNotifyDirectoryReal, + MappingParentRequestContext ); + + MappingParentRequestContext = NULL; + NewMappingParentRequest = NULL; + } + } + + ReturnValue = FLT_PREOP_PENDING; + + } + + FLT_ASSERT( NotCtx->Mode != Uninitialized ); + + FLT_ASSERT( NotCtx->InstanceContext != NULL ); + + +NcPreNotifyDirectoryCleanup: + + if (ReturnValue == FLT_PREOP_COMPLETE) { + + // + // We need to write back results of query. + // + + Data->IoStatus.Status = Status; + + if (NT_SUCCESS( Status )) { + + //success + Data->IoStatus.Information = SizeWeReturn; + + } else { + + //failure + Data->IoStatus.Information = 0; + + } + + // + // Since we're completing the request, remove it from the notify + // context structure. Note that since we're completing it, it + // must still be valid and owned by us, so we're absolutely + // entitled (and required!) to remove it. + // + + if (HandleContext != NULL) { + + if (!UnlockContext) { + NcLockStreamHandleContext( HandleContext ); + UnlockContext = TRUE; + } + + if (NotCtx->UserRequest == Data) { + NotCtx->UserRequest = NULL; + } + } + } + + if (NewShadowRequest) { + + // + // We should only be cleaning this up if we hold the lock. + // + + FLT_ASSERT( UnlockContext ); + + // + // Either this request is still set in the context (and we'll + // take care of that), or it's been cancelled and hence + // removed already. In either case, we still need to tear it + // down. + // + + FLT_ASSERT( NotCtx->ShadowRequest == NULL || + NotCtx->ShadowRequest == NewShadowRequest ); + + NcCleanupSubNotifyRequest( NewShadowRequest ); + NotCtx->ShadowRequest = NewShadowRequest = NULL; + } + + if (NewMappingParentRequest) { + + // + // We should only be cleaning this up if we hold the lock. + // + + FLT_ASSERT( UnlockContext ); + + // + // Either this request is still set in the context (and we'll + // take care of that), or it's been cancelled and hence + // removed already. In either case, we still need to tear it + // down. + // + + FLT_ASSERT( NotCtx->MappingRequest == NULL || + NotCtx->MappingRequest == NewMappingParentRequest ); + + NcCleanupSubNotifyRequest( NewMappingParentRequest ); + NotCtx->MappingRequest = NewMappingParentRequest = NULL; + } + + if (InstanceContext != NULL) { + + FltReleaseContext( InstanceContext ); + } + + if (UnlockContext) { + + FLT_ASSERT( HandleContext != NULL ); + NcUnlockStreamHandleContext( HandleContext ); + } + + // + // Now that we've dropped the lock and can issue IO, tear down any + // request contexts from failed requests. + // + + if (ShadowRequestContext) { + NcFreeNotifyRequestContext( ShadowRequestContext ); + } + + if (MappingParentRequestContext) { + NcFreeNotifyRequestContext( MappingParentRequestContext ); + } + + if (HandleContext != NULL) { + + FltReleaseContext( HandleContext ); + } + + if (FileNameInformation != NULL) { + + FltReleaseFileNameInformation( FileNameInformation ); + } + + return ReturnValue; +} + + +VOID +NcPostNotifyDirectoryReal ( + _Inout_ PFLT_CALLBACK_DATA Data, + _In_ PVOID CompletionContext + ) +/*++ + +Routine Description: + + Routine is invoked after the filesystem has returned a change + notification, or if we are processing a cancellation for an + outstanding change notification. + + This routine is guaranteed to be called <= APC level. It is + still not really safe to issue IO from here, since that may + require us to be at passive level. We also have no guarantees + that TopLevelIrp == NULL at this point (and in many cases, we + wouldn't expect it to be.) Accordingly, this function should + not call back into the filesystem directly itself. + +Arguments: + + Data - Pointer to the request. This could be the user's request, + or it could be a subrequest we created for ourselves. + + CompletionContext - The context for the completion routine for + this operation. We set this to the handle context for + directory change notifications. + +Return Value: + + None. If we are completing a request, any errors will be + associated with that request. + +--*/ +{ + NTSTATUS Status; + + PFILE_NOTIFY_INFORMATION SourceBuffer = NULL; + PFILE_NOTIFY_INFORMATION DestBuffer; + + PNC_INSTANCE_CONTEXT InstanceContext; + PNC_NOTIFY_REQUEST_CONTEXT RequestContext = (PNC_NOTIFY_REQUEST_CONTEXT)CompletionContext; + PNC_STREAM_HANDLE_CONTEXT HandleContext = RequestContext->UserHandleContext; + PNC_DIR_NOT_CONTEXT NotCtx = NULL; + + ULONG SizeActuallyReturned = (ULONG)Data->IoStatus.Information; + ULONG BufferSize; + ULONG InputConsumed; + ULONG SizeWeReturn; + + BOOLEAN UnlockContext = FALSE; + BOOLEAN CompleteUserRequest = TRUE; + BOOLEAN ReissuedRequest = FALSE; + + PAGED_CODE(); + + NotCtx = &HandleContext->DirectoryNotificationContext; + + // + // Before looking at the context, we have to acquire the lock. + // + + NcLockStreamHandleContext( HandleContext ); + UnlockContext = TRUE; + + // + // Perform debug-only sanity checking and set up our state so we + // can quickly tell which kind of request we're dealing with. + // + + FLT_ASSERT( NotCtx->Mode == Filter || NotCtx->Mode == Munge || NotCtx->Mode == Merge ); + FLT_ASSERT( RequestContext->Request == Data ); + + // + // If the user's handle has gone through cleanup, and we're completing + // it, make sure it fails correctly. Make sure we don't propagate any + // success or meaningful information beyond this point. + // + + if (NotCtx->CleanupSeen) { + if (NotCtx->UserRequest == NULL) { + CompleteUserRequest = FALSE; + } else { + Status = STATUS_NOTIFY_CLEANUP; + SizeWeReturn = 0; + } + goto NcPostNotifyDirectoryRealCleanup; + } + + // + // If the user has cancelled their request, make sure any completing + // subrequests are failed with STATUS_CANCELLED. This is primarily to + // ensure that we don't reissue requests post-cancel (which will never + // be cancelled.) + // + + if (NotCtx->CancelSeen) { + + Data->IoStatus.Status = STATUS_CANCELLED; + } + + // + // Flow any failures back to the user's request, if we have one. + // + + if (!NT_SUCCESS( Data->IoStatus.Status ) || + Data->IoStatus.Status == STATUS_NOTIFY_CLEANUP || + Data->IoStatus.Status == STATUS_NOTIFY_ENUM_DIR ) { + + Status = Data->IoStatus.Status; + SizeWeReturn = 0; + + if (NotCtx->UserRequest == NULL) { + + CompleteUserRequest = FALSE; + + if (Data->IoStatus.Status == STATUS_NOTIFY_ENUM_DIR) { + + // + // If the filesystem is trying to tell the app to rescan, + // but we don't have the app's request right now, make a + // note to tell the app that it must rescan as soon as it + // asks us again. + // + + NotCtx->InsufficientBufferSeen = TRUE; + } + } + goto NcPostNotifyDirectoryRealCleanup; + } + + FLT_ASSERT( NotCtx->Mode != Merge || + (NotCtx->RealParentFileObject != NULL && + NotCtx->UserRequestName.Buffer != NULL )); + + FLT_ASSERT( Data == NotCtx->UserRequest || + Data == NotCtx->ShadowRequest || + Data == NotCtx->MappingRequest ); + + InstanceContext = NotCtx->InstanceContext; + + Status = NcGetDestinationNotifyBuffer( Data, &DestBuffer, &BufferSize ); + if (!NT_SUCCESS( Status )) { + + // + // This can fail due no pages/VA to lock the user's buffer, or a + // 'user buffer' that points to kernel space. By the time we get + // here, we expect that our pages are either already locked or we + // do not need to lock them; and we expect that requests we + // generate internally are based on pool and should not require VA + // to map, nor be usermode pointers into kernel space. Really, the + // only time this should fail is if we have no VA to map the user's + // request. + // + // If this assumption is wrong, we need to be smarter about whether + // we want to complete the user's request in this path or not. + // + + FLT_ASSERT( Data == NotCtx->UserRequest ); + goto NcPostNotifyDirectoryRealCleanup; + } + + FLT_ASSERT( SizeActuallyReturned <= BufferSize ); + + // + // If we have a zero-length buffer, the filesystem should not have + // returned STATUS_SUCCESS. We still try to tolerate this + // condition regardless. + // + + FLT_ASSERT( BufferSize > 0 ); + + // + // If the filesystem returned something, go ahead and try to munge it. + // + + if (SizeActuallyReturned > (ULONG)FIELD_OFFSET( FILE_NOTIFY_INFORMATION, FileName )) { + + // + // Allocate a new buffer and copy the contents. Note that this is + // particularly important with this call, since it's not always + // system buffered; the contents are free to change underneath us. + // This allocation protects us against that, but we still must be + // paranoid touching the buffer, since we cannot trust that it has + // any integrity at this point. + // + + SourceBuffer = ExAllocatePoolWithTag( PagedPool, + SizeActuallyReturned, + NC_TAG ); + + if (SourceBuffer == NULL) { + + Status = STATUS_INSUFFICIENT_RESOURCES; + goto NcPostNotifyDirectoryRealCleanup; + } + + try { + + // + // The #pragma is a notation to the static code analyzer that the + // buffer sizes involved have been computed correctly so no buffer + // overrun is possible here. + // +#pragma warning(suppress:6385) + RtlCopyMemory( SourceBuffer, DestBuffer, SizeActuallyReturned ); + + } except (NcExceptionFilter( GetExceptionInformation(), TRUE )) { + + Status = STATUS_INVALID_USER_BUFFER; + goto NcPostNotifyDirectoryRealCleanup; + } + + // + // Now that we have a copy of the filesystem data, we need to + // transform it and return it to the user. So now we point our + // destination buffers at the original request if we own it, if it + // wasn't already. + // + // When merging from the mapping and non-mapping paths, we may have + // completed the user's request from one path and then receive + // notification on the second. In this case, we buffer the + // notification so the caller can receieve it again next call. We + // do not expect to need more than one buffer. If this overflows, + // just tell the caller their buffer was too small. + // + + if (RequestContext->RequestType == NotifyShadowRequest || + RequestContext->RequestType == NotifyMappingRequest) { + + if (NotCtx->UserRequest != NULL) { + + Status = NcGetDestinationNotifyBuffer( NotCtx->UserRequest, + &DestBuffer, + &BufferSize ); + + if (!NT_SUCCESS( Status )) { + goto NcPostNotifyDirectoryRealCleanup; + } + + } else { + + FLT_ASSERT( NotCtx->Mode == Merge ); + + // + // We have at most two outstanding child requests, and if + // one completes we'll complete the master request, + // buffering with the second. We therefore only need one + // buffer - most of the time. + // + // There is a case where one buffer is insufficient: if the + // user issues a cancel while both child requests are + // completing, we may have a cancelled user request and two + // incoming pieces of data. In this case, it's safe to + // throw one away since the act of cancelling implies the + // user doesn't expect to see everything. However in that + // case we should have failed out above, and should never + // get here. + // + + FLT_ASSERT( NotCtx->BufferToFree == NULL ); + if (NotCtx->BufferToFree != NULL) { + + ExFreePoolWithTag( NotCtx->BufferToFree, NC_TAG ); + NotCtx->BufferToFree = NULL; + NotCtx->BufferLength = 0; + } + + // + // There is no user request, don't complete it. + // + + CompleteUserRequest = FALSE; + + if (BufferSize > 0) { + + // + // Save away the output to our buffer. Note that we + // process the data now because we won't know which call + // generated the data later. + // + + NotCtx->BufferToFree = ExAllocatePoolWithTag( PagedPool, + BufferSize, + NC_TAG ); + + if (NotCtx->BufferToFree == NULL) { + + Status = STATUS_INSUFFICIENT_RESOURCES; + goto NcPostNotifyDirectoryRealCleanup; + } + + } + + DestBuffer = NotCtx->BufferToFree; + FLT_ASSERT( NotCtx->BufferLength == 0 ); + } + } + + // + // If we have a zero length buffer, return to the user that something + // changed and do not attempt to return anything more. + // + + if (BufferSize > 0) { + + Status = NcDirNotifyTranslateBuffers( InstanceContext, + NotCtx->IgnoreCase, + &NotCtx->UserRequestName, + (RequestContext->RequestType == NotifyMappingRequest)? + &NotCtx->MappingParentName: + &NotCtx->UserRequestName, + SourceBuffer, + DestBuffer, + SizeActuallyReturned, + BufferSize, + &InputConsumed, + &SizeWeReturn, + (BOOLEAN)(NotCtx->Mode == Munge || NotCtx->Mode == Merge), + (BOOLEAN)(RequestContext->RequestType == NotifyMappingRequest) ); + + } else { + + FLT_ASSERT( NT_SUCCESS( Status )); + } + + + if (!NT_SUCCESS( Status )) { + + // + // If we failed, don't leave the garbage buffer to be picked + // up again. Tear it down now. + // + + if (DestBuffer == NotCtx->BufferToFree) { + ExFreePoolWithTag( NotCtx->BufferToFree, NC_TAG ); + NotCtx->BufferToFree = NULL; + NotCtx->BufferLength = 0; + } + goto NcPostNotifyDirectoryRealCleanup; + } + + // + // We couldn't fit the translated information into the caller's + // buffer. For directory change notifications, there is a special + // status to use in this situation, which tells the caller to + // rescan from scratch. It's a heavy hammer, but might teach the + // caller to use a bigger buffer. + // + // Unfortunately this is lost in translation between NT & Win32, + // so most applications end up guessing. + // + + if ((BufferSize == 0) || + (InputConsumed < SizeActuallyReturned)) { + + if (!CompleteUserRequest) { + + ExFreePoolWithTag( NotCtx->BufferToFree, NC_TAG ); + NotCtx->BufferToFree = NULL; + NotCtx->BufferLength = 0; + NotCtx->InsufficientBufferSeen = TRUE; + } + + SizeWeReturn = 0; + Status = STATUS_NOTIFY_ENUM_DIR; + goto NcPostNotifyDirectoryRealCleanup; + + } else { + + Status = STATUS_SUCCESS; + + if (DestBuffer == NotCtx->BufferToFree) { + NotCtx->BufferLength = SizeWeReturn; + } + } + + // + // Our worst nightmare has come true. The filesystem completed the + // request but we filtered out all the contents. We certainly + // don't want to tell the caller nothing whatsoever happened, so we + // try to reissue this request. + // + + if (SizeWeReturn == 0) { + + PMDL OldMdl = Data->Iopb->Parameters.DirectoryControl.NotifyDirectory.MdlAddress; + PFLT_GENERIC_WORKITEM WorkItem; + + FLT_ASSERT( (NotCtx->Mode == Filter || NotCtx->Mode == Merge ) && + (RequestContext->RequestType == NotifyShadowRequest || RequestContext->RequestType == NotifyMappingRequest ) ); + + if (DestBuffer == NotCtx->BufferToFree) { + + ExFreePoolWithTag( NotCtx->BufferToFree, NC_TAG ); + NotCtx->BufferToFree = NULL; + NotCtx->BufferLength = 0; + } + + Status = NcGetDestinationNotifyBuffer( Data, + &DestBuffer, + &BufferSize ); + if (!NT_SUCCESS( Status )) { + goto NcPostNotifyDirectoryRealCleanup; + } + + WorkItem = FltAllocateGenericWorkItem(); + if (WorkItem == NULL) { + Status = STATUS_INSUFFICIENT_RESOURCES; + goto NcPostNotifyDirectoryRealCleanup; + } + + FLT_ASSERT( RequestContext->Request == Data ); + + // + // Clear and reinitialize the request using the Mdl and buffer + // that it was previously using. Note that we know it will be + // system buffered if it has a buffer, because the only + // requests that can get here are requests we created. + // + + FltReuseCallbackData( Data ); + + Data->Iopb->MajorFunction = IRP_MJ_DIRECTORY_CONTROL; + Data->Iopb->MinorFunction = IRP_MN_NOTIFY_CHANGE_DIRECTORY; + Data->Iopb->OperationFlags = NotCtx->OperationFlags; + Data->Iopb->Parameters.DirectoryControl.NotifyDirectory.Length = + BufferSize; + Data->Iopb->Parameters.DirectoryControl.NotifyDirectory.DirectoryBuffer = + DestBuffer; + Data->Iopb->Parameters.DirectoryControl.NotifyDirectory.CompletionFilter = + NotCtx->CompletionFilter; + Data->Iopb->Parameters.DirectoryControl.NotifyDirectory.Spare1 = 0; + Data->Iopb->Parameters.DirectoryControl.NotifyDirectory.Spare2 = 0; + Data->Iopb->Parameters.DirectoryControl.NotifyDirectory.MdlAddress = + OldMdl; + + if (BufferSize > 0) { + + Data->Flags |= FLTFL_CALLBACK_DATA_SYSTEM_BUFFER; + } + + // + // Post issuing new IO to passive level, where we are sure TopLevelIrp + // is actually NULL. + // + + Status = FltQueueGenericWorkItem( WorkItem, + NcGlobalData.FilterHandle, + NcReissueNotifyRequestWorkerRoutine, + DelayedWorkQueue, + RequestContext ); + + if (NT_SUCCESS( Status )) { + ReissuedRequest = TRUE; + CompleteUserRequest = FALSE; + } else { + goto NcPostNotifyDirectoryRealCleanup; + } + + } + + // + // If we successfully parsed and returned data either to the user's + // call or saved it to our buffer, we will not reissue the + // associated call. If the user calls us again, we'll repeat any + // completed call(s). Doing this allows the filter to delegate + // buffering of operations to the filesystem, except for the above + // case (both sides of a merge complete in parallel before the user + // calls again.) + // + + + } else { + + // + // If the filesystem returned something less than one single + // entry, return nothing. + // + + SizeWeReturn = 0; + if (NotCtx->UserRequest == NULL) { + CompleteUserRequest = FALSE; + } + } + +NcPostNotifyDirectoryRealCleanup: + + FLT_ASSERT( CompleteUserRequest || RequestContext->RequestType != NotifyUserRequest ); + + // + // We've just processed something from one of the child Irps. + // Tear it down, NULL it out. We'll rebuild it if we're asked + // for another change notification. + // + + if (!ReissuedRequest) { + + if (RequestContext->RequestType == NotifyShadowRequest || + RequestContext->RequestType == NotifyMappingRequest ) { + + if (Data == NotCtx->ShadowRequest) { + NotCtx->ShadowRequest = NULL; + } + + if (Data == NotCtx->MappingRequest) { + NotCtx->MappingRequest = NULL; + } + + // + // This routine will free the FLT_CALLBACK_DATA. + // + + NcCleanupSubNotifyRequest( Data ); + } + } + + // + // We need to write back results of query. + // + + if (CompleteUserRequest) { + + FLT_ASSERT( UnlockContext ); + + FLT_ASSERT( NotCtx->UserRequest != NULL ); + FLT_ASSERT( RequestContext->RequestType != NotifyUserRequest || + Data == NotCtx->UserRequest ); + + NotCtx->UserRequest->IoStatus.Status = Status; + + if (NT_SUCCESS( Status )) { + + //success + NotCtx->UserRequest->IoStatus.Information = SizeWeReturn; + + } else { + + //failure + NotCtx->UserRequest->IoStatus.Information = 0; + } + + if (RequestContext->RequestType != NotifyUserRequest) { + + PFLT_CALLBACK_DATA RequestToComplete = NotCtx->UserRequest; + NTSTATUS CancelStatus; + + // + // Clear the cancel routine. If cancel has already been + // invoked, don't complete now (leave the cancel routine to + // complete the request, and give the user nothing.) If + // cancel has not yet been invoked, after we clear the + // routine it cannot be invoked, so we are free to complete + // the request ourselves unconditionally. + // + + CancelStatus = FltClearCancelCompletion( RequestToComplete ); + + if (CancelStatus != STATUS_CANCELLED) { + + NotCtx->UserRequest = NULL; + + NcUnlockStreamHandleContext( HandleContext ); + UnlockContext = FALSE; + + FltCompletePendedPreOperation( RequestToComplete, + FLT_PREOP_COMPLETE, + NULL ); + } + + } else { + + NotCtx->UserRequest = NULL; + } + } + + if (SourceBuffer != NULL) { + + ExFreePoolWithTag( SourceBuffer, NC_TAG ); + } + + if (UnlockContext) { + + FLT_ASSERT( HandleContext != NULL ); + NcUnlockStreamHandleContext( HandleContext ); + } + + // + // Now that we've dropped the lock, drop our references. + // + + if (!ReissuedRequest) { + NcFreeNotifyRequestContext( RequestContext ); + } + +} + +FLT_POSTOP_CALLBACK_STATUS +NcPostNotifyDirectorySafe ( + _Inout_ PFLT_CALLBACK_DATA Data, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _In_ PVOID CompletionContext, + _In_ FLT_POST_OPERATION_FLAGS Flags + ) +/*++ + +Routine Description: + + Routine is invoked when a directory change notification request + completes. The request must be the user's request. This + function is called when <= APC_LEVEL. + +Arguments: + + Data - Pointer to the filter CallbackData that is passed to us. + + FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing + opaque handles to this filter, instance, its associated volume and + file object. + + CompletionContext - The context for the completion routine for this + operation. For directory change notifications, this is a pointer + to our handle context. + + Flags - Flags for this operation. + +Return Value: + + The return value is the Status of the operation. + +--*/ +{ + + PAGED_CODE(); + + NcPostNotifyDirectoryReal( Data, CompletionContext ); + + UNREFERENCED_PARAMETER( Flags ); + UNREFERENCED_PARAMETER( FltObjects ); + + return FLT_POSTOP_FINISHED_PROCESSING; +} + + +FLT_POSTOP_CALLBACK_STATUS +NcPostNotifyDirectory ( + _Inout_ PFLT_CALLBACK_DATA Data, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _In_ PVOID CompletionContext, + _In_ FLT_POST_OPERATION_FLAGS Flags + ) +/*++ + +Routine Description: + + Routine is invoked when a directory change notification request + completes. The request must be the user's request. This routine + may be called at DISPATCH_LEVEL and must be nonpaged. + +Arguments: + + Data - Pointer to the filter CallbackData that is passed to us. + + FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing + opaque handles to this filter, instance, its associated volume and + file object. + + CompletionContext - The context for the completion routine for this + operation. For directory change notifications, this is a pointer + to our handle context. + + Flags - Flags for this operation. + +Return Value: + + The return value is the Status of the operation. + +--*/ +{ + + FLT_POSTOP_CALLBACK_STATUS Status; + BOOLEAN Success; + + if (FlagOn( Flags, FLTFL_POST_OPERATION_DRAINING )) { + + // + // We can only be here on a user initiated operation that we sent + // to the filesystem. + // + // TODO: Really what we want to do here is return + // STATUS_NOTIFY_ENUM_DIR to the caller, but we no longer own the + // request. Should we bite the bullet and shadow all munge requests + // so that this can work? + // + + NcFreeNotifyRequestContext( CompletionContext ); + + Status = FLT_POSTOP_FINISHED_PROCESSING; + + } else { + + // + // For simplicity, and to avoid needing everything to be nonpaged, + // we perform completion at APC_LEVEL or below. + // + + Success = FltDoCompletionProcessingWhenSafe( Data, + FltObjects, + CompletionContext, + Flags, + NcPostNotifyDirectorySafe, + &Status ); + + if (!Success) { + + // + // It would be nice to know _why_ this fails, but since we + // don't, neither will anybody else. + // + + Data->IoStatus.Status = STATUS_UNSUCCESSFUL; + Data->IoStatus.Information = 0; + Status = FLT_POSTOP_FINISHED_PROCESSING; + } + } + + return Status; +} + +VOID +NcReissueNotifyRequestWorkerRoutine ( + _In_ PFLT_GENERIC_WORKITEM WorkItem, + _In_ PFLT_FILTER Filter, + _In_ PVOID RequestPtr + ) +/*++ + +Routine Description: + + This function reissues an subrequest that is part of an + oustanding directory change notification request. If it is + unable to reissue the request, this function is responsible + for all cleanup of the request. + +Arguments: + + WorkItem - Pointer to the workitem which triggered the call to this + function. + + Filter - Pointer to our filter object. + + RequestPtr - Our context, specifically the request we wish to reissue. + +Return Value: + + None. + +--*/ +{ + PNC_NOTIFY_REQUEST_CONTEXT RequestContext = (PNC_NOTIFY_REQUEST_CONTEXT)RequestPtr; + + PAGED_CODE(); + + UNREFERENCED_PARAMETER( Filter ); + + FLT_ASSERT( IoGetTopLevelIrp() == NULL ); + + FLT_ASSERT( RequestContext->RequestType == NotifyShadowRequest || + RequestContext->RequestType == NotifyMappingRequest ); + + // + // Since we're being called asynchronously, it's possible + // that this request has already been cancelled, or that + // cleanup has already occurred. In the event of a cancel, + // this request should be marked as canceled and the + // filesystem will complete it immediately. In the event + // of cleanup, we are sending the request to a cleaned up + // handle and the filesystem will complete it immediately. + // + // On failure, Fltmgr will call our completion routine, + // so we don't need to clean up here. + // + + (VOID) FltPerformAsynchronousIo( RequestContext->Request, + NcPostNotifyDirectoryReal, + RequestContext ); + + FltFreeGenericWorkItem( WorkItem ); +} + +VOID +NcCloseHandleWorkerRoutine ( + _In_ PFLT_GENERIC_WORKITEM WorkItem, + _In_ PFLT_FILTER Filter, + _In_ PVOID HandlePtr + ) +/*++ + +Routine Description: + + This function performs a handle close operation. Since handle + close operations must occur at passive, we queue a workitem to + close the handle when we cannot do so inline. This function + actually performs the close. + +Arguments: + + WorkItem - Pointer to the workitem which triggered the call to this + function. + + Filter - Pointer to our filter object. + + HandlePtr - Our context, specifically the handle we wish to close. + +Return Value: + + None. + +--*/ +{ + HANDLE Handle = (HANDLE)HandlePtr; + NTSTATUS DummyStatus; + + PAGED_CODE(); + + UNREFERENCED_PARAMETER( Filter ); + + DummyStatus = FltClose( Handle ); + FLT_ASSERT( NT_SUCCESS( DummyStatus )); + + FltFreeGenericWorkItem( WorkItem ); +} + +_Pre_satisfies_(*LockHeld) +_Requires_lock_held_(_Global_critical_region_) +_Requires_lock_held_(*HandleContext->Lock) +_When_(*LockHeld == FALSE, _Releases_lock_(_Global_critical_region_)) +_When_(*LockHeld == FALSE, _Releases_lock_(*HandleContext->Lock)) +VOID +NcNotifyAbort ( + _In_ PNC_STREAM_HANDLE_CONTEXT HandleContext, + _In_ NTSTATUS Status, + _Inout_ PBOOLEAN LockHeld + ) +/*++ + +Routine Description: + + This function aborts a change notify operation. It is shared code + called from both cancel and handle cleanup. It assumes that it is + called with the context lock already held, and may drop the lock + if it needs to complete or cancel requests. + +Arguments: + + HandleContext - The context describing the request we wish to abort. + + Status - Status code to abort with. This should be STATUS_CANCELLED + for cancel requests or STATUS_NOTIFY_CLEANUP for cleanup requests. + + LockHeld - Pointer to a boolean value. On input, this should contain + a value indicating whether the handle context lock is acquired + (and it should be.) On output, this will be set to TRUE if the + lock is acquired or FALSE if not. + +Return Value: + + None. + +--*/ +{ + PNC_DIR_NOT_CONTEXT NotCtx = &HandleContext->DirectoryNotificationContext; + + FLT_ASSERT( *LockHeld ); + + PAGED_CODE(); + + // + // If we are hanging on to the user's request, complete it now. The status + // code for this is very specific. Note that in the Munge case the request + // is owned by the filesystem, so we leave the filesystem to deal with this + // when it gets the cleanup request. + // + // Cancel any outstanding requests we have issued (if any.) + // + + if ((NotCtx->Mode == Filter) || + (NotCtx->Mode == Merge)) { + + PFLT_CALLBACK_DATA RequestToComplete = NotCtx->UserRequest; + PFLT_CALLBACK_DATA RequestToCancel1 = NotCtx->ShadowRequest; + PFLT_CALLBACK_DATA RequestToCancel2 = NotCtx->MappingRequest; + HANDLE HandleToClose = NotCtx->RealParentHandle; + PFILE_OBJECT FileObjectToDereference = NotCtx->RealParentFileObject; + PFLT_GENERIC_WORKITEM WorkItem = NotCtx->RealParentCloseWorkItem; + + NotCtx->ShadowRequest = NULL; + NotCtx->MappingRequest = NULL; + NotCtx->RealParentHandle = NULL; + NotCtx->RealParentFileObject = NULL; + NotCtx->RealParentCloseWorkItem = NULL; + + // + // Attempt to clear the cancel callback on the user's request. If + // this fails, it may indicate that we are cancelling the irp ourselves, + // or may indicate that we're in cleanup and racing with a cancel. + // When racing with cancel, cancel always wins. + // + + if (RequestToComplete) { + NTSTATUS CancelStatus; + + CancelStatus = FltClearCancelCompletion( RequestToComplete ); + + if (CancelStatus == STATUS_CANCELLED && Status != STATUS_CANCELLED) { + RequestToComplete = NULL; + } else { + NotCtx->UserRequest = NULL; + } + } + + NcUnlockStreamHandleContext( HandleContext ); + *LockHeld = FALSE; + + if (RequestToComplete) { + RequestToComplete->IoStatus.Status = Status; + RequestToComplete->IoStatus.Information = 0; + + FltCompletePendedPreOperation( RequestToComplete, FLT_PREOP_COMPLETE, NULL ); + } + + + // + // Cancel any outstanding IOs, ignoring status. + // + // It is possible that we can't cancel because: + // + // 1. The request hasn't reached the filesystem so there's no cancel + // routine. This is not a problem, since the below call will + // mark the request as cancelled so it will complete immediately. + // + // 2. The request is already being completed. It's no big deal if + // we let it complete, just so long as it finishes soon. Note + // that we've already set CleanupSeen/CancelSeen by this point, + // so unless we're cancelling and get a new user request, the + // outcome will be the same as if our cancel succeeded. + // + + if (RequestToCancel1) { + + (VOID)FltCancelIo( RequestToCancel1 ); + } + + if (RequestToCancel2) { + + (VOID)FltCancelIo( RequestToCancel2 ); + } + + if (HandleToClose) { + + NTSTATUS WorkItemStatus; + + FLT_ASSERT( WorkItem != NULL ); + + WorkItemStatus = FltQueueGenericWorkItem( WorkItem, + NcGlobalData.FilterHandle, + NcCloseHandleWorkerRoutine, + DelayedWorkQueue, + HandleToClose ); + + // + // Queuing the work item will fail if the filter is unloading. All + // we're doing is a handle close, which will get taken care of when + // the process we're in eventually goes away. However we've still + // got an allocated work item to take care of. + // + + if (!NT_SUCCESS( WorkItemStatus )) { + + FltFreeGenericWorkItem( WorkItem ); + } + } + + if (FileObjectToDereference) { + ObDereferenceObject( FileObjectToDereference ); + } + } +} + +VOID +NcNotifyCancelCallback( + _In_ PFLT_CALLBACK_DATA Data + ) +/*++ + +Routine Description: + + This function is called to cancel a change notify operation. + +Arguments: + + Data - The request to cancel. This should be caller-initiated (or we + shouldn't have set a cancel routine on it.) + +Return Value: + + None. + +--*/ +{ + PNC_STREAM_HANDLE_CONTEXT HandleContext; + PNC_DIR_NOT_CONTEXT NotCtx; + NTSTATUS Status; + BOOLEAN UnlockContext; + + PAGED_CODE(); + + // + // Try to figure out the context associated with this request. + // It would be really nice if we had a FltObjects structure for + // this. Are filters really supposed to do this? + // + + Status = FltGetStreamHandleContext( Data->Iopb->TargetInstance, + Data->Iopb->TargetFileObject, + &HandleContext ); + + FLT_ASSERT( NT_SUCCESS( Status )); + if (!NT_SUCCESS( Status )) { + return; + } + + FLT_ASSERT( HandleContext != NULL ); + + NotCtx = &HandleContext->DirectoryNotificationContext; + + // + // Before looking at the context, we have to acquire the lock. + // + + NcLockStreamHandleContext( HandleContext ); + UnlockContext = TRUE; + + // + // We should only ever be called on the user's request. + // It follows that this is a Merge or Filter operation. + // + + FLT_ASSERT( Data == NotCtx->UserRequest ); + FLT_ASSERT( NotCtx->Mode == Filter || NotCtx->Mode == Merge ); + + // + // Indicate to completing requests that we are cancelling. + // While we are cancelling, if child requests are racing + // with us and completing legitimately, we force them to + // drain out. This flag will be cleared next time the + // user asks for a change notification on this handle. + // + + NotCtx->CancelSeen = TRUE; + + // + // If the user is cancelling, it follows that they cannot + // expect a complete picture of data. Tear down any held + // over buffer that we may happen to have, since it may be + // large and we're not optimizing for recurring work after + // cancel. + // + // We cannot tear down any file names at this point, since + // we're racing with IO completion which may depend on + // those names remaining intact. + // + + if (NotCtx->BufferToFree != NULL) { + + ExFreePoolWithTag( NotCtx->BufferToFree, NC_TAG ); + NotCtx->BufferToFree = NULL; + NotCtx->BufferLength = 0; + } + + // + // This call may drop our locks. If it does, we are no + // longer synchronized against incoming requests and + // must not tear anything down any further. + // + + NcNotifyAbort( HandleContext, STATUS_CANCELLED, &UnlockContext ); + + if (UnlockContext) { + NcUnlockStreamHandleContext( HandleContext ); + UnlockContext = FALSE; + } + + FltReleaseContext( HandleContext ); +} + +NTSTATUS +NcStreamHandleContextNotCreate( + _Out_ PNC_DIR_NOT_CONTEXT Context + ) +/*++ + +Routine Description: + + This function is called to initialize the directory change notification + portion of a stream handle context. + +Arguments: + + Context - Pointer to the directory change notification portion of the + stream handle context. + +Return Value: + + Returns the status of the operation (currently only STATUS_SUCCESS.) + +--*/ +{ + NTSTATUS Status = STATUS_SUCCESS; + + PAGED_CODE(); + + Context->Mode = Uninitialized; + Context->CleanupSeen = FALSE; + Context->InsufficientBufferSeen = FALSE; + Context->UserRequestName.Buffer = NULL; + Context->UserRequestName.Length = Context->UserRequestName.MaximumLength = 0; + + Context->MappingParentName.Buffer = NULL; + Context->MappingParentName.Length = Context->MappingParentName.MaximumLength = 0; + + Context->UserRequest = NULL; + Context->ShadowRequest = NULL; + Context->MappingRequest = NULL; + + Context->InstanceContext = NULL; + Context->RealParentHandle = NULL; + Context->RealParentFileObject = NULL; + + Context->BufferToFree = NULL; + Context->BufferLength = 0; + + return Status; +} + +VOID +NcStreamHandleContextNotCleanup( + _In_ PNC_STREAM_HANDLE_CONTEXT HandleContext + ) +/*++ + +Routine Description: + + This function is called to process IRP_MJ_CLEANUP for a directory change + notification request. Directory change notifications are cancelled + with a special status code at handle cleanup time. We take this + opportunity to tear down anything we reasonably can, since a file may + be in limbo between cleanup and close for a long time. + +Arguments: + + HandleContext - Pointer to the stream handle context. + +Return Value: + + None. + +--*/ +{ + PNC_DIR_NOT_CONTEXT NotCtx = &HandleContext->DirectoryNotificationContext; + BOOLEAN UnlockContext; + + PAGED_CODE(); + + NcLockStreamHandleContext( HandleContext ); + UnlockContext = TRUE; + + // + // Set a flag to indicate that outstanding requests should complete immediately + // without propagating status to the user or buffering results. This also + // prevents new work starting after this point. + // + + FLT_ASSERT( !NotCtx->CleanupSeen ); + NotCtx->CleanupSeen = TRUE; + + // + // Complete our requests. Note that this routine may drop our lock. + // + + NcNotifyAbort( HandleContext, STATUS_NOTIFY_CLEANUP, &UnlockContext ); + + // + // Lock the structure again if necessary after performing any IO so we can + // continue teardown. Note that the user's request should not come back + // at this point in the case of cleanup. + // + + if (!UnlockContext) { + NcLockStreamHandleContext( HandleContext ); + UnlockContext = TRUE; + } + + // + // Once a handle is closed, it should stay closed. + // + + FLT_ASSERT( NotCtx->CleanupSeen ); + + FLT_ASSERT( NotCtx->UserRequest == NULL || + NotCtx->Mode == Munge); + + // + // Although requests may remain, if we've been through cleanup our post + // routine will ensure they can't do squat. + // + + if (NotCtx->UserRequestName.Buffer != NULL) { + NcFreeUnicodeString( &NotCtx->UserRequestName ); + } + + if (NotCtx->MappingParentName.Buffer != NULL) { + NcFreeUnicodeString( &NotCtx->MappingParentName ); + } + + if (NotCtx->BufferToFree != NULL) { + + ExFreePoolWithTag( NotCtx->BufferToFree, NC_TAG ); + NotCtx->BufferToFree = NULL; + NotCtx->BufferLength = 0; + } + + if (NotCtx->InstanceContext != NULL) { + FltReleaseContext( NotCtx->InstanceContext ); + NotCtx->InstanceContext = NULL; + } + + NotCtx->Mode = Uninitialized; + + NcUnlockStreamHandleContext( HandleContext ); + UnlockContext = FALSE; +} + +VOID +NcStreamHandleContextNotClose( + _In_ PNC_DIR_NOT_CONTEXT Context + ) +/*++ + +Routine Description: + + This function is called to tear down the directory change notification + portion of a stream handle context. + +Arguments: + + Context - Pointer to the directory change notification portion of the + stream handle context. + +Return Value: + + None. + +--*/ +{ + + PAGED_CODE(); + + // + // TODO: Determine when/how this is called. What IRQL are we really at + // here? Are we top level? What should we do if we're not? + // + FLT_ASSERT( IoGetTopLevelIrp() == NULL ); + FLT_ASSERT( !KeAreAllApcsDisabled() ); + + + // + // We need to be protected against any new work arriving on this handle. + // Typically we expect cleanup to have already been seen by this point, + // which will have torn down most state for this handle. This is not + // necessarily true when the filter is being detached. Since we can't + // tear down a context with active references, we expect that mapping/ + // shadow requests are currently NULL, and should not come back - either + // because CleanupSeen is set, or FltMgr is draining us. + // + + FLT_ASSERT( Context->MappingRequest == NULL && + Context->ShadowRequest == NULL ); + + // + // Firstly, close the handles. These can recurse back into the + // filesystem and generate notifications themselves, or cancel + // outstanding notifications, etc. Note that we do not hold the lock + // around this operation. + // + + if (Context->RealParentHandle != NULL) { + + FltClose( Context->RealParentHandle ); + + } + + // + // In theory, we should no longer have outstanding notifications at + // this point. The user has closed their handle (completing any + // shadow request) and we have closed ours (completing any mapping + // request.) Now we are safe to teardown, and we don't require a + // lock to do so. + // + + if (Context->RealParentFileObject != NULL) { + + ObDereferenceObject( Context->RealParentFileObject ); + } + + Context->RealParentFileObject = NULL; + Context->RealParentHandle = NULL; + + if (Context->RealParentCloseWorkItem != NULL) { + FltFreeGenericWorkItem( Context->RealParentCloseWorkItem ); + Context->RealParentCloseWorkItem = NULL; + } + + if (Context->UserRequestName.Buffer != NULL) { + NcFreeUnicodeString( &Context->UserRequestName ); + } + + if (Context->MappingParentName.Buffer != NULL) { + NcFreeUnicodeString( &Context->MappingParentName ); + } + + if (Context->BufferToFree != NULL) { + + ExFreePoolWithTag( Context->BufferToFree, NC_TAG ); + Context->BufferToFree = NULL; + Context->BufferLength = 0; + } + + Context->Mode = Uninitialized; + + if (Context->InstanceContext != NULL) { + FltReleaseContext( Context->InstanceContext ); + Context->InstanceContext = NULL; + } +} + + + diff --git a/filesys/miniFilter/NameChanger/ncfileinfo.c b/filesys/miniFilter/NameChanger/ncfileinfo.c new file mode 100644 index 00000000..ea5708e6 --- /dev/null +++ b/filesys/miniFilter/NameChanger/ncfileinfo.c @@ -0,0 +1,1971 @@ +/*++ + +Copyright (c) 2008 - 2009 Microsoft Corporation + +Module Name: + + ncfileinfo.c + +Abstract: + + Contains routines to process user-initiated query file and set file + information requests. + +Environment: + + Kernel mode + +--*/ + +#include "nc.h" + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE, NcPreQueryAlternateName) +#pragma alloc_text(PAGE, NcPostQueryHardLinks) +#pragma alloc_text(PAGE, NcPostQueryName) +#pragma alloc_text(PAGE, NcPreSetDisposition) +#pragma alloc_text(PAGE, NcPreSetLinkInformation) +#pragma alloc_text(PAGE, NcPreSetShortName) +#pragma alloc_text(PAGE, NcPreRename) +#endif + +FLT_POSTOP_CALLBACK_STATUS +NcPostQueryName ( + _Inout_ PFLT_CALLBACK_DATA Data, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _In_opt_ PVOID CompletionContext, + _In_ FLT_POST_OPERATION_FLAGS Flags + ) +/*++ + +Routine Description: + + This routine is called when the user wants to request a name for a + previously opened handle. Since we munged the name to be to the real + mapping in pre-create, we must munge it back to the user visible view + in response to name requests, even by opened name. + + Note that this function processes three information classes: + + FileNameInformation + FileNormalizedNameInformation + FileAllInformation + +Arguments: + + Data - Pointer to the filter CallbackData that is passed to us. + + FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure + containing opaque handles to this filter, instance, its + associated volume and file object. + + CompletionContext - The context for the completion routine for + this operation. We set this to the handle context for + directory change notifications. + +Return Value: + + The return value is the Status of the operation. + +--*/ +{ + NTSTATUS Status = STATUS_SUCCESS; + NC_PATH_OVERLAP Overlap; + PNC_INSTANCE_CONTEXT InstanceContext = NULL; + FILE_INFORMATION_CLASS InfoClass = Data->Iopb->Parameters.QueryFileInformation.FileInformationClass; + PVOID UserBuffer = Data->Iopb->Parameters.QueryFileInformation.InfoBuffer; + ULONG UserBufferLength = Data->Iopb->Parameters.QueryFileInformation.Length; + ULONG SizeActuallyReturned = (ULONG)Data->IoStatus.Information; + ULONG LengthNeeded = 0; + ULONG UserStructureSize = 0; + ULONG RequiredNameSize = 0; + ULONG NameLengthAvailable = 0; + PFILE_NAME_INFORMATION NameInfo; + BOOLEAN IgnoreCase = !BooleanFlagOn( FltObjects->FileObject->Flags, + FO_OPENED_CASE_SENSITIVE ); + UNICODE_STRING Remainder; + UNICODE_STRING RemainderCopy = EMPTY_UNICODE_STRING; + UNICODE_STRING ReturnedName; + + UNREFERENCED_PARAMETER( CompletionContext ); + UNREFERENCED_PARAMETER( Flags ); + + PAGED_CODE(); + + FLT_ASSERT( IoGetTopLevelIrp() == NULL ); + + // + // If the operation failed already, we have no processing to do unless the + // failure is a buffer overflow. + // + + if (!NT_SUCCESS( Data->IoStatus.Status ) && + (Data->IoStatus.Status != STATUS_BUFFER_OVERFLOW)) { + + Status = Data->IoStatus.Status; + goto NcPostQueryNameInformationCleanup; + } + + // + // Get our instance context. + // + + Status = FltGetInstanceContext( FltObjects->Instance, + &InstanceContext); + + if (!NT_SUCCESS( Status )) { + + goto NcPostQueryNameInformationCleanup; + } + + // + // Find the name in the user buffer. + // + + if (InfoClass == FileAllInformation) { + + NameInfo = & ((PFILE_ALL_INFORMATION) UserBuffer)->NameInformation; + + } else { + + FLT_ASSERT( InfoClass == FileNameInformation || + InfoClass == FileNormalizedNameInformation ); + + NameInfo = UserBuffer; + } + + // + // If the name is too long for a UNICODE_STRING, we can't process it. + // This should never really happen, since UNICODE_STRINGs are used + // all across the NT IO model. + // + + if (NameInfo->FileNameLength >= MAXUSHORT) { + + Status = STATUS_OBJECT_PATH_INVALID; + goto NcPostQueryNameInformationCleanup; + } + + // + // Now that we have an instance context and NameInfo buffer, see if the file + // system failed with a buffer overflow. + // + + if (Data->IoStatus.Status == STATUS_BUFFER_OVERFLOW) { + + // + // We need to bias the FileNameLength field by the difference between + // the real and user mapping lengths if the user mapping is longer. This + // is so that if the caller re-issues the name query we won't fail with + // a buffer overflow in the filter even if the file system succeeded. + // + + if (InstanceContext->Mapping.UserMapping.LongNamePath.VolumelessName.Length > + InstanceContext->Mapping.RealMapping.LongNamePath.VolumelessName.Length) { + + NameInfo->FileNameLength += InstanceContext->Mapping.UserMapping.LongNamePath.VolumelessName.Length - + InstanceContext->Mapping.RealMapping.LongNamePath.VolumelessName.Length; + } + + Status = Data->IoStatus.Status; + LengthNeeded = SizeActuallyReturned; + + goto NcPostQueryNameInformationCleanup; + } + + ReturnedName.Buffer = NameInfo->FileName; + ReturnedName.MaximumLength = + ReturnedName.Length = (USHORT)NameInfo->FileNameLength; + + // + // Check if the name being returned is within the real mapping. + // If not, we have no translation to perform. + // + + NcComparePath( &ReturnedName, + &InstanceContext->Mapping.RealMapping, + &Remainder, + IgnoreCase, + FALSE, + &Overlap ); + + if (!Overlap.InMapping && !Overlap.Match) { + + Status = Data->IoStatus.Status; + LengthNeeded = SizeActuallyReturned; + + goto NcPostQueryNameInformationCleanup; + } + + // + // Make sure that the user buffer is long enough. + // + + UserStructureSize = FIELD_OFFSET( FILE_NAME_INFORMATION, FileName ); + + if (InfoClass == FileAllInformation) { + + UserStructureSize += FIELD_OFFSET( FILE_ALL_INFORMATION, NameInformation ); + } + + RequiredNameSize = InstanceContext->Mapping.UserMapping.LongNamePath.VolumelessName.Length; + + // + // Add back the trailing portion of the name. Note that Remainder + // is only defined if InMapping is TRUE. + // + + if (Overlap.InMapping && !Overlap.Match) { + + RequiredNameSize += Remainder.Length + sizeof(WCHAR); + } + + LengthNeeded = UserStructureSize + RequiredNameSize; + + // + // Whether the user has provided enough buffer or not, the + // FILE_NAME_INFORMATION.FileNameLength field has to contain the total length + // of the name we want to return. + // + + NameInfo->FileNameLength = RequiredNameSize; + + // + // If the user's buffer is not big enough to handle the name we need to return, + // we will copy in as much as we can and return STATUS_BUFFER_OVERFLOW. The + // user expects that the needed name length will be reported in the + // FILE_NAME_INFORMATION.FileNameLength field. + // + + if (UserBufferLength < LengthNeeded) { + + NameLengthAvailable = UserBufferLength - UserStructureSize; + + // + // Truncate the LengthNeeded value since it will be returned in the + // IoStatus block to tell I/O Manager how much to copy back to the + // user's buffer. + // + + LengthNeeded = UserBufferLength; + + Status = STATUS_BUFFER_OVERFLOW; + + // + // We have enough space. Let's assume we'll succeed to copy the name. + // + + } else { + + NameLengthAvailable = NameInfo->FileNameLength; + + Status = STATUS_SUCCESS; + } + + if (Overlap.InMapping && !Overlap.Match) { + + // + // Copy the remainder of the returned name from the user. This is + // done so that we can rewrite the user's buffer. Note that if we + // are not a match, we expect some remainder. + // + + FLT_ASSERT( Remainder.Length > 0 ); + + RemainderCopy.Buffer = ExAllocatePoolWithTag( PagedPool, + Remainder.Length, + NC_TAG ); + + if (RemainderCopy.Buffer == NULL) { + + Status = STATUS_INSUFFICIENT_RESOURCES; + goto NcPostQueryNameInformationCleanup; + } + + RtlCopyMemory( RemainderCopy.Buffer, + Remainder.Buffer, + Remainder.Length ); + + RemainderCopy.MaximumLength = + RemainderCopy.Length = Remainder.Length; + } + + // + // Firstly, copy back the name to our mapping. + // + + RtlCopyMemory( &NameInfo->FileName, + InstanceContext->Mapping.UserMapping.LongNamePath.VolumelessName.Buffer, + min(InstanceContext->Mapping.UserMapping.LongNamePath.VolumelessName.Length, + NameLengthAvailable) ); + + if (NameLengthAvailable > InstanceContext->Mapping.UserMapping.LongNamePath.VolumelessName.Length) { + + NameLengthAvailable -= InstanceContext->Mapping.UserMapping.LongNamePath.VolumelessName.Length; + + } else { + + NameLengthAvailable = 0; + } + + // + // If the object being queried is within the mapping, copy back the + // remainder of that name. + // + + if ((NameLengthAvailable > 0) && + Overlap.InMapping && !Overlap.Match) { + + NameInfo->FileName[InstanceContext->Mapping.UserMapping.LongNamePath.VolumelessName.Length / sizeof(WCHAR)] = '\\'; + + RtlCopyMemory( Add2Ptr( &NameInfo->FileName, + InstanceContext->Mapping.UserMapping.LongNamePath.VolumelessName.Length + sizeof(WCHAR) ), + RemainderCopy.Buffer, + min(RemainderCopy.Length, NameLengthAvailable) ); + } + + // + // We have finished the query, complete operation. + // + +NcPostQueryNameInformationCleanup: + + Data->IoStatus.Status = Status; + + // + // Note that STATUS_BUFFER_OVERFLOW is not a success code, but for name queries + // it indicates that the caller needs to allocate a bigger buffer. The needed + // size for the name is stored in the FILE_NAME_INFORMATION.FileNameLength field. + // Therefore the IoStatus.Information field must not be 0 for a buffer overflow, + // it must contain the size of the data that was actually copied. + // + + if (NT_SUCCESS( Status ) || + (Status == STATUS_BUFFER_OVERFLOW)) { + + Data->IoStatus.Information = LengthNeeded; + + } else { + + Data->IoStatus.Information = 0; + } + + if (RemainderCopy.Buffer != NULL) { + + ExFreePoolWithTag( RemainderCopy.Buffer, NC_TAG ); + } + + if (InstanceContext != NULL) { + + FltReleaseContext( InstanceContext ); + } + + return FLT_POSTOP_FINISHED_PROCESSING; +} + +FLT_PREOP_CALLBACK_STATUS +NcPreQueryAlternateName ( + _Inout_ PFLT_CALLBACK_DATA Data, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _Flt_CompletionContext_Outptr_ PVOID *CompletionContext + ) +/*++ + +Routine Description: + + This routine is called when the user wants to find the alternate name + for a previously opened handle. An alternate name means the short + half of a long/short name pair. + +Arguments: + + Data - Pointer to the filter CallbackData that is passed to us. + + FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure + containing opaque handles to this filter, instance, its + associated volume and file object. + + CompletionContext - The context for the completion routine for + this operation. We set this to the handle context for + directory change notifications. + +Return Value: + + The return value is the Status of the operation. + +--*/ +{ + NTSTATUS Status; + FLT_PREOP_CALLBACK_STATUS ReturnValue; + NC_PATH_OVERLAP Overlap; + PFLT_FILE_NAME_INFORMATION FileInfo = NULL; + PNC_INSTANCE_CONTEXT InstanceContext = NULL; + PVOID UserBuffer = Data->Iopb->Parameters.QueryFileInformation.InfoBuffer; + ULONG UserBufferLength = Data->Iopb->Parameters.QueryFileInformation.Length; + ULONG LengthNeeded = 0; + PFILE_NAME_INFORMATION NameInfo; + BOOLEAN IgnoreCase = !BooleanFlagOn( FltObjects->FileObject->Flags, + FO_OPENED_CASE_SENSITIVE ); + PUNICODE_STRING FinalComponentToReturn; + + UNREFERENCED_PARAMETER( CompletionContext ); + + PAGED_CODE(); + + FLT_ASSERT( IoGetTopLevelIrp() == NULL ); + + // + // Get our instance context. + // + + Status = FltGetInstanceContext( FltObjects->Instance, + &InstanceContext); + + if (!NT_SUCCESS( Status )) { + + ReturnValue = FLT_PREOP_COMPLETE; + goto NcPreQueryAlternateNameInformationCleanup; + } + + // + // Get the file's name. + // + + Status = NcGetFileNameInformation( Data, + NULL, + NULL, + FLT_FILE_NAME_OPENED | + FLT_FILE_NAME_QUERY_DEFAULT | + FLT_FILE_NAME_REQUEST_FROM_CURRENT_PROVIDER, + &FileInfo ); + + if (!NT_SUCCESS( Status )) { + + ReturnValue = FLT_PREOP_COMPLETE; + goto NcPreQueryAlternateNameInformationCleanup; + } + + Status = FltParseFileNameInformation( FileInfo ); + + if (!NT_SUCCESS( Status )) { + + ReturnValue = FLT_PREOP_COMPLETE; + goto NcPreQueryAlternateNameInformationCleanup; + } + + // + // We only need to handle the case where a shortname is being + // generated on the mapping itself. These names are final + // component path only, so any files within the mapping will + // still be correct even if we don't munge them. + // + + NcComparePath( &FileInfo->Name, + &InstanceContext->Mapping.UserMapping, + NULL, + IgnoreCase, + TRUE, + &Overlap ); + + if (!Overlap.Match) { + + NcComparePath( &FileInfo->Name, + &InstanceContext->Mapping.RealMapping, + NULL, + IgnoreCase, + TRUE, + &Overlap ); + + FLT_ASSERT( !Overlap.Match ); + + if (!Overlap.Match) { + + // + // This file is not the mapping, so we can just let this + // request go down normally. + // + + ReturnValue = FLT_PREOP_SUCCESS_NO_CALLBACK; + goto NcPreQueryAlternateNameInformationCleanup; + } + } + + // + // Return the short name. + // + // Note that this behavior differs from the filesystem in two respects: + // + // 1. We are not attempting to detect (and fail for) an open-by-ID + // handle. Since these are link agnostic, returning data is + // meaningless. + // + // 2. We may support having multiple alternate names for multiple + // links on the file, if the mapping was created as a file then + // a hardlink was created with a mapping name. This file thus + // contains two shortnames, which NTFS does not support. In + // theory APIs should be clean to this (and a future filesystem + // may wish to support it.) + // + + FinalComponentToReturn = &InstanceContext->Mapping.UserMapping.ShortNamePath.FinalComponentName; + + // + // Make sure that the user buffer is long enough. + // + + LengthNeeded = FIELD_OFFSET( FILE_NAME_INFORMATION, FileName ); + + LengthNeeded += FinalComponentToReturn->Length; + + if (UserBufferLength < LengthNeeded) { + + Status = STATUS_BUFFER_OVERFLOW; + ReturnValue = FLT_PREOP_COMPLETE; + goto NcPreQueryAlternateNameInformationCleanup; + } + + NameInfo = UserBuffer; + + // + // Copy back the name to our mapping. + // + + RtlCopyMemory( &NameInfo->FileName, + FinalComponentToReturn->Buffer, + FinalComponentToReturn->Length ); + + NameInfo->FileNameLength = FinalComponentToReturn->Length; + + // + // We have finished the query, complete operation. + // + + Status = STATUS_SUCCESS; + ReturnValue = FLT_PREOP_COMPLETE; + +NcPreQueryAlternateNameInformationCleanup: + + if (ReturnValue == FLT_PREOP_COMPLETE) { + + Data->IoStatus.Status = Status; + + // + // Note that STATUS_BUFFER_OVERFLOW is not a success code, and + // will result in zero bytes being copied back to the caller. + // + + if (NT_SUCCESS( Status )) { + + Data->IoStatus.Information = LengthNeeded; + } else { + + Data->IoStatus.Information = 0; + } + } + + if (FileInfo != NULL) { + + FltReleaseFileNameInformation( FileInfo ); + } + + if (InstanceContext != NULL) { + + FltReleaseContext( InstanceContext ); + } + + return ReturnValue; +} + + +FLT_POSTOP_CALLBACK_STATUS +NcPostQueryHardLinks ( + _Inout_ PFLT_CALLBACK_DATA Data, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _In_opt_ PVOID CompletionContext, + _In_ FLT_POST_OPERATION_FLAGS Flags + ) +/*++ + +Routine Description: + + This routine is called when the user wants to enumerate all hard links + for a previously opened handle. + +Arguments: + + Data - Pointer to the filter CallbackData that is passed to us. + + FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure + containing opaque handles to this filter, instance, its + associated volume and file object. + + CompletionContext - The context for the completion routine for + this operation. We set this to the handle context for + directory change notifications. + +Return Value: + + The return value is the Status of the operation. + +--*/ +{ + NTSTATUS Status; + PNC_INSTANCE_CONTEXT InstanceContext = NULL; + BOOLEAN IgnoreCase = !BooleanFlagOn( FltObjects->FileObject->Flags, + FO_OPENED_CASE_SENSITIVE ); + + // + // Pointer to the buffer returned to us, which we will also return to + // our caller; length of the buffer; size of the buffer filled in + // by the filesystem; size of the buffer that we filled in + // + + PFILE_LINKS_INFORMATION UserBuffer = Data->Iopb->Parameters.QueryFileInformation.InfoBuffer; + ULONG UserBufferLength = Data->Iopb->Parameters.QueryFileInformation.Length; + ULONG SizeActuallyReturned = (ULONG)Data->IoStatus.Information; + ULONG BytesWritten = 0; + + // + // Length of the current entry that we're processing; a UNICODE_STRING + // for the final component of the name that we're processing; and + // a flag indicating whether this entry is being modified + // + + ULONG EntrySize; + UNICODE_STRING EntryName; + BOOLEAN MungeEntry; + + // + // Copy of the buffer returned from the filesystem, our iterators as + // we process this buffer, and a pointer to the previous destination + // entry (if one exists) so we can zero the offset to next entry + // field on completion + // + + PFILE_LINKS_INFORMATION OriginalBuffer = NULL; + PFILE_LINK_ENTRY_INFORMATION SourceEntry; + PFILE_LINK_ENTRY_INFORMATION DestEntry; + PFILE_LINK_ENTRY_INFORMATION PrevDestEntry = NULL; + + + // + // Variables that we use to obtain IDs to the mapping parents. + // + + OBJECT_ATTRIBUTES MappingParentAttributes; + HANDLE MappingParentHandle = NULL; + PFILE_OBJECT MappingParentFileObject = NULL; + IO_STATUS_BLOCK MappingParentStatusBlock; + + // + // File IDs for the mapping parents + // + + LONGLONG RealMappingParentId; + LONGLONG UserMappingParentId; + + UNREFERENCED_PARAMETER( CompletionContext ); + UNREFERENCED_PARAMETER( Flags ); + + PAGED_CODE(); + + FLT_ASSERT( IoGetTopLevelIrp() == NULL ); + + // + // If the buffer was invalid, or if the call failed, leave now. Note + // that this may be STATUS_BUFFER_OVERFLOW and the number of bytes the + // caller needs will be reported inaccurately. To handle this we'd + // really need to issue our own call to get the full buffer, then + // transform it to find the "correct" length the user will need. + // + // Rather than do this, we return the caller a value for bytes required + // which may not be accurate. When they call us again, we will + // have data to transform, and can then fail the call again specifying + // a new value for bytes required that is accurate. + // + + if (SizeActuallyReturned <= (ULONG)FIELD_OFFSET( FILE_LINKS_INFORMATION, Entry ) || + !NT_SUCCESS( Data->IoStatus.Status )) { + + BytesWritten = SizeActuallyReturned; + + Status = Data->IoStatus.Status; + goto NcPostQueryHardLinkInformationCleanup; + } + + // + // Get our instance context. + // + + Status = FltGetInstanceContext( FltObjects->Instance, + &InstanceContext); + + if (!NT_SUCCESS( Status )) { + + goto NcPostQueryHardLinkInformationCleanup; + } + + // + // Open the mapping parents and query IDs. + // + + InitializeObjectAttributes( &MappingParentAttributes, + &InstanceContext->Mapping.RealMapping.LongNamePath.ParentPath, + OBJ_KERNEL_HANDLE | (IgnoreCase?OBJ_CASE_INSENSITIVE:0), + NULL, + NULL); + + Status = NcCreateFileHelper( NcGlobalData.FilterHandle, // Filter + Data->Iopb->TargetInstance, // Instance + &MappingParentHandle, // Returned Handle + &MappingParentFileObject, // Returned FileObject + FILE_READ_ATTRIBUTES|FILE_TRAVERSE, // Desired Access + &MappingParentAttributes, // object attributes + &MappingParentStatusBlock, // Returned IOStatusBlock + 0, // Allocation Size + FILE_ATTRIBUTE_NORMAL, // File Attributes + 0, // Share Access + FILE_OPEN, // Create Disposition + FILE_DIRECTORY_FILE, // Create Options + NULL, // Ea Buffer + 0, // EA Length + IO_IGNORE_SHARE_ACCESS_CHECK, // Flags + Data->Iopb->TargetFileObject ); // Transaction info. + + if (!NT_SUCCESS( Status )) { + + FLT_ASSERT( Status != STATUS_OBJECT_PATH_NOT_FOUND && + Status != STATUS_OBJECT_NAME_NOT_FOUND ); + + goto NcPostQueryHardLinkInformationCleanup; + } + + Status = FltQueryInformationFile( Data->Iopb->TargetInstance, + MappingParentFileObject, + &RealMappingParentId, + sizeof(RealMappingParentId), + FileInternalInformation, + NULL ); + + if (!NT_SUCCESS( Status )) { + + goto NcPostQueryHardLinkInformationCleanup; + } + + FltClose( MappingParentHandle ); + ObDereferenceObject( MappingParentFileObject ); + + MappingParentHandle = NULL; + MappingParentFileObject = NULL; + + InitializeObjectAttributes( &MappingParentAttributes, + &InstanceContext->Mapping.UserMapping.LongNamePath.ParentPath, + OBJ_KERNEL_HANDLE | (IgnoreCase?OBJ_CASE_INSENSITIVE:0), + NULL, + NULL); + + Status = NcCreateFileHelper( NcGlobalData.FilterHandle, // Filter + Data->Iopb->TargetInstance, // Instance + &MappingParentHandle, // Returned Handle + &MappingParentFileObject, // Returned FileObject + FILE_READ_ATTRIBUTES|FILE_TRAVERSE, // Desired Access + &MappingParentAttributes, // object attributes + &MappingParentStatusBlock, // Returned IOStatusBlock + 0, // Allocation Size + FILE_ATTRIBUTE_NORMAL, // File Attributes + 0, // Share Access + FILE_OPEN, // Create Disposition + FILE_DIRECTORY_FILE, // Create Options + NULL, // Ea Buffer + 0, // EA Length + IO_IGNORE_SHARE_ACCESS_CHECK, // Flags + Data->Iopb->TargetFileObject ); // Transaction info. + + if (!NT_SUCCESS( Status )) { + + FLT_ASSERT( Status != STATUS_OBJECT_PATH_NOT_FOUND && + Status != STATUS_OBJECT_NAME_NOT_FOUND ); + + goto NcPostQueryHardLinkInformationCleanup; + } + + Status = FltQueryInformationFile( Data->Iopb->TargetInstance, + MappingParentFileObject, + &UserMappingParentId, + sizeof(UserMappingParentId), + FileInternalInformation, + NULL ); + + if (!NT_SUCCESS( Status )) { + + goto NcPostQueryHardLinkInformationCleanup; + } + + FltClose( MappingParentHandle ); + ObDereferenceObject( MappingParentFileObject ); + + MappingParentHandle = NULL; + MappingParentFileObject = NULL; + + // + // Take a copy of the results of the call from the filesystem. + // + + OriginalBuffer = ExAllocatePoolWithTag( PagedPool, + SizeActuallyReturned, + NC_TAG ); + + if (OriginalBuffer == NULL) { + + Status = STATUS_INSUFFICIENT_RESOURCES; + goto NcPostQueryHardLinkInformationCleanup; + } + + RtlCopyMemory( OriginalBuffer, UserBuffer, SizeActuallyReturned ); + + // + // Set up our iterators to walk through the returned links. + // + + DestEntry = &UserBuffer->Entry; + + if (UserBuffer->EntriesReturned >= 1) { + SourceEntry = &OriginalBuffer->Entry; + } else { + SourceEntry = NULL; + } + UserBuffer->EntriesReturned = 0; + BytesWritten = FIELD_OFFSET( FILE_LINKS_INFORMATION, Entry ); + UserBuffer->BytesNeeded = BytesWritten; + + while( SourceEntry ) { + + // + // Assume we don't need to munge the link. If the parent IDs, + // final component lengths and final component strings correspond + // to the real mapping, we will need to transform it. + // + + MungeEntry = FALSE; + + if (SourceEntry->ParentFileId == RealMappingParentId) { + + if (SourceEntry->FileNameLength * sizeof(WCHAR) >= MAXUSHORT) { + + Status = STATUS_OBJECT_PATH_INVALID; + goto NcPostQueryHardLinkInformationCleanup; + } + + EntryName.Buffer = SourceEntry->FileName; + EntryName.Length = EntryName.MaximumLength = (USHORT)SourceEntry->FileNameLength * sizeof(WCHAR); + + if (EntryName.Length == InstanceContext->Mapping.RealMapping.LongNamePath.FinalComponentName.Length && + RtlCompareUnicodeString( &EntryName, &InstanceContext->Mapping.RealMapping.LongNamePath.FinalComponentName, IgnoreCase ) == 0) { + + MungeEntry = TRUE; + } + + // + // TODO: Preserve shortness in output + // + + if (EntryName.Length == InstanceContext->Mapping.RealMapping.ShortNamePath.FinalComponentName.Length && + RtlCompareUnicodeString( &EntryName, &InstanceContext->Mapping.RealMapping.ShortNamePath.FinalComponentName, IgnoreCase ) == 0) { + + MungeEntry = TRUE; + } + } + + // + // Calculate the length of the entry that we want to write. + // + + if (MungeEntry) { + + EntrySize = FIELD_OFFSET( FILE_LINK_ENTRY_INFORMATION, FileName ) + + InstanceContext->Mapping.UserMapping.LongNamePath.FinalComponentName.Length; + + EntrySize = AlignToSize( EntrySize, 8 ); + + } else { + + EntrySize = FIELD_OFFSET( FILE_LINK_ENTRY_INFORMATION, FileName ) + + SourceEntry->FileNameLength * sizeof(WCHAR); + + EntrySize = AlignToSize( EntrySize, 8 ); + } + + // + // Record how much space the caller would need to return all entries. + // + + UserBuffer->BytesNeeded += EntrySize; + + // + // If we have space, copy this entry into the user's buffer and + // advance our destination iterator. + // + + if (BytesWritten + EntrySize <= UserBufferLength) { + + if (MungeEntry) { + + DestEntry->NextEntryOffset = EntrySize; + DestEntry->ParentFileId = UserMappingParentId; + DestEntry->FileNameLength = InstanceContext->Mapping.UserMapping.LongNamePath.FinalComponentName.Length / sizeof(WCHAR); + RtlCopyMemory( DestEntry->FileName, + InstanceContext->Mapping.UserMapping.LongNamePath.FinalComponentName.Buffer, + InstanceContext->Mapping.UserMapping.LongNamePath.FinalComponentName.Length ); + } else { + + RtlCopyMemory( DestEntry, SourceEntry, EntrySize ); + } + PrevDestEntry = DestEntry; + DestEntry = Add2Ptr( DestEntry, EntrySize ); + UserBuffer->EntriesReturned++; + BytesWritten += EntrySize; + } + + // + // If we still have links that we have not yet consumed, move + // to those. + // + + if (SourceEntry->NextEntryOffset != 0) { + SourceEntry = Add2Ptr( SourceEntry, SourceEntry->NextEntryOffset ); + } else { + SourceEntry = NULL; + } + } + + // + // If we already copied one or more links, make sure our list is + // correctly terminated. + // + + if (PrevDestEntry != NULL) { + PrevDestEntry->NextEntryOffset = 0; + } + + // + // If we copied all results, return STATUS_SUCCESS. If we saw entries + // that we did not copy, return STATUS_BUFFER_OVERFLOW. + // + + if (BytesWritten == UserBuffer->BytesNeeded) { + Status = STATUS_SUCCESS; + } else { + Status = STATUS_BUFFER_OVERFLOW; + } + +NcPostQueryHardLinkInformationCleanup: + + Data->IoStatus.Status = Status; + + if (NT_SUCCESS( Status ) || Status == STATUS_BUFFER_OVERFLOW) { + + Data->IoStatus.Information = BytesWritten; + } else { + + Data->IoStatus.Information = 0; + } + + if (MappingParentHandle != NULL) { + + FltClose( MappingParentHandle ); + MappingParentHandle = NULL; + } + + if (MappingParentFileObject != NULL) { + + ObDereferenceObject( MappingParentFileObject ); + MappingParentFileObject = NULL; + } + + if (OriginalBuffer != NULL) { + + ExFreePoolWithTag( OriginalBuffer, NC_TAG ); + } + + if (InstanceContext != NULL) { + + FltReleaseContext( InstanceContext ); + } + + return FLT_POSTOP_FINISHED_PROCESSING; +} + +FLT_PREOP_CALLBACK_STATUS +NcPreSetShortName ( + _Inout_ PFLT_CALLBACK_DATA Data, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _Flt_CompletionContext_Outptr_ PVOID *CompletionContext + ) +/*++ + +Routine Description: + + This routine is called when the user wants to change the short name + for a previously opened handle. + +Arguments: + + Data - Pointer to the filter CallbackData that is passed to us. + + FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure + containing opaque handles to this filter, instance, its + associated volume and file object. + + CompletionContext - The context for the completion routine for + this operation. We set this to the handle context for + directory change notifications. + +Return Value: + + The return value is the Status of the operation. + +--*/ +{ + FLT_PREOP_CALLBACK_STATUS ReturnValue; + NTSTATUS Status; + PFILE_NAME_INFORMATION NameInfo = + Data->Iopb->Parameters.SetFileInformation.InfoBuffer; + PFLT_FILE_NAME_INFORMATION FileInfo = NULL; + PNC_INSTANCE_CONTEXT InstanceContext = NULL; + NC_PATH_OVERLAP RealOverlap; + NC_PATH_OVERLAP UserOverlap; + BOOLEAN IgnoreCase = !BooleanFlagOn( FltObjects->FileObject->Flags, + FO_OPENED_CASE_SENSITIVE ); + + PAGED_CODE(); + + FLT_ASSERT( IoGetTopLevelIrp() == NULL ); + + UNREFERENCED_PARAMETER( CompletionContext ); + + Status = FltGetInstanceContext( FltObjects->Instance, + &InstanceContext); + + if (!NT_SUCCESS( Status )) { + + ReturnValue = FLT_PREOP_COMPLETE; + goto NcPreSetShortNameCleanup; + } + + // + // Let's skip doing any of this work for file systems that we know don't + // have short names. + // + + if ((InstanceContext->VolumeFilesystemType == FLT_FSTYPE_EXFAT) || + (InstanceContext->VolumeFilesystemType == FLT_FSTYPE_REFS)) { + + ReturnValue = FLT_PREOP_COMPLETE; + goto NcPreSetShortNameCleanup; + } + + // + // Get the file's name. + // + + Status = NcGetFileNameInformation( Data, + NULL, + NULL, + FLT_FILE_NAME_OPENED | + FLT_FILE_NAME_QUERY_DEFAULT | + FLT_FILE_NAME_REQUEST_FROM_CURRENT_PROVIDER, + &FileInfo ); + + if (!NT_SUCCESS( Status )) { + + ReturnValue = FLT_PREOP_COMPLETE; + goto NcPreSetShortNameCleanup; + } + + Status = FltParseFileNameInformation( FileInfo ); + + if (!NT_SUCCESS( Status )) { + + ReturnValue = FLT_PREOP_COMPLETE; + goto NcPreSetShortNameCleanup; + } + + // + // Calculate Overlap and Remainder + // + + NcComparePath( &FileInfo->Name, + &InstanceContext->Mapping.UserMapping, + NULL, + IgnoreCase, + TRUE, + &UserOverlap ); + + NcComparePath( &FileInfo->Name, + &InstanceContext->Mapping.RealMapping, + NULL, + IgnoreCase, + TRUE, + &RealOverlap ); + + // + // Currently the file names that we use are read only, so changing a + // shortname on the mapping or any of its ancestors cannot be + // supported. + // + // TODO: Should we support this? + // + + if (RealOverlap.Match || + UserOverlap.Match || + RealOverlap.Ancestor || + UserOverlap.Ancestor || + NameInfo->FileNameLength > MAXUSHORT) { + + Status = STATUS_ACCESS_DENIED; + ReturnValue = FLT_PREOP_COMPLETE; + goto NcPreSetShortNameCleanup; + } + + // + // If the user is attempting to set a name which is used by the real + // file, we let the request go to the file system (which will fail + // it.) For names used by the user mapping, we need to detect and + // fail those. + // + + if (UserOverlap.Peer) { + + UNICODE_STRING TargetComponent; + + TargetComponent.Buffer = NameInfo->FileName; + TargetComponent.Length = TargetComponent.MaximumLength = (USHORT)NameInfo->FileNameLength; + + if( RtlCompareUnicodeString( &TargetComponent, + &InstanceContext->Mapping.UserMapping.LongNamePath.FinalComponentName, + IgnoreCase) == 0 || + RtlCompareUnicodeString( &TargetComponent, + &InstanceContext->Mapping.UserMapping.ShortNamePath.FinalComponentName, + IgnoreCase) == 0 ) { + + Status = STATUS_ACCESS_DENIED; + ReturnValue = FLT_PREOP_COMPLETE; + goto NcPreSetShortNameCleanup; + } + + } + + // + // If the user is not setting a short name on our mapping, an ancestor + // of our mapping or targetting our mapping, let the request go to the + // file system. + // + + Status = STATUS_SUCCESS; + ReturnValue = FLT_PREOP_SUCCESS_NO_CALLBACK; + +NcPreSetShortNameCleanup: + + if (ReturnValue == FLT_PREOP_COMPLETE) { + + Data->IoStatus.Status = Status; + } + + if (FileInfo != NULL) { + + FltReleaseFileNameInformation( FileInfo ); + } + + if (InstanceContext != NULL) { + + FltReleaseContext( InstanceContext ); + } + + return ReturnValue; +} + + +FLT_PREOP_CALLBACK_STATUS +NcPreSetDisposition ( + _Inout_ PFLT_CALLBACK_DATA Data, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _Flt_CompletionContext_Outptr_ PVOID *CompletionContext + ) +/*++ + +Routine Description: + + Fltmgr callback which manages setting the delete disposition on a file. + We must disallow setting the delete disposition on an ancestor of either + mapping because otherwise we would have to maintain the mapping's + short/long name pairings. + +Arguments: + + Data - Pointer to the filter CallbackData that is passed to us. + + FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing + opaque handles to this filter, instance, its associated volume and + file object. + + CompletionContext - The context for the completion routine for this + operation. + +Return Value: + + The return value is the Status of the operation. + +--*/ +{ + NTSTATUS Status; + FLT_PREOP_CALLBACK_STATUS ReturnValue; + PFLT_FILE_NAME_INFORMATION FileInfo = NULL; + PNC_INSTANCE_CONTEXT InstanceContext = NULL; + PNC_MAPPING Mapping; + NC_PATH_OVERLAP RealOverlap; + NC_PATH_OVERLAP UserOverlap; + PFILE_DISPOSITION_INFORMATION Disposition; + BOOLEAN IgnoreCase = !BooleanFlagOn( FltObjects->FileObject->Flags, + FO_OPENED_CASE_SENSITIVE ); + + PAGED_CODE(); + + UNREFERENCED_PARAMETER( CompletionContext ); + + FLT_ASSERT( IoGetTopLevelIrp() == NULL ); + + // + // See if they are setting the delete disposition to false. + // If they are we can passthrough. We don't care if people + // want to mark the mapping as "don't delete". + // + + Disposition = Data->Iopb->Parameters.SetFileInformation.InfoBuffer; + if (Disposition->DeleteFile == FALSE) { + + Status = STATUS_SUCCESS; + goto NcPreSetDispositionCleanup; + } + + // + // The user is trying to delete a file. + // We have to make sure that the file is not an ancestor of either mapping. + // + + // + // Get the file's name. + // + + Status = NcGetFileNameInformation( Data, + NULL, + NULL, + FLT_FILE_NAME_OPENED | + FLT_FILE_NAME_QUERY_DEFAULT | + FLT_FILE_NAME_REQUEST_FROM_CURRENT_PROVIDER, + &FileInfo); + + if (!NT_SUCCESS( Status )) { + + goto NcPreSetDispositionCleanup; + } + + Status = FltParseFileNameInformation( FileInfo ); + + if (!NT_SUCCESS( Status )) { + + goto NcPreSetDispositionCleanup; + } + + // + // Get the mapping + // + + Status = FltGetInstanceContext( FltObjects->Instance, + &InstanceContext ); + + if (!NT_SUCCESS( Status )) { + + goto NcPreSetDispositionCleanup; + } + + Mapping = &InstanceContext->Mapping; + + // + // Check to see of this will delete an ancestor of the real mapping. + // + + NcComparePath( &FileInfo->Name, + &Mapping->RealMapping, + NULL, + IgnoreCase, + TRUE, + &RealOverlap ); + + if (RealOverlap.Ancestor) { + + // + // The file is an ancestor of the real mapping, so disallow setting + // disposition. + // + + Status = STATUS_ACCESS_DENIED; + goto NcPreSetDispositionCleanup; + } + + // + // Check the user mapping. + // + + NcComparePath( &FileInfo->Name, + &Mapping->UserMapping, + NULL, + IgnoreCase, + TRUE, + &UserOverlap ); + + if (UserOverlap.Ancestor) { + + // + // The file is an ancestor of the user mapping, so disallow setting + // disposition. + // + + Status = STATUS_ACCESS_DENIED; + goto NcPreSetDispositionCleanup; + } + + // + // The file is ok to mark for delete. + // + + Status = STATUS_SUCCESS; + goto NcPreSetDispositionCleanup; + +NcPreSetDispositionCleanup: + + if (!NT_SUCCESS( Status )) { + + ReturnValue = FLT_PREOP_COMPLETE; + Data->IoStatus.Status = Status; + + } else { + + ReturnValue = FLT_PREOP_SUCCESS_NO_CALLBACK; + } + + if (FileInfo) { + + FltReleaseFileNameInformation( FileInfo ); + } + + if (InstanceContext) { + + FltReleaseContext( InstanceContext ); + } + + return ReturnValue; +} + + +FLT_PREOP_CALLBACK_STATUS +NcPreSetLinkInformation ( + _Inout_ PFLT_CALLBACK_DATA Data, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _Flt_CompletionContext_Outptr_ PVOID *CompletionContext + ) +/*++ + +Routine Description: + + Fltmgr callback which manages link creation on a file. + We need to make sure that new links down the user mapping + are redirected to the real mapping. + +Arguments: + + Data - Pointer to the filter CallbackData that is passed to us. + + FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing + opaque handles to this filter, instance, its associated volume and + file object. + + CompletionContext - The context for the completion routine for this + operation. + +Return Value: + + The return value is the Status of the operation. + +--*/ +{ + FLT_PREOP_CALLBACK_STATUS ReturnValue; + NTSTATUS Status; + PFILE_LINK_INFORMATION LinkInfo = + Data->Iopb->Parameters.SetFileInformation.InfoBuffer; + PFILE_LINK_INFORMATION MungedLinkInfo = NULL; + ULONG MungedLinkInfoSize; + PFLT_FILE_NAME_INFORMATION FileInfo = NULL; + PNC_INSTANCE_CONTEXT InstanceContext = NULL; + NC_PATH_OVERLAP RealOverlap; + NC_PATH_OVERLAP UserOverlap; + UNICODE_STRING UserRemainder; + UNICODE_STRING MungedName = EMPTY_UNICODE_STRING; + BOOLEAN IgnoreCase = !BooleanFlagOn( FltObjects->FileObject->Flags, + FO_OPENED_CASE_SENSITIVE ); + + PAGED_CODE(); + + FLT_ASSERT( IoGetTopLevelIrp() == NULL ); + + UNREFERENCED_PARAMETER( CompletionContext ); + + Status = FltGetInstanceContext( FltObjects->Instance, + &InstanceContext); + + if (!NT_SUCCESS( Status )) { + + ReturnValue = FLT_PREOP_COMPLETE; + goto NcPreSetLinkInformationCleanup; + } + + Status = FltGetDestinationFileNameInformation( FltObjects->Instance, + FltObjects->FileObject, + LinkInfo->RootDirectory, + LinkInfo->FileName, + LinkInfo->FileNameLength, + FLT_FILE_NAME_OPENED | + FLT_FILE_NAME_QUERY_DEFAULT | + FLT_FILE_NAME_REQUEST_FROM_CURRENT_PROVIDER, + &FileInfo); + + if (!NT_SUCCESS( Status )) { + + ReturnValue = FLT_PREOP_COMPLETE; + goto NcPreSetLinkInformationCleanup; + } + + Status = FltParseFileNameInformation( FileInfo ); + + if (!NT_SUCCESS( Status )) { + + ReturnValue = FLT_PREOP_COMPLETE; + goto NcPreSetLinkInformationCleanup; + } + + // + // Calculate Overlap and Remainder + // + + NcComparePath( &FileInfo->Name, + &InstanceContext->Mapping.UserMapping, + &UserRemainder, + IgnoreCase, + TRUE, + &UserOverlap ); + + NcComparePath( &FileInfo->Name, + &InstanceContext->Mapping.RealMapping, + NULL, + IgnoreCase, + TRUE, + &RealOverlap ); + + // + // We cannot allow the user to link inside the real mapping, since it + // is hidden. + // + + if (RealOverlap.Match) { + + Status = STATUS_ACCESS_DENIED; + ReturnValue = FLT_PREOP_COMPLETE; + goto NcPreSetLinkInformationCleanup; + + } else if (RealOverlap.InMapping) { + + // + // We should never get here. Getting here requires an + // OPEN_TARGET_DIRECTORY open which should already have failed. + // + + FLT_ASSERT( !RealOverlap.InMapping ); + + Status = STATUS_OBJECT_PATH_NOT_FOUND; + ReturnValue = FLT_PREOP_COMPLETE; + goto NcPreSetLinkInformationCleanup; + + } else if ((RealOverlap.Ancestor || UserOverlap.Ancestor) && + LinkInfo->ReplaceIfExists) { + + // + // The user is attempting to overwrite a parent of the mapping. + // Fail this operation. + // + + Status = STATUS_ACCESS_DENIED; + ReturnValue = FLT_PREOP_COMPLETE; + goto NcPreSetLinkInformationCleanup; + } + + // + // If the destination path is outside the mapping then we can pass it + // through without a problem. + // + + if (!UserOverlap.InMapping) { + + // + // The destination outside the mapping. We can ignore this IO. + // + + Status = STATUS_SUCCESS; + ReturnValue = FLT_PREOP_SUCCESS_NO_CALLBACK; + goto NcPreSetLinkInformationCleanup; + } + + // + // The destination is inside the mapping. This means we have to issue + // our own request and forward the results to the user. + // + + // + // We need to build a new path to link on. + // + + Status = NcConstructPath( &InstanceContext->Mapping.RealMapping, + &UserRemainder, + TRUE, + &MungedName ); + + if (!NT_SUCCESS( Status )) { + + ReturnValue = FLT_PREOP_COMPLETE; + goto NcPreSetLinkInformationCleanup; + } + + // + // Create our own link structure. + // + + MungedLinkInfoSize = sizeof(FILE_LINK_INFORMATION) + MungedName.Length - sizeof(WCHAR); + MungedLinkInfo = ExAllocatePoolWithTag( PagedPool, + MungedLinkInfoSize, + NC_SET_LINK_BUFFER_TAG ); + + if (MungedLinkInfo == NULL) { + + Status = STATUS_INSUFFICIENT_RESOURCES; + ReturnValue = FLT_PREOP_COMPLETE; + goto NcPreSetLinkInformationCleanup; + } + + MungedLinkInfo->ReplaceIfExists = LinkInfo->ReplaceIfExists; + MungedLinkInfo->RootDirectory = NULL; + MungedLinkInfo->FileNameLength = MungedName.Length; + + RtlCopyMemory( &MungedLinkInfo->FileName, MungedName.Buffer, MungedName.Length ); + + // + // Issue our own request. + // + + Status = FltSetInformationFile( FltObjects->Instance, + FltObjects->FileObject, + MungedLinkInfo, + MungedLinkInfoSize, + FileLinkInformation ); + + // + // Because we issued the IO, we will pass complete this ourselves. + // + + ReturnValue = FLT_PREOP_COMPLETE; + +NcPreSetLinkInformationCleanup: + + if (ReturnValue == FLT_PREOP_COMPLETE) { + + Data->IoStatus.Status = Status; + } + + if (MungedLinkInfo != NULL) { + + ExFreePoolWithTag( MungedLinkInfo, NC_SET_LINK_BUFFER_TAG ); + } + + if (FileInfo != NULL) { + + FltReleaseFileNameInformation( FileInfo ); + } + + if (InstanceContext != NULL) { + + FltReleaseContext( InstanceContext ); + } + + if (MungedName.Buffer != NULL) { + + ExFreePoolWithTag( MungedName.Buffer, NC_TAG ); + } + + return ReturnValue; +} + +FLT_PREOP_CALLBACK_STATUS +NcPreRename( + _Inout_ PFLT_CALLBACK_DATA Data, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _Flt_CompletionContext_Outptr_ PVOID *CompletionContext + ) +/*++ + +Routine Description: + + Fltmgr callback which manages renaming files. We must disallow renaming + on an ancestor of either mapping because otherwise we would have to + maintain the mapping's short/long name pairings. + +Arguments: + + Data - Pointer to the filter CallbackData that is passed to us. + + FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing + opaque handles to this filter, instance, its associated volume and + file object. + + CompletionContext - The context for the completion routine for this + operation. + +Return Value: + + The return value is the Status of the operation. + +--*/ +{ + // + // Return Values + // + + NTSTATUS Status; + FLT_PREOP_CALLBACK_STATUS ReturnValue; + + // + // Contexts + // + + PNC_INSTANCE_CONTEXT InstanceContext = NULL; + + // + // Data + // + + PFILE_RENAME_INFORMATION RenameInfo = + Data->Iopb->Parameters.SetFileInformation.InfoBuffer; + + // + // FileInformation + // + + PFLT_FILE_NAME_INFORMATION TargetInfo = NULL; + PFLT_FILE_NAME_INFORMATION SrcInfo = NULL; + + // + // Target Real Overlap + // + + NC_PATH_OVERLAP TargetRealOverlap; + UNICODE_STRING TargetRealRemainder; + + // + // Target User Overlap + // + + NC_PATH_OVERLAP TargetUserOverlap; + UNICODE_STRING TargetUserRemainder; + + // + // Src Real Overlap + // + + NC_PATH_OVERLAP SrcRealOverlap; + NC_PATH_OVERLAP SrcUserOverlap; + + // + // Munge Data + // + + UNICODE_STRING MungedTargetName = EMPTY_UNICODE_STRING; + PFILE_RENAME_INFORMATION MungedRenameInfo = NULL; + ULONG MungedRenameLength; + BOOLEAN IgnoreCase = !BooleanFlagOn( FltObjects->FileObject->Flags, + FO_OPENED_CASE_SENSITIVE ); + + PAGED_CODE(); + + UNREFERENCED_PARAMETER( CompletionContext ); + + FLT_ASSERT( IoGetTopLevelIrp() == NULL ); + + + // + // Get Instance Context + // + + Status = FltGetInstanceContext( FltObjects->Instance, + &InstanceContext ); + + if (!NT_SUCCESS( Status )) { + + ReturnValue = FLT_PREOP_COMPLETE; + goto NcPreRenameCleanup; + } + + // + // Find out the src file's name. + // + + Status = NcGetFileNameInformation( Data, + NULL, + NULL, + FLT_FILE_NAME_OPENED | + FLT_FILE_NAME_QUERY_DEFAULT | + FLT_FILE_NAME_REQUEST_FROM_CURRENT_PROVIDER, + &SrcInfo); + + if (!NT_SUCCESS( Status )) { + + ReturnValue = FLT_PREOP_COMPLETE; + goto NcPreRenameCleanup; + } + + Status = FltParseFileNameInformation( SrcInfo ); + + if (!NT_SUCCESS( Status )) { + + ReturnValue = FLT_PREOP_COMPLETE; + goto NcPreRenameCleanup; + } + + // + // Find the src's overlap with the real and user mappings. + // + + NcComparePath( &SrcInfo->Name, + &InstanceContext->Mapping.RealMapping, + NULL, + IgnoreCase, + TRUE, + &SrcRealOverlap ); + + NcComparePath( &SrcInfo->Name, + &InstanceContext->Mapping.UserMapping, + NULL, + IgnoreCase, + TRUE, + &SrcUserOverlap ); + + // + // If the src is an ancestor of either the user or real mappings we can + // fail the request. + // + + if (SrcUserOverlap.Ancestor || SrcRealOverlap.Ancestor) { + + ReturnValue = FLT_PREOP_COMPLETE; + Status = STATUS_ACCESS_DENIED; + goto NcPreRenameCleanup; + } + + // + // Find out the target file's name. + // + + Status = FltGetDestinationFileNameInformation( FltObjects->Instance, + FltObjects->FileObject, + RenameInfo->RootDirectory, + RenameInfo->FileName, + RenameInfo->FileNameLength, + FLT_FILE_NAME_OPENED | + FLT_FILE_NAME_QUERY_DEFAULT | + FLT_FILE_NAME_REQUEST_FROM_CURRENT_PROVIDER, + &TargetInfo); + + if (!NT_SUCCESS( Status )) { + + ReturnValue = FLT_PREOP_COMPLETE; + goto NcPreRenameCleanup; + } + + Status = FltParseFileNameInformation( TargetInfo ); + + if( !NT_SUCCESS( Status ) ) { + + FLT_ASSERT( NT_SUCCESS( Status ) ); + + ReturnValue = FLT_PREOP_COMPLETE; + goto NcPreRenameCleanup; + } + + // + // Find the target's overlap with the real and user mappings. + // + + NcComparePath( &TargetInfo->Name, + &InstanceContext->Mapping.RealMapping, + &TargetRealRemainder, + IgnoreCase, + TRUE, + &TargetRealOverlap ); + + NcComparePath( &TargetInfo->Name, + &InstanceContext->Mapping.UserMapping, + &TargetUserRemainder, + IgnoreCase, + TRUE, + &TargetUserOverlap ); + + // + // If the target is in the real mapping, then disallow the rename. If + // the target is to an ancestor of the mappings, this could change IDs + // and is therefore also disallowed. + // + + if (TargetRealOverlap.InMapping) { + + Status = STATUS_ACCESS_DENIED; + ReturnValue = FLT_PREOP_COMPLETE; + goto NcPreRenameCleanup; + + } else if ((TargetRealOverlap.Ancestor || TargetUserOverlap.Ancestor) && + RenameInfo->ReplaceIfExists) { + + Status = STATUS_ACCESS_DENIED; + ReturnValue = FLT_PREOP_COMPLETE; + goto NcPreRenameCleanup; + } + + + // + // If the target is in the user mapping, then we need to munge the + // name and send the request down. If this is a stream rename we + // do not perform the mapping since only the stream name is changing. + // + + if (TargetUserOverlap.InMapping && + (RenameInfo->FileName[0] != ':')) { + + Status = NcConstructPath( &InstanceContext->Mapping.RealMapping, + &TargetUserRemainder, + TRUE, + &MungedTargetName ); + + if (!NT_SUCCESS( Status )) { + + ReturnValue = FLT_PREOP_COMPLETE; + goto NcPreRenameCleanup; + } + + + // + // Because the target is in the user mapping, we have to issue + // our own rename down the real mapping. + // + + // + // Allocate rename information structure. + // + + MungedRenameLength = sizeof(FILE_RENAME_INFORMATION) - + sizeof(WCHAR) + + MungedTargetName.Length; + + MungedRenameInfo = ExAllocatePoolWithTag( PagedPool, + MungedRenameLength, + NC_RENAME_BUFFER_TAG ); + + if (MungedRenameInfo == NULL) { + + Status = STATUS_INSUFFICIENT_RESOURCES; + ReturnValue = FLT_PREOP_COMPLETE; + goto NcPreRenameCleanup; + } + + // + // Copy user rename parameters. + // + + MungedRenameInfo->ReplaceIfExists = RenameInfo->ReplaceIfExists; + MungedRenameInfo->RootDirectory = NULL; + MungedRenameInfo->FileNameLength = MungedTargetName.Length; + RtlCopyMemory( &MungedRenameInfo->FileName, + MungedTargetName.Buffer, + MungedTargetName.Length ); + + // + // Send the request. Note that we cannot just place the new buffer + // in the CallbackData; filesystems use the name from a previous + // OPEN_TARGET_DIRECTORY open, so changing the buffer here would + // result in unexpected (and undefined!) behavior. + // + + Status = FltSetInformationFile( FltObjects->Instance, + FltObjects->FileObject, + MungedRenameInfo, + MungedRenameLength, + FileRenameInformation ); + + // + // Complete the IO. + // + + ReturnValue = FLT_PREOP_COMPLETE; + goto NcPreRenameCleanup; + + } else { + + // + // The target was outside the mapping. The rename does not have + // to be munged. Pass through. + // + + ReturnValue = FLT_PREOP_SUCCESS_NO_CALLBACK; + goto NcPreRenameCleanup; + + } + +NcPreRenameCleanup: + + if (ReturnValue == FLT_PREOP_COMPLETE) { + + Data->IoStatus.Status = Status; + } + + if (InstanceContext != NULL) { + + FltReleaseContext( InstanceContext ); + } + + if (TargetInfo != NULL) { + + FltReleaseFileNameInformation( TargetInfo ); + } + + if (SrcInfo != NULL) { + + FltReleaseFileNameInformation( SrcInfo ); + } + + if (MungedTargetName.Buffer != NULL) { + + ExFreePoolWithTag( MungedTargetName.Buffer, NC_GENERATE_NAME_TAG ); + } + + if (MungedRenameInfo != NULL) { + + ExFreePoolWithTag( MungedRenameInfo, NC_RENAME_BUFFER_TAG ); + } + + return ReturnValue; +} + + diff --git a/filesys/miniFilter/NameChanger/ncfsctrl.c b/filesys/miniFilter/NameChanger/ncfsctrl.c new file mode 100644 index 00000000..32752810 --- /dev/null +++ b/filesys/miniFilter/NameChanger/ncfsctrl.c @@ -0,0 +1,3634 @@ +/*++ + +Copyright (c) 2008 - 2009 Microsoft Corporation + +Module Name: + + ncfsctrl.c + +Abstract: + + Contains routines to process user-initiated file system control + (FSCTL) requests. + +Environment: + + Kernel mode + +--*/ + +#include "nc.h" + +NTSTATUS +NcFindFilesBySidTranslateBuffers ( + _In_ PNC_INSTANCE_CONTEXT InstanceContext, + _In_ BOOLEAN IgnoreCase, + _In_ PUNICODE_STRING UserRequestName, + _In_ PUNICODE_STRING OpenedName, + _In_ PFILE_NAME_INFORMATION InputSystemBuffer, + _Out_writes_bytes_to_(OutputBufferLength, *OutputBufferWritten) PFILE_NAME_INFORMATION OutputUserBuffer, + _In_ ULONG InputBufferLength, + _In_ ULONG OutputBufferLength, + _Out_ PULONG InputBufferConsumed, + _Out_ PULONG OutputBufferWritten, + _In_ BOOLEAN ReturnRealMappingPaths + ) ; + +NTSTATUS +NcUsnTranslateBuffers ( + _In_ PNC_INSTANCE_CONTEXT InstanceContext, + _In_ BOOLEAN IgnoreCase, + _In_ ULONGLONG RealMappingParentId, + _In_ ULONGLONG UserMappingParentId, + _In_ PUSN_RECORD InputSystemBuffer, + _Out_writes_bytes_to_(OutputBufferLength, *OutputBufferWritten) PUSN_RECORD OutputUserBuffer, + _In_ ULONG InputBufferLength, + _In_ ULONG OutputBufferLength, + _Out_ PULONG InputBufferConsumed, + _Out_ PULONG OutputBufferWritten + ); + +VOID +NcPostReadUsnJournalWorker ( + _In_ PFLT_GENERIC_WORKITEM WorkItem, + _In_ PFLT_FILTER Filter, + _In_ PVOID Context + ); + + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE, NcFindFilesBySidTranslateBuffers) +#pragma alloc_text(PAGE, NcStreamHandleContextFindBySidCreate) +#pragma alloc_text(PAGE, NcStreamHandleContextFindBySidClose) +#pragma alloc_text(PAGE, NcPreFindFilesBySid) +#pragma alloc_text(PAGE, NcPostFindFilesBySid) +#if FLT_MGR_WIN7 +#pragma alloc_text(PAGE, NcPostLookupStreamFromCluster) +#endif +#pragma alloc_text(PAGE, NcUsnTranslateBuffers) +#pragma alloc_text(PAGE, NcPostEnumUsnData) +#pragma alloc_text(PAGE, NcPostReadUsnJournalWorker) +#pragma alloc_text(PAGE, NcPostReadFileUsnData) +#endif + +NTSTATUS +NcStreamHandleContextFindBySidCreate ( + _Out_ PNC_FIND_BY_SID_CONTEXT Context + ) +/*++ + +Routine Description: + + This function is called to initialize the find files by SID portion of + a stream handle context. + +Arguments: + + Context - Pointer to the find files by SID portion of the stream handle + context. + +Return Value: + + Returns the status of the operation (currently only STATUS_SUCCESS.) + +--*/ +{ + + PAGED_CODE(); + + Context->RealHandle = NULL; + Context->RealFileObject = NULL; + + Context->BufferToFree = NULL; + Context->BufferSize = 0; + Context->CurrentEntry = 0; + + Context->OutstandingRequests = 0; + + return STATUS_SUCCESS; + +} + +VOID +NcStreamHandleContextFindBySidClose ( + _In_ PNC_FIND_BY_SID_CONTEXT Context + ) +/*++ + +Routine Description: + + This function is called to tear down the find files by SID portion of + a stream handle context. + +Arguments: + + Context - Pointer to the find files by SID portion of the stream handle + context. + +Return Value: + + None. + +--*/ +{ + + PAGED_CODE(); + + FLT_ASSERT( IoGetTopLevelIrp() == NULL ); + + // + // This assert is overactive. There are cases which we cannot + // prevent which can cause it to fire (eg. we successfully + // sent a request down but failed on completion before being able + // to obtain/lock the handle context.) The effect of leaving + // this nonzero is that we will not clean up the handle and + // file object until the user's handle is closed. We are prepared + // to live with that (and the user could generate this condition + // herself by ceasing issuing queries before the query is fully + // complete.) + // + + FLT_ASSERT( Context->OutstandingRequests == 0 ); + + if (Context->RealHandle != NULL) { + + FltClose( Context->RealHandle ); + Context->RealHandle = NULL; + } + + if (Context->RealFileObject != NULL) { + + ObDereferenceObject( Context->RealFileObject ); + Context->RealFileObject = NULL; + } + + if (Context->BufferToFree != NULL) { + + ExFreePoolWithTag( Context->BufferToFree, NC_TAG ); + Context->BufferToFree = NULL; + Context->BufferSize = 0; + Context->CurrentEntry = 0; + } + + FLT_ASSERT( Context->BufferSize == 0 && Context->CurrentEntry == 0 ); + +} + +NTSTATUS +NcFindFilesBySidTranslateBuffers ( + _In_ PNC_INSTANCE_CONTEXT InstanceContext, + _In_ BOOLEAN IgnoreCase, + _In_ PUNICODE_STRING UserRequestName, + _In_ PUNICODE_STRING OpenedName, + _In_ PFILE_NAME_INFORMATION InputSystemBuffer, + _Out_writes_bytes_to_(OutputBufferLength, *OutputBufferWritten) PFILE_NAME_INFORMATION OutputUserBuffer, + _In_ ULONG InputBufferLength, + _In_ ULONG OutputBufferLength, + _Out_ PULONG InputBufferConsumed, + _Out_ PULONG OutputBufferWritten, + _In_ BOOLEAN ReturnRealMappingPaths + ) +/*++ + +Routine Description: + + This routine is used to transform buffers from a filesystem view to the + user view. Depending on flags we either replace references to the real + mapping with the user mapping or suppress all entries from the real + mapping. + +Arguments: + + InstanceContext - Pointer to the context describing this instance of the + filter. + + IgnoreCase - TRUE if comparisons should be case insensitive, FALSE if + comparisons should be case sensitive. + + UserRequestName - The string for the path that the user opened and is + finding child files by SID on. + + OpenedName - The string for the path that we are processing child files + on. "Typically" the same as UserRequestName, but may be different if + we are merging results from the user's handle with those of the + real mapping. In this case, OpenedName may refer to the path to + the real mapping. + + InputSystemBuffer - The buffer we are processing from. Note that this + routine assumes the buffer is not volatile (cannot be externally + modified.) For this reason, the buffer is expected to be system + buffered by the caller if it is not already. + + Note however that the contents of the buffer may have originated from + a user buffer (e.g. via a memcpy), so although the contents are non-volatile, + they are not to be trusted. + + OutputUserBuffer - The buffer we are returning munged results into. + This buffer is expected to have been probed, and this function will + catch and return any invalid buffer exceptions. + + InputBufferLength - Size, in bytes, of the input buffer. + + OutputBufferLength - Size, in bytes, of the output buffer. + + InputBufferConsumed - Pointer to a ULONG which will contain, on output, + the number of bytes processed from the input buffer. This may be + zero, the length of the input buffer, or any value in between. + This value is undefined on failure. + + OutputBufferWritten - Pointer to a ULONG which will contain, on output, + the number of bytes written into the output buffer. This may be + zero, the length of the output buffer, or any value in between. + This value is undefined on failure. + + ReturnRealMappingPaths - TRUE if this function should transform and + return any paths that are within the real mapping. If FALSE, we + omit these entries. + +Return Value: + + The return value is the Status of the operation. + +--*/ +{ + NTSTATUS Status = STATUS_SUCCESS; + NC_PATH_OVERLAP RealOverlap; + + // + // Pointers into the above buffers used as we read entries from + // one buffer and write them to the other. + // + + PFILE_NAME_INFORMATION SourceEntry = NULL; + PFILE_NAME_INFORMATION DestEntry = NULL; + + // + // The name of the object opened by the user; a full path to the path + // returned from the filesystem that we are currently examining; the + // Remainder of that path if it turns out to be in a mapping; the + // transformed name if one is required. + // + + UNICODE_STRING NameString = EMPTY_UNICODE_STRING; + UNICODE_STRING Remainder; + UNICODE_STRING MungedName = EMPTY_UNICODE_STRING; + + // + // A pointer to one of the above buffers that we intend on returning + // to the application. Note that this may be NULL if an entry is + // being suppressed. + // + + PUNICODE_STRING ReturnName; + ULONG EntryLength; + + ULONG UlongResult; + PVOID PointerResult; + + PAGED_CODE(); + + SourceEntry = InputSystemBuffer; + DestEntry = OutputUserBuffer; + *InputBufferConsumed = 0; + *OutputBufferWritten = 0; + + // + // This routine assumes it will only be called if there is work to do. + // + + FLT_ASSERT( InputBufferLength && OutputBufferLength ); + + try { + + while( SourceEntry ) { + + // + // The path returned is relative to the handle used to request + // the service. We now allocate and construct a full path name. + // Use safe math routines when consulting the buffer, since it is + // possible that the buffer contents were modified by malicious + // code before getting here. + // + + EntryLength = OpenedName->Length + + sizeof(WCHAR); + + if (EntryLength >= MAXUSHORT) { + + Status = STATUS_OBJECT_PATH_INVALID; + goto NcFindFilesBySidTranslateBuffersCleanup; + } + + Status = RtlULongAdd( EntryLength, + SourceEntry->FileNameLength, + &EntryLength ); + + if (!NT_SUCCESS( Status ) || + (EntryLength >= MAXUSHORT)) { + + Status = STATUS_OBJECT_PATH_INVALID; + goto NcFindFilesBySidTranslateBuffersCleanup; + } + + Status = RtlULongAdd( *InputBufferConsumed, + FIELD_OFFSET( FILE_NAME_INFORMATION, FileName ), + &UlongResult ); + + if (NT_SUCCESS( Status )) { + + Status = RtlULongAdd( UlongResult, + SourceEntry->FileNameLength, + &UlongResult ); + } + + if (!NT_SUCCESS( Status ) || + (UlongResult > InputBufferLength)) { + + // + // We have an entry that walks off the end of the buffer. + // Since the buffer that we get from the filesystem is not + // system buffered, we cannot guarantee that a caller is not + // corrupting it in an in-flight request. This condition + // should never occur without aforementioned corruption. + // + + FLT_ASSERT( FALSE ); + Status = STATUS_INVALID_USER_BUFFER; + goto NcFindFilesBySidTranslateBuffersCleanup; + + } + + if (EntryLength > NameString.MaximumLength) { + + if (NameString.Buffer != NULL) { + NcFreeUnicodeString( &NameString ); + } + + NameString.Buffer = ExAllocatePoolWithTag( PagedPool, + EntryLength, + NC_TAG ); + + if (NameString.Buffer == NULL) { + + Status = STATUS_INSUFFICIENT_RESOURCES; + goto NcFindFilesBySidTranslateBuffersCleanup; + } + + NameString.MaximumLength = (USHORT)EntryLength; + } + + _Analysis_assume_(NameString.Buffer != NULL); + RtlCopyMemory( NameString.Buffer, + OpenedName->Buffer, + OpenedName->Length ); + + NameString.Buffer[OpenedName->Length / sizeof(WCHAR)] = NC_SEPARATOR; + + RtlCopyMemory( Add2Ptr( NameString.Buffer, OpenedName->Length + sizeof(WCHAR) ), + SourceEntry->FileName, + SourceEntry->FileNameLength ); + + NameString.Length = (USHORT)EntryLength; + + // + // Now see if this name needs to be munged. + // + + NcComparePath( &NameString, + &InstanceContext->Mapping.RealMapping, + &Remainder, + IgnoreCase, + TRUE, + &RealOverlap ); + + if (RealOverlap.InMapping && ReturnRealMappingPaths) { + + // + // If the name is under the real mapping and we're returning + // paths under the real mapping, the query is a common + // ancestor of both real and user mappings. In this case, we + // need to translate real mapping paths to user mapping paths. + // + + Status = NcConstructPath( &InstanceContext->Mapping.UserMapping, + &Remainder, + TRUE, + &MungedName ); + + if (!NT_SUCCESS( Status )) { + goto NcFindFilesBySidTranslateBuffersCleanup; + } + + ReturnName = &MungedName; + + } else if (RealOverlap.InMapping) { + + // + // If the name is in the real mapping but the caller is asking + // for a tree which is not an ancestor of the user mapping, + // then this name should not be visible under this tree. + // + + ReturnName = NULL; + + } else { + + ReturnName = &NameString; + + } + + if (ReturnName != NULL) { + + // + // Since this API returns paths under the one the query was + // issued on, the path we have now had better be longer than + // that path length. Even if we refer to the same object, + // our path includes a trailing slash. + // + + FLT_ASSERT( ReturnName->Length > UserRequestName->Length ); + + // + // We take care not to copy the leading slash. If we have + // a trailing slash as well as a leading slash, truncate the + // string. This can occur when we're injecting an entry for + // the mapping. + // + + if (ReturnName->Length - UserRequestName->Length > sizeof(WCHAR) && + ReturnName->Buffer[ReturnName->Length/sizeof(WCHAR) - 1] == NC_SEPARATOR) { + + ReturnName->Length -= sizeof(WCHAR); + } + + EntryLength = AlignToSize( FIELD_OFFSET( FILE_NAME_INFORMATION, FileName ) + ReturnName->Length - UserRequestName->Length - sizeof(WCHAR), 8); + + // + // We've done all we can. Return now to let our caller deal + // with the remaining buffer. + // + + Status = RtlULongAdd( EntryLength, + *OutputBufferWritten, + &UlongResult ); + + if (!NT_SUCCESS( Status ) || + (UlongResult > OutputBufferLength)) { + + SourceEntry = NULL; + DestEntry = NULL; + break; + } + + // + // Copy the relative path name, taking care to exclude the + // initial slash. + // + + DestEntry->FileNameLength = ReturnName->Length - UserRequestName->Length - sizeof(WCHAR); + RtlCopyMemory( DestEntry->FileName, + Add2Ptr( ReturnName->Buffer, UserRequestName->Length + sizeof(WCHAR)), + ReturnName->Length - UserRequestName->Length - sizeof(WCHAR)); + + // + // Advance the destination that we're writing new entries by + // however much we just consumed. + // + + *OutputBufferWritten += EntryLength; + DestEntry = Add2Ptr( DestEntry, EntryLength ); + + if (MungedName.Buffer != NULL) { + ExFreePoolWithTag( MungedName.Buffer, NC_GENERATE_NAME_TAG ); + MungedName.Buffer = NULL; + } + } + + // + // Now calculate and advance the location we're reading and + // processing from. If we're have no more buffer left, we're + // done. + // + + EntryLength = AlignToSize( FIELD_OFFSET( FILE_NAME_INFORMATION, FileName ) + SourceEntry->FileNameLength, 8 ); + + PointerResult = Add2Ptr( SourceEntry, EntryLength ); + + Status = RtlULongAdd( *InputBufferConsumed, + EntryLength, + InputBufferConsumed ); + + // + // There's a problem if one of the following happened: + // + // 1) We overflowed when accounting for for consumed input buffer + // 2) We wrapped when advancing SourceEntry + // 3) PointerResult is not within InputSystemBuffer + // + + if (!NT_SUCCESS( Status ) || + (PointerResult < (PVOID)SourceEntry) || + (PointerResult < Add2Ptr( InputSystemBuffer, sizeof(FILE_NAME_INFORMATION) ))) { + + FLT_ASSERT( FALSE ); + + Status = STATUS_INVALID_USER_BUFFER; + goto NcFindFilesBySidTranslateBuffersCleanup; + } + + SourceEntry = (PFILE_NAME_INFORMATION)PointerResult; + + // + // If we've just advanced our next location beyond the end of the + // input buffer, or there isn't enough room in it for even a FILE_NAME_INFORMATION + // structure, terminate the loop by setting SourceEntry to NULL so + // we can at least return the valid entries we have. + // + + FLT_ASSERT( *InputBufferConsumed <= InputBufferLength ); + + if ((*InputBufferConsumed >= InputBufferLength) || + (*InputBufferConsumed + FIELD_OFFSET( FILE_NAME_INFORMATION, FileName ) > InputBufferLength)) { + + // + // Indicate to the caller that we consumed exactly the input buffer. + // Otherwise it may hold the possibly small remnant and come back + // in to this routine later with that remnant, causing us to overread + // the buffer. + // + + *InputBufferConsumed = InputBufferLength; + SourceEntry = NULL; + } + } + + } except (NcExceptionFilter( GetExceptionInformation(), TRUE )) { + + Status = STATUS_INVALID_USER_BUFFER; + } + +NcFindFilesBySidTranslateBuffersCleanup: + + if (MungedName.Buffer != NULL) { + + ExFreePoolWithTag( MungedName.Buffer, NC_GENERATE_NAME_TAG ); + } + + if (NameString.Buffer != NULL) { + + NcFreeUnicodeString( &NameString ); + } + + return Status; + +} + +FLT_PREOP_CALLBACK_STATUS +NcPreFindFilesBySid ( + _Inout_ PFLT_CALLBACK_DATA Data, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _Flt_CompletionContext_Outptr_ PVOID *CompletionContext + ) +/*++ + +Routine Description: + + Routine is invoked when the user wants to query files owned by + a particular SID under a subtree. For this call, we must return + paths relative to the user's handle. + + Implementationally, we have four cases: + + 1. If the handle is an ancestor or match of the real mapping, we may + need to remove entries. + + 2. If the handle is an ancestor or match of the user mapping, we may + need to insert entries. We implement this in two phases: first, + we enumerate all results under the user's handle; when complete, + we open a handle to the mapping and enumerate all results under + that. + + 3. If the handle is an ancestor of both, we may need to transform + entries. + + 4. If the handle is not an ancestor of either, we have no work to do. + + For cases 2 and 3, the size of the data may change. Since we can't + omit entries, we add those to a buffer, then return (and process) + entries from the buffer next time this function is invoked on the + handle. Only when we have nothing buffered do we continue sending + requests to the filesystem. + +Arguments: + + Data - Pointer to the filter CallbackData that is passed to us. + + FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure + containing opaque handles to this filter, instance, its + associated volume and file object. + + CompletionContext - The context for the completion routine for + this operation. We set this to the file object we are enumerating + under for find files by SID. + +Return Value: + + The return value is the Status of the operation. + +--*/ +{ + NTSTATUS Status; + FLT_PREOP_CALLBACK_STATUS ReturnValue = FLT_PREOP_SYNCHRONIZE; + NC_PATH_OVERLAP RealOverlap, UserOverlap; + PNC_INSTANCE_CONTEXT InstanceContext = NULL; + BOOLEAN IgnoreCase = !BooleanFlagOn( FltObjects->FileObject->Flags, + FO_OPENED_CASE_SENSITIVE ); + PFLT_FILE_NAME_INFORMATION FileInfo = NULL; + PFLT_FILE_NAME_INFORMATION FileInfoInternalHandle = NULL; + PNC_STREAM_HANDLE_CONTEXT HandleContext = NULL; + PNC_FIND_BY_SID_CONTEXT FindBySidCtx = NULL; + ULONG SizeWeReturn = 0; + BOOLEAN UnlockContext = FALSE; + + // + // The name of the object opened by the user, and the path of the object + // we're issuing queries on. These are typically the same, but will + // differ when we're injecting entries (user opens an ancestor of the + // user mapping, but we're sending queries to the real mapping.) + // + + UNICODE_STRING UserRequestName; + UNICODE_STRING OpenedName; + + PAGED_CODE(); + + FLT_ASSERT( IoGetTopLevelIrp() == NULL ); + + if (Data->Iopb->Parameters.FileSystemControl.Neither.OutputBufferLength < sizeof( FILE_NAME_INFORMATION )) { + + // + // This somewhat strange code is used to maintain parity with the + // filesystem. + // + + ReturnValue = FLT_PREOP_COMPLETE; + Status = STATUS_INVALID_USER_BUFFER; + goto NcPreFindFilesBySidCleanup; + } + + // + // Get our instance context. + // + + Status = FltGetInstanceContext( FltObjects->Instance, + &InstanceContext); + + if (!NT_SUCCESS( Status )) { + + ReturnValue = FLT_PREOP_COMPLETE; + goto NcPreFindFilesBySidCleanup; + } + + // + // Get the file's name. + // + + Status = NcGetFileNameInformation( Data, + NULL, + NULL, + FLT_FILE_NAME_OPENED | + FLT_FILE_NAME_QUERY_DEFAULT | + FLT_FILE_NAME_REQUEST_FROM_CURRENT_PROVIDER, + &FileInfo ); + + if (!NT_SUCCESS( Status )) { + + ReturnValue = FLT_PREOP_COMPLETE; + goto NcPreFindFilesBySidCleanup; + } + + Status = FltParseFileNameInformation( FileInfo ); + + if (!NT_SUCCESS( Status )) { + + ReturnValue = FLT_PREOP_COMPLETE; + goto NcPreFindFilesBySidCleanup; + } + + // + // If the path that was used for the query ends in a trailing slash + // (ie., the root directory), shave it off here. This keeps our logic + // simple, rather than dealing with this over and over. + // + + UserRequestName = FileInfo->Name; + FLT_ASSERT( UserRequestName.Length > 0 ); + if (UserRequestName.Buffer[UserRequestName.Length/sizeof(WCHAR) - 1] == NC_SEPARATOR) { + UserRequestName.Length -= sizeof(WCHAR); + } + + // + // As an optimization, check if the handle queried on is an ancestor of + // either mapping. Cases to consider: + // + // 1. If the handle is an ancestor or match of the real mapping, we may + // need to remove entries. + // + // 2. If the handle is an ancestor or match of the user mapping, we may + // need to insert entries. + // + // 3. If the handle is an ancestor of both, we may need to transform + // entries. + // + // 4. If the handle is not an ancestor of either, we have no work to + // do. As an optimization, we can stop now if this is the case. + // + + NcComparePath( &FileInfo->Name, + &InstanceContext->Mapping.UserMapping, + NULL, + IgnoreCase, + TRUE, + &UserOverlap ); + + NcComparePath( &FileInfo->Name, + &InstanceContext->Mapping.RealMapping, + NULL, + IgnoreCase, + TRUE, + &RealOverlap ); + + if (!(UserOverlap.Ancestor || RealOverlap.Ancestor)) { + + // + // In case 4 above, leave now. + // + + ReturnValue = FLT_PREOP_SUCCESS_NO_CALLBACK; + goto NcPreFindFilesBySidCleanup; + } + + Status = NcStreamHandleContextAllocAndAttach( FltObjects->Filter, + FltObjects->Instance, + FltObjects->FileObject, + &HandleContext ); + + if (!NT_SUCCESS( Status )) { + + ReturnValue = FLT_PREOP_COMPLETE; + goto NcPreFindFilesBySidCleanup; + } + + FLT_ASSERT( HandleContext != NULL ); + + NcLockStreamHandleContext( HandleContext ); + UnlockContext = TRUE; + + FindBySidCtx = &HandleContext->FindBySidContext; + + // + // Typically we query on the user's file object. We change file + // objects if the query is an ancestor of the mapping and we need to + // query the mapping itself. We will need to translate names when + // this happens. Since we cannot hold locks calling into the + // filesystem and don't want to drop locks during the calculation + // below, build a name for the mapping (pessimistically!) now. + // + // We only really need this if BufferToFree != NULL, but this may + // change as soon as we drop the lock. + // + + if (FindBySidCtx->RealFileObject == NULL) { + + OpenedName = UserRequestName; + + } else { + + PFILE_OBJECT RealFileObject = FindBySidCtx->RealFileObject; + + // + // Drop the lock. Note that there are two possibilities for the + // FileObject - it either refers to the mapping, or it is NULL to + // indicate that we do not need to process the mapping, are not + // yet processing the mapping, or we are done with the operation. + // + // In dropping the lock, it is possible that the FileObject to go + // to NULL. However, since we know it was non-NULL, the only + // possibility if this occurs is that we are done with the + // enumeration. + // + + ObReferenceObject( RealFileObject ); + NcUnlockStreamHandleContext( HandleContext ); + UnlockContext = FALSE; + + Status = NcGetFileNameInformation( NULL, + RealFileObject, + FltObjects->Instance, + FLT_FILE_NAME_OPENED | + FLT_FILE_NAME_QUERY_DEFAULT | + FLT_FILE_NAME_REQUEST_FROM_CURRENT_PROVIDER, + &FileInfoInternalHandle ); + + if (!NT_SUCCESS( Status )) { + + ObDereferenceObject( RealFileObject ); + goto NcPreFindFilesBySidCleanup; + } + + Status = FltParseFileNameInformation( FileInfoInternalHandle ); + + if (!NT_SUCCESS( Status )) { + + ObDereferenceObject( RealFileObject ); + goto NcPreFindFilesBySidCleanup; + } + + OpenedName = FileInfoInternalHandle->Name; + FLT_ASSERT( OpenedName.Length > 0 ); + if (OpenedName.Buffer[OpenedName.Length/sizeof(WCHAR) - 1] == NC_SEPARATOR) { + OpenedName.Length -= sizeof(WCHAR); + } + + // + // This may trigger a close, and must be done before we acquire the + // lock. + // + + ObDereferenceObject( RealFileObject ); + + // + // Now reacquire the lock so we can detect if we have a leftover + // buffer to munge and munge it safely. Check whether the + // enumeration is still ongoing or if we are already complete. + // + + NcLockStreamHandleContext( HandleContext ); + UnlockContext = TRUE; + + if (FindBySidCtx->RealFileObject == NULL) { + + FLT_ASSERT( FindBySidCtx->BufferToFree == NULL && + FindBySidCtx->OutstandingRequests == 0 ); + + ReturnValue = FLT_PREOP_COMPLETE; + Status = STATUS_SUCCESS; + SizeWeReturn = 0; + + goto NcPreFindFilesBySidCleanup; + } + } + + if (FindBySidCtx->BufferToFree != NULL) { + + // + // The user's buffer that we will be writing to + // + + PFILE_NAME_INFORMATION DestBuffer = Data->Iopb->Parameters.FileSystemControl.Neither.OutputBuffer; + ULONG BufferSize = Data->Iopb->Parameters.FileSystemControl.Neither.OutputBufferLength; + + ULONG InputConsumed; + + FLT_ASSERT( FindBySidCtx->BufferSize > 0 && + FindBySidCtx->CurrentEntry < FindBySidCtx->BufferSize ); + + // + // Whether we succeed or fail, we don't intend to let this request + // go to the filesystem if we have data that has not been returned + // yet. + // + + ReturnValue = FLT_PREOP_COMPLETE; + + // + // If a driver above us has posted the request, we may need to + // map a system buffer for the call from its Mdl. If not, we can + // use the user address passed in to the call. Be sure to check + // the "user" address really does point to user memory. + // + + if (Data->Iopb->Parameters.FileSystemControl.Neither.OutputMdlAddress != NULL) { + Status = FltLockUserBuffer( Data ); + + if (!NT_SUCCESS( Status )) { + + goto NcPreFindFilesBySidCleanup; + } + + DestBuffer = MmGetSystemAddressForMdlSafe( Data->Iopb->Parameters.FileSystemControl.Neither.OutputMdlAddress, + NormalPagePriority | MdlMappingNoExecute ); + + if (DestBuffer == NULL) { + + Status = STATUS_NO_MEMORY; + goto NcPreFindFilesBySidCleanup; + } + } else { + + try { + + if (Data->RequestorMode != KernelMode) { + ProbeForWrite( DestBuffer, BufferSize, sizeof( UCHAR )); + } + + } except (NcExceptionFilter( GetExceptionInformation(), TRUE )) { + + Status = STATUS_INVALID_USER_BUFFER; + } + + if (!NT_SUCCESS( Status )) { + + goto NcPreFindFilesBySidCleanup; + } + } + + // + // Translate the strings in the buffer by applying the parent's path + // (either the opened handle's path or the mapping's path), then + // change the mapping as necessary. + // + + Status = NcFindFilesBySidTranslateBuffers( InstanceContext, + IgnoreCase, + &UserRequestName, + &OpenedName, + Add2Ptr( FindBySidCtx->BufferToFree, FindBySidCtx->CurrentEntry ), + DestBuffer, + FindBySidCtx->BufferSize - FindBySidCtx->CurrentEntry, + BufferSize, + &InputConsumed, + &SizeWeReturn, + (BOOLEAN)UserOverlap.Ancestor ); + + if (!NT_SUCCESS( Status )) { + + goto NcPreFindFilesBySidCleanup; + } + + FindBySidCtx->CurrentEntry += InputConsumed; + FLT_ASSERT( FindBySidCtx->CurrentEntry <= FindBySidCtx->BufferSize ); + + if (FindBySidCtx->CurrentEntry >= FindBySidCtx->BufferSize) { + + // + // We've finished processing the leftover buffer. Tear it down + // now. Note that we will not attempt to call into the + // filesystem and fully pack the buffer; so long as we return + // something, that's good enough. + // + + ExFreePoolWithTag( FindBySidCtx->BufferToFree, NC_TAG ); + FindBySidCtx->BufferToFree = NULL; + FindBySidCtx->CurrentEntry = 0; + FindBySidCtx->BufferSize = 0; + } + + if (InputConsumed == 0) { + + FLT_ASSERT( SizeWeReturn == 0 ); + Status = STATUS_BUFFER_TOO_SMALL; + } + + } else if (FindBySidCtx->RealFileObject) { + + // + // We don't have a buffer, but we do have a file object to redirect + // to. This implies that we've finished reporting on the user's + // handle, and are now reporting on a redirected handle. For + // simplicity, switch the file objects used by this request and + // send it down. + // + + Data->Iopb->TargetFileObject = FindBySidCtx->RealFileObject; + FltSetCallbackDataDirty( Data ); + + // + // Pass a note back to ourselves about which file we're querying + // on. + // + + *CompletionContext = FindBySidCtx->RealFileObject; + + // + // If we're sending down this request to the filesystem, bump the + // outstanding request count. + // + + FLT_ASSERT( UnlockContext ); + FindBySidCtx->OutstandingRequests++; + + FLT_ASSERT( ReturnValue == FLT_PREOP_SYNCHRONIZE ); + + } else { + + // + // Pass a note back to ourselves about which file we're querying + // on. + // + + *CompletionContext = Data->Iopb->TargetFileObject; + + // + // If we're sending down this request to the filesystem, bump the + // outstanding request count. + // + + FLT_ASSERT( UnlockContext ); + FindBySidCtx->OutstandingRequests++; + + FLT_ASSERT( ReturnValue == FLT_PREOP_SYNCHRONIZE ); + + } + +NcPreFindFilesBySidCleanup: + + if (ReturnValue == FLT_PREOP_COMPLETE) { + + Data->IoStatus.Status = Status; + + if (NT_SUCCESS( Status )) { + + Data->IoStatus.Information = SizeWeReturn; + } else { + + Data->IoStatus.Information = 0; + } + } + + if (UnlockContext) { + + FLT_ASSERT( HandleContext != NULL ); + NcUnlockStreamHandleContext( HandleContext ); + + } + + if (FileInfo != NULL) { + + FltReleaseFileNameInformation( FileInfo ); + } + + if (FileInfoInternalHandle != NULL) { + + FltReleaseFileNameInformation( FileInfoInternalHandle ); + } + + if (HandleContext != NULL) { + + FltReleaseContext( HandleContext ); + } + + if (InstanceContext != NULL) { + + FltReleaseContext( InstanceContext ); + } + + return ReturnValue; +} + + + +FLT_POSTOP_CALLBACK_STATUS +NcPostFindFilesBySid ( + _Inout_ PFLT_CALLBACK_DATA Data, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _In_ PVOID CompletionContext, + _In_ FLT_POST_OPERATION_FLAGS Flags + ) +/*++ + +Routine Description: + + Routine is invoked when the user wants to query files owned by + a particular SID under a subtree. For this call, we must return + paths relative to the user's handle. + + This routine must consider the following three cases: + + 1. If the handle is an ancestor or match of the real mapping, we may + need to remove entries. + + 2. If the handle is an ancestor or match of the user mapping, we may + need to insert entries. We implement this in two phases: first, + we enumerate all results under the user's handle; when complete, + we open a handle to the mapping and enumerate all results under + that. + + 3. If the handle is an ancestor of both, we may need to transform + entries. + + Logically, we take the data returned from the filesystem (if any), + transform the buffers, and return it to the user. If we have more than + we can return, we add it to our leftover buffer. If we don't have any + data from the filesystem, we check if we have any data left over in the + leftover buffer, transform and return that. If we don't have any data + in the leftover buffer, we check if we need to enumerate from the + mapping handle (in number 2 above), and if so, open and query that, + transform the results, and return. If we've already done that and + still have no data, we close our handles, and return an empty buffer + to the caller, indicating the series of requests is complete. + +Arguments: + + Data - Pointer to the filter CallbackData that is passed to us. + + FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure + containing opaque handles to this filter, instance, its + associated volume and file object. + + CompletionContext - The context for the completion routine for + this operation. We set this to the file object we are enumerating + under for find files by SID. NcPreFindFilesBySid ensures that this + will never be NULL if the post-op is invoked. + + Flags - The flags for this operation. + +Return Value: + + The return value is the Status of the operation. + +--*/ +{ + PNC_INSTANCE_CONTEXT InstanceContext = NULL; + NTSTATUS Status; + BOOLEAN IgnoreCase = !BooleanFlagOn( FltObjects->FileObject->Flags, + FO_OPENED_CASE_SENSITIVE ); + PNC_STREAM_HANDLE_CONTEXT HandleContext = NULL; + PNC_FIND_BY_SID_CONTEXT FindBySidCtx = NULL; + PFLT_FILE_NAME_INFORMATION FileInfo = NULL; + PFLT_FILE_NAME_INFORMATION FileInfoInternalHandle = NULL; + + // + // The FileObject that this request was sent to. + // + + PFILE_OBJECT FileObject = (PFILE_OBJECT)CompletionContext; + + // + // The user's buffer that we will be writing to, and the system copy + // of the data returned by the file system which we will read from. + // + + PFILE_NAME_INFORMATION DestBuffer = Data->Iopb->Parameters.FileSystemControl.Neither.OutputBuffer; + PFILE_NAME_INFORMATION SourceBuffer = NULL; + ULONG SourceBufferSize; + + // + // The opened path's relation to the mappings. + // + + NC_PATH_OVERLAP RealOverlap; + NC_PATH_OVERLAP UserOverlap; + + // + // Size returned from the filesystem to us, size of the user's buffer + // that we can legitimately write to, the amount we actually wrote into + // the user's buffer, and the amount of the filesystem's buffer we have + // processed so far. + // + + ULONG SizeActuallyReturned = (ULONG)Data->IoStatus.Information; + ULONG BufferSize = Data->Iopb->Parameters.FileSystemControl.Neither.OutputBufferLength; + ULONG InputConsumed; + ULONG SizeWeReturn; + + // + // The name of the object opened by the user, and the path of the object + // we're issuing queries on. These are typically the same, but will + // differ when we're injecting entries (user opens an ancestor of the + // user mapping, but we're sending queries to the real mapping.) + // + + UNICODE_STRING UserRequestName; + UNICODE_STRING OpenedName; + + BOOLEAN InjectionRequired = FALSE; + BOOLEAN UnlockContext = FALSE; + + PAGED_CODE(); + + FLT_ASSERT( IoGetTopLevelIrp() == NULL ); + + // + // If the operation has already failed, we're not interested in attempting + // to process it. + // + + if (!NT_SUCCESS( Data->IoStatus.Status )) { + + Status = Data->IoStatus.Status; + goto NcPostFindFilesBySidCleanup; + } + + Status = FltGetInstanceContext( FltObjects->Instance, + &InstanceContext); + + if (!NT_SUCCESS( Status )) { + + goto NcPostFindFilesBySidCleanup; + } + + FLT_ASSERT( BufferSize >= SizeActuallyReturned ); + if (BufferSize < sizeof( FILE_NAME_INFORMATION )) { + + // + // This somewhat strange code is used to maintain parity with the + // filesystem. Note that we checked this in pre, so this check + // should be redundant. + // + + FLT_ASSERT( BufferSize >= sizeof( FILE_NAME_INFORMATION )); + Status = STATUS_INVALID_USER_BUFFER; + goto NcPostFindFilesBySidCleanup; + } + + // + // Get the file handle's name. Names returned via this FSCTL are + // relative to the handle used to obtain them. We will need to + // construct names by combining these values. + // + + Status = NcGetFileNameInformation( Data, + NULL, + NULL, + FLT_FILE_NAME_OPENED | + FLT_FILE_NAME_QUERY_DEFAULT | + FLT_FILE_NAME_REQUEST_FROM_CURRENT_PROVIDER, + &FileInfo ); + + if (!NT_SUCCESS( Status )) { + + goto NcPostFindFilesBySidCleanup; + } + + Status = FltParseFileNameInformation( FileInfo ); + + if (!NT_SUCCESS( Status )) { + + goto NcPostFindFilesBySidCleanup; + } + + // + // As an optimization, check if the handle queried on is an + // ancestor of either mapping. Cases to consider: + // + // 1. If the handle is an ancestor or match of the real + // mapping, we may need to remove entries. + // + // 2. If the handle is an ancestor or match of the user + // mapping, we may need to insert entries. + // + // 3. If the handle is an ancestor of both, we may need + // to transform entries. + // + // 4. If the handle is not an ancestor of either, we have + // no work to do. As an optimization, we can stop now + // if this is the case. + // + + NcComparePath( &FileInfo->Name, + &InstanceContext->Mapping.UserMapping, + NULL, + IgnoreCase, + TRUE, + &UserOverlap ); + + NcComparePath( &FileInfo->Name, + &InstanceContext->Mapping.RealMapping, + NULL, + IgnoreCase, + TRUE, + &RealOverlap ); + + if (!(UserOverlap.Ancestor || RealOverlap.Ancestor)) { + + // + // If we are not an ancestor, our post callback should + // not have been invoked. + // + + FLT_ASSERT( UserOverlap.Ancestor || RealOverlap.Ancestor ); + + // + // In case 4 above, leave now. + // + + Status = STATUS_SUCCESS; + goto NcPostFindFilesBySidCleanup; + } + + // + // If the path that was used for the query ends in a trailing slash + // (ie., the root directory), shave it off here. This keeps our logic + // simple, rather than dealing with this over and over. + // + + UserRequestName = FileInfo->Name; + FLT_ASSERT( UserRequestName.Length > 0 ); + if (UserRequestName.Buffer[UserRequestName.Length/sizeof(WCHAR) - 1] == NC_SEPARATOR) { + UserRequestName.Length -= sizeof(WCHAR); + } + + if (UserOverlap.Ancestor && !RealOverlap.Ancestor) { + + InjectionRequired = TRUE; + } + + Status = NcStreamHandleContextAllocAndAttach( FltObjects->Filter, + FltObjects->Instance, + FltObjects->FileObject, + &HandleContext ); + + if (!NT_SUCCESS( Status )) { + + goto NcPostFindFilesBySidCleanup; + } + + FLT_ASSERT( HandleContext != NULL ); + + NcLockStreamHandleContext( HandleContext ); + UnlockContext = TRUE; + + FindBySidCtx = &HandleContext->FindBySidContext; + + // + // If we're being notified of a filesystem completing a request, we'd + // better have seen it. + // + + FLT_ASSERT( FindBySidCtx->OutstandingRequests > 0 ); + + // + // If another driver has posted the request, we may need to map a + // system buffer for the call from its Mdl. If not, we can use the + // user address passed in to the call. Be sure to check the "user" + // address really does point to user memory. + // + + if (Data->Iopb->Parameters.FileSystemControl.Neither.OutputMdlAddress != NULL) { + Status = FltLockUserBuffer( Data ); + + if (!NT_SUCCESS( Status )) { + + goto NcPostFindFilesBySidCleanup; + } + + DestBuffer = MmGetSystemAddressForMdlSafe( Data->Iopb->Parameters.FileSystemControl.Neither.OutputMdlAddress, + NormalPagePriority | MdlMappingNoExecute ); + + if (DestBuffer == NULL) { + + Status = STATUS_NO_MEMORY; + goto NcPostFindFilesBySidCleanup; + } + + } else { + + try { + + if (Data->RequestorMode != KernelMode) { + ProbeForWrite( DestBuffer, BufferSize, sizeof( UCHAR )); + } + + } except (NcExceptionFilter( GetExceptionInformation(), TRUE )) { + + Status = STATUS_INVALID_USER_BUFFER; + } + + if (!NT_SUCCESS( Status )) { + + goto NcPostFindFilesBySidCleanup; + } + } + +NcPostFindFilesBySidMungeBuffer: + + // + // In the typical case, we're querying on the user's object. In that + // case, the name we're querying on is the same name that will be the + // basis for returned results. + // + + if (FileObject != FindBySidCtx->RealFileObject) { + + OpenedName = UserRequestName; + + } else { + + if (UnlockContext) { + NcUnlockStreamHandleContext( HandleContext ); + UnlockContext = FALSE; + } + + // + // We should query this only once, either because we just opened this + // object and are looping, or because it was previously set up and + // we do not loop. If we are looping, we did not reacquire the lock, + // and did not need to drop it above. + // + + FLT_ASSERT( FileInfoInternalHandle == NULL ); + + Status = NcGetFileNameInformation( NULL, + FindBySidCtx->RealFileObject, + FltObjects->Instance, + FLT_FILE_NAME_OPENED | + FLT_FILE_NAME_QUERY_DEFAULT | + FLT_FILE_NAME_REQUEST_FROM_CURRENT_PROVIDER, + &FileInfoInternalHandle ); + + if (!NT_SUCCESS( Status )) { + + goto NcPostFindFilesBySidCleanup; + } + + Status = FltParseFileNameInformation( FileInfoInternalHandle ); + + if (!NT_SUCCESS( Status )) { + + goto NcPostFindFilesBySidCleanup; + } + + OpenedName = FileInfoInternalHandle->Name; + FLT_ASSERT( OpenedName.Length > 0 ); + if (OpenedName.Buffer[OpenedName.Length/sizeof(WCHAR) - 1] == NC_SEPARATOR) { + OpenedName.Length -= sizeof(WCHAR); + } + + } + + if (!UnlockContext) { + NcLockStreamHandleContext( HandleContext ); + UnlockContext = TRUE; + } + + // + // If the filesystem returned something, go ahead and try to munge it. + // + + if (SizeActuallyReturned > sizeof( FILE_NAME_INFORMATION ) - sizeof(WCHAR)) { + + // + // Allocate a new buffer and copy the contents. Note that this is + // particularly important with this call, since it's not system + // buffered; the contents are free to change underneath us. This + // allocation protects us against that, but we still must be + // paranoid touching the buffer, since we cannot trust that it has + // any integrity at this point. + // + // Make sure we allocate enough space to deal with this request, + // plus any leftover buffer. If we don't process this entire buffer + // right now, we'll need to store our remnants with accumulated + // remnants. + // + // The #pragma is a notation to the static code analyzer to not worry + // that we're apparently leaking SourceBuffer. It gets put in to + // FindBySidCtx, which is a part of our stream handle context. When + // the stream handle context is eventually torn down this allocated + // memory will be freed. Naturally you must take care that on any + // paths where SourceBuffer doesn't make it in to the stream handle + // context you deallocate SourceBuffer before this routine exits. + // + + Status = RtlULongAdd( SizeActuallyReturned, + FindBySidCtx->BufferSize, + &SourceBufferSize ); + + if (NT_SUCCESS( Status )) { + + Status = RtlULongSub( SourceBufferSize, + FindBySidCtx->CurrentEntry, + &SourceBufferSize ); + } + + if (!NT_SUCCESS( Status )) { + + goto NcPostFindFilesBySidCleanup; + } + +#pragma warning(suppress: __WARNING_MEMORY_LEAK) + SourceBuffer = ExAllocatePoolWithTag( PagedPool, + SourceBufferSize, + NC_TAG ); + + if (SourceBuffer == NULL) { + + Status = STATUS_INSUFFICIENT_RESOURCES; + goto NcPostFindFilesBySidCleanup; + } + + try { + + RtlCopyMemory( SourceBuffer, DestBuffer, SizeActuallyReturned ); + + } except (NcExceptionFilter( GetExceptionInformation(), TRUE )) { + + Status = STATUS_INVALID_USER_BUFFER; + goto NcPostFindFilesBySidCleanup; + } + + Status = NcFindFilesBySidTranslateBuffers( InstanceContext, + IgnoreCase, + &UserRequestName, + &OpenedName, + SourceBuffer, + DestBuffer, + SizeActuallyReturned, + BufferSize, + &InputConsumed, + &SizeWeReturn, + (BOOLEAN)UserOverlap.Ancestor ); + + if (!NT_SUCCESS( Status )) { + + goto NcPostFindFilesBySidCleanup; + } + + if (InputConsumed == 0) { + FLT_ASSERT( SizeWeReturn == 0 ); + Status = STATUS_BUFFER_TOO_SMALL; + } + + if (InputConsumed < SizeActuallyReturned) { + + ULONG RemnantsSize = SizeActuallyReturned; + + // + // We have successfully processed a portion of the buffer, + // but more remains. Append any previously leftover portion + // of buffer to our own, and attach the combined remnants to + // our handle context for later processing. Importantly, + // don't free the buffer here. + // + + if (FindBySidCtx->BufferToFree != NULL) { + + RtlCopyMemory( Add2Ptr( SourceBuffer, SizeActuallyReturned ), + Add2Ptr( FindBySidCtx->BufferToFree, FindBySidCtx->CurrentEntry ), + FindBySidCtx->BufferSize - FindBySidCtx->CurrentEntry ); + + RemnantsSize += FindBySidCtx->BufferSize - FindBySidCtx->CurrentEntry; + + ExFreePoolWithTag( FindBySidCtx->BufferToFree, NC_TAG ); + + } + + FindBySidCtx->BufferToFree = SourceBuffer; + FindBySidCtx->BufferSize = RemnantsSize; + FindBySidCtx->CurrentEntry = InputConsumed; + + SourceBuffer = NULL; + } + + } else { + + // + // We have nothing from the filesystem. Now see what else we need + // to do: + // + // 1. If we have anything left in the buffer, return it now. This + // should be rare, but can happen with multiple async requests + // in different threads on the same handle. If we saw nothing + // in the buffer when this request started (in pre), but there + // is data now, another simultaneous request must have generated + // it. + // + // 2. If this request was sent to the mapping, we are done. Tear + // down mapping state if this is the final outstanding request. + // + // 3. If we need to return results from the mapping, we need to + // set up support for that now. It is important that we return + // all buffered results first, so that name translation is still + // accurate. + // + + FLT_ASSERT( SizeActuallyReturned == 0 ); + SizeWeReturn = 0; + + if (FindBySidCtx->BufferToFree != NULL) { + + // + // We need to clean up any outstanding buffer now. Normally + // this will happen in a pre operation, but we must return some + // data in order for the caller to call us again, and we can't + // set up or tear down the mapping or any existing data in the + // buffer will be returned with wrong names, since the root of + // the operation has changed. + // + + FLT_ASSERT( FindBySidCtx->BufferSize > 0 && + FindBySidCtx->CurrentEntry < FindBySidCtx->BufferSize ); + + // + // Translate the strings in the buffer by applying the parent's + // path, then change the mapping as necessary. + // + + Status = NcFindFilesBySidTranslateBuffers( InstanceContext, + IgnoreCase, + &UserRequestName, + &OpenedName, + Add2Ptr( FindBySidCtx->BufferToFree, FindBySidCtx->CurrentEntry ), + DestBuffer, + FindBySidCtx->BufferSize - FindBySidCtx->CurrentEntry, + BufferSize, + &InputConsumed, + &SizeWeReturn, + (BOOLEAN)UserOverlap.Ancestor ); + + if (!NT_SUCCESS( Status )) { + + goto NcPostFindFilesBySidCleanup; + } + + FindBySidCtx->CurrentEntry += InputConsumed; + FLT_ASSERT( FindBySidCtx->CurrentEntry <= FindBySidCtx->BufferSize ); + + if (FindBySidCtx->CurrentEntry >= FindBySidCtx->BufferSize) { + + // + // We've finished processing the leftover buffer. Tear it + // down now. Note that we will not attempt to call into + // the filesystem and fully pack the buffer; so long as we + // return something, that's good enough. + // + + ExFreePoolWithTag( FindBySidCtx->BufferToFree, NC_TAG ); + FindBySidCtx->BufferToFree = NULL; + FindBySidCtx->CurrentEntry = 0; + FindBySidCtx->BufferSize = 0; + + } + + if (InputConsumed == 0) { + + FLT_ASSERT( SizeWeReturn == 0 ); + Status = STATUS_BUFFER_TOO_SMALL; + } + + // + // As an optimization, we could set up the handle here. Doing + // so would save one trip to the filesystem, since the next + // request on this handle will go directly to the mapping. For + // simplicity, we skip this, so the next request will go to the + // filesystem (which will tell us it has nothing to say), and + // we'll perform the create, then retry the request. + // + + goto NcPostFindFilesBySidCleanup; + } + + if (FileObject == FindBySidCtx->RealFileObject) { + + // + // We've completed the request on the user's handle, and we've + // completed the request on the real handle. We are done. + // + // If this is the final outstanding request from the completed + // operation, start cleaning everything up. + // + + if (FindBySidCtx->OutstandingRequests == 1) { + + HANDLE HandleToClose = FindBySidCtx->RealHandle; + PFILE_OBJECT FileObjectToDereference = FindBySidCtx->RealFileObject; + + FindBySidCtx->RealHandle = NULL; + FindBySidCtx->RealFileObject = NULL; + + NcUnlockStreamHandleContext( HandleContext ); + UnlockContext = FALSE; + + FltClose( HandleToClose ); + ObDereferenceObject( FileObjectToDereference ); + } + + } else if (InjectionRequired) { + + OBJECT_ATTRIBUTES MappingAttributes; + HANDLE MappingHandle = NULL; + PFILE_OBJECT MappingFileObject = NULL; + IO_STATUS_BLOCK MappingStatusBlock; + + FLT_ASSERT( FindBySidCtx->RealFileObject == NULL ); + + // + // We have finished enumerating from the filesystem, and we + // need to enumerate from the mapping. At this point, the + // mapping has not been set up yet, so we do that now. + // + // Because we can't hold a lock doing this, we do so + // speculatively: two threads may end up doing this work, and + // one may be thrown away. + // + // Note that if two threads are racing, we should have an + // OutstandingRequests count of 2, so the result cannot be torn + // down by the other thread. + // + + FLT_ASSERT( FindBySidCtx->RealHandle == NULL ); + FLT_ASSERT( FindBySidCtx->OutstandingRequests > 0 ); + + NcUnlockStreamHandleContext( HandleContext ); + UnlockContext = FALSE; + + // + // Open the mapping. We're done returning data on the user's + // handle, but we still need to return data from the mapping. + // + + InitializeObjectAttributes( &MappingAttributes, + &InstanceContext->Mapping.RealMapping.LongNamePath.FullPath, + OBJ_KERNEL_HANDLE | (IgnoreCase?OBJ_CASE_INSENSITIVE:0), + NULL, + NULL); + + Status = NcCreateFileHelper( NcGlobalData.FilterHandle, // Filter + FltObjects->Instance, // Instance + &MappingHandle, // Returned Handle + &MappingFileObject, // Returned FileObject + FILE_READ_ATTRIBUTES|FILE_TRAVERSE, // Desired Access + &MappingAttributes, // object attributes + &MappingStatusBlock, // Returned IOStatusBlock + 0, // Allocation Size + FILE_ATTRIBUTE_NORMAL, // File Attributes + 0, // Share Access + FILE_OPEN, // Create Disposition + FILE_DIRECTORY_FILE, // Create Options + NULL, // Ea Buffer + 0, // EA Length + IO_IGNORE_SHARE_ACCESS_CHECK, // Flags + FltObjects->FileObject ); // Transaction info. + + if (!NT_SUCCESS( Status )) { + + if ( Status == STATUS_OBJECT_PATH_NOT_FOUND || + Status == STATUS_OBJECT_NAME_NOT_FOUND ) { + + Status = STATUS_SUCCESS; + } + goto NcPostFindFilesBySidCleanup; + } + + NcLockStreamHandleContext( HandleContext ); + UnlockContext = TRUE; + + if (FindBySidCtx->RealHandle == NULL) { + + // + // Store our object into the context. + // + + FindBySidCtx->RealHandle = MappingHandle; + FindBySidCtx->RealFileObject = MappingFileObject; + + NcUnlockStreamHandleContext( HandleContext ); + UnlockContext = FALSE; + + } else { + + // + // Another thread beat us to the punch. Tear down + // our state and reload from theirs. + // + + NcUnlockStreamHandleContext( HandleContext ); + UnlockContext = FALSE; + + FltClose( MappingHandle ); + ObDereferenceObject( MappingFileObject ); + } + + MappingHandle = NULL; + MappingFileObject = NULL; + + FileObject = FindBySidCtx->RealFileObject; + + Status = FltFsControlFile( FltObjects->Instance, + FindBySidCtx->RealFileObject, + FSCTL_FIND_FILES_BY_SID, + Data->Iopb->Parameters.FileSystemControl.Neither.InputBuffer, + Data->Iopb->Parameters.FileSystemControl.Neither.InputBufferLength, + Data->Iopb->Parameters.FileSystemControl.Neither.OutputBuffer, + Data->Iopb->Parameters.FileSystemControl.Neither.OutputBufferLength, + &SizeActuallyReturned ); + + if (!NT_SUCCESS( Status )) { + + goto NcPostFindFilesBySidCleanup; + } + + goto NcPostFindFilesBySidMungeBuffer; + + } + } + + Data->IoStatus.Information = SizeWeReturn; + +NcPostFindFilesBySidCleanup: + + if (SourceBuffer != NULL) { + + ExFreePoolWithTag( SourceBuffer, NC_TAG ); + } + + // + // If this function is being called, we were counted as an outstanding + // request. If we made it far enough to have our handle context, we + // can un-count ourselves now. If we failed before that, we remain + // counted, and cleanup occurs when the handle is closed. + // + + FLT_ASSERT( FindBySidCtx != NULL ); + if (FindBySidCtx != NULL) { + FLT_ASSERT( HandleContext != NULL ); + + if (!UnlockContext) { + NcLockStreamHandleContext( HandleContext ); + UnlockContext = TRUE; + } + + FLT_ASSERT( FindBySidCtx->OutstandingRequests > 0 ); + FindBySidCtx->OutstandingRequests--; + } + + if (UnlockContext) { + + FLT_ASSERT( HandleContext != NULL ); + NcUnlockStreamHandleContext( HandleContext ); + } + + if (FileInfo != NULL) { + + FltReleaseFileNameInformation( FileInfo ); + } + + if (FileInfoInternalHandle != NULL) { + + FltReleaseFileNameInformation( FileInfoInternalHandle ); + } + + if (HandleContext != NULL) { + + FltReleaseContext( HandleContext ); + } + + if (InstanceContext != NULL) { + + FltReleaseContext( InstanceContext ); + } + + if (!NT_SUCCESS( Status )) { + Data->IoStatus.Status = Status; + Data->IoStatus.Information = 0; + } + + UNREFERENCED_PARAMETER( Flags ); + + return FLT_POSTOP_FINISHED_PROCESSING; + +} + +#if FLT_MGR_WIN7 +FLT_POSTOP_CALLBACK_STATUS +NcPostLookupStreamFromCluster ( + _Inout_ PFLT_CALLBACK_DATA Data, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _In_opt_ PVOID CompletionContext, + _In_ FLT_POST_OPERATION_FLAGS Flags + ) +/*++ + +Routine Description: + + Routine is invoked when the user wants to find a stream owning + a particular cluster. For this call, paths are absolute relative to + the start of the volume. + + Note that this call is system buffered. This means we don't need + to process MDLs, or perform probes, or treat our input data as + suspect. + + All we need to do is walk through the returned data, change names that + refer to the mappings, and return the result. Since the lengths may + change, we may return fewer entries, but will still tell the caller + the number of entries that actually exist and the size of the buffer + to obtain all of them. + +Arguments: + + Data - Pointer to the filter CallbackData that is passed to us. + + FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure + containing opaque handles to this filter, instance, its + associated volume and file object. + + CompletionContext - The context for the completion routine for + this operation. + + Flags - The flags for this operation. + +Return Value: + + The return value is the Status of the operation. + +--*/ +{ + PLOOKUP_STREAM_FROM_CLUSTER_OUTPUT DestBuffer = Data->Iopb->Parameters.FileSystemControl.Buffered.SystemBuffer; + PLOOKUP_STREAM_FROM_CLUSTER_ENTRY SourceEntry = NULL; + PLOOKUP_STREAM_FROM_CLUSTER_ENTRY DestEntry = NULL; + PLOOKUP_STREAM_FROM_CLUSTER_ENTRY PrevDestEntry = NULL; + PNC_INSTANCE_CONTEXT InstanceContext = NULL; + NTSTATUS Status; + NC_PATH_OVERLAP Overlap; + ULONG SizeActuallyReturned = (ULONG)Data->IoStatus.Information; + ULONG BufferSize = Data->Iopb->Parameters.FileSystemControl.Buffered.OutputBufferLength; + ULONG EntryLength; + BOOLEAN IgnoreCase = !BooleanFlagOn( FltObjects->FileObject->Flags, + FO_OPENED_CASE_SENSITIVE ); + PLOOKUP_STREAM_FROM_CLUSTER_OUTPUT SourceBuffer = NULL; + UNICODE_STRING NameString; + UNICODE_STRING Remainder; + + PAGED_CODE(); + + FLT_ASSERT( IoGetTopLevelIrp() == NULL ); + + // + // If the operation has already failed, we're not interested in attempting + // to process it. + // + + if (!NT_SUCCESS( Data->IoStatus.Status ) || SizeActuallyReturned == 0) { + + Status = Data->IoStatus.Status; + goto NcPostLookupStreamFromClusterCleanup; + } + + Status = FltGetInstanceContext( FltObjects->Instance, + &InstanceContext); + + if (!NT_SUCCESS( Status )) { + + goto NcPostLookupStreamFromClusterCleanup; + } + + if (BufferSize < sizeof( LOOKUP_STREAM_FROM_CLUSTER_OUTPUT )) { + + Status = STATUS_INVALID_PARAMETER; + goto NcPostLookupStreamFromClusterCleanup; + } + + // + // We take a copy of the buffer so that we can re-write the request's + // buffer with our modified data. + // + + SourceBuffer = ExAllocatePoolWithTag( PagedPool, + SizeActuallyReturned, + NC_TAG ); + + if (SourceBuffer == NULL) { + + Status = STATUS_INSUFFICIENT_RESOURCES; + goto NcPostLookupStreamFromClusterCleanup; + } + + RtlCopyMemory( SourceBuffer, DestBuffer, SizeActuallyReturned ); + + // + // We initialize this for the first entry. If we don't actually + // copy an entry, it is re-zeroed later. + // + + DestBuffer->Offset = AlignToSize( sizeof( LOOKUP_STREAM_FROM_CLUSTER_OUTPUT ), 8); + DestBuffer->NumberOfMatches = 0; + DestBuffer->BufferSizeRequired = AlignToSize( sizeof( LOOKUP_STREAM_FROM_CLUSTER_OUTPUT ), 8); + + // + // Since this is a buffered FSCTL, we treat the output buffer + // as well formed data. This enables us to make a few assumptions. + // Firstly, we don't expect to walk off the end of the allocation. + // It follows that at least for now, both source and destination + // have the same offsets. + // + + if (SourceBuffer->Offset > 0) { + SourceEntry = Add2Ptr( SourceBuffer, SourceBuffer->Offset ); + DestEntry = Add2Ptr( DestBuffer, SourceBuffer->Offset ); + } + + while (SourceEntry) { + + RtlInitUnicodeString( &NameString, SourceEntry->FileName ); + + // + // Check if the path refers to a location within the real side of + // the mapping. If it does, translate the data to the user side + // of the mapping. + // + + NcComparePath( &NameString, + &InstanceContext->Mapping.RealMapping, + &Remainder, + IgnoreCase, + FALSE, + &Overlap ); + + if (Overlap.InMapping) { + + Status = NcConstructPath( &InstanceContext->Mapping.UserMapping, + &Remainder, + FALSE, + &NameString ); + + if (!NT_SUCCESS( Status )) { + goto NcPostLookupStreamFromClusterCleanup; + } + } + + // + // Note that we're not allowing for NULL, because the structure + // already includes one WCHAR. + // + + EntryLength = AlignToSize( sizeof( LOOKUP_STREAM_FROM_CLUSTER_ENTRY ) + + NameString.Length, 8 ); + + // + // If it fits, copy the data into the returned entry, and advance + // to the next entry to return. + // + + if (DestBuffer->BufferSizeRequired + EntryLength <= BufferSize) { + + DestEntry->Flags = SourceEntry->Flags; + DestEntry->Reserved = SourceEntry->Reserved; + DestEntry->Cluster = SourceEntry->Cluster; + RtlCopyMemory( DestEntry->FileName, + NameString.Buffer, + NameString.Length ); + + DestEntry->FileName[ NameString.Length / sizeof(WCHAR)] = L'\0'; + + DestEntry->OffsetToNext = EntryLength; + + PrevDestEntry = DestEntry; + DestEntry = Add2Ptr( DestEntry, DestEntry->OffsetToNext ); + } + + // + // If we needed to munge the name, we allocated pool to store the + // result. Free that pool now. + // + + if (Overlap.InMapping) { + ExFreePoolWithTag( NameString.Buffer, NC_GENERATE_NAME_TAG ); + } + + // + // We must keep track of the required buffer size and number of + // matches regardless of whether it is returned. + // + + DestBuffer->BufferSizeRequired += EntryLength; + DestBuffer->NumberOfMatches++; + + // + // Advance to the next source entry. We assume our input is + // well formed, and therefore, we do not expect to walk off the + // end of this buffer. + // + + if (SourceEntry->OffsetToNext > 0) { + SourceEntry = Add2Ptr( SourceEntry, SourceEntry->OffsetToNext ); + } else { + SourceEntry = NULL; + } + } + + if (PrevDestEntry) { + PrevDestEntry->OffsetToNext = 0; + } else { + DestBuffer->Offset = 0; + } + + Data->IoStatus.Information = min( DestBuffer->BufferSizeRequired, BufferSize ); + + // + // Since this filter may change the length of names returned, we may + // also change the layout and bytes required. We will not, however, + // change the number of matches; this value refers to the total number + // that exist, not the number that can fit in the buffer. + // + + FLT_ASSERT( DestBuffer->NumberOfMatches == SourceBuffer->NumberOfMatches ); + +NcPostLookupStreamFromClusterCleanup: + + if (SourceBuffer != NULL) { + + ExFreePoolWithTag( SourceBuffer, NC_TAG ); + } + + if (InstanceContext != NULL) { + + FltReleaseContext( InstanceContext ); + } + + if (!NT_SUCCESS( Status )) { + Data->IoStatus.Status = Status; + Data->IoStatus.Information = 0; + } + + UNREFERENCED_PARAMETER( CompletionContext ); + UNREFERENCED_PARAMETER( Flags ); + + return FLT_POSTOP_FINISHED_PROCESSING; + +} +#endif + +NTSTATUS +NcUsnTranslateBuffers ( + _In_ PNC_INSTANCE_CONTEXT InstanceContext, + _In_ BOOLEAN IgnoreCase, + _In_ ULONGLONG RealMappingParentId, + _In_ ULONGLONG UserMappingParentId, + _In_ PUSN_RECORD InputSystemBuffer, + _Out_writes_bytes_to_(OutputBufferLength, *OutputBufferWritten) PUSN_RECORD OutputUserBuffer, + _In_ ULONG InputBufferLength, + _In_ ULONG OutputBufferLength, + _Out_ PULONG InputBufferConsumed, + _Out_ PULONG OutputBufferWritten + ) +/*++ + +Routine Description: + + This routine is used to transform buffers from a filesystem view to the + user view. We must replace both the parent ID and link name of any + records referring to the real mapping with corresponding values for the + user mapping. + +Arguments: + + InstanceContext - Pointer to the context describing this instance of the + filter. + + IgnoreCase - TRUE if comparisons should be case insensitive, FALSE if + comparisons should be case sensitive. TODO: Is this required? + + RealMappingParentId - The file ID corresponding to the real mapping + parent. + + UserMappingParentId - The file ID corresponding to the user mapping + parent. + + InputSystemBuffer - The buffer we are processing from. Note that this + routine assumes the buffer is not volatile (cannot be externally + modified.) For this reason, the buffer is expected to be system + buffered by the caller if it is not already. + + Note however that the contents of the buffer may have originated from + a user buffer (via a memcpy), so although the contents are non-volatile, + they are not to be trusted. + + OutputUserBuffer - The buffer we are returning munged results into. + This buffer is expected to have been probed, and this function will + catch and return any invalid buffer exceptions. + + InputBufferLength - Size, in bytes, of the input buffer. + + OutputBufferLength - Size, in bytes, of the output buffer. + + InputBufferConsumed - Pointer to a ULONG which will contain, on output, + the number of bytes processed from the input buffer. This may be + zero, the length of the input buffer, or any value in between. + This value is undefined on failure. + + OutputBufferWritten - Pointer to a ULONG which will contain, on output, + the number of bytes written into the output buffer. This may be + zero, the length of the output buffer, or any value in between. + This value is undefined on failure. + +Return Value: + + The return value is the Status of the operation. + +--*/ +{ + NTSTATUS Status = STATUS_SUCCESS; + + // + // Pointers into the above buffers used as we read entries from + // one buffer and write them to the other. + // + + PUSN_RECORD SourceEntry = NULL; + PUSN_RECORD DestEntry = NULL; + + // + // Points to a new name if we are required to substitute names for + // this record. If no substitution is required, it is NULL. + // + + PUNICODE_STRING NewLink; + + // + // The length of this record, in bytes. We use this field to refer + // to source and destination records at different times. + // + + ULONG EntryLength; + + ULONG UlongResult; + PVOID PointerResult; + + PAGED_CODE(); + + SourceEntry = InputSystemBuffer; + DestEntry = OutputUserBuffer; + *InputBufferConsumed = 0; + *OutputBufferWritten = 0; + + // + // This routine assumes it will only be called if there is work to do. + // + + FLT_ASSERT( InputBufferLength && OutputBufferLength ); + + try { + + while (SourceEntry) { + + // + // Assume we're not transforming any records, which is the + // common case. + // + + NewLink = NULL; + + // + // If we're about to walk off the end of the buffer, get out + // now. This should only happen if the user has modified the + // buffer after it was returned from the filesystem and before + // we had a chance to copy it. + // + // Firstly check we have enough space for a record, and having + // established that we have enough space to read the first few + // bytes containing the record length, check against that. Use + // safe math routines for the untrusted SourceEntry values. + // + + Status = RtlULongAdd( *InputBufferConsumed, + sizeof(USN_RECORD), + &UlongResult ); + + if (!NT_SUCCESS( Status ) || + (UlongResult > InputBufferLength)) { + + goto FailedBufferCheck; + } + + Status = RtlULongAdd( *InputBufferConsumed, + SourceEntry->RecordLength, + &UlongResult ); + + if (!NT_SUCCESS( Status ) || + (UlongResult > InputBufferLength)) { + + goto FailedBufferCheck; + } + + Status = RtlULongAdd( *InputBufferConsumed, + SourceEntry->FileNameOffset, + &UlongResult ); + + if (NT_SUCCESS( Status )) { + + Status = RtlULongAdd( UlongResult, + SourceEntry->FileNameLength, + &UlongResult ); + } + + if (!NT_SUCCESS( Status ) || + (UlongResult > InputBufferLength) || + (SourceEntry->FileNameOffset < FIELD_OFFSET( USN_RECORD, FileName ))) { + +FailedBufferCheck: + FLT_ASSERT( FALSE ); + SourceEntry = NULL; + Status = STATUS_INVALID_USER_BUFFER; + break; + } + + // + // Assume that the destination record will be the same size as + // the source record. Note that SourceEntry->RecordLength is untrusted, + // so now EntryLength is. + // + + EntryLength = SourceEntry->RecordLength; + + // + // We have encountered a USN record with an incompatible + // version. In theory, MinorVersion changes are compatible, + // MajorVersion changes are not. In practice, a MinorVersion + // change could include offsets to additional data which we have + // no knowledge of, so we can never be sure that we're not + // returning corrupt records on a MinorVersion change. Rather + // than do that, we just give up. + // + + if (SourceEntry->MajorVersion != 2 || + SourceEntry->MinorVersion != 0) { + + SourceEntry = NULL; + Status = STATUS_NOT_IMPLEMENTED; + break; + } + + // + // Check if this is a record we need to transform. If so, adjust + // the length of the destination record appropriately, and record + // which name we should transform to. + // + + if (SourceEntry->ParentFileReferenceNumber == RealMappingParentId && + (SourceEntry->FileNameLength == InstanceContext->Mapping.RealMapping.LongNamePath.FinalComponentName.Length || + SourceEntry->FileNameLength == InstanceContext->Mapping.RealMapping.ShortNamePath.FinalComponentName.Length)) { + + UNICODE_STRING TempString; + + TempString.Buffer = Add2Ptr( SourceEntry, SourceEntry->FileNameOffset ); + TempString.Length = TempString.MaximumLength = SourceEntry->FileNameLength; + + if (RtlCompareUnicodeString( &TempString, + &InstanceContext->Mapping.RealMapping.LongNamePath.FinalComponentName, + IgnoreCase ) == 0) { + + NewLink = &InstanceContext->Mapping.UserMapping.LongNamePath.FinalComponentName; + + } else + if (RtlCompareUnicodeString( &TempString, + &InstanceContext->Mapping.RealMapping.ShortNamePath.FinalComponentName, + IgnoreCase ) == 0) { + + NewLink = &InstanceContext->Mapping.UserMapping.LongNamePath.FinalComponentName; + + } + + if (NewLink != NULL) { + + EntryLength = AlignToSize( SourceEntry->FileNameOffset + NewLink->Length, 8 ); + } + } + + // + // If the current entry would overflow the remaining output buffer + // then we've done all we can. Return now to let our caller deal + // with the remaining buffer. + // + + Status = RtlULongAdd( EntryLength, + *OutputBufferWritten, + &UlongResult ); + + if (!NT_SUCCESS( Status ) || + (UlongResult > OutputBufferLength)) { + + break; + } + + // + // If we're not transforming (the common case) copy the entire + // record blindly from source to destination. If we are + // transforming, copy the record, switch the file ID, then + // copy the name. + // + + if (NewLink == NULL) { + + RtlCopyMemory( DestEntry, + SourceEntry, + EntryLength ); + + } else { + + + // + // Copy all of the record up to the file name offset. This + // is the most resilient approach to a minor version change + // which adds new fields. We will preserve the minor + // version number, and preserve the fields in this process. + // Note that this is a moot exercise here, since we are + // failing on unknown minor versions above. + // + + RtlCopyMemory( DestEntry, + SourceEntry, + SourceEntry->FileNameOffset ); + + DestEntry->ParentFileReferenceNumber = UserMappingParentId; + + DestEntry->FileNameLength = NewLink->Length; + DestEntry->FileNameOffset = FIELD_OFFSET( USN_RECORD, FileName ); + DestEntry->RecordLength = EntryLength; + + // + // Since the DestBuffer is user-exposed, we cannot trust + // its contents immediately after writing them. Here, we + // calculate the file offset from the source entry because + // that is system buffered. + // + + RtlCopyMemory( Add2Ptr( DestEntry, SourceEntry->FileNameOffset ), + NewLink->Buffer, + NewLink->Length ); + } + + Status = RtlULongAdd( *InputBufferConsumed, + SourceEntry->RecordLength, + InputBufferConsumed ); + + PointerResult = Add2Ptr( SourceEntry, SourceEntry->RecordLength ); + + // + // There's a problem if one of the following happened: + // + // 1) We overflowed when accounting for for consumed input buffer + // 2) We wrapped when advancing SourceEntry + // 3) PointerResult is not within InputSystemBuffer + // + + if (!NT_SUCCESS( Status ) || + (PointerResult < (PVOID)SourceEntry) || + (PointerResult < Add2Ptr( InputSystemBuffer, sizeof(USN_RECORD) ))) { + + FLT_ASSERT( FALSE ); + + Status = STATUS_INVALID_USER_BUFFER; + break; + } + + // + // We verified earlier that adding EntryLength to *OutputBufferWritten + // would not overflow our output buffer, meaning advancing DestEntry + // by EntryLength bytes is also safe. + // + + *OutputBufferWritten += EntryLength; + + DestEntry = Add2Ptr( DestEntry, EntryLength ); + + SourceEntry = (PUSN_RECORD)PointerResult; + + // + // If we've just advanced our next location beyond the end of the + // input buffer, or there isn't enough room in it for even a USN_RECORD + // structure, terminate the loop by setting SourceEntry to NULL so + // we can at least return the valid entries we have. + // + + FLT_ASSERT( *InputBufferConsumed <= InputBufferLength ); + + if ((*InputBufferConsumed >= InputBufferLength) || + (*InputBufferConsumed + FIELD_OFFSET( USN_RECORD, FileName ) > InputBufferLength)) { + + // + // Indicate to the caller that we consumed exactly the input buffer. + // Otherwise it may hold the possibly small remnant and come back + // in to this routine later with that remnant, causing us to overread + // the buffer. + // + + *InputBufferConsumed = InputBufferLength; + SourceEntry = NULL; + } + } + + } except (NcExceptionFilter( GetExceptionInformation(), TRUE )) { + + Status = STATUS_INVALID_USER_BUFFER; + } + + return Status; +} + +FLT_POSTOP_CALLBACK_STATUS +NcPostReadFileUsnData ( + _Inout_ PFLT_CALLBACK_DATA Data, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _In_opt_ PVOID CompletionContext, + _In_ FLT_POST_OPERATION_FLAGS Flags + ) +/*++ + +Routine Description: + + +Arguments: + + Data - Pointer to the filter CallbackData that is passed to us. + + FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure + containing opaque handles to this filter, instance, its + associated volume and file object. + + CompletionContext - The context for the completion routine for + this operation. We set this to the file object we are enumerating + under for find files by SID. + + Flags - The flags for this operation. + +Return Value: + + The return value is the Status of the operation. + +--*/ +{ + PNC_INSTANCE_CONTEXT InstanceContext = NULL; + NTSTATUS Status; + BOOLEAN IgnoreCase = !BooleanFlagOn( FltObjects->FileObject->Flags, + FO_OPENED_CASE_SENSITIVE ); + PFLT_FILE_NAME_INFORMATION FileInfo = NULL; + + // + // The user's buffer that we will be writing to, and the system copy + // of the data returned by the file system which we will read from. + // + + PUSN_RECORD DestBuffer = Data->Iopb->Parameters.FileSystemControl.Neither.OutputBuffer; + PUSN_RECORD SourceBuffer = NULL; + + // + // The opened path's relation to the mappings. + // + + NC_PATH_OVERLAP UserOverlap; + + // + // Size returned from the filesystem to us, size of the user's buffer + // that we can legitimately write to, the amount we actually wrote into + // the user's buffer, and the amount of the filesystem's buffer we have + // processed so far. + // + + ULONG SizeActuallyReturned = (ULONG)Data->IoStatus.Information; + ULONG BufferSize = Data->Iopb->Parameters.FileSystemControl.Neither.OutputBufferLength; + ULONG InputConsumed; + ULONG SizeWeReturn; + + // + // File IDs corresponding to the parent of the user mapping, and + // parent of the real mapping. + // + + ULONGLONG RealMappingParentId; + ULONGLONG UserMappingParentId; + + OBJECT_ATTRIBUTES MappingParentAttributes; + HANDLE MappingParentHandle = NULL; + PFILE_OBJECT MappingParentFileObject = NULL; + IO_STATUS_BLOCK MappingParentStatusBlock; + + UNREFERENCED_PARAMETER( CompletionContext ); + + PAGED_CODE(); + + FLT_ASSERT( IoGetTopLevelIrp() == NULL ); + + // + // If the operation has already failed, we're not interested in attempting + // to process it. + // + + if (!NT_SUCCESS( Data->IoStatus.Status )) { + + Status = Data->IoStatus.Status; + goto NcPostReadFileUsnDataCleanup; + } + + Status = FltGetInstanceContext( FltObjects->Instance, + &InstanceContext); + + if (!NT_SUCCESS( Status )) { + + goto NcPostReadFileUsnDataCleanup; + } + + FLT_ASSERT( BufferSize >= SizeActuallyReturned ); + if (BufferSize < sizeof( USN_RECORD ) || + SizeActuallyReturned < sizeof( USN_RECORD )) { + + Status = STATUS_BUFFER_TOO_SMALL; + goto NcPostReadFileUsnDataCleanup; + } + + // + // Get the file handle's name. We are only interested in + // processing calls destined to the mapping. + // + + Status = NcGetFileNameInformation( Data, + NULL, + NULL, + FLT_FILE_NAME_OPENED | + FLT_FILE_NAME_QUERY_DEFAULT | + FLT_FILE_NAME_REQUEST_FROM_CURRENT_PROVIDER, + &FileInfo ); + + if (!NT_SUCCESS( Status )) { + + goto NcPostReadFileUsnDataCleanup; + } + + Status = FltParseFileNameInformation( FileInfo ); + + if (!NT_SUCCESS( Status )) { + + goto NcPostReadFileUsnDataCleanup; + } + + NcComparePath( &FileInfo->Name, + &InstanceContext->Mapping.UserMapping, + NULL, + IgnoreCase, + TRUE, + &UserOverlap ); + + if (!UserOverlap.Match) { + + Status = STATUS_SUCCESS; + goto NcPostReadFileUsnDataCleanup; + } + + // + // If another driver has posted the request, we may need to map a + // system buffer for the call from its Mdl. If not, we can use the + // user address passed in to the call. Be sure to check the "user" + // address really does point to user memory. + // + + if (Data->Iopb->Parameters.FileSystemControl.Neither.OutputMdlAddress != NULL) { + Status = FltLockUserBuffer( Data ); + + if (!NT_SUCCESS( Status )) { + + goto NcPostReadFileUsnDataCleanup; + } + + DestBuffer = MmGetSystemAddressForMdlSafe( Data->Iopb->Parameters.FileSystemControl.Neither.OutputMdlAddress, + NormalPagePriority | MdlMappingNoExecute ); + + if (DestBuffer == NULL) { + + Status = STATUS_NO_MEMORY; + goto NcPostReadFileUsnDataCleanup; + } + + } else { + + try { + + if (Data->RequestorMode != KernelMode) { + ProbeForWrite( DestBuffer, BufferSize, sizeof( UCHAR )); + } + + } except (NcExceptionFilter( GetExceptionInformation(), TRUE )) { + + Status = STATUS_INVALID_USER_BUFFER; + } + + if (!NT_SUCCESS( Status )) { + + goto NcPostReadFileUsnDataCleanup; + } + } + + // + // Open the mapping parents and query IDs. + // + + InitializeObjectAttributes( &MappingParentAttributes, + &InstanceContext->Mapping.RealMapping.LongNamePath.ParentPath, + OBJ_KERNEL_HANDLE | (IgnoreCase?OBJ_CASE_INSENSITIVE:0), + NULL, + NULL); + + Status = NcCreateFileHelper( NcGlobalData.FilterHandle, // Filter + FltObjects->Instance, // Instance + &MappingParentHandle, // Returned Handle + &MappingParentFileObject, // Returned FileObject + FILE_READ_ATTRIBUTES|FILE_TRAVERSE, // Desired Access + &MappingParentAttributes, // object attributes + &MappingParentStatusBlock, // Returned IOStatusBlock + 0, // Allocation Size + FILE_ATTRIBUTE_NORMAL, // File Attributes + 0, // Share Access + FILE_OPEN, // Create Disposition + FILE_DIRECTORY_FILE, // Create Options + NULL, // Ea Buffer + 0, // EA Length + IO_IGNORE_SHARE_ACCESS_CHECK, // Flags + FltObjects->FileObject ); // Transaction info. + + if (!NT_SUCCESS( Status )) { + + FLT_ASSERT( Status != STATUS_OBJECT_PATH_NOT_FOUND && + Status != STATUS_OBJECT_NAME_NOT_FOUND ); + + goto NcPostReadFileUsnDataCleanup; + } + + Status = FltQueryInformationFile( FltObjects->Instance, + MappingParentFileObject, + &RealMappingParentId, + sizeof(RealMappingParentId), + FileInternalInformation, + NULL ); + + if (!NT_SUCCESS( Status )) { + + goto NcPostReadFileUsnDataCleanup; + } + + FltClose( MappingParentHandle ); + ObDereferenceObject( MappingParentFileObject ); + + MappingParentHandle = NULL; + MappingParentFileObject = NULL; + + InitializeObjectAttributes( &MappingParentAttributes, + &InstanceContext->Mapping.UserMapping.LongNamePath.ParentPath, + OBJ_KERNEL_HANDLE | (IgnoreCase?OBJ_CASE_INSENSITIVE:0), + NULL, + NULL); + + Status = NcCreateFileHelper( NcGlobalData.FilterHandle, // Filter + FltObjects->Instance, // Instance + &MappingParentHandle, // Returned Handle + &MappingParentFileObject, // Returned FileObject + FILE_READ_ATTRIBUTES|FILE_TRAVERSE, // Desired Access + &MappingParentAttributes, // object attributes + &MappingParentStatusBlock, // Returned IOStatusBlock + 0, // Allocation Size + FILE_ATTRIBUTE_NORMAL, // File Attributes + 0, // Share Access + FILE_OPEN, // Create Disposition + FILE_DIRECTORY_FILE, // Create Options + NULL, // Ea Buffer + 0, // EA Length + IO_IGNORE_SHARE_ACCESS_CHECK, // Flags + FltObjects->FileObject ); // Transaction info. + + if (!NT_SUCCESS( Status )) { + + FLT_ASSERT( Status != STATUS_OBJECT_PATH_NOT_FOUND && + Status != STATUS_OBJECT_NAME_NOT_FOUND ); + + goto NcPostReadFileUsnDataCleanup; + } + + Status = FltQueryInformationFile( FltObjects->Instance, + MappingParentFileObject, + &UserMappingParentId, + sizeof(UserMappingParentId), + FileInternalInformation, + NULL ); + + if (!NT_SUCCESS( Status )) { + + goto NcPostReadFileUsnDataCleanup; + } + + FltClose( MappingParentHandle ); + ObDereferenceObject( MappingParentFileObject ); + + MappingParentHandle = NULL; + MappingParentFileObject = NULL; + + // + // Allocate a new buffer and copy the contents. Note that this is + // particularly important with this call, since it's not system + // buffered; the contents are free to change underneath us. This + // allocation protects us against that, but we still must be + // paranoid touching the buffer, since we cannot trust that it has + // any integrity at this point. + // + + SourceBuffer = ExAllocatePoolWithTag( PagedPool, + SizeActuallyReturned, + NC_TAG ); + + if (SourceBuffer == NULL) { + + Status = STATUS_INSUFFICIENT_RESOURCES; + goto NcPostReadFileUsnDataCleanup; + } + + try { + + RtlCopyMemory( SourceBuffer, DestBuffer, SizeActuallyReturned ); + + } except (NcExceptionFilter( GetExceptionInformation(), TRUE )) { + + Status = STATUS_INVALID_USER_BUFFER; + goto NcPostReadFileUsnDataCleanup; + } + + Status = NcUsnTranslateBuffers( InstanceContext, + IgnoreCase, + RealMappingParentId, + UserMappingParentId, + SourceBuffer, + DestBuffer, + SizeActuallyReturned, + BufferSize, + &InputConsumed, + &SizeWeReturn ); + + if (!NT_SUCCESS( Status )) { + + goto NcPostReadFileUsnDataCleanup; + } + + if (InputConsumed == 0) { + FLT_ASSERT( SizeWeReturn == 0 ); + Status = STATUS_BUFFER_TOO_SMALL; + } + + FLT_ASSERT( InputConsumed == SizeActuallyReturned ); + + Data->IoStatus.Information = SizeWeReturn; + +NcPostReadFileUsnDataCleanup: + + if (SourceBuffer != NULL) { + + ExFreePoolWithTag( SourceBuffer, NC_TAG ); + } + + if (FileInfo != NULL) { + + FltReleaseFileNameInformation( FileInfo ); + } + + if (MappingParentHandle != NULL) { + + FltClose( MappingParentHandle ); + } + + if (MappingParentFileObject != NULL) { + + ObDereferenceObject( MappingParentFileObject ); + } + + if (InstanceContext != NULL) { + + FltReleaseContext( InstanceContext ); + } + + if (!NT_SUCCESS( Status )) { + Data->IoStatus.Status = Status; + Data->IoStatus.Information = 0; + } + + UNREFERENCED_PARAMETER( Flags ); + + return FLT_POSTOP_FINISHED_PROCESSING; + +} + + +FLT_POSTOP_CALLBACK_STATUS +NcPostEnumUsnData ( + _Inout_ PFLT_CALLBACK_DATA Data, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _In_opt_ PVOID CompletionContext, + _In_ FLT_POST_OPERATION_FLAGS Flags + ) +/*++ + +Routine Description: + + +Arguments: + + Data - Pointer to the filter CallbackData that is passed to us. + + FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure + containing opaque handles to this filter, instance, its + associated volume and file object. + + CompletionContext - The context for the completion routine for + this operation. We set this to the file object we are enumerating + under for find files by SID. + + Flags - The flags for this operation. + +Return Value: + + The return value is the Status of the operation. + +--*/ +{ + PNC_INSTANCE_CONTEXT InstanceContext = NULL; + NTSTATUS Status; + BOOLEAN IgnoreCase = !BooleanFlagOn( FltObjects->FileObject->Flags, + FO_OPENED_CASE_SENSITIVE ); + + // + // The user's buffer that we will be writing to, and the system copy + // of the data returned by the file system which we will read from. + // + + PUSN_RECORD DestBuffer = Data->Iopb->Parameters.FileSystemControl.Neither.OutputBuffer; + PUSN_RECORD SourceBuffer = NULL; + + // + // Size returned from the filesystem to us, size of the user's buffer + // that we can legitimately write to, the amount we actually wrote into + // the user's buffer, and the amount of the filesystem's buffer we have + // processed so far. + // + + ULONG SizeActuallyReturned = (ULONG)Data->IoStatus.Information; + ULONG BufferSize = Data->Iopb->Parameters.FileSystemControl.Neither.OutputBufferLength; + ULONG InputConsumed; + ULONG SizeWeReturn; + + // + // File IDs corresponding to the parent of the user mapping, and + // parent of the real mapping. + // + + ULONGLONG RealMappingParentId; + ULONGLONG UserMappingParentId; + + OBJECT_ATTRIBUTES MappingParentAttributes; + HANDLE MappingParentHandle = NULL; + PFILE_OBJECT MappingParentFileObject = NULL; + IO_STATUS_BLOCK MappingParentStatusBlock; + + UNREFERENCED_PARAMETER( CompletionContext ); + + PAGED_CODE(); + + FLT_ASSERT( IoGetTopLevelIrp() == NULL ); + + // + // If the operation has already failed, we're not interested in attempting + // to process it. + // + + if (!NT_SUCCESS( Data->IoStatus.Status )) { + + Status = Data->IoStatus.Status; + goto NcPostEnumUsnDataCleanup; + } + + Status = FltGetInstanceContext( FltObjects->Instance, + &InstanceContext); + + if (!NT_SUCCESS( Status )) { + + goto NcPostEnumUsnDataCleanup; + } + + FLT_ASSERT( BufferSize >= SizeActuallyReturned ); + if (BufferSize < sizeof( USN_RECORD ) || + SizeActuallyReturned < sizeof( USN_RECORD )) { + + Status = STATUS_BUFFER_TOO_SMALL; + goto NcPostEnumUsnDataCleanup; + } + + // + // If another driver has posted the request, we may need to map a + // system buffer for the call from its Mdl. If not, we can use the + // user address passed in to the call. Be sure to check the "user" + // address really does point to user memory. + // + + if (Data->Iopb->Parameters.FileSystemControl.Neither.OutputMdlAddress != NULL) { + Status = FltLockUserBuffer( Data ); + + if (!NT_SUCCESS( Status )) { + + goto NcPostEnumUsnDataCleanup; + } + + DestBuffer = MmGetSystemAddressForMdlSafe( Data->Iopb->Parameters.FileSystemControl.Neither.OutputMdlAddress, + NormalPagePriority | MdlMappingNoExecute ); + + if (DestBuffer == NULL) { + + Status = STATUS_NO_MEMORY; + goto NcPostEnumUsnDataCleanup; + } + + } else { + + try { + + if (Data->RequestorMode != KernelMode) { + ProbeForWrite( DestBuffer, BufferSize, sizeof( UCHAR )); + } + + } except (NcExceptionFilter( GetExceptionInformation(), TRUE )) { + + Status = STATUS_INVALID_USER_BUFFER; + } + + if (!NT_SUCCESS( Status )) { + + goto NcPostEnumUsnDataCleanup; + } + } + + // + // Open the mapping parents and query IDs. + // + + InitializeObjectAttributes( &MappingParentAttributes, + &InstanceContext->Mapping.RealMapping.LongNamePath.ParentPath, + OBJ_KERNEL_HANDLE | (IgnoreCase?OBJ_CASE_INSENSITIVE:0), + NULL, + NULL); + + Status = NcCreateFileHelper( NcGlobalData.FilterHandle, // Filter + FltObjects->Instance, // Instance + &MappingParentHandle, // Returned Handle + &MappingParentFileObject, // Returned FileObject + FILE_READ_ATTRIBUTES|FILE_TRAVERSE, // Desired Access + &MappingParentAttributes, // object attributes + &MappingParentStatusBlock, // Returned IOStatusBlock + 0, // Allocation Size + FILE_ATTRIBUTE_NORMAL, // File Attributes + 0, // Share Access + FILE_OPEN, // Create Disposition + FILE_DIRECTORY_FILE, // Create Options + NULL, // Ea Buffer + 0, // EA Length + IO_IGNORE_SHARE_ACCESS_CHECK, // Flags + FltObjects->FileObject ); // Transaction info. + + if (!NT_SUCCESS( Status )) { + + FLT_ASSERT( Status != STATUS_OBJECT_PATH_NOT_FOUND && + Status != STATUS_OBJECT_NAME_NOT_FOUND ); + + goto NcPostEnumUsnDataCleanup; + } + + Status = FltQueryInformationFile( FltObjects->Instance, + MappingParentFileObject, + &RealMappingParentId, + sizeof(RealMappingParentId), + FileInternalInformation, + NULL ); + + if (!NT_SUCCESS( Status )) { + + goto NcPostEnumUsnDataCleanup; + } + + FltClose( MappingParentHandle ); + ObDereferenceObject( MappingParentFileObject ); + + MappingParentHandle = NULL; + MappingParentFileObject = NULL; + + InitializeObjectAttributes( &MappingParentAttributes, + &InstanceContext->Mapping.UserMapping.LongNamePath.ParentPath, + OBJ_KERNEL_HANDLE | (IgnoreCase?OBJ_CASE_INSENSITIVE:0), + NULL, + NULL); + + Status = NcCreateFileHelper( NcGlobalData.FilterHandle, // Filter + FltObjects->Instance, // Instance + &MappingParentHandle, // Returned Handle + &MappingParentFileObject, // Returned FileObject + FILE_READ_ATTRIBUTES|FILE_TRAVERSE, // Desired Access + &MappingParentAttributes, // object attributes + &MappingParentStatusBlock, // Returned IOStatusBlock + 0, // Allocation Size + FILE_ATTRIBUTE_NORMAL, // File Attributes + 0, // Share Access + FILE_OPEN, // Create Disposition + FILE_DIRECTORY_FILE, // Create Options + NULL, // Ea Buffer + 0, // EA Length + IO_IGNORE_SHARE_ACCESS_CHECK, // Flags + FltObjects->FileObject ); // Transaction info. + + if (!NT_SUCCESS( Status )) { + + FLT_ASSERT( Status != STATUS_OBJECT_PATH_NOT_FOUND && + Status != STATUS_OBJECT_NAME_NOT_FOUND ); + + goto NcPostEnumUsnDataCleanup; + } + + Status = FltQueryInformationFile( FltObjects->Instance, + MappingParentFileObject, + &UserMappingParentId, + sizeof(UserMappingParentId), + FileInternalInformation, + NULL ); + + if (!NT_SUCCESS( Status )) { + + goto NcPostEnumUsnDataCleanup; + } + + FltClose( MappingParentHandle ); + ObDereferenceObject( MappingParentFileObject ); + + MappingParentHandle = NULL; + MappingParentFileObject = NULL; + + // + // Allocate a new buffer and copy the contents. Note that this is + // particularly important with this call, since it's not system + // buffered; the contents are free to change underneath us. This + // allocation protects us against that, but we still must be + // paranoid touching the buffer, since we cannot trust that it has + // any integrity at this point. + // + + SourceBuffer = ExAllocatePoolWithTag( PagedPool, + SizeActuallyReturned, + NC_TAG ); + + if (SourceBuffer == NULL) { + + Status = STATUS_INSUFFICIENT_RESOURCES; + goto NcPostEnumUsnDataCleanup; + } + + try { + + RtlCopyMemory( SourceBuffer, DestBuffer, SizeActuallyReturned ); + + } except (NcExceptionFilter( GetExceptionInformation(), TRUE )) { + + Status = STATUS_INVALID_USER_BUFFER; + goto NcPostEnumUsnDataCleanup; + } + + Status = NcUsnTranslateBuffers( InstanceContext, + IgnoreCase, + RealMappingParentId, + UserMappingParentId, + Add2Ptr( SourceBuffer, sizeof(USN) ), + Add2Ptr( DestBuffer, sizeof(USN) ), + SizeActuallyReturned - sizeof(USN), + BufferSize - sizeof(USN), + &InputConsumed, + &SizeWeReturn ); + + if (!NT_SUCCESS( Status )) { + + goto NcPostEnumUsnDataCleanup; + } + + if (InputConsumed == 0) { + FLT_ASSERT( SizeWeReturn == 0 ); + Status = STATUS_BUFFER_TOO_SMALL; + } + + FLT_ASSERT( InputConsumed == SizeActuallyReturned - sizeof( USN )); + + Data->IoStatus.Information = SizeWeReturn + sizeof(USN); + +NcPostEnumUsnDataCleanup: + + if (SourceBuffer != NULL) { + + ExFreePoolWithTag( SourceBuffer, NC_TAG ); + } + + if (MappingParentHandle != NULL) { + + FltClose( MappingParentHandle ); + } + + if (MappingParentFileObject != NULL) { + + ObDereferenceObject( MappingParentFileObject ); + } + + if (InstanceContext != NULL) { + + FltReleaseContext( InstanceContext ); + } + + if (!NT_SUCCESS( Status )) { + Data->IoStatus.Status = Status; + Data->IoStatus.Information = 0; + } + + UNREFERENCED_PARAMETER( Flags ); + + return FLT_POSTOP_FINISHED_PROCESSING; + +} + +VOID +NcPostReadUsnJournalWorker ( + _In_ PFLT_GENERIC_WORKITEM WorkItem, + _In_ PFLT_FILTER Filter, + _In_ PVOID Context + ) +/*++ + +Routine Description: + + +Arguments: + + Data - Pointer to the filter CallbackData that is passed to us. + + FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure + containing opaque handles to this filter, instance, its + associated volume and file object. + + CompletionContext - The context for the completion routine for + this operation. We set this to the file object we are enumerating + under for find files by SID. + + Flags - The flags for this operation. + +Return Value: + + The return value is the Status of the operation. + +--*/ +{ + PFLT_CALLBACK_DATA Data = (PFLT_CALLBACK_DATA)Context; + PNC_INSTANCE_CONTEXT InstanceContext = NULL; + NTSTATUS Status; + BOOLEAN IgnoreCase = !BooleanFlagOn( Data->Iopb->TargetFileObject->Flags, + FO_OPENED_CASE_SENSITIVE ); + + // + // The user's buffer that we will be writing to, and the system copy + // of the data returned by the file system which we will read from. + // + + PUSN_RECORD DestBuffer = Data->Iopb->Parameters.FileSystemControl.Neither.OutputBuffer; + PUSN_RECORD SourceBuffer = NULL; + + // + // Size returned from the filesystem to us, size of the user's buffer + // that we can legitimately write to, the amount we actually wrote into + // the user's buffer, and the amount of the filesystem's buffer we have + // processed so far. + // + + ULONG SizeActuallyReturned = (ULONG)Data->IoStatus.Information; + ULONG BufferSize = Data->Iopb->Parameters.FileSystemControl.Neither.OutputBufferLength; + ULONG InputConsumed; + ULONG SizeWeReturn; + + // + // File IDs corresponding to the parent of the user mapping, and + // parent of the real mapping. + // + + ULONGLONG RealMappingParentId; + ULONGLONG UserMappingParentId; + + OBJECT_ATTRIBUTES MappingParentAttributes; + HANDLE MappingParentHandle = NULL; + PFILE_OBJECT MappingParentFileObject = NULL; + IO_STATUS_BLOCK MappingParentStatusBlock; + + PAGED_CODE(); + + FLT_ASSERT( IoGetTopLevelIrp() == NULL ); + + // + // If the operation has already failed, we're not interested in attempting + // to process it. + // + + if (!NT_SUCCESS( Data->IoStatus.Status )) { + + Status = Data->IoStatus.Status; + goto NcPostReadUsnJournalSafeCleanup; + } + + Status = FltGetInstanceContext( Data->Iopb->TargetInstance, + &InstanceContext); + + if (!NT_SUCCESS( Status )) { + + goto NcPostReadUsnJournalSafeCleanup; + } + + FLT_ASSERT( BufferSize >= SizeActuallyReturned ); + if (BufferSize < sizeof( USN_RECORD ) + sizeof( USN )|| + SizeActuallyReturned < sizeof( USN_RECORD ) + sizeof( USN )) { + + Status = STATUS_BUFFER_TOO_SMALL; + goto NcPostReadUsnJournalSafeCleanup; + } + + // + // We always post this request. In future, we may skip this post + // in some conditions, but for now, OutputMdlAddress had better + // be valid. + // + + FLT_ASSERT( Data->Iopb->Parameters.FileSystemControl.Neither.OutputMdlAddress != NULL ); + if (Data->Iopb->Parameters.FileSystemControl.Neither.OutputMdlAddress != NULL) { + Status = FltLockUserBuffer( Data ); + + if (!NT_SUCCESS( Status )) { + + goto NcPostReadUsnJournalSafeCleanup; + } + + DestBuffer = MmGetSystemAddressForMdlSafe( Data->Iopb->Parameters.FileSystemControl.Neither.OutputMdlAddress, + NormalPagePriority | MdlMappingNoExecute ); + + if (DestBuffer == NULL) { + + Status = STATUS_NO_MEMORY; + goto NcPostReadUsnJournalSafeCleanup; + } + + } else { + + try { + + if (Data->RequestorMode != KernelMode) { + ProbeForWrite( DestBuffer, BufferSize, sizeof( UCHAR )); + } + + } except (NcExceptionFilter( GetExceptionInformation(), TRUE )) { + + Status = STATUS_INVALID_USER_BUFFER; + } + + if (!NT_SUCCESS( Status )) { + + goto NcPostReadUsnJournalSafeCleanup; + } + } + + // + // Open the mapping parents and query IDs. + // + + InitializeObjectAttributes( &MappingParentAttributes, + &InstanceContext->Mapping.RealMapping.LongNamePath.ParentPath, + OBJ_KERNEL_HANDLE | (IgnoreCase?OBJ_CASE_INSENSITIVE:0), + NULL, + NULL); + + Status = NcCreateFileHelper( NcGlobalData.FilterHandle, // Filter + Data->Iopb->TargetInstance, // Instance + &MappingParentHandle, // Returned Handle + &MappingParentFileObject, // Returned FileObject + FILE_READ_ATTRIBUTES|FILE_TRAVERSE, // Desired Access + &MappingParentAttributes, // object attributes + &MappingParentStatusBlock, // Returned IOStatusBlock + 0, // Allocation Size + FILE_ATTRIBUTE_NORMAL, // File Attributes + 0, // Share Access + FILE_OPEN, // Create Disposition + FILE_DIRECTORY_FILE, // Create Options + NULL, // Ea Buffer + 0, // EA Length + IO_IGNORE_SHARE_ACCESS_CHECK, // Flags + Data->Iopb->TargetFileObject ); // Transaction info. + + if (!NT_SUCCESS( Status )) { + + FLT_ASSERT( Status != STATUS_OBJECT_PATH_NOT_FOUND && + Status != STATUS_OBJECT_NAME_NOT_FOUND ); + + goto NcPostReadUsnJournalSafeCleanup; + } + + Status = FltQueryInformationFile( Data->Iopb->TargetInstance, + MappingParentFileObject, + &RealMappingParentId, + sizeof(RealMappingParentId), + FileInternalInformation, + NULL ); + + if (!NT_SUCCESS( Status )) { + + goto NcPostReadUsnJournalSafeCleanup; + } + + FltClose( MappingParentHandle ); + ObDereferenceObject( MappingParentFileObject ); + + MappingParentHandle = NULL; + MappingParentFileObject = NULL; + + InitializeObjectAttributes( &MappingParentAttributes, + &InstanceContext->Mapping.UserMapping.LongNamePath.ParentPath, + OBJ_KERNEL_HANDLE | (IgnoreCase?OBJ_CASE_INSENSITIVE:0), + NULL, + NULL); + + Status = NcCreateFileHelper( NcGlobalData.FilterHandle, // Filter + Data->Iopb->TargetInstance, // Instance + &MappingParentHandle, // Returned Handle + &MappingParentFileObject, // Returned FileObject + FILE_READ_ATTRIBUTES|FILE_TRAVERSE, // Desired Access + &MappingParentAttributes, // object attributes + &MappingParentStatusBlock, // Returned IOStatusBlock + 0, // Allocation Size + FILE_ATTRIBUTE_NORMAL, // File Attributes + 0, // Share Access + FILE_OPEN, // Create Disposition + FILE_DIRECTORY_FILE, // Create Options + NULL, // Ea Buffer + 0, // EA Length + IO_IGNORE_SHARE_ACCESS_CHECK, // Flags + Data->Iopb->TargetFileObject ); // Transaction info. + + if (!NT_SUCCESS( Status )) { + + FLT_ASSERT( Status != STATUS_OBJECT_PATH_NOT_FOUND && + Status != STATUS_OBJECT_NAME_NOT_FOUND ); + + goto NcPostReadUsnJournalSafeCleanup; + } + + Status = FltQueryInformationFile( Data->Iopb->TargetInstance, + MappingParentFileObject, + &UserMappingParentId, + sizeof(UserMappingParentId), + FileInternalInformation, + NULL ); + + if (!NT_SUCCESS( Status )) { + + goto NcPostReadUsnJournalSafeCleanup; + } + + FltClose( MappingParentHandle ); + ObDereferenceObject( MappingParentFileObject ); + + MappingParentHandle = NULL; + MappingParentFileObject = NULL; + + // + // Allocate a new buffer and copy the contents. Note that this is + // particularly important with this call, since it's not system + // buffered; the contents are free to change underneath us. This + // allocation protects us against that, but we still must be + // paranoid touching the buffer, since we cannot trust that it has + // any integrity at this point. + // + + SourceBuffer = ExAllocatePoolWithTag( PagedPool, + SizeActuallyReturned, + NC_TAG ); + + if (SourceBuffer == NULL) { + + Status = STATUS_INSUFFICIENT_RESOURCES; + goto NcPostReadUsnJournalSafeCleanup; + } + + try { + + RtlCopyMemory( SourceBuffer, DestBuffer, SizeActuallyReturned ); + + } except (NcExceptionFilter( GetExceptionInformation(), TRUE )) { + + Status = STATUS_INVALID_USER_BUFFER; + goto NcPostReadUsnJournalSafeCleanup; + } + + Status = NcUsnTranslateBuffers( InstanceContext, + IgnoreCase, + RealMappingParentId, + UserMappingParentId, + Add2Ptr( SourceBuffer, sizeof(USN) ), + Add2Ptr( DestBuffer, sizeof(USN) ), + SizeActuallyReturned - sizeof(USN), + BufferSize - sizeof(USN), + &InputConsumed, + &SizeWeReturn ); + + if (!NT_SUCCESS( Status )) { + + goto NcPostReadUsnJournalSafeCleanup; + } + + if (InputConsumed == 0) { + FLT_ASSERT( SizeWeReturn == 0 ); + Status = STATUS_BUFFER_TOO_SMALL; + } + + FLT_ASSERT( InputConsumed == SizeActuallyReturned - sizeof( USN )); + + Data->IoStatus.Information = SizeWeReturn + sizeof(USN); + +NcPostReadUsnJournalSafeCleanup: + + if (SourceBuffer != NULL) { + + ExFreePoolWithTag( SourceBuffer, NC_TAG ); + } + + if (MappingParentHandle != NULL) { + + FltClose( MappingParentHandle ); + } + + if (MappingParentFileObject != NULL) { + + ObDereferenceObject( MappingParentFileObject ); + } + + if (InstanceContext != NULL) { + + FltReleaseContext( InstanceContext ); + } + + if (!NT_SUCCESS( Status )) { + Data->IoStatus.Status = Status; + Data->IoStatus.Information = 0; + } + + FltCompletePendedPostOperation( Data ); + + FltFreeGenericWorkItem( WorkItem ); + + UNREFERENCED_PARAMETER( Filter ); + +} + +FLT_POSTOP_CALLBACK_STATUS +NcPostReadUsnJournal ( + _Inout_ PFLT_CALLBACK_DATA Data, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _In_opt_ PVOID CompletionContext, + _In_ FLT_POST_OPERATION_FLAGS Flags + ) +{ + NTSTATUS Status; + PFLT_GENERIC_WORKITEM WorkItem; + + // + // Lock the user's buffer so we can post this request. + // + + Status = FltLockUserBuffer( Data ); + if (!NT_SUCCESS( Status )) { + + Data->IoStatus.Status = Status; + Data->IoStatus.Information = 0; + return FLT_POSTOP_FINISHED_PROCESSING; + } + + // + // Allocate a workitem and post. At this point, we will typically + // have TopLevelIrp set (along with filesystem locks.) We don't want + // to issue creates back into the filesystem from here. Note that + // we can get away with this because the filesystem will not wait - + // it has completed this request, and will go on from here. + // + + WorkItem = FltAllocateGenericWorkItem(); + + if (WorkItem == NULL) { + + Data->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; + Data->IoStatus.Information = 0; + return FLT_POSTOP_FINISHED_PROCESSING; + } + + Status = FltQueueGenericWorkItem( WorkItem, + Data->Iopb->TargetInstance, + NcPostReadUsnJournalWorker, + CriticalWorkQueue, + Data ); + + if (!NT_SUCCESS( Status )) { + + Data->IoStatus.Status = Status; + Data->IoStatus.Information = 0; + return FLT_POSTOP_FINISHED_PROCESSING; + } + + return FLT_POSTOP_MORE_PROCESSING_REQUIRED; + + UNREFERENCED_PARAMETER( FltObjects ); + UNREFERENCED_PARAMETER( CompletionContext ); + UNREFERENCED_PARAMETER( Flags ); +} + diff --git a/filesys/miniFilter/NameChanger/nchelper.c b/filesys/miniFilter/NameChanger/nchelper.c new file mode 100644 index 00000000..72443de4 --- /dev/null +++ b/filesys/miniFilter/NameChanger/nchelper.c @@ -0,0 +1,365 @@ +/*++ + +Copyright (c) 2008 - 2009 Microsoft Corporation + +Module Name: + + nchelper.c + +Abstract: + + Contains helper routines of general applicability across name changer. + +Environment: + + Kernel mode + +--*/ + +#include "nc.h" + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE, NcAllocateEResource) +#pragma alloc_text(PAGE, NcCreateFileHelper) +#pragma alloc_text(PAGE, NcGetFileNameInformation) +#endif + +_When_(Data == NULL, _Pre_satisfies_(FileObject != NULL && Instance != NULL)) +_When_(FileObject == NULL || Instance == NULL, _Pre_satisfies_(Data != NULL)) +NTSTATUS +NcGetFileNameInformation( + _In_opt_ PFLT_CALLBACK_DATA Data, + _In_opt_ PFILE_OBJECT FileObject, + _In_opt_ PFLT_INSTANCE Instance, + _In_ FLT_FILE_NAME_OPTIONS NameOptions, + _Outptr_ PFLT_FILE_NAME_INFORMATION *FileNameInformation + ) +/*++ + +Routine Description: + + This function is a wrapper to call the correct variant of + FltGetFileNameInformation depending on the information we happen to + have available. + +Arguments: + + Data - Pointer to the callback data structure associated with a request. + This is optional, but if not specified, FileObject and Instance must + be supplied. + + FileObject - Pointer to the file object to query a name on. Optional, + but if not supplied, Data must be supplied. + + Instance - Pointer to the instance of our filter to query the name on. + Optional, but if not supplied, Data must be supplied. + + NameOptions - FLT_FILE_NAME_* flags for this request. + + FileNameInformation - On output, contains the file name information + resulting from this query. On failure, contents are undefined. + On success, caller is responsible for releasing this with + FltReleaseFileNameInformation. + +Return Value: + + Returns the status of the operation. + +--*/ +{ + NTSTATUS Status; + + PAGED_CODE(); + + FLT_ASSERT( Data || FileObject ); + + *FileNameInformation = NULL; + + if (ARGUMENT_PRESENT( Data )) { + + Status = FltGetFileNameInformation( Data, + NameOptions, + FileNameInformation ); + + } else if (ARGUMENT_PRESENT( FileObject )) { + + Status = FltGetFileNameInformationUnsafe( FileObject, + Instance, + NameOptions, + FileNameInformation ); + // + // This should never happen, as either Data or FileObject must be non-NULL. + // + + } else { + + FLT_ASSERT( FALSE ); + Status = STATUS_INVALID_PARAMETER; + } + + return Status; +} + +NTSTATUS +NcAllocateEResource( + _Out_ PERESOURCE * OutputLock + ) +/*++ + +Routine Description: + + This function allocates a new ERESOURCE. + +Arguments: + + OutputLock - On output, points to a newly allocated ERESOURCE. This + value is undefined on failure. Caller is responsible for deleting + this with a call to NcFreeEResource. + +Return Value: + + Returns the status of the operation. + +--*/ +{ + NTSTATUS Status; + + PERESOURCE Lock = NULL; + BOOLEAN DeleteLock = FALSE; + + PAGED_CODE(); + + Lock = ExAllocatePoolWithTag( NonPagedPool, + sizeof(ERESOURCE), + NC_LOCK_TAG ); + + if (Lock == NULL) { + + Status = STATUS_INSUFFICIENT_RESOURCES; + goto NcAllocateEResourceCleanup; + } + + Status = ExInitializeResourceLite( Lock ); + + if (!NT_SUCCESS( Status )) { + + goto NcAllocateEResourceCleanup; + } + + Status = STATUS_SUCCESS; + DeleteLock = TRUE; + *OutputLock = Lock; + +NcAllocateEResourceCleanup: + + if (!NT_SUCCESS( Status )) { + + if (Lock) { + + if (DeleteLock) { + + ExDeleteResourceLite( Lock ); + } + ExFreePoolWithTag( Lock, NC_LOCK_TAG ); + } + } + return Status; +} + +VOID +NcFreeEResource( + _In_ PERESOURCE Lock + ) +/*++ + +Routine Description: + + This function frees an ERESOURCE. + +Arguments: + + Lock - Points to an ERESOURCE allocated previously via + NcAllocateEResource that needs to be torn down. + +Return Value: + + Returns the status of the operation. + +--*/ +{ + ExDeleteResourceLite( Lock ); + ExFreePoolWithTag( Lock, NC_LOCK_TAG ); +} + +NTSTATUS +NcCreateFileHelper ( + _In_ PFLT_FILTER Filter, + _In_opt_ PFLT_INSTANCE Instance, + _Out_ PHANDLE FileHandle, + _Outptr_opt_ PFILE_OBJECT *FileObject, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _In_opt_ PLARGE_INTEGER AllocationSize, + _In_ ULONG FileAttributes, + _In_ ULONG ShareAccess, + _In_ ULONG CreateDisposition, + _In_ ULONG CreateOptions, + _In_reads_bytes_opt_(EaLength) PVOID EaBuffer, + _In_ ULONG EaLength, + _In_ ULONG Flags, + _In_opt_ PFILE_OBJECT ParentFileObject + ) +{ + +#if FLT_MGR_LONGHORN + IO_DRIVER_CREATE_CONTEXT DriverContext; +#endif + NTSTATUS Status; + + PAGED_CODE(); + +#if FLT_MGR_LONGHORN + IoInitializeDriverCreateContext( &DriverContext ); + + if (ARGUMENT_PRESENT( ParentFileObject )) { + PTXN_PARAMETER_BLOCK TxnInfo; + + TxnInfo = IoGetTransactionParameterBlock( ParentFileObject ); + + // + // If we have a FileObject, and if it has a transaction, pass the + // same transaction context along to our internal creates. + // + // TxfInfo will be valid so long as the file object is valid, which + // it is assumed to be across the call to this routine. + // + + DriverContext.TxnParameters = TxnInfo; + } +#else + UNREFERENCED_PARAMETER( ParentFileObject ); +#endif + + Status = NcCreateFileEx2( Filter, + Instance, + FileHandle, + FileObject, + DesiredAccess, + ObjectAttributes, + IoStatusBlock, + AllocationSize, + FileAttributes, + ShareAccess, + CreateDisposition, + CreateOptions, + EaBuffer, + EaLength, + Flags, +#if FLT_MGR_LONGHORN + &DriverContext ); +#else + NULL ); +#endif + + return Status; +} + + +NTSTATUS +NcSetCancelCompletion( + _In_ PFLT_CALLBACK_DATA Data, + _In_ PFLT_COMPLETE_CANCELED_CALLBACK CanceledCallback + ) +/*++ + +Routine Description: + + This sets the cancel routine attached to the request. We + synchronize against the request being cancelled via the system + global cancel spinlock, and if the request is already cancelled, + this function returns STATUS_CANCELLED to the caller to + indicate that the caller must clean up the request. Otherwise, + the cancel routine is set and immediately upon return any + cancellation will be via that mechanism. + + NOTE: This routine must be nonpaged, since we require + synchronization with the system global cancel spinlock. + +Arguments: + + Data - Pointer to the request we wish to assign cancellation to. + + CanceledCallback - Pointer to the functin to call upon + cancellation. + +Return Value: + + STATUS_CANCELLED if the request should be completed by the + caller, STATUS_SUCCESS to indicate that the cancellation + routine is associated with the request. + +--*/ +{ + NTSTATUS Status; + KIRQL OldIrql; + + IoAcquireCancelSpinLock( &OldIrql ); + + if (FltIsIoCanceled( Data )) { + IoReleaseCancelSpinLock( OldIrql ); + return STATUS_CANCELLED; + + } + Status = FltSetCancelCompletion( Data, CanceledCallback ); + + IoReleaseCancelSpinLock( OldIrql ); + return Status; +} + + +LONG +NcExceptionFilter ( + _In_ PEXCEPTION_POINTERS ExceptionPointer, + _In_ BOOLEAN AccessingUserBuffer + ) +/*++ + +Routine Description: + + Exception filter to catch errors touching user buffers. + +Arguments: + + ExceptionPointer - The exception record. + + AccessingUserBuffer - If TRUE, overrides FsRtlIsNtStatusExpected to allow + the caller to munge the error to a desired status. + +Return Value: + + EXCEPTION_EXECUTE_HANDLER - If the exception handler should be run. + + EXCEPTION_CONTINUE_SEARCH - If a higher exception handler should take care of + this exception. + +--*/ +{ + NTSTATUS Status; + + Status = ExceptionPointer->ExceptionRecord->ExceptionCode; + + // + // Certain exceptions shouldn't be dismissed within the namechanger filter + // unless we're touching user memory. + // + + if (!FsRtlIsNtstatusExpected( Status ) && + !AccessingUserBuffer) { + + return EXCEPTION_CONTINUE_SEARCH; + } + + return EXCEPTION_EXECUTE_HANDLER; +} + diff --git a/filesys/miniFilter/NameChanger/ncinit.c b/filesys/miniFilter/NameChanger/ncinit.c new file mode 100644 index 00000000..b61f76d9 --- /dev/null +++ b/filesys/miniFilter/NameChanger/ncinit.c @@ -0,0 +1,491 @@ + +#include "nc.h" + +_At_(OutputString->Buffer, _Post_notnull_) +NTSTATUS +NcLoadRegistryString ( + _In_ HANDLE Key, + _In_ PCWSTR valueName, + _Out_ PUNICODE_STRING OutputString + ); + +BOOLEAN +NcIs8DOT3Compatible ( + _In_ PUNICODE_STRING TestName, + _In_opt_ PUNICODE_STRING LongName + ); + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(INIT, NcInitializeMapping) +#pragma alloc_text(INIT, NcLoadRegistryString) +#pragma alloc_text(INIT, NcIs8DOT3Compatible) +#endif + +// The #pragma is a notation to the static code analyzer that the Buffer +// returned from the function will always be properly initialized. +// The multiple allocations/frees of the buffers causes it to lose track. +#pragma warning(push) +#pragma warning(disable:6001) +_At_(OutputString->Buffer, _Post_notnull_) +NTSTATUS +NcLoadRegistryString ( + _In_ HANDLE Key, + _In_ PCWSTR valueName, + _Out_ PUNICODE_STRING OutputString + ) +{ +#pragma warning(pop) + PKEY_VALUE_PARTIAL_INFORMATION TempMappingBuffer = NULL; + ULONG TempMappingKeyLength = 0; + UNICODE_STRING ValueString; + PWCHAR OutputStringBuffer = NULL; + NTSTATUS Status; + + PAGED_CODE(); + + // + // Query the length of the registry value. + // + + RtlInitUnicodeString( &ValueString, valueName ); + +NcLoadRegistryStringRetry: + Status = ZwQueryValueKey( Key, + &ValueString, + KeyValuePartialInformation, + NULL, + 0, + &TempMappingKeyLength ); + + // + // If we could not successfully locate the value, return the + // error to our caller. + // + + if (Status != STATUS_BUFFER_TOO_SMALL && + Status != STATUS_BUFFER_OVERFLOW) { + + goto NcLoadRegistryStringCleanup; + } + + // + // Allocate a buffer large enough to hold the string. + // + + if (TempMappingBuffer != NULL) { + ExFreePoolWithTag( TempMappingBuffer, NC_TAG ); + } + + TempMappingBuffer = ExAllocatePoolWithTag( PagedPool, + TempMappingKeyLength, + NC_TAG ); + + if (TempMappingBuffer == NULL) { + + Status = STATUS_INSUFFICIENT_RESOURCES; + goto NcLoadRegistryStringCleanup; + } + + // + // Now attempt to read the string. + // + + Status = ZwQueryValueKey( Key, + &ValueString, + KeyValuePartialInformation, + TempMappingBuffer, + TempMappingKeyLength, + &TempMappingKeyLength ); + + // + // If the value is changing underneath us, the length we + // collected above may be stale. Loop back, reallocate + // and try again. + // + + if (Status == STATUS_BUFFER_TOO_SMALL || + Status == STATUS_BUFFER_OVERFLOW) { + + goto NcLoadRegistryStringRetry; + } + + if (!NT_SUCCESS( Status )) { + + goto NcLoadRegistryStringCleanup; + } + + // + // If we're reading a string, it had better: + // 1. Be a string. + // 2. Fit in a UNICODE_STRING. + // 3. Have some characters in it (we never need empty strings in this filter.) + // + + if (TempMappingBuffer->Type != REG_SZ || + TempMappingBuffer->DataLength >= MAXUSHORT || + TempMappingBuffer->DataLength <= sizeof(WCHAR)) { + + Status = STATUS_INVALID_PARAMETER; + goto NcLoadRegistryStringCleanup; + } + + // + // Allocate a buffer for the target string. Note that we + // allocate one fewer WCHAR, as we have no need for the + // NULL terminator in our UNICODE_STRING. + // + + OutputStringBuffer = ExAllocatePoolWithTag( NonPagedPool, + TempMappingBuffer->DataLength - sizeof(WCHAR), + NC_TAG ); + + if (OutputStringBuffer == NULL) { + + Status = STATUS_INSUFFICIENT_RESOURCES; + goto NcLoadRegistryStringCleanup; + } + + // + // We only modify the output string on success. On failure, it is + // left with previous values. + // + + Status = STATUS_SUCCESS; + + OutputString->MaximumLength = (USHORT)TempMappingBuffer->DataLength - sizeof(WCHAR); + OutputString->Buffer = OutputStringBuffer; + + RtlCopyMemory( OutputStringBuffer, TempMappingBuffer->Data, OutputString->MaximumLength ); + OutputString->Length = OutputString->MaximumLength; + + // + // This buffer is in use and should not be cleaned up. + // + + OutputStringBuffer = NULL; + +NcLoadRegistryStringCleanup: + + if (TempMappingBuffer != NULL) { + ExFreePoolWithTag( TempMappingBuffer, NC_TAG ); + } + + if (OutputStringBuffer != NULL) { + ExFreePoolWithTag( OutputStringBuffer, NC_TAG ); + } + + return Status; +} + +BOOLEAN +NcIs8DOT3Compatible ( + _In_ PUNICODE_STRING TestName, + _In_opt_ PUNICODE_STRING LongName + ) +{ + BOOLEAN SpacesPresent; + USHORT Index; + PAGED_CODE(); + + // + // When the user supplies a shortname, we expect it to be a valid + // shortname. This function will check the name's length. + // + + if (!RtlIsNameLegalDOS8Dot3( TestName, + NULL, + &SpacesPresent )) { + + return FALSE; + + } + + // + // Our shortnames should not have spaces. + // + + if (SpacesPresent) { + return FALSE; + } + + // + // In this sample, we enforce that the shortname must NOT contain + // a tilde (~). + // + // If the shortname could contain a tilde, the filesystem would + // be able to autogenerate a conflicting shortname in response to + // an operation on a long name. We could only detect this + // afterwards (in a post-operation callback), but we may not be + // able to handle the condition correctly. Explicitly changing + // a shortname requires NTFS and restore privilege. Rather than + // attempt to obtain this functionality via creative mechanism, + // this filter simply prevents a shortname which could create + // this condition. + // + // Note that in a product it may be advantageous to create both + // sides of the mapping on disk. Part of this sample is to + // illustrate the emulation of an object which does not exist, + // so we did not do this here. + // + // We enforce: + // 1. The name must not have a tilde (for the above reasons); + // 2. The name must not contain a path seperator; + // 3. The name must be fully uppercase to be a valid DOS name + // + + for (Index = 0; + Index < TestName->Length/sizeof(WCHAR); + Index++) { + + if (TestName->Buffer[Index] == L'~' || + TestName->Buffer[Index] == L'\\' || + TestName->Buffer[Index] != RtlUpcaseUnicodeChar( TestName->Buffer[Index] )) { + + return FALSE; + + } + } + + // + // We're done validating the short name. Now we must check the + // long and short names for consistency. If we have no long name, + // we're done. + // + + if (!ARGUMENT_PRESENT( LongName )) { + return TRUE; + } + + // + // Check if the long name is a valid shortname. We recurse into + // ourselves for this. Note that since we're not specifying a + // long name, the recursion is bounded. + // + + if (NcIs8DOT3Compatible( LongName, NULL )) { + + // + // If both our long and short paths are compliant, they had + // better be the same. + // + + if (!RtlEqualUnicodeString( TestName, LongName, FALSE )) { + return FALSE; + } + } + + return TRUE; + +} + +NTSTATUS +NcInitializeMapping( + _In_ PUNICODE_STRING RegistryPath + ) +/*++ + +Routine Descrition: + + This routine initializes the mapping structure. It will + try to populate it from the registry, and if that fails + use a default string. + +Arguments: + + RegistryPath - The path key passed to the driver during DriverEntry. + +Return Value: + + None. + +--*/ +{ + NTSTATUS Status; + OBJECT_ATTRIBUTES Attributes; + HANDLE DriverRegKey = NULL; + UNICODE_STRING TempPath = EMPTY_UNICODE_STRING; + USHORT Index; + + PAGED_CODE(); + + RtlZeroMemory( &NcGlobalData, sizeof( NcGlobalData )); + + // + // Open the mapping registry key. + // + + InitializeObjectAttributes( &Attributes, + RegistryPath, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, + NULL, + NULL ); + + Status = ZwOpenKey( &DriverRegKey, + KEY_READ, + &Attributes ); + + if (!NT_SUCCESS( Status )) { + + FLT_ASSERT( DriverRegKey == NULL ); + goto NcInitializeMappingCleanup; + } + + Status = NcLoadRegistryString( DriverRegKey, + L"UserMapping", + &TempPath ); + + if (!NT_SUCCESS( Status )) { + goto NcInitializeMappingCleanup; + } + + // + // We check that the name does not contain two + // contiguous slashes. This implies an empty + // name component, which we make no attempt to + // handle. + // + + for (Index = 1; Index < TempPath.Length/sizeof(WCHAR); Index++) { + + if (TempPath.Buffer[Index] == L'\\' && + TempPath.Buffer[Index - 1] == L'\\') { + + Status = STATUS_INVALID_PARAMETER; + goto NcInitializeMappingCleanup; + + } + } + + Status = NcParseFinalComponent( &TempPath, + &NcGlobalData.UserMappingPath, + &NcGlobalData.UserMappingFinalComponentLong ); + + if (!NT_SUCCESS( Status )) { + goto NcInitializeMappingCleanup; + } + + NcFreeUnicodeString( &TempPath ); + + Status = NcLoadRegistryString( DriverRegKey, + L"UserMappingFinalComponentShort", + &NcGlobalData.UserMappingFinalComponentShort ); + + if (!NT_SUCCESS( Status )) { + goto NcInitializeMappingCleanup; + } + + Status = NcLoadRegistryString( DriverRegKey, + L"RealMapping", + &TempPath ); + + if (!NT_SUCCESS( Status )) { + goto NcInitializeMappingCleanup; + } + + // + // We check that the name does not contain two + // contiguous slashes. This implies an empty + // name component, which we make no attempt to + // handle. + // + + for (Index = 1; Index < TempPath.Length/sizeof(WCHAR); Index++) { + + if (TempPath.Buffer[Index] == L'\\' && + TempPath.Buffer[Index - 1] == L'\\') { + + Status = STATUS_INVALID_PARAMETER; + goto NcInitializeMappingCleanup; + + } + } + + Status = NcParseFinalComponent( &TempPath, + &NcGlobalData.RealMappingPath, + &NcGlobalData.RealMappingFinalComponent ); + + if (!NT_SUCCESS( Status )) { + goto NcInitializeMappingCleanup; + } + + // + // We expect out parent mappings to start with '\', and we expect + // no final component to start with '\'. We have already checked + // that the strings contain one WCHAR, but we require two for the + // parent mappings, since the first one is '\'. + // + + if (NcGlobalData.RealMappingPath.Length < (2 * sizeof(WCHAR)) || + NcGlobalData.UserMappingPath.Length < (2 * sizeof(WCHAR)) || + NcGlobalData.RealMappingPath.Buffer[0] != L'\\' || + NcGlobalData.UserMappingPath.Buffer[0] != L'\\' || + NcGlobalData.UserMappingFinalComponentShort.Buffer[0] == L'\\' || + NcGlobalData.UserMappingFinalComponentLong.Buffer[0] == L'\\' || + NcGlobalData.RealMappingFinalComponent.Buffer[0] == L'\\') { + + Status = STATUS_INVALID_PARAMETER; + goto NcInitializeMappingCleanup; + } + + if (!NcIs8DOT3Compatible( &NcGlobalData.UserMappingFinalComponentShort, + &NcGlobalData.UserMappingFinalComponentLong )) { + + Status = STATUS_INVALID_PARAMETER; + goto NcInitializeMappingCleanup; + } + + // + // TODO: This sample assumes that the real mapping final component + // is short. This should not be a required assumption. Note that + // since we only have one component for the real mapping (long and + // short), we don't need to check the long name for compatibility + // with the short name. + // + + if (!NcIs8DOT3Compatible( &NcGlobalData.RealMappingFinalComponent, NULL )) { + + Status = STATUS_INVALID_PARAMETER; + goto NcInitializeMappingCleanup; + } + +NcInitializeMappingCleanup: + + + if (!NT_SUCCESS( Status )) { + + if (NcGlobalData.UserMappingPath.Buffer != NULL) { + NcFreeUnicodeString( &NcGlobalData.UserMappingPath ); + } + + if (NcGlobalData.UserMappingFinalComponentShort.Buffer != NULL) { + NcFreeUnicodeString( &NcGlobalData.UserMappingFinalComponentShort ); + } + + if (NcGlobalData.UserMappingFinalComponentLong.Buffer != NULL) { + NcFreeUnicodeString( &NcGlobalData.UserMappingFinalComponentLong ); + } + + if (NcGlobalData.RealMappingPath.Buffer != NULL) { + NcFreeUnicodeString( &NcGlobalData.RealMappingPath ); + } + + if (NcGlobalData.RealMappingFinalComponent.Buffer != NULL) { + NcFreeUnicodeString( &NcGlobalData.RealMappingFinalComponent ); + } + } + + if (TempPath.Buffer != NULL) { + NcFreeUnicodeString( &TempPath ); + } + + if (DriverRegKey != NULL) { + + NTSTATUS BogusStatus; + + BogusStatus = ZwClose( DriverRegKey ); + FLT_ASSERT(NT_SUCCESS( BogusStatus )); + } + + return Status; +} + diff --git a/filesys/miniFilter/NameChanger/ncmapping.c b/filesys/miniFilter/NameChanger/ncmapping.c new file mode 100644 index 00000000..3dd05135 --- /dev/null +++ b/filesys/miniFilter/NameChanger/ncmapping.c @@ -0,0 +1,796 @@ +/*++ + +Copyright (c) 1999 - 2002 Microsoft Corporation + +Module Name: + + ncmapping.c + +Abstract: + + This module contains helper routines for manipulating mapping + objects. + +Environment: + + Kernel mode + +--*/ + +#include "nc.h" + +BOOLEAN +NcIsMappingPathZeroed ( + _In_ PNC_MAPPING_PATH Path + ); + +NTSTATUS +NcBuildMappingPath ( + _In_ PUNICODE_STRING VolumeName, + _In_ PUNICODE_STRING ParentPath, + _In_ PUNICODE_STRING FinalComponent, + _Inout_ PNC_MAPPING_PATH Path + ); + +NTSTATUS +NcBuildMappingPathFromFile ( + _In_ PFILE_OBJECT Parent, + _In_ PUNICODE_STRING FinalComponent, + _In_ PFLT_INSTANCE Instance, + _In_ BOOLEAN Normalized, + _Inout_ PNC_MAPPING_PATH Path + ); + + +// +// Functions to manage mapping entry +// + +BOOLEAN +NcIsMappingEntryZeroed ( + PNC_MAPPING_ENTRY Entry + ); + +VOID +NcInitMappingEntry ( + _Inout_ PNC_MAPPING_ENTRY Entry + ); + +VOID +NcTeardownMappingEntry ( + _Inout_ PNC_MAPPING_ENTRY Path + ); + + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE, NcBuildMappingPath) +#pragma alloc_text(PAGE, NcBuildMappingPathFromFile) +#pragma alloc_text(PAGE, NcBuildMappingPathFromVolume) +#pragma alloc_text(PAGE, NcInitMappingPath) +#pragma alloc_text(PAGE, NcIsMappingPathZeroed) +#pragma alloc_text(PAGE, NcTeardownMappingPath) +#pragma alloc_text(PAGE, NcInitMappingEntry) +#pragma alloc_text(PAGE, NcIsMappingEntryZeroed) +#pragma alloc_text(PAGE, NcTeardownMappingEntry) +#pragma alloc_text(PAGE, NcInitMapping) +#pragma alloc_text(PAGE, NcIsMappingZeroed) +#pragma alloc_text(PAGE, NcTeardownMapping) +#pragma alloc_text(PAGE, NcBuildMapping) +#endif + +// +// Functions to manage the mapping path. +// + +BOOLEAN +NcIsMappingPathZeroed( + _In_ PNC_MAPPING_PATH Path + ) +{ + PAGED_CODE(); + + if (Path->FullPath.Buffer != NULL || + Path->FullPath.Length != 0 || + Path->FullPath.MaximumLength != 0) { + + return FALSE; + } + + if (Path->VolumePath.Buffer != NULL || + Path->VolumePath.Length != 0 || + Path->VolumePath.MaximumLength != 0) { + + return FALSE; + } + + if (Path->ParentPath.Buffer != NULL || + Path->ParentPath.Length != 0 || + Path->ParentPath.MaximumLength != 0) { + + return FALSE; + } + + if (Path->FinalComponentName.Buffer != NULL || + Path->FinalComponentName.Length != 0 || + Path->FinalComponentName.MaximumLength != 0) { + + return FALSE; + } + + if (Path->VolumelessName.Buffer != NULL || + Path->VolumelessName.Length != 0 || + Path->VolumelessName.MaximumLength != 0) { + + return FALSE; + } + + return TRUE; +} + +VOID +NcInitMappingPath ( + _Out_ PNC_MAPPING_PATH Path + ) +/*++ + +Routine Description: + + Routine to initialize a mapping path. + +Arguments: + + Path - Pointer to a user allocated NC_MAPPING_PATH. + +Return Value: + + None. + +--*/ +{ + PAGED_CODE(); + RtlZeroMemory( Path, sizeof( NC_MAPPING_PATH ) ); +} + +VOID +NcTeardownMappingPath ( + _Inout_ PNC_MAPPING_PATH Path + ) +/*++ + +Routine Description: + + Frees the allocations in a NC_MAPPING_PATH. + +Arguments: + + Path - The mapping which you want to clean up. + +Return Value: + + None. + +--*/ +{ + + PAGED_CODE(); + + if (Path->FullPath.Buffer != NULL) { + + ExFreePoolWithTag( Path->FullPath.Buffer, NC_MAPPING_TAG ); + } + + // + // All of the strings point at the same buffer allocation. + // So once we free the buffer in the FullPath, we just zero out + // all of the other strings. + // + + NcInitMappingPath( Path ); +} + +NTSTATUS +NcBuildMappingPath ( + _In_ PUNICODE_STRING VolumeName, + _In_ PUNICODE_STRING ParentPath, + _In_ PUNICODE_STRING FinalComponent, + _Inout_ PNC_MAPPING_PATH Path + ) +/*++ + +Routine Description: + + Builds a NC_MAPPING_PATH from a collection of Unicode strings. + +Arguments: + + VolumeName - Name of the volume. + + ParentPath - string for the parent of mapping. + + FinalComponent - The final component of the mapping path. + + Path - Pointer to a used allocated and zeroed NC_MAPPING_PATH. + +Return Value: + + Returns STATUS_SUCCESS on success. Otherwise returns an error code. + + +--*/ +{ + NTSTATUS Status = STATUS_SUCCESS; + USHORT NameLength; + PWCHAR NameBuffer = NULL; + UNICODE_STRING NameString; + USHORT SeparatorLength; + WCHAR ParentEnd; + USHORT Index; + + PAGED_CODE(); + + FLT_ASSERT( NcIsMappingPathZeroed( Path ) ); + + // + // We cannot remap to/from the root of the volume. + // + + FLT_ASSERT( FinalComponent->Length > 0 ); + + // + // If the parent path does not end with a '\' then we insert one + // between the parent and the final component. + // + + ParentEnd = ParentPath->Buffer[(ParentPath->Length / sizeof(WCHAR)) - 1]; + + if (ParentEnd != NC_SEPARATOR) { + + SeparatorLength = sizeof(WCHAR); + } else { + + SeparatorLength = 0; + } + + // + // Allocate Buffer for Name. + // + + NameLength = VolumeName->Length + ParentPath->Length + SeparatorLength + FinalComponent->Length; + + NameBuffer = ExAllocatePoolWithTag( PagedPool, + NameLength, + NC_MAPPING_TAG ); + + if (NameBuffer == NULL) { + + Status = STATUS_INSUFFICIENT_RESOURCES; + goto NcBuildMappingPathCleanup; + } + + // + // Create String + // + + NameString.Length = 0; + NameString.MaximumLength = NameLength; + NameString.Buffer = NameBuffer; + + // + // Copy Volume Name + // + + RtlCopyUnicodeString( &NameString, VolumeName ); + + // + // Copy Parent Path + // + + RtlAppendUnicodeStringToString( &NameString,ParentPath ); + + // + // Add separator + // + + if (SeparatorLength != 0) { + + NameString.Buffer[NameString.Length/SeparatorLength] = NC_SEPARATOR; + NameString.Length = NameString.Length + SeparatorLength; + FLT_ASSERT( NameString.Length <= NameString.MaximumLength ); + } + + // + // Copy Final Component + // + + RtlAppendUnicodeStringToString( &NameString, FinalComponent ); + + // + // Setup Unicode Strings + // + + Path->FullPath.Buffer = NameString.Buffer; + Path->FullPath.Length = NameString.Length; + Path->FullPath.MaximumLength = NameString.MaximumLength; + + Path->VolumePath.Buffer = NameString.Buffer; + Path->VolumePath.Length = VolumeName->Length; + Path->VolumePath.MaximumLength = VolumeName->Length; + + Path->ParentPath.Buffer = NameString.Buffer; + Path->ParentPath.Length = SeparatorLength == sizeof(WCHAR) ? + VolumeName->Length+ParentPath->Length : + VolumeName->Length+ParentPath->Length-sizeof(WCHAR); + Path->ParentPath.MaximumLength = SeparatorLength == sizeof(WCHAR) ? + VolumeName->Length+ParentPath->Length : + VolumeName->Length+ParentPath->Length-sizeof(WCHAR); + + Path->FinalComponentName.Buffer = (PWSTR)Add2Ptr( NameString.Buffer, + VolumeName->Length+ParentPath->Length+SeparatorLength ); + + Path->FinalComponentName.Length = FinalComponent->Length; + Path->FinalComponentName.MaximumLength = FinalComponent->Length; + + Path->VolumelessName.Buffer = (PWSTR)Add2Ptr( NameString.Buffer, VolumeName->Length ); + Path->VolumelessName.Length = NameString.Length - VolumeName->Length; + Path->VolumelessName.MaximumLength = Path->VolumelessName.Length; + + Path->NumberComponentsInVolumePath = 0; + + for (Index = 0; Index < Path->VolumePath.Length/sizeof(WCHAR); Index++) { + if (Path->VolumePath.Buffer[Index] == L'\\') { + Path->NumberComponentsInVolumePath++; + } + } + + Path->NumberComponentsInFullPath = 0; + + for (Index = 0; Index < Path->FullPath.Length/sizeof(WCHAR); Index++) { + if (Path->FullPath.Buffer[Index] == L'\\') { + Path->NumberComponentsInFullPath++; + } + } + + FLT_ASSERT( Path->NumberComponentsInFullPath > Path->NumberComponentsInVolumePath ); + + // + // We reached the end without incident. + // + + Status = STATUS_SUCCESS; + +NcBuildMappingPathCleanup: + + if (!NT_SUCCESS( Status )) { + + if (NameBuffer != NULL) { + ExFreePoolWithTag( NameBuffer, NC_MAPPING_TAG ); + } + + NcInitMappingPath( Path ); + } + + return Status; +} + +NTSTATUS +NcBuildMappingPathFromVolume ( + _In_ PFLT_VOLUME CONST Volume, + _In_ PUNICODE_STRING ParentPath, + _In_ PUNICODE_STRING FinalComponentName, + _Inout_ PNC_MAPPING_PATH Entry + ) +/*++ + +Routine Description: + + Constructs a path from a Volume and a Caller Specified Path. + +Arguments: + + Volume - Pointer to the volume which the mapping path will be used on. + + ParentPath - Path to the parent of the mapping. + + FinalComponentName - The final component name. + + Entry - Pointer to a user allocated NC_MAPPING_PATH. + +Return Value: + + Returns STATUS_SUCCESS on success. Otherwise returns an error code. + +--*/ +{ + NTSTATUS Status; + ULONG VolumeNameLength; + PVOID VolumeNameBuffer = NULL; + UNICODE_STRING VolumeNameString; + + PAGED_CODE(); + + FLT_ASSERT( NcIsMappingPathZeroed( Entry ) ); + + // + // Query the volume name length. + // + + Status = FltGetVolumeName( Volume, + NULL, + &VolumeNameLength); + + if (!NT_SUCCESS( Status ) && Status != STATUS_BUFFER_TOO_SMALL) { + + goto NcBuildPathCleanup; + } + + // + // Allocate a buffer for the name. + // + + Status = STATUS_SUCCESS; + + VolumeNameBuffer = ExAllocatePoolWithTag( PagedPool, + VolumeNameLength, + NC_MAPPING_TAG ); + + if (VolumeNameBuffer == NULL) { + + Status = STATUS_INSUFFICIENT_RESOURCES; + goto NcBuildPathCleanup; + } + + RtlInitEmptyUnicodeString( &VolumeNameString, VolumeNameBuffer, (USHORT) VolumeNameLength ); + + // + // Query the volume name + // + + Status = FltGetVolumeName( Volume, + &VolumeNameString, + NULL ); + + if (!NT_SUCCESS( Status )) { + + goto NcBuildPathCleanup; + } + + // + // Generate Mapping Path + // + + Status = NcBuildMappingPath( &VolumeNameString, + ParentPath, + FinalComponentName, + Entry ); + + if (!NT_SUCCESS( Status )) { + + goto NcBuildPathCleanup; + } + +NcBuildPathCleanup: + + if (!NT_SUCCESS( Status )) { + + NcTeardownMappingPath( Entry ); + } + + if (VolumeNameBuffer != NULL) { + + ExFreePoolWithTag( VolumeNameBuffer, NC_MAPPING_TAG ); + } + + return Status; +} + +NTSTATUS +NcBuildMappingPathFromFile ( + _In_ PFILE_OBJECT Parent, + _In_ PUNICODE_STRING FinalComponent, + _In_ PFLT_INSTANCE Instance, + _In_ BOOLEAN Normalized, + _Inout_ PNC_MAPPING_PATH Path + ) +/*++ + +Routine Description: + + Builds a path from the parent of the mapping and string for the final component. + +Arguments: + + Parent - The file object for the parent of the mapping. + + FinalComponent - A string which is to be used as the final component of the name. + + Instance - The instance for which we are building the mapping. + + NameFlags - Parameters which we will use when checking the name from the file object. + + Path - Pointer to a user allocated NC_MAPPING_PATH which will be populated. + +Return Value + + On success, returns STATUS_SUCCESS, otherwise returns an error code. + +--*/ +{ + NTSTATUS Status; + UNICODE_STRING ParentPath; + PFLT_FILE_NAME_INFORMATION ParentNameInfo = NULL; + FLT_FILE_NAME_OPTIONS NameFlags; + + PAGED_CODE(); + + FLT_ASSERT( NcIsMappingPathZeroed( Path ) ); + + if (Normalized) { + + NameFlags = FLT_FILE_NAME_NORMALIZED | FLT_FILE_NAME_QUERY_DEFAULT; + + } else { + + NameFlags = FLT_FILE_NAME_OPENED | FLT_FILE_NAME_QUERY_DEFAULT; + + } + + // + // Get File parent's name info. + // + + Status = NcGetFileNameInformation( NULL, + Parent, + Instance, + NameFlags, + &ParentNameInfo ); + + if (!NT_SUCCESS( Status )) { + + goto NcBuildMappingPathFromFileCleanup; + } + + Status = FltParseFileNameInformation( ParentNameInfo ); + + if (!NT_SUCCESS( Status )) { + + goto NcBuildMappingPathFromFileCleanup; + } + + + FLT_ASSERT( ParentNameInfo->Format == FLT_FILE_NAME_NORMALIZED || + ParentNameInfo->Format == FLT_FILE_NAME_OPENED ); + + + // + // Format Parent Name + // + + ParentPath.Buffer = ParentNameInfo->ParentDir.Buffer; + ParentPath.Length = ParentNameInfo->ParentDir.Length+ParentNameInfo->FinalComponent.Length; + ParentPath.MaximumLength = ParentPath.Length; + + // + // Generate name + // + + Status = NcBuildMappingPath( &ParentNameInfo->Volume, + &ParentPath, + FinalComponent, + Path ); + +NcBuildMappingPathFromFileCleanup: + + if (!NT_SUCCESS( Status )) { + + NcTeardownMappingPath( Path ); + } + + if (ParentNameInfo != NULL) { + + FltReleaseFileNameInformation( ParentNameInfo ); + } + + return Status; +} + +// +// Functions to manage mapping entry +// + +BOOLEAN +NcIsMappingEntryZeroed ( + PNC_MAPPING_ENTRY Entry + ) +{ + PAGED_CODE(); + + if (!NcIsMappingPathZeroed( &Entry->LongNamePath )) + return FALSE; + + if (!NcIsMappingPathZeroed( &Entry->ShortNamePath )) + return FALSE; + + return TRUE; +} + +VOID +NcInitMappingEntry ( + _Inout_ PNC_MAPPING_ENTRY Entry + ) +{ + PAGED_CODE(); + + NcInitMappingPath( &Entry->LongNamePath ); + NcInitMappingPath( &Entry->ShortNamePath ); +} + +VOID +NcTeardownMappingEntry ( + _Inout_ PNC_MAPPING_ENTRY Path + ) +{ + PWCHAR StrBuff = Path->LongNamePath.FullPath.Buffer; + + PAGED_CODE(); + + NcTeardownMappingPath( &Path->LongNamePath ); + + if (StrBuff != Path->ShortNamePath.FullPath.Buffer) { + + // + // There are situations where the two paths point to the + // same buffer. We do this check to make sure that + // we don't double free it. + // + + NcTeardownMappingPath( &Path->ShortNamePath ); + + } else { + + NcInitMappingPath( &Path->ShortNamePath ); + } +} + +// +// Functions to manage mapping +// + +BOOLEAN +NcIsMappingZeroed ( + PNC_MAPPING Mapping + ) +{ + PAGED_CODE(); + if (!NcIsMappingEntryZeroed( &Mapping->RealMapping )) { + + return FALSE; + } + + if (!NcIsMappingEntryZeroed( &Mapping->UserMapping )) { + + return FALSE; + } + + return TRUE; +} + +VOID +NcInitMapping ( + PNC_MAPPING Mapping + ) +{ + PAGED_CODE(); + NcInitMappingEntry( &Mapping->RealMapping ); + NcInitMappingEntry( &Mapping->UserMapping ); +} + +VOID +NcTeardownMapping ( + _Inout_ PNC_MAPPING Mapping + ) +{ + PAGED_CODE(); + NcTeardownMappingEntry( &Mapping->RealMapping ); + NcTeardownMappingEntry( &Mapping->UserMapping ); +} + +NTSTATUS +NcBuildMapping ( + _In_ PFILE_OBJECT UserParent, + _In_ PFILE_OBJECT RealParent, + _In_ PUNICODE_STRING UserFinalComponentShortName, + _In_ PUNICODE_STRING UserFinalComponentLongName, + _In_ PUNICODE_STRING RealFinalComponentName, + _In_ PFLT_INSTANCE Instance, + _Out_ PNC_MAPPING Mapping + ) +/*++ + +Routine Description: + + Constructs the mapping for instance setup. + +Arguments: + + UserParent - File object of the parent of the user mapping. + + RealParent - File object of the parent of the real mapping. + + UserFinalComponentShortName - Short name for the user mapping's final component. + + UserFinalComponentLongName - Long name for the user mapping's final component. + + RealFinalComponentName - Final component name for the real mapping (either long or short). + + Instance - Instance for which we are constructing the mapping. + + Mapping - Pointer to a user allocated NC_MAPPING which will be populated. + +--*/ +{ + + NTSTATUS Status; + PAGED_CODE(); + + FLT_ASSERT( NcIsMappingZeroed( Mapping ) ); + + // + // Build the Real Path. + // + + Status = NcBuildMappingPathFromFile( RealParent, + RealFinalComponentName, + Instance, + TRUE, + &Mapping->RealMapping.LongNamePath ); + + if (!NT_SUCCESS( Status )) { + + goto NcBuildMappingCleanup; + } + + // TODO: Do we really know that the real path is 8dot3 compliant? + + // + // Reuse the real path for long and short name. + // + + Mapping->RealMapping.ShortNamePath = + Mapping->RealMapping.LongNamePath; + + // + // Build the user short path. + // + + Status = NcBuildMappingPathFromFile( UserParent, + UserFinalComponentShortName, + Instance, + FALSE, + &Mapping->UserMapping.ShortNamePath ); + + if (!NT_SUCCESS( Status )) { + + goto NcBuildMappingCleanup; + } + + // + // Build the user long path. + // + + Status = NcBuildMappingPathFromFile( UserParent, + UserFinalComponentLongName, + Instance, + TRUE, + &Mapping->UserMapping.LongNamePath ); + + if (!NT_SUCCESS( Status )) { + + goto NcBuildMappingCleanup; + } + +NcBuildMappingCleanup: + + return Status; +} + + diff --git a/filesys/miniFilter/NameChanger/ncnameprov.c b/filesys/miniFilter/NameChanger/ncnameprov.c new file mode 100644 index 00000000..1d746388 --- /dev/null +++ b/filesys/miniFilter/NameChanger/ncnameprov.c @@ -0,0 +1,576 @@ + +#include "nc.h" + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE, NcGenerateFileName) +#pragma alloc_text(PAGE, NcNormalizeNameComponentEx) +#endif + +NTSTATUS +NcGenerateFileName ( + _In_ PFLT_INSTANCE Instance, + _In_ PFILE_OBJECT FileObject, + _In_opt_ PFLT_CALLBACK_DATA Data, + _In_ FLT_FILE_NAME_OPTIONS NameOptions, + _Out_ PBOOLEAN CacheFileNameInformation, + _Inout_ PFLT_NAME_CONTROL OutputNameControl + ) +{ + // + // Status vars + // + + NTSTATUS Status; + + // + // State lookup vars + // + + BOOLEAN Opened = (BOOLEAN)(FileObject->FsContext != NULL); // True if file object is opened. + BOOLEAN ReturnShortName = (BOOLEAN)(FltGetFileNameFormat(NameOptions) == FLT_FILE_NAME_SHORT); // True if the user is requesting short name + BOOLEAN ReturnOpenedName = (BOOLEAN)(FltGetFileNameFormat(NameOptions) == FLT_FILE_NAME_OPENED); // True if user is requesting opened name. + BOOLEAN ReturnNormalizedName = (BOOLEAN)(FltGetFileNameFormat(NameOptions) == FLT_FILE_NAME_NORMALIZED); // True if user is requesting normalized name. + BOOLEAN IgnoreCase; + FLT_FILE_NAME_OPTIONS NameQueryMethod = FltGetFileNameQueryMethod( NameOptions ); + FLT_FILE_NAME_OPTIONS NameFlags = FLT_VALID_FILE_NAME_FLAGS & NameOptions; + + // + // File name information + // + + PFLT_FILE_NAME_INFORMATION LowerNameInfo = NULL; // File name as reported by lower name provider. Will always be down real mapping. + PFLT_FILE_NAME_INFORMATION ShortInfo = NULL; // We will use ShortInfo to store the short name if needed. + + // + // Contexts + // + + PNC_INSTANCE_CONTEXT InstanceContext = NULL; + + // + // Overlap + // + + NC_PATH_OVERLAP RealOverlap; + UNICODE_STRING RealRemainder = EMPTY_UNICODE_STRING; + + // + // Temp storage + // + + UNICODE_STRING MungedName = EMPTY_UNICODE_STRING; + + // + // Temp pointer + // + + PUNICODE_STRING Name = NULL; // Pointer to the name we are going to use. + + PAGED_CODE(); + + FLT_ASSERT( IoGetTopLevelIrp() == NULL ); + + // + // This should never happen, but let's be safe. + // + + if (!ReturnShortName && + !ReturnOpenedName && + !ReturnNormalizedName) { + + FLT_ASSERT( FALSE ); + Status = STATUS_NOT_SUPPORTED; + goto NcGenerateFileNameCleanup; + } + + RealOverlap.EntireFlags = 0; + + // + // To prevent infinite recursion, calls to FltGetFileNameInformation + // from generate file name callbacks should not target current provider. + // + + ClearFlag( NameFlags, FLT_FILE_NAME_REQUEST_FROM_CURRENT_PROVIDER ); + + // + // Fetch the instance context. + // + + Status = FltGetInstanceContext( Instance, &InstanceContext ); + + if (!NT_SUCCESS( Status )) { + + goto NcGenerateFileNameCleanup; + } + + // + // We need to know what the name provider under us thinks the file is called. + // If the caller wants the normalized name we query that, otherwise we query + // the opened name because we have to compare the full path of the file vs. + // the real mapping to determine if the file is mapped. + // + + Status = NcGetFileNameInformation( Data, + FileObject, + Instance, + (ReturnNormalizedName ? FLT_FILE_NAME_NORMALIZED + : FLT_FILE_NAME_OPENED) | + NameQueryMethod | + NameFlags, + &LowerNameInfo ); + + if (!NT_SUCCESS( Status )) { + + goto NcGenerateFileNameCleanup; + } + + Status = FltParseFileNameInformation( LowerNameInfo ); + + if (!NT_SUCCESS( Status )) { + + goto NcGenerateFileNameCleanup; + } + + // + // Issues With Pre-open path: + // + // 1) Poison name cache below name provider: + // If a filter above a name provider calls FltGetFileNameInformation on a + // file object in his precreate callback, fltmgr will call the name + // provider's generate name callback before the name provider's pre create + // callback is invoked. Name providers by their nature change names in their + // pre-create. Because the name provider has not had the opportunity to + // modify the name yet, we need to make sure that fltmgr does not cache the name we + // return below us, so we set the FLT_FILE_NAME_DO_NOT_CACHE flag. + // //TODO: TRY TO GET ACROSS THAT THIS IS A NAME CHANGER PROBLEM, NOT ALL NAME PROVIDERS NEED TO. + // + + if (!Opened) { + + SetFlag( NameFlags, FLT_FILE_NAME_DO_NOT_CACHE ); + + if (Data) { + + // + // NT supports case sensitive and non-case sensitive naming in file systems. + // This is handled on a per-open basis. Weather an open is case senstive is + // determined by the FO_OPENED_CASE_SENSITIVE flag on the file object. + // In pre-create the SL_CASE_SENSITIVE flag on the create IRP specifies the mode. + // + // If this is on an unopened FileObject, it had better be pre-create so we know + // how to process the operation. If we are queried on an unopened FileObject + // at any other time we have no way to handle the request. + // + + FLT_ASSERT( Data->Iopb->MajorFunction == IRP_MJ_CREATE || + Data->Iopb->MajorFunction == IRP_MJ_NETWORK_QUERY_OPEN ); + + IgnoreCase = !BooleanFlagOn( Data->Iopb->OperationFlags, SL_CASE_SENSITIVE ); + + } else { + + // + // If people do unsafe queries on preopened IOs, we cannot + // determine if the open is case sensitive or not. + // So we cannot determine if this open is down the mapping. + // fail. + // + + FLT_ASSERT( FALSE ); + Status = STATUS_INVALID_PARAMETER; + goto NcGenerateFileNameCleanup; + + } + + } else { + + // + // After a file has been opened, the case sensitivity is stored in the file object. + // + + IgnoreCase = !BooleanFlagOn( FileObject->Flags, FO_OPENED_CASE_SENSITIVE ); + } + + // + // Calculate the overlap with the real mapping. + // + + NcComparePath( &LowerNameInfo->Name, + &InstanceContext->Mapping.RealMapping, + &RealRemainder, + IgnoreCase, + TRUE, + &RealOverlap ); + + // + // Whether we munge depends on what name is requested. + // + + if (ReturnOpenedName || + ReturnNormalizedName) { + + if (Opened && + RealOverlap.InMapping) { + + // + // We munge the opened name if it overlaps with the real mapping. + // The returned path will be down the user mapping. + // + + Status = NcConstructPath( &InstanceContext->Mapping.UserMapping, + &RealRemainder, + TRUE, + &MungedName); + + if (!NT_SUCCESS( Status )) { + + goto NcGenerateFileNameCleanup; + } + + Name = &MungedName; + + } else { + + // + // We return the queried result if the path is not in the + // mapping. + // + + Name = &LowerNameInfo->Name; + + } + + } else if (ReturnShortName) { + + // + // Note that unlike opened names, a query for a shortname only returns + // the final component, not the full path. + // + + // TODO: Assert not preopen + + if (RealOverlap.Match) { + + // + // The opened path is the mapping path. + // This means that if we queried the filesystem + // he would return the wrong path. + // + // Luckily, we can just use the mapping. + // + + Name = &InstanceContext->Mapping.UserMapping.ShortNamePath.FinalComponentName; + + } else { + + // + // We have to query below us to get the short name. + // + + Status = NcGetFileNameInformation( Data, + FileObject, + Instance, + FLT_FILE_NAME_SHORT | + NameQueryMethod | + NameFlags, + &ShortInfo ); + + if (!NT_SUCCESS( Status )) { + + goto NcGenerateFileNameCleanup; + } + + Status = FltParseFileNameInformation( ShortInfo ); + + if (!NT_SUCCESS(Status)) { + + goto NcGenerateFileNameCleanup; + } + + // + // Set name to returned name. + // + + Name = &ShortInfo->Name; + } + } + + FLT_ASSERT( Name != NULL ); + + // + // Try to grow the namechanger's record to accommodate the result. + // + + Status = FltCheckAndGrowNameControl( OutputNameControl, Name->Length ); + + if (NT_SUCCESS( Status )) { + + // + // Copy the new name into the buffer. + // + + RtlCopyUnicodeString( &OutputNameControl->Name, Name ); + *CacheFileNameInformation = TRUE; + } + +NcGenerateFileNameCleanup: + + if (LowerNameInfo != NULL) { + + FltReleaseFileNameInformation( LowerNameInfo ); + } + + if (ShortInfo != NULL) { + + FltReleaseFileNameInformation( ShortInfo ); + } + + if (InstanceContext != NULL) { + + FltReleaseContext( InstanceContext ); + } + + if (MungedName.Buffer != NULL) { + + ExFreePoolWithTag( MungedName.Buffer, NC_GENERATE_NAME_TAG ); + } + + return Status; +} + +NTSTATUS +NcNormalizeNameComponentEx ( + _In_ PFLT_INSTANCE Instance, + _In_opt_ PFILE_OBJECT FileObject, + _In_ PCUNICODE_STRING ParentDirectory, + _In_ USHORT DeviceNameLength, + _In_ PCUNICODE_STRING Component, + _Out_writes_bytes_(ExpandComponentNameLength) PFILE_NAMES_INFORMATION ExpandComponentName, + _In_ ULONG ExpandComponentNameLength, + _In_ FLT_NORMALIZE_NAME_FLAGS Flags, + _Inout_ PVOID *NormalizationContext + ) +{ + + NTSTATUS Status; + PNC_INSTANCE_CONTEXT InstanceContext = NULL; + NC_PATH_OVERLAP ParentOverlap; //overlap between the parent path and the user mapping. + UNICODE_STRING Remainder; + UNICODE_STRING MungedParentPath; // Path we are going to open for query + PCUNICODE_STRING MungedComponent; // File name to enumerate + PWSTR MungedBuffer = NULL; + ULONG MungedBufferLength; + + IO_STATUS_BLOCK ParentStatusBlock; + OBJECT_ATTRIBUTES ParentAttributes; + HANDLE ParentHandle = 0; + PFILE_OBJECT ParentFileObject = NULL; + BOOLEAN IgnoreCase = !BooleanFlagOn( Flags, FLTFL_NORMALIZE_NAME_CASE_SENSITIVE ); + + PAGED_CODE(); + + FLT_ASSERT( IoGetTopLevelIrp() == NULL ); + + UNREFERENCED_PARAMETER( NormalizationContext ); + UNREFERENCED_PARAMETER( DeviceNameLength ); + UNREFERENCED_PARAMETER( FileObject ); + + Status = FltGetInstanceContext( Instance, + &InstanceContext ); + + if (!NT_SUCCESS( Status )) { + + goto NcNormalizeNameComponentExCleanup; + } + + // + // Default to enumerating the component specified by the + // caller. + // + + MungedComponent = Component; + + NcComparePath( ParentDirectory, + &InstanceContext->Mapping.UserMapping, + &Remainder, + IgnoreCase, + TRUE, + &ParentOverlap ); + + // + // We need to figure out which path we are going to open. + // + + if (ParentOverlap.InMapping) { + + // + // The parent is in the mapping, so it has to be + // munged in order to be opened. + // + + MungedBufferLength = Remainder.Length + InstanceContext->Mapping.RealMapping.LongNamePath.FullPath.Length; + + MungedBuffer = ExAllocatePoolWithTag( PagedPool, MungedBufferLength, NC_NORMALIZE_NAME_TAG ); + + if (MungedBuffer == NULL) { + + Status = STATUS_INSUFFICIENT_RESOURCES; + goto NcNormalizeNameComponentExCleanup; + } + + // + // Construct munged name. + // + + MungedParentPath.Buffer = MungedBuffer; + MungedParentPath.Length = 0; + MungedParentPath.MaximumLength = (USHORT) MungedBufferLength; + + RtlCopyUnicodeString( &MungedParentPath, + &InstanceContext->Mapping.RealMapping.LongNamePath.FullPath ); + + RtlAppendUnicodeStringToString( &MungedParentPath, + &Remainder); + + } else if (ParentOverlap.Parent) { + + // + // The parent is the parent of the user mapping. + // That means we need to see if the final component is + // the mapping path itself. + // + + if( RtlCompareUnicodeString( Component, + &InstanceContext->Mapping.UserMapping.LongNamePath.FinalComponentName, + IgnoreCase) == 0 || + RtlCompareUnicodeString( Component, + &InstanceContext->Mapping.UserMapping.ShortNamePath.FinalComponentName, + IgnoreCase) == 0) { + + // + // The requested final component is the mapping itself. + // Hence the real mapping is the munged name. + // + + MungedParentPath = InstanceContext->Mapping.RealMapping.LongNamePath.ParentPath; + MungedComponent = &InstanceContext->Mapping.RealMapping.LongNamePath.FinalComponentName; + + } else { + + // + // The system is requesting another path in the user mapping's parent. + // Go ahead and open the given path. + // + + MungedParentPath = *ParentDirectory; + } + + } else { //ParentOverlap is not within or parent of mapping. + + MungedParentPath = *ParentDirectory; + } + + // + // We should open MungedParentPath and enumerate it. + // + + InitializeObjectAttributes( &ParentAttributes, + &MungedParentPath, + OBJ_KERNEL_HANDLE | (IgnoreCase?OBJ_CASE_INSENSITIVE:0), + NULL, + NULL); + + Status = NcCreateFileHelper( NcGlobalData.FilterHandle, + Instance, + &ParentHandle, + &ParentFileObject, + FILE_LIST_DIRECTORY | FILE_TRAVERSE, + &ParentAttributes, + &ParentStatusBlock, + 0, + FILE_ATTRIBUTE_NORMAL, + 0, + FILE_OPEN, + FILE_DIRECTORY_FILE, + NULL, + 0, + IO_IGNORE_SHARE_ACCESS_CHECK, + FileObject ); + + if (!NT_SUCCESS( Status )) { + + goto NcNormalizeNameComponentExCleanup; + } + + Status = NcQueryDirectoryFile( Instance, + ParentFileObject, + ExpandComponentName, + ExpandComponentNameLength, + FileNamesInformation, + TRUE, + (PUNICODE_STRING) MungedComponent, + TRUE, + NULL ); + + if (!NT_SUCCESS( Status )) { + + goto NcNormalizeNameComponentExCleanup; + } + + // + // The object exists. Now we need to return the correct + // final name. + // + + if (Component != MungedComponent) { + + ULONG SizeRequired; + + SizeRequired = FIELD_OFFSET( FILE_NAMES_INFORMATION, FileName ) + + InstanceContext->Mapping.UserMapping.LongNamePath.FinalComponentName.Length; + + if (ExpandComponentNameLength < SizeRequired) { + + Status = STATUS_BUFFER_OVERFLOW; + goto NcNormalizeNameComponentExCleanup; + } + + FLT_ASSERT( ExpandComponentName->NextEntryOffset == 0 ); + ExpandComponentName->NextEntryOffset = 0; + ExpandComponentName->FileIndex = 0; + ExpandComponentName->FileNameLength = InstanceContext->Mapping.UserMapping.LongNamePath.FinalComponentName.Length; + RtlCopyMemory( ExpandComponentName->FileName, + InstanceContext->Mapping.UserMapping.LongNamePath.FinalComponentName.Buffer, + InstanceContext->Mapping.UserMapping.LongNamePath.FinalComponentName.Length ); + + } + + //TODO THIS NEEDS TO + +NcNormalizeNameComponentExCleanup: + + if (InstanceContext != NULL) { + + FltReleaseContext( InstanceContext ); + } + + if (MungedBuffer != NULL) { + + ExFreePoolWithTag( MungedBuffer, NC_NORMALIZE_NAME_TAG ); + } + + if (ParentHandle != 0) { + + FltClose( ParentHandle ); + } + + if (ParentFileObject != NULL) { + + ObDereferenceObject( ParentFileObject ); + + } + + //TODO THERE ARE ONLY TWO VALID ERROR CODES: STATUS_NO_SUCH_FILE, STATUS_SUCCESS if you want the name construction to continue. + //any other code will stop the query. + return Status; +} diff --git a/filesys/miniFilter/NameChanger/ncoffsets.c b/filesys/miniFilter/NameChanger/ncoffsets.c new file mode 100644 index 00000000..f958b21b --- /dev/null +++ b/filesys/miniFilter/NameChanger/ncoffsets.c @@ -0,0 +1,632 @@ +#include "nc.h" + +/* + +Munging entries from the directory query responses requires name changer +to interpret the data returned from the query. There are currently 9 +information classes, each with a different structure for holding the file data. + +Of the 9 queries, we are interested in the following: + +FileBothDirectoryInformation +FileDirectoryInformation +FileFullDirectoryInformation +FileFullDirectoryInformation +FileIdFullDirectoryInformation +FileNamesInformation +FileObjectIdInformation + +Each of structures related to these queries have the following properties: +1) Holds the offset to the next entry +2) Holds the file name length (in bytes) +3) The first WCHAR of the file name is the last entry of the structure, +with the remainder of the name following the structure. + +The purpose of the DIRECTORY_CONTROL_OFFSETS structure is to allow +a generic method of interpreting the query data by holding the offset +information for each of the above variables. Combined with the directory +walking functions (below) we now have an easy uniform means of parsing +the directory queries. + +*/ + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE, NcCalculateDirectoryNotificationOffsets) +#pragma alloc_text(PAGE, NcDetermineStructureOffsets) +#pragma alloc_text(PAGE, NcGetEntrySize) +#pragma alloc_text(PAGE, NcGetFileName) +#pragma alloc_text(PAGE, NcGetFileNameLength) +#pragma alloc_text(PAGE, NcGetNextEntry) +#pragma alloc_text(PAGE, NcGetNextEntryOffset) +#pragma alloc_text(PAGE, NcGetShortName) +#pragma alloc_text(PAGE, NcGetShortNameLength) +#pragma alloc_text(PAGE, NcSetFileName) +#pragma alloc_text(PAGE, NcSetNextEntryOffset) +#pragma alloc_text(PAGE, NcSetShortName) +#endif + +//--------------------------------------------------------------------------- +// FUNCTIONS FOR WALKING DIRECTORY STRUCTURE +//--------------------------------------------------------------------------- +BOOLEAN +NcDetermineStructureOffsets ( + _Out_ PDIRECTORY_CONTROL_OFFSETS Offsets, + _In_ FILE_INFORMATION_CLASS Information + ) +/*++ + +Routine Description: + + Determines the structure offsets for the FILE_INFORMATION_CLASS provided. + +Arguments: + + Offsets - Output DIRECTORY_CONTROL_OFFSETS pointer. + + Information - What structure to use. + + DirectoryBuffer - A sample buffer for us to test with. + +Returns: + + return TRUE if we have a structure to handle this request, + otherwise return FALSE. Offsets are returned through the Offsets + pointer. + +--*/ +{ + BOOLEAN ReturnValue = TRUE; + PAGED_CODE(); + + // + // Not all directory information classes have short names. + // So we'll zero out short name data for classes that don't expose it . + // + + Offsets->ShortNamePresent = FALSE; + Offsets->ShortNameLengthDist = 0; + Offsets->ShortNameDist = 0; + + switch( Information ) { + + case FileBothDirectoryInformation: + + Offsets->NextEntryOffsetDist = + FIELD_OFFSET( FILE_BOTH_DIR_INFORMATION, NextEntryOffset ); + + Offsets->FileNameLengthDist = + FIELD_OFFSET( FILE_BOTH_DIR_INFORMATION, FileNameLength ); + + Offsets->FileNameDist = + FIELD_OFFSET( FILE_BOTH_DIR_INFORMATION, FileName ); + + Offsets->ShortNamePresent = TRUE; + + Offsets->ShortNameLengthDist = + FIELD_OFFSET( FILE_BOTH_DIR_INFORMATION, ShortNameLength ); + + Offsets->ShortNameDist = + FIELD_OFFSET( FILE_BOTH_DIR_INFORMATION, ShortName ); + + break; + + case FileDirectoryInformation: + + Offsets->NextEntryOffsetDist = + FIELD_OFFSET( FILE_DIRECTORY_INFORMATION, NextEntryOffset ); + + Offsets->FileNameLengthDist = + FIELD_OFFSET( FILE_DIRECTORY_INFORMATION, FileNameLength ); + + Offsets->FileNameDist = + FIELD_OFFSET( FILE_DIRECTORY_INFORMATION, FileName ); + + break; + + case FileFullDirectoryInformation: + + Offsets->NextEntryOffsetDist = + FIELD_OFFSET( FILE_FULL_DIR_INFORMATION, NextEntryOffset ); + + Offsets->FileNameLengthDist = + FIELD_OFFSET( FILE_FULL_DIR_INFORMATION, FileNameLength ); + + Offsets->FileNameDist = + FIELD_OFFSET( FILE_FULL_DIR_INFORMATION, FileName ); + + break; + + case FileIdBothDirectoryInformation: + + Offsets->NextEntryOffsetDist = + FIELD_OFFSET( FILE_ID_BOTH_DIR_INFORMATION, NextEntryOffset ); + + Offsets->FileNameLengthDist = + FIELD_OFFSET( FILE_ID_BOTH_DIR_INFORMATION, FileNameLength ); + + Offsets->FileNameDist = + FIELD_OFFSET( FILE_ID_BOTH_DIR_INFORMATION, FileName ); + + Offsets->ShortNamePresent = TRUE; + + Offsets->ShortNameLengthDist = + FIELD_OFFSET( FILE_ID_BOTH_DIR_INFORMATION, ShortNameLength ); + + Offsets->ShortNameDist = + FIELD_OFFSET( FILE_ID_BOTH_DIR_INFORMATION, ShortName ); + + break; + + case FileIdFullDirectoryInformation: + + Offsets->NextEntryOffsetDist = + FIELD_OFFSET( FILE_ID_FULL_DIR_INFORMATION, NextEntryOffset ); + + Offsets->FileNameLengthDist = + FIELD_OFFSET( FILE_ID_FULL_DIR_INFORMATION, FileNameLength ); + + Offsets->FileNameDist = + FIELD_OFFSET( FILE_ID_FULL_DIR_INFORMATION, FileName ); + + break; + + case FileNamesInformation: + + Offsets->NextEntryOffsetDist = + FIELD_OFFSET( FILE_NAMES_INFORMATION, NextEntryOffset ); + + Offsets->FileNameLengthDist = + FIELD_OFFSET( FILE_NAMES_INFORMATION, FileNameLength ); + + Offsets->FileNameDist = + FIELD_OFFSET( FILE_NAMES_INFORMATION, FileName ); + + break; + + default: + + // + // There are queries that we don't filter, + // so just return FALSE to state failure. + // + + ReturnValue = FALSE; + break; + } + + return ReturnValue; +} + +VOID +NcCalculateDirectoryNotificationOffsets ( + PDIRECTORY_CONTROL_OFFSETS Offsets + ) +/*++ + +Routine Description: + + Directory Notifications use a structure with similar properties + to a directory query. CalculateDirectoryNotificationOffsets allows + us to reuse the ncoffsets library with directory notification structures. + +Arguments + + Offsets - Output DIRECTORY_CONTROL_OFFSETS pointer. + +--*/ +{ + + PAGED_CODE(); + + // + // Place offsets for next entry and file name. + // + + Offsets->NextEntryOffsetDist = FIELD_OFFSET( FILE_NOTIFY_INFORMATION, NextEntryOffset ); + Offsets->FileNameLengthDist = FIELD_OFFSET( FILE_NOTIFY_INFORMATION, FileNameLength ); + Offsets->FileNameDist = FIELD_OFFSET( FILE_NOTIFY_INFORMATION, FileName ); + + // + // Directory notification does not have short names. + // + + Offsets->ShortNamePresent = FALSE; + Offsets->ShortNameLengthDist = 0; + Offsets->ShortNameDist = 0; +} + + +ULONG +NcGetNextEntryOffset ( + _In_ CONST PVOID Buffer, + _In_ CONST PDIRECTORY_CONTROL_OFFSETS Offsets + ) +/*++ + +Routine Description: + + Returns the offset in bytes to the next entry. + +Arguments: + + Buffer - Pointer to the start of the current entry. + + Offsets - Offsets structure for this information class. + +Return Value: + + The number of bytes from Buffer to the next entry. + +--*/ +{ + PULONG Offset = Add2Ptr( Buffer, Offsets->NextEntryOffsetDist ); + PAGED_CODE(); + return *Offset; +} + + +PVOID +NcGetNextEntry ( + _In_ CONST PVOID Buffer, + _In_ CONST PDIRECTORY_CONTROL_OFFSETS Offsets + ) +/*++ + +Routine Description: + + Returns a pointer to the next entry in the buffer. + +Arguments: + + Buffer - Pointer to the start of the current entry. + + Offsets - Offsets structure for this information class. + +Return Value: + + Returns a pointer to the beginning of the next entry. + +--*/ +{ + ULONG Offset = NcGetNextEntryOffset( Buffer, Offsets ); + PVOID NextEntry = Add2Ptr( Buffer, Offset ); + PAGED_CODE(); + return NextEntry; +} + + +ULONG +NcGetFileNameLength ( + _In_ CONST PVOID Buffer, + _In_ CONST PDIRECTORY_CONTROL_OFFSETS Offsets + ) +/*++ + +Routine Description: + + Returns the length of the file name in bytes. + +Arguments: + + Buffer - Pointer to the start of the entry. + + Offsets - Offsets structure for the information class. + +Return Value: + + Returns the length of the file name component of the buffer. + +--*/ +{ + ULONG Result = *((PULONG)(Add2Ptr( Buffer, Offsets->FileNameLengthDist ))); + PAGED_CODE(); + return Result; +} + + +ULONG +NcGetEntrySize ( + _In_ CONST PVOID Buffer, + _In_ CONST PDIRECTORY_CONTROL_OFFSETS Offsets + ) +/*++ + +Routine Description: + + Returns the size of this entry in bytes. + +Arguments: + + Buffer - Pointer to the start of the entry. + + Offsets - Offsets structure for the information class. + +Return Value: + + Returns the size of this entry in bytes. + +--*/ +{ + ULONG EntrySize = NcGetNextEntryOffset(Buffer, Offsets); + PAGED_CODE(); + + if (EntrySize == 0) { + + // + // We are at last entry, so we need to calculate this ourselves. + // + + EntrySize = NcGetFileNameLength( Buffer, Offsets ); + EntrySize += Offsets->FileNameDist; + } + + return EntrySize; +} + + +PWSTR +NcGetFileName ( + _In_ CONST PVOID Buffer, + _In_ CONST PDIRECTORY_CONTROL_OFFSETS Offsets + ) +/*++ + +Routine Description: + + Returns a pointer to the file name string. + +Arguments: + + Buffer - Pointer to the start of the entry. + + Offsets - Offsets structure for the information class. + +Return Value: + + A pointer to the start of the file name for this entry. + +--*/ +{ + PAGED_CODE(); + return Add2Ptr(Buffer, Offsets->FileNameDist); +} + + +PWSTR +NcGetShortName ( + _In_ CONST PVOID Buffer, + _In_ CONST PDIRECTORY_CONTROL_OFFSETS Offsets + ) +/*++ + +Routine Description: + + Returns a pointer to the short name for this entry. + +Arguments: + + Buffer - Pointer to the start of this entry. + + Offsets - Offsets structure for the information class. + +Return Value: + + If there is a short name in this information class, returns a pointer to the + start of the short name. Otherwise, returns NULL. +--*/ +{ + PAGED_CODE(); + + if (Offsets->ShortNamePresent) { + + return Add2Ptr(Buffer, Offsets->ShortNameDist); + + } else { + + return NULL; + } +} + + +CCHAR +NcGetShortNameLength ( + _In_ CONST PVOID Buffer, + _In_ CONST PDIRECTORY_CONTROL_OFFSETS Offsets + ) +/*++ + +Routine Description: + + Returns the length of the shortname. + +Arguments + + Buffer - Pointer to the start of this entry. + + Offsets - Offsets structure for the information class. + +Return Value + + Returns the length of the short name. + Returns -1 on failure. + +--*/ +{ + CCHAR *Ptr; + PAGED_CODE(); + + if (Offsets->ShortNamePresent) { + + Ptr = Add2Ptr(Buffer, Offsets->ShortNameLengthDist); + return *Ptr; + } else { + + return -1; + } +} + + +VOID +NcSetNextEntryOffset ( + _Inout_ PVOID Buffer, + _In_ CONST PDIRECTORY_CONTROL_OFFSETS Offsets, + _In_ BOOLEAN ForceLast + ) +/*++ + +Routine Description: + + Sets the Next Entry Offset to Value. + +Arguments: + + Buffer - Pointer to the start of this entry. + + Offsets - Offsets structure for the information class. + + ForceLast - If true, the size of the next entry is set to zero. + Otherwise, the size will be set to the size of the + information class + the file name's length. + +--*/ +{ + // + // Get pointer to NextEntryOffset value. + // + + PULONG NextEntry = Add2Ptr( Buffer, Offsets->NextEntryOffsetDist ); + PAGED_CODE(); + + // + // Get length of name. + // + + if (ForceLast) { + + // + // This is the last entry, so we need to make sure 0 is in the + // next entry offset. + // + + *NextEntry = 0; + + } else { + + // + // Next entry offset is the distance to the name + // plus the length of the name. + // + + ULONG NameLength = NcGetFileNameLength( Buffer, Offsets ); + *NextEntry = Offsets->FileNameDist + NameLength; + } +} + + +VOID +NcSetFileName ( + _In_ PVOID Entry, + _In_ PWSTR NewName, + _In_ ULONG Length, + _In_ CONST PDIRECTORY_CONTROL_OFFSETS Offsets, + _In_ BOOLEAN ForceLast + ) +/*++ + +Routine Description: + + Sets a new file name into the entry. + +Arguments: + + Entry - A pointer to the start of the entry. + + NewName - A pointer to the new file name. + + Length - The length of the new name (in bytes). + + Offsets - Offsets structure for the information class. + + ForceLast - If true, the entry's size will be set to zero + so that it looks like a valid last entry. + +Return Value + + None. + +--*/ +{ + PWSTR NamePtr; + PULONG NameLength; + + PAGED_CODE(); + + // + // Get a pointer to the name in the buffer. + // + + NamePtr = NcGetFileName( Entry, Offsets); + NameLength = Add2Ptr( Entry, Offsets->FileNameLengthDist ); + + // + // Copy the new name into buffer. + // + + RtlCopyMemory( NamePtr, NewName, Length ); + *NameLength = Length; + + // + // Now we have to update the size of this entry. + // + + NcSetNextEntryOffset( Entry, Offsets, ForceLast ); +} + + +VOID +NcSetShortName ( + _In_ PVOID Entry, + _In_ PWSTR NewShortName, + _In_ USHORT Length, + _In_ CONST PDIRECTORY_CONTROL_OFFSETS Offsets + ) +/*++ + +Routine Description: + + Sets a new short name into an entry if the information class + supports short names. + +Arguments: + + Entry - Pointer to the start of an entry. + + NewShortName - Pointer to the new shortname. + + Length - The length of the short name in bytes. + + Offsets - Offsets structure for the information class. + +Return Value: + + None. + +--*/ +{ + PWSTR NamePtr; + PCCHAR NameLength; + + PAGED_CODE(); + + if( Offsets->ShortNamePresent ) { + + NamePtr = NcGetShortName( Entry, Offsets ); + NameLength = Add2Ptr( Entry, Offsets->ShortNameLengthDist ); + + FLT_ASSERT( Length <= (12 * sizeof(WCHAR)) ); + + RtlCopyMemory(NamePtr, NewShortName, Length ); + *NameLength = (UCHAR) Length; + } +} + diff --git a/filesys/miniFilter/NameChanger/ncpath.c b/filesys/miniFilter/NameChanger/ncpath.c new file mode 100644 index 00000000..4f892e36 --- /dev/null +++ b/filesys/miniFilter/NameChanger/ncpath.c @@ -0,0 +1,674 @@ +#include "nc.h" + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE, NcComparePath) +#pragma alloc_text(PAGE, NcConstructPath) +#pragma alloc_text(PAGE, NcParseFinalComponent) +#endif + +#define NcIsCharComponentTerminator( C ) \ + ((C) == L'\\' || (C) == L':') + +BOOLEAN +NcComparePath ( + _In_ PCUNICODE_STRING Name, + _In_ PNC_MAPPING_ENTRY Mapping, + _Out_opt_ PUNICODE_STRING Remainder, + _In_ BOOLEAN IgnoreCase, + _In_ BOOLEAN ContainsDevice, + _Out_ PNC_PATH_OVERLAP Overlap + ) +/*++ + +Routine Description: + + Compares a name against a mapping and returns the Overlap. + +Arguments: + + Name - The name we are checking. + + Mapping - The mapping path we are comparing against. + + Remainder - If the string matches the mapping, then Remainder will be + the portion of the name after the mapping to the end of the + string. + + IgnoreCase - Case sensitivity. + + ContainsDevice - TRUE if the input name is expected to contain a fully + qualified path including the device name. FALSE if the + path is relative to the root of the volume (excludes + device.) + + Overlap - Pointer to an NC_PATH_OVERLAP structure. Structure members will + be set when this routine exits. + +Return Value: + + TRUE if the string is in the mapping; Remainder is written to if present. + FALSE if the string is not in the mapping; Remainder is not written to. + + Note that this is not a success code; this routine always succeeds. Further + information about the mapping is in the Overlap parameter. + +--*/ +{ + PUNICODE_STRING LongName; + PUNICODE_STRING ShortName; + + PWSTR NameBuff; + PWSTR LongBuff; + PWSTR ShortBuff; + + WCHAR NameBuffCur; + WCHAR LongBuffCur; + WCHAR ShortBuffCur; + + USHORT NameIndex; // Our index in Name + USHORT NameMatchIndex = 0; // Our index of matched components in Name + USHORT LongIndex; // Our index in MappingPath->LongNamePath + USHORT ShortIndex; // Our index in MappingPath->ShortNamePath + + BOOLEAN LongMatch; // TRUE if long name component matches + BOOLEAN ShortMatch; // TRUE if short name component matches + + USHORT NameLength; // Max index for NameIndex + USHORT LongLength; + USHORT ShortLength; + + BOOLEAN NameDone; // TRUE when we hit a '\',stop comparing for this component. + BOOLEAN LongDone; + BOOLEAN ShortDone; + + USHORT ComponentMatches = 0; // Number of component matches. + USHORT MappingComponents; + USHORT VolumeComponents; + + PAGED_CODE(); + + if (ContainsDevice) { + LongName = &Mapping->LongNamePath.FullPath; + ShortName = &Mapping->ShortNamePath.FullPath; + + MappingComponents = Mapping->LongNamePath.NumberComponentsInFullPath; + VolumeComponents = Mapping->LongNamePath.NumberComponentsInVolumePath; + } else { + LongName = &Mapping->LongNamePath.VolumelessName; + ShortName = &Mapping->ShortNamePath.VolumelessName; + + MappingComponents = Mapping->LongNamePath.NumberComponentsInFullPath - Mapping->LongNamePath.NumberComponentsInVolumePath; + VolumeComponents = 0; + } + + NameBuff = Name->Buffer; + LongBuff = LongName->Buffer; + ShortBuff = ShortName->Buffer; + + NameLength = Name->Length/sizeof(WCHAR); // Max index for NameIndex + LongLength = LongName->Length/sizeof(WCHAR); + ShortLength = ShortName->Length/sizeof(WCHAR); + + // + // Names are Unicode strings, so the number of bytes in + // the length should always be even. + // + + FLT_ASSERT( Name->Length % sizeof(WCHAR) == 0 ); + FLT_ASSERT( LongName->Length % sizeof(WCHAR) == 0 ); + FLT_ASSERT( ShortName->Length % sizeof(WCHAR) == 0 ); + FLT_ASSERT( Mapping->LongNamePath.NumberComponentsInFullPath == Mapping->ShortNamePath.NumberComponentsInFullPath ); + + // Set initial values + NameIndex = 0; + LongIndex = 0; + ShortIndex = 0; + NameMatchIndex = 0; + + do // Loop for component scan + { + + // + // Mark that we have not reached the end of the component. + // Once we reach end of component, we stop going forward until everyone has caught up. + // + + NameDone = FALSE; + LongDone = FALSE; + ShortDone = FALSE; + + // + // Mark that the names match + // We assume they match until we prove otherwise. + // + + LongMatch = TRUE; + ShortMatch = TRUE; + + do // Loop for character scan. + { + + // + // See if we have reached the end of the component. + // + + NameDone = (BOOLEAN)(NameIndex >= NameLength || NcIsCharComponentTerminator( NameBuff[NameIndex] )); + LongDone = (BOOLEAN)(LongIndex >= LongLength || LongBuff[LongIndex] == '\\'); + ShortDone = (BOOLEAN)(ShortIndex >= ShortLength || ShortBuff[ShortIndex] == '\\'); + + if (NameDone) { + + // + // If name has run off end, or hit end of component, + // then we need to break. + // + + break; + } + + if(LongDone && ShortDone) { + + // + // If the paths we are comparing against have + // both ether run out or hit the end of their + // respective components, then we need to break. + // + + break; + } + + // + // Convert characters into case insensitive mode (if needed) + // + + if (IgnoreCase) { + + NameBuffCur = RtlUpcaseUnicodeChar( NameBuff[NameIndex] ); + if (!LongDone) { + LongBuffCur = RtlUpcaseUnicodeChar( LongBuff[LongIndex] ); + } + + if (!ShortDone) { + ShortBuffCur = RtlUpcaseUnicodeChar( ShortBuff[ShortIndex] ); + } + + } else { + + NameBuffCur = NameBuff[NameIndex]; + if (!LongDone) { + LongBuffCur = LongBuff[LongIndex]; + } + + if (!ShortDone) { + ShortBuffCur = ShortBuff[ShortIndex]; + } + } + + // + // Compare characters to verify match. + // + + if (!LongDone) { + if (NameBuffCur != LongBuffCur) { + LongMatch = FALSE; // If the characters are not matches, then we are not a match. + } + } else { + LongMatch = FALSE; // If we're comparing beyond the end of the buffer, we don't match. + } + + if (!ShortDone) { + if (NameBuffCur != ShortBuffCur) { + ShortMatch = FALSE; // If the characters are not matches, then we are not a match. + } + } else { + ShortMatch = FALSE; + } + + // + // Move to next index + // + + NameIndex++; + if (!LongDone) { + LongIndex++; + } + if (!ShortDone) { + ShortIndex++; + } + + // + // Loop if there is still chance of match + // + + } while(LongMatch || ShortMatch);// end of character scan. + + // + // We scanned until we had 2 mismatches or we ran off the end of the name, + // or we ran off the end of the long and short names. + // We should scan everyone forward until they are all off the end of their + // buffer, or it the end of their component. + // + + if (NameIndex < NameLength && !NcIsCharComponentTerminator( NameBuff[NameIndex] )) { + + // + // We broke out of character comparison, but were not at the end + // of the name's component. This means that both the long and short + // names were shorter than the name's component. Thus they cannot + // be matches. Furthermore, because neither of them are matches, we + // can stop the search. + // + + LongMatch = FALSE; + ShortMatch = FALSE; + break; + } + + while (NameIndex < NameLength && NameBuff[NameIndex] != '\\') { + + // + // We may still consider this component a match due to a stream. + // In this case, we need to advance the name index until we + // find the next slash. + // + // TODO: Note one effect of this is we will believe + // \dir1\foo matches \dir1:Stream\foo. The latter name is not a + // valid name on any Microsoft filesystem. + // + + NameIndex++; + } + + while( LongIndex < LongLength && LongBuff[LongIndex] != '\\' ) { + + // + // We were not at the end of the long name's component. + // So it cannot be a match. + // Scan forward until we find the end. + // + + LongMatch = FALSE; + LongIndex++; + } + + while( ShortIndex < ShortLength && ShortBuff[ShortIndex] != '\\' ) { + + // + // We were not at the end of the short name's component. + // So it cannot be a match. + // Scan forward until we find the end. + // + + ShortMatch = FALSE; + ShortIndex++; + } + + if ((LongMatch || ShortMatch) && NameIndex != 0) { + ComponentMatches++; + } + + // + // All the indexes should be at the end of their buffer or their component. + // + + FLT_ASSERT( NameIndex == NameLength || NameBuff[NameIndex] == '\\' ); + FLT_ASSERT( LongIndex == LongLength || LongBuff[LongIndex] == '\\' ); + FLT_ASSERT( ShortIndex == ShortLength || ShortBuff[ShortIndex] == '\\' ); + + // + // Since we are all lined up on '\', lets move forward to next component... + // + + if (NameIndex < NameLength) { + NameIndex++; + } + + if (LongIndex < LongLength) { + LongIndex++; + } + + if (ShortIndex < ShortLength) { + ShortIndex++; + } + + if (LongMatch || ShortMatch) { + NameMatchIndex = NameIndex; + } + + // + // Keep looping if name's last component matched either + // the long or short's component and name and the mapping + // have more components. + // + // NOTE: if LongIndex < LongLength, + // then ShortIndex < ShortLength because they have the same number of components. + // + + FLT_ASSERT( (LongIndex < LongLength) ? (ShortIndex < ShortLength) : TRUE ); + + } while( (LongMatch || ShortMatch) && NameIndex < NameLength && LongIndex < LongLength ); + + // + // Now we need to figure out how far we made it, and + // apply the appropriate flags. + // + + Overlap->EntireFlags = 0; + + // + // We can't match more components than exist or something's seriously wrong. + // + FLT_ASSERT( ComponentMatches <= MappingComponents ); + + if (ComponentMatches >= MappingComponents && + NameLength > NameMatchIndex) { + + // + // If we've matched all the components in the mapping and still have data + // left over, we're in the mapping. + // + + Overlap->InMapping = TRUE; + + if (Remainder != NULL) { + + Remainder->Buffer = &NameBuff[NameMatchIndex]; + Remainder->Length = (NameLength - NameMatchIndex) * sizeof(WCHAR); + Remainder->MaximumLength = Remainder->Length; + } + + } else if (ComponentMatches == MappingComponents) { + + // + // If we matched all the components in the mapping and have nothing + // left over, we are the mapping. + // + + Overlap->Match = TRUE; + Overlap->InMapping = TRUE; + + if (Remainder != NULL) { + + Remainder->Buffer = &NameBuff[NameIndex]; + Remainder->MaximumLength = Remainder->Length = 0; + } + + } else if (ComponentMatches == MappingComponents - 1 && + NameLength > NameMatchIndex) { + + // + // If we matched everything except the final component but have data + // left over, we may be a peer of the mapping. For this to be true, + // the only string left must be a filename, not a path. + // + + Overlap->Peer = TRUE; + + for (;NameIndex < NameLength;NameIndex++) { + if (NameBuff[NameIndex] == L'\\') { + Overlap->Peer = FALSE; + break; + } + } + + + } else if (ComponentMatches == MappingComponents - 1) { + + // + // If we matched everything except the final component, then we must + // be the parent. + // + + Overlap->Parent = TRUE; + Overlap->Ancestor = TRUE; + + } else if (ComponentMatches >= VolumeComponents && + NameLength == NameMatchIndex) { + + // + // If we matched something and have no data left over, then we are + // an ancestor path. + // + + Overlap->Ancestor = TRUE; + } + + return (BOOLEAN)Overlap->InMapping; +} + +_Post_satisfies_(NewName->MaximumLength < MAXUSHORT) +_Post_satisfies_(NewName->Length <= NewName->MaximumLength) +_Must_inspect_result_ +NTSTATUS +NcConstructPath ( + _In_ PNC_MAPPING_ENTRY RealPath, + _In_ PUNICODE_STRING Remainder, + _In_ BOOLEAN IncludeVolume, + _Out_ _At_(NewName->Buffer, __drv_allocatesMem(Mem)) PUNICODE_STRING NewName + ) +/*++ + +Routine Description: + + Constructs a path + +Arguments: + + RealPath - Path from the mapping we want to use in name generation. + + Remainder - Remainder string generated by NcComparePath. + + IncludeVolume - If TRUE, the volume will be prepended to the name. + + NewName - Output name. + +Return Value: + + STATUS_SUCCESS or an appropriate error code. + +--*/ +{ + NTSTATUS Status = STATUS_SUCCESS; + USHORT NameLength; + PWCHAR NameBuffer; + USHORT SeparatorLength; + + PAGED_CODE(); + + // + // Calculate length of combined name. + // + + SeparatorLength = (Remainder->Length == 0 ? 0 : sizeof(WCHAR)); + NameLength = RealPath->LongNamePath.VolumelessName.Length + SeparatorLength + Remainder->Length; + if( IncludeVolume ) { + + NameLength = NameLength + RealPath->LongNamePath.VolumePath.Length; + } + + // + // Potentially a file may exist on disk which is less than MAXUSHORT, + // but our mapping changes the length such that it now exceeds + // MAXUSHORT. We can't really handle this object meaningfully, since + // all path operations have a UNICODE_STRING limitation. Accordingly, + // some files may be inaccessible for some purposes as a result of + // this. In practice it won't happen, and the important thing is to + // ensure we don't overflow and create security vulnerabilities. + // + if (NameLength >= MAXUSHORT) { + + Status = STATUS_OBJECT_PATH_INVALID; + goto NcConstructPathCleanup; + } + + // + // Allocate space for combined name. + // + + NameBuffer = ExAllocatePoolWithTag( PagedPool, + NameLength, + NC_GENERATE_NAME_TAG ); + + if (NameBuffer == NULL) { + + Status = STATUS_INSUFFICIENT_RESOURCES; + goto NcConstructPathCleanup; + } + + // + // Zero out destination + // + + NewName->Buffer = NameBuffer; + NewName->Length = 0; + NewName->MaximumLength = NameLength; + + // + // Copy Volume Path + // + + if (IncludeVolume) { + + Status = RtlAppendUnicodeStringToString( NewName, &RealPath->LongNamePath.VolumePath ); + + FLT_ASSERT( Status == STATUS_SUCCESS ); + } + + // + // Copy mapping path. + // + + Status = RtlAppendUnicodeStringToString( NewName, + &RealPath->LongNamePath.VolumelessName ); + + FLT_ASSERT( Status == STATUS_SUCCESS ); + + // + // Append separator + // + + if (SeparatorLength > 0) { + + NewName->Buffer[NewName->Length/sizeof(WCHAR)] = NC_SEPARATOR; + NewName->Length += sizeof(WCHAR); + + FLT_ASSERT( NewName->Length <= NewName->MaximumLength ); + } + + // + // Append Remainder. + // + + Status = RtlAppendUnicodeStringToString( NewName, Remainder ); + + FLT_ASSERT( Status == STATUS_SUCCESS ); + +NcConstructPathCleanup: + + return Status; +} + +NTSTATUS +NcParseFinalComponent( + _In_ PUNICODE_STRING EntirePath, + _Out_ PUNICODE_STRING ParentPath, + _Out_ PUNICODE_STRING FinalComponent + ) +{ + USHORT Index = EntirePath->Length / sizeof(WCHAR); + USHORT ParentLength; + USHORT FinalComponentLength; + BOOLEAN FoundFinalComponent = FALSE; + NTSTATUS Status = STATUS_SUCCESS; + PWSTR ParentStringBuffer = NULL; + PWSTR FinalStringBuffer = NULL; + + PAGED_CODE(); + + while(Index > 0) { + Index--; + if (EntirePath->Buffer[Index] == L'\\') { + FoundFinalComponent = TRUE; + break; + } + } + + // + // Paths should contain at least one seperator. + // We expect all paths to be absolute, relative to + // the volume, so they should always start with '\'. + // + if (!FoundFinalComponent) { + return STATUS_INVALID_PARAMETER; + } + + // + // Typically we don't want to include a trailing + // slash in the parent path. The exception to this + // rule is for the volume root. + // + if (Index > 1) { + ParentLength = Index * sizeof(WCHAR); + } else { + ParentLength = (Index + 1) * sizeof(WCHAR); + } + + // + // We also don't want to have no final component. + // This implies a user configured the path as + // \a\b\c\, including the trailing slash. + // + FinalComponentLength = EntirePath->Length - (Index + 1) * sizeof(WCHAR); + if (FinalComponentLength == 0) { + return STATUS_INVALID_PARAMETER; + } + + ParentStringBuffer = ExAllocatePoolWithTag( NonPagedPool, + ParentLength, + NC_TAG ); + + if (ParentStringBuffer == NULL) { + Status = STATUS_INSUFFICIENT_RESOURCES; + goto NcParseFinalComponentCleanup; + } + + FinalStringBuffer = ExAllocatePoolWithTag( NonPagedPool, + FinalComponentLength, + NC_TAG ); + + if (FinalStringBuffer == NULL) { + Status = STATUS_INSUFFICIENT_RESOURCES; + goto NcParseFinalComponentCleanup; + } + + RtlCopyMemory( ParentStringBuffer, EntirePath->Buffer, ParentLength ); + + ParentPath->Buffer = ParentStringBuffer; + ParentPath->MaximumLength = + ParentPath->Length = ParentLength; + + RtlCopyMemory( FinalStringBuffer, &EntirePath->Buffer[Index + 1], FinalComponentLength ); + + FinalComponent->Buffer = FinalStringBuffer; + FinalComponent->MaximumLength = + FinalComponent->Length = FinalComponentLength; + + // + // We've completed successfully, and our allocated + // buffers are in use. + // + ParentStringBuffer = NULL; + FinalStringBuffer = NULL; + +NcParseFinalComponentCleanup: + + if (ParentStringBuffer) { + ExFreePoolWithTag( ParentStringBuffer, NC_TAG ); + } + + if (FinalStringBuffer) { + ExFreePoolWithTag( FinalStringBuffer, NC_TAG ); + } + + return Status; +} diff --git a/filesys/miniFilter/avscan/avscan.sln b/filesys/miniFilter/avscan/avscan.sln index 0fc17fad..d5f16333 100644 --- a/filesys/miniFilter/avscan/avscan.sln +++ b/filesys/miniFilter/avscan/avscan.sln @@ -3,13 +3,13 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Filter", "Filter", "{9B4F0964-C698-49FE-B160-251A3A483399}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Filter", "Filter", "{D78D0CAE-EF4B-44FC-A328-A04817C7A02D}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "User", "User", "{4A27FF26-F700-4D97-9F45-F1CBD7C78513}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "User", "User", "{8B8F8102-C54A-4300-966E-EC924824AB8A}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "avscan", "filter\avscan.vcxproj", "{9D7DE7C5-51FC-4465-B1F9-0B3C9900477A}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "avscan", "filter\avscan.vcxproj", "{E4CD5CAB-EC77-4E94-88DE-174D361CD4B3}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "avscan", "user\avscan.vcxproj", "{23D46B81-CF8D-48E5-BF28-3679E6106D7F}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "avscan", "user\avscan.vcxproj", "{71D634DA-3CBE-46FD-B793-50EE8660A13A}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -19,28 +19,28 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {9D7DE7C5-51FC-4465-B1F9-0B3C9900477A}.Debug|Win32.ActiveCfg = Debug|Win32 - {9D7DE7C5-51FC-4465-B1F9-0B3C9900477A}.Debug|Win32.Build.0 = Debug|Win32 - {9D7DE7C5-51FC-4465-B1F9-0B3C9900477A}.Release|Win32.ActiveCfg = Release|Win32 - {9D7DE7C5-51FC-4465-B1F9-0B3C9900477A}.Release|Win32.Build.0 = Release|Win32 - {9D7DE7C5-51FC-4465-B1F9-0B3C9900477A}.Debug|x64.ActiveCfg = Debug|x64 - {9D7DE7C5-51FC-4465-B1F9-0B3C9900477A}.Debug|x64.Build.0 = Debug|x64 - {9D7DE7C5-51FC-4465-B1F9-0B3C9900477A}.Release|x64.ActiveCfg = Release|x64 - {9D7DE7C5-51FC-4465-B1F9-0B3C9900477A}.Release|x64.Build.0 = Release|x64 - {23D46B81-CF8D-48E5-BF28-3679E6106D7F}.Debug|Win32.ActiveCfg = Debug|Win32 - {23D46B81-CF8D-48E5-BF28-3679E6106D7F}.Debug|Win32.Build.0 = Debug|Win32 - {23D46B81-CF8D-48E5-BF28-3679E6106D7F}.Release|Win32.ActiveCfg = Release|Win32 - {23D46B81-CF8D-48E5-BF28-3679E6106D7F}.Release|Win32.Build.0 = Release|Win32 - {23D46B81-CF8D-48E5-BF28-3679E6106D7F}.Debug|x64.ActiveCfg = Debug|x64 - {23D46B81-CF8D-48E5-BF28-3679E6106D7F}.Debug|x64.Build.0 = Debug|x64 - {23D46B81-CF8D-48E5-BF28-3679E6106D7F}.Release|x64.ActiveCfg = Release|x64 - {23D46B81-CF8D-48E5-BF28-3679E6106D7F}.Release|x64.Build.0 = Release|x64 + {E4CD5CAB-EC77-4E94-88DE-174D361CD4B3}.Debug|Win32.ActiveCfg = Debug|Win32 + {E4CD5CAB-EC77-4E94-88DE-174D361CD4B3}.Debug|Win32.Build.0 = Debug|Win32 + {E4CD5CAB-EC77-4E94-88DE-174D361CD4B3}.Release|Win32.ActiveCfg = Release|Win32 + {E4CD5CAB-EC77-4E94-88DE-174D361CD4B3}.Release|Win32.Build.0 = Release|Win32 + {E4CD5CAB-EC77-4E94-88DE-174D361CD4B3}.Debug|x64.ActiveCfg = Debug|x64 + {E4CD5CAB-EC77-4E94-88DE-174D361CD4B3}.Debug|x64.Build.0 = Debug|x64 + {E4CD5CAB-EC77-4E94-88DE-174D361CD4B3}.Release|x64.ActiveCfg = Release|x64 + {E4CD5CAB-EC77-4E94-88DE-174D361CD4B3}.Release|x64.Build.0 = Release|x64 + {71D634DA-3CBE-46FD-B793-50EE8660A13A}.Debug|Win32.ActiveCfg = Debug|Win32 + {71D634DA-3CBE-46FD-B793-50EE8660A13A}.Debug|Win32.Build.0 = Debug|Win32 + {71D634DA-3CBE-46FD-B793-50EE8660A13A}.Release|Win32.ActiveCfg = Release|Win32 + {71D634DA-3CBE-46FD-B793-50EE8660A13A}.Release|Win32.Build.0 = Release|Win32 + {71D634DA-3CBE-46FD-B793-50EE8660A13A}.Debug|x64.ActiveCfg = Debug|x64 + {71D634DA-3CBE-46FD-B793-50EE8660A13A}.Debug|x64.Build.0 = Debug|x64 + {71D634DA-3CBE-46FD-B793-50EE8660A13A}.Release|x64.ActiveCfg = Release|x64 + {71D634DA-3CBE-46FD-B793-50EE8660A13A}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {9D7DE7C5-51FC-4465-B1F9-0B3C9900477A} = {9B4F0964-C698-49FE-B160-251A3A483399} - {23D46B81-CF8D-48E5-BF28-3679E6106D7F} = {4A27FF26-F700-4D97-9F45-F1CBD7C78513} + {E4CD5CAB-EC77-4E94-88DE-174D361CD4B3} = {D78D0CAE-EF4B-44FC-A328-A04817C7A02D} + {71D634DA-3CBE-46FD-B793-50EE8660A13A} = {8B8F8102-C54A-4300-966E-EC924824AB8A} EndGlobalSection EndGlobal diff --git a/filesys/miniFilter/avscan/filter/avscan.vcxproj b/filesys/miniFilter/avscan/filter/avscan.vcxproj index d68461a9..1ffed653 100644 --- a/filesys/miniFilter/avscan/filter/avscan.vcxproj +++ b/filesys/miniFilter/avscan/filter/avscan.vcxproj @@ -19,11 +19,11 @@
- {9D7DE7C5-51FC-4465-B1F9-0B3C9900477A} + {E4CD5CAB-EC77-4E94-88DE-174D361CD4B3} $(MSBuildProjectName) Debug Win32 - {94FDDA0B-6FFA-4B09-A8F0-A303F46D8BF0} + {1067E8CA-F2D6-4D98-BC94-B86E241AAA17} diff --git a/filesys/miniFilter/avscan/filter/avscan.vcxproj.Filters b/filesys/miniFilter/avscan/filter/avscan.vcxproj.Filters index 56c60b39..366bc916 100644 --- a/filesys/miniFilter/avscan/filter/avscan.vcxproj.Filters +++ b/filesys/miniFilter/avscan/filter/avscan.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {6A96A213-242A-44D1-87C3-9EF1E57E7EC9} + {1A8B08AD-02ED-4F8D-9692-2C34A5799CEE} h;hpp;hxx;hm;inl;inc;xsd - {794C3035-6983-4AF3-A981-5EEAA51276B3} + {8DD0310C-BC99-44D2-A386-3B07A6947AAA} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {A7F78AF9-20F5-4D0E-83A9-8E19405F5C0C} + {C38EDF08-31B6-4B26-BA29-02805AA5D698} inf;inv;inx;mof;mc; - {0D596D83-E754-4E17-BD2E-884C8CCFCF7D} + {151004C3-679F-4485-BF94-3CC5842AF213} diff --git a/filesys/miniFilter/avscan/user/avscan.vcxproj b/filesys/miniFilter/avscan/user/avscan.vcxproj index 7a3112b0..95b470ac 100644 --- a/filesys/miniFilter/avscan/user/avscan.vcxproj +++ b/filesys/miniFilter/avscan/user/avscan.vcxproj @@ -19,11 +19,11 @@ - {23D46B81-CF8D-48E5-BF28-3679E6106D7F} + {71D634DA-3CBE-46FD-B793-50EE8660A13A} $(MSBuildProjectName) Debug Win32 - {0D25D92A-41FF-4D6F-A937-A24EE3010777} + {E649BB1A-4B9F-4AF5-B5E2-9DED21AA79C6} diff --git a/filesys/miniFilter/avscan/user/avscan.vcxproj.Filters b/filesys/miniFilter/avscan/user/avscan.vcxproj.Filters index 5ca0df68..75b4df39 100644 --- a/filesys/miniFilter/avscan/user/avscan.vcxproj.Filters +++ b/filesys/miniFilter/avscan/user/avscan.vcxproj.Filters @@ -3,15 +3,15 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {7C20F6A5-EEFE-4E1E-ACA6-D81A9175944F} + {6330BD20-823F-41C7-8759-F6597157F670} h;hpp;hxx;hm;inl;inc;xsd - {A175AC1D-BDB6-4F3C-B19E-42160282E929} + {AC298499-B215-4A19-85AB-4A72B4A56B49} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {B2375B4F-9F4C-4FA5-9C19-76A963F2A7DA} + {C0A004FA-FFA1-4504-9AF4-3671E5079F64} diff --git a/filesys/miniFilter/cancelSafe/cancelSafe.c b/filesys/miniFilter/cancelSafe/cancelSafe.c index 202803ef..d2f4b83d 100644 --- a/filesys/miniFilter/cancelSafe/cancelSafe.c +++ b/filesys/miniFilter/cancelSafe/cancelSafe.c @@ -1235,6 +1235,20 @@ Return Value: if (!NT_SUCCESS( Status )) { + // + // If we failed to queue a workitem we need to + // decrement the worker thread flag. If we did + // not decrement it future queue insertions would + // not trigger a workitem and requests added to + // the queue would be orphaned. We can safely + // decrement the flag here because we are + // guaranteed that no worker routine is currently + // running and that the queue is currently locked. + // + + InterlockedDecrement( &InstCtx->WorkerThreadFlag ); + NT_ASSERT( InstCtx->WorkerThreadFlag == 0 ); + // // Remove the callback data that was inserted into the queue. // diff --git a/filesys/miniFilter/cancelSafe/cancelSafe.sln b/filesys/miniFilter/cancelSafe/cancelSafe.sln index 17d34d65..a85db67b 100644 --- a/filesys/miniFilter/cancelSafe/cancelSafe.sln +++ b/filesys/miniFilter/cancelSafe/cancelSafe.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cancelSafe", "cancelSafe.vcxproj", "{AC99C662-1480-43BF-B6C1-5B3055F228E2}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cancelSafe", "cancelSafe.vcxproj", "{17EA55B5-5F8B-49FE-AF79-20F8F5E9CBB8}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +13,14 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {AC99C662-1480-43BF-B6C1-5B3055F228E2}.Debug|Win32.ActiveCfg = Debug|Win32 - {AC99C662-1480-43BF-B6C1-5B3055F228E2}.Debug|Win32.Build.0 = Debug|Win32 - {AC99C662-1480-43BF-B6C1-5B3055F228E2}.Release|Win32.ActiveCfg = Release|Win32 - {AC99C662-1480-43BF-B6C1-5B3055F228E2}.Release|Win32.Build.0 = Release|Win32 - {AC99C662-1480-43BF-B6C1-5B3055F228E2}.Debug|x64.ActiveCfg = Debug|x64 - {AC99C662-1480-43BF-B6C1-5B3055F228E2}.Debug|x64.Build.0 = Debug|x64 - {AC99C662-1480-43BF-B6C1-5B3055F228E2}.Release|x64.ActiveCfg = Release|x64 - {AC99C662-1480-43BF-B6C1-5B3055F228E2}.Release|x64.Build.0 = Release|x64 + {17EA55B5-5F8B-49FE-AF79-20F8F5E9CBB8}.Debug|Win32.ActiveCfg = Debug|Win32 + {17EA55B5-5F8B-49FE-AF79-20F8F5E9CBB8}.Debug|Win32.Build.0 = Debug|Win32 + {17EA55B5-5F8B-49FE-AF79-20F8F5E9CBB8}.Release|Win32.ActiveCfg = Release|Win32 + {17EA55B5-5F8B-49FE-AF79-20F8F5E9CBB8}.Release|Win32.Build.0 = Release|Win32 + {17EA55B5-5F8B-49FE-AF79-20F8F5E9CBB8}.Debug|x64.ActiveCfg = Debug|x64 + {17EA55B5-5F8B-49FE-AF79-20F8F5E9CBB8}.Debug|x64.Build.0 = Debug|x64 + {17EA55B5-5F8B-49FE-AF79-20F8F5E9CBB8}.Release|x64.ActiveCfg = Release|x64 + {17EA55B5-5F8B-49FE-AF79-20F8F5E9CBB8}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/filesys/miniFilter/cancelSafe/cancelSafe.vcxproj b/filesys/miniFilter/cancelSafe/cancelSafe.vcxproj index 8e6a1960..c5e30e9e 100644 --- a/filesys/miniFilter/cancelSafe/cancelSafe.vcxproj +++ b/filesys/miniFilter/cancelSafe/cancelSafe.vcxproj @@ -19,11 +19,11 @@ - {AC99C662-1480-43BF-B6C1-5B3055F228E2} + {17EA55B5-5F8B-49FE-AF79-20F8F5E9CBB8} $(MSBuildProjectName) Debug Win32 - {71FE15A0-262E-47F8-BEFF-3C73167F2349} + {1A4310B8-0486-411A-876C-A46B9F451585} diff --git a/filesys/miniFilter/cancelSafe/cancelSafe.vcxproj.Filters b/filesys/miniFilter/cancelSafe/cancelSafe.vcxproj.Filters index 11736279..db122ac6 100644 --- a/filesys/miniFilter/cancelSafe/cancelSafe.vcxproj.Filters +++ b/filesys/miniFilter/cancelSafe/cancelSafe.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {4671E7BF-8D01-45C4-A3C1-20A08F5BBEDF} + {FAEAE193-5200-4618-812C-70AFA581370C} h;hpp;hxx;hm;inl;inc;xsd - {ABBB6D26-48D1-4341-AC20-F5D5C5329766} + {9F8F1EC3-3CF7-4411-BEE9-5DEFA1D2AE58} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {483287C7-E0B5-452F-BB3A-486026CBBB4F} + {3331A654-2D71-4859-AC8B-FC9157021A59} inf;inv;inx;mof;mc; - {DF4558B9-9BF3-4D98-B89E-718878687D2C} + {1877FF63-A2D6-4D22-85FF-5158F35E2AAF} diff --git a/filesys/miniFilter/cdo/cdo.sln b/filesys/miniFilter/cdo/cdo.sln index c0fd8f6d..b6441b60 100644 --- a/filesys/miniFilter/cdo/cdo.sln +++ b/filesys/miniFilter/cdo/cdo.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cdo", "cdo.vcxproj", "{1C6DC452-62DC-48E5-9C9F-B32BDF4C8F2F}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cdo", "cdo.vcxproj", "{4A98BEA4-7D70-4642-814D-B3E69149E496}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +13,14 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {1C6DC452-62DC-48E5-9C9F-B32BDF4C8F2F}.Debug|Win32.ActiveCfg = Debug|Win32 - {1C6DC452-62DC-48E5-9C9F-B32BDF4C8F2F}.Debug|Win32.Build.0 = Debug|Win32 - {1C6DC452-62DC-48E5-9C9F-B32BDF4C8F2F}.Release|Win32.ActiveCfg = Release|Win32 - {1C6DC452-62DC-48E5-9C9F-B32BDF4C8F2F}.Release|Win32.Build.0 = Release|Win32 - {1C6DC452-62DC-48E5-9C9F-B32BDF4C8F2F}.Debug|x64.ActiveCfg = Debug|x64 - {1C6DC452-62DC-48E5-9C9F-B32BDF4C8F2F}.Debug|x64.Build.0 = Debug|x64 - {1C6DC452-62DC-48E5-9C9F-B32BDF4C8F2F}.Release|x64.ActiveCfg = Release|x64 - {1C6DC452-62DC-48E5-9C9F-B32BDF4C8F2F}.Release|x64.Build.0 = Release|x64 + {4A98BEA4-7D70-4642-814D-B3E69149E496}.Debug|Win32.ActiveCfg = Debug|Win32 + {4A98BEA4-7D70-4642-814D-B3E69149E496}.Debug|Win32.Build.0 = Debug|Win32 + {4A98BEA4-7D70-4642-814D-B3E69149E496}.Release|Win32.ActiveCfg = Release|Win32 + {4A98BEA4-7D70-4642-814D-B3E69149E496}.Release|Win32.Build.0 = Release|Win32 + {4A98BEA4-7D70-4642-814D-B3E69149E496}.Debug|x64.ActiveCfg = Debug|x64 + {4A98BEA4-7D70-4642-814D-B3E69149E496}.Debug|x64.Build.0 = Debug|x64 + {4A98BEA4-7D70-4642-814D-B3E69149E496}.Release|x64.ActiveCfg = Release|x64 + {4A98BEA4-7D70-4642-814D-B3E69149E496}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/filesys/miniFilter/cdo/cdo.vcxproj b/filesys/miniFilter/cdo/cdo.vcxproj index 52dc8e52..3e5171f4 100644 --- a/filesys/miniFilter/cdo/cdo.vcxproj +++ b/filesys/miniFilter/cdo/cdo.vcxproj @@ -19,11 +19,11 @@ - {1C6DC452-62DC-48E5-9C9F-B32BDF4C8F2F} + {4A98BEA4-7D70-4642-814D-B3E69149E496} $(MSBuildProjectName) Debug Win32 - {6ABBD5BA-9307-4ABF-821A-66D082F38769} + {59E189BC-6395-42FB-BA5D-85848C0F7789} diff --git a/filesys/miniFilter/cdo/cdo.vcxproj.Filters b/filesys/miniFilter/cdo/cdo.vcxproj.Filters index 04f6e7f0..9741b152 100644 --- a/filesys/miniFilter/cdo/cdo.vcxproj.Filters +++ b/filesys/miniFilter/cdo/cdo.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {33D6FDE5-707F-4D9E-A316-A031D1F83BC8} + {4EDD470E-081B-42DB-AC5F-16296A253546} h;hpp;hxx;hm;inl;inc;xsd - {3BD87E43-9C30-4470-9754-3114B37E0BFD} + {B80F0DF0-E538-4454-9BE3-551C8D46C3EE} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {4A9AC38F-BAFE-45E1-929D-047A9F3680ED} + {35CA4FF2-18D8-4F39-98A2-81E504C473CA} inf;inv;inx;mof;mc; - {AA17AAA7-BDC6-41C8-9342-FF2F9D6AE3CB} + {D5FEDC88-C91B-4136-8438-A7A7A7A7F1DC} diff --git a/filesys/miniFilter/change/change.sln b/filesys/miniFilter/change/change.sln index 98e886ed..62a967ed 100644 --- a/filesys/miniFilter/change/change.sln +++ b/filesys/miniFilter/change/change.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "change", "change.vcxproj", "{0E6C9EB8-07AE-4E07-BEFB-D7C0E98D8442}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "change", "change.vcxproj", "{60E86F7F-16E4-4F3C-91A5-F8E202386F10}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +13,14 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {0E6C9EB8-07AE-4E07-BEFB-D7C0E98D8442}.Debug|Win32.ActiveCfg = Debug|Win32 - {0E6C9EB8-07AE-4E07-BEFB-D7C0E98D8442}.Debug|Win32.Build.0 = Debug|Win32 - {0E6C9EB8-07AE-4E07-BEFB-D7C0E98D8442}.Release|Win32.ActiveCfg = Release|Win32 - {0E6C9EB8-07AE-4E07-BEFB-D7C0E98D8442}.Release|Win32.Build.0 = Release|Win32 - {0E6C9EB8-07AE-4E07-BEFB-D7C0E98D8442}.Debug|x64.ActiveCfg = Debug|x64 - {0E6C9EB8-07AE-4E07-BEFB-D7C0E98D8442}.Debug|x64.Build.0 = Debug|x64 - {0E6C9EB8-07AE-4E07-BEFB-D7C0E98D8442}.Release|x64.ActiveCfg = Release|x64 - {0E6C9EB8-07AE-4E07-BEFB-D7C0E98D8442}.Release|x64.Build.0 = Release|x64 + {60E86F7F-16E4-4F3C-91A5-F8E202386F10}.Debug|Win32.ActiveCfg = Debug|Win32 + {60E86F7F-16E4-4F3C-91A5-F8E202386F10}.Debug|Win32.Build.0 = Debug|Win32 + {60E86F7F-16E4-4F3C-91A5-F8E202386F10}.Release|Win32.ActiveCfg = Release|Win32 + {60E86F7F-16E4-4F3C-91A5-F8E202386F10}.Release|Win32.Build.0 = Release|Win32 + {60E86F7F-16E4-4F3C-91A5-F8E202386F10}.Debug|x64.ActiveCfg = Debug|x64 + {60E86F7F-16E4-4F3C-91A5-F8E202386F10}.Debug|x64.Build.0 = Debug|x64 + {60E86F7F-16E4-4F3C-91A5-F8E202386F10}.Release|x64.ActiveCfg = Release|x64 + {60E86F7F-16E4-4F3C-91A5-F8E202386F10}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/filesys/miniFilter/change/change.vcxproj b/filesys/miniFilter/change/change.vcxproj index d16c83bf..7f34ea33 100644 --- a/filesys/miniFilter/change/change.vcxproj +++ b/filesys/miniFilter/change/change.vcxproj @@ -19,11 +19,11 @@ - {0E6C9EB8-07AE-4E07-BEFB-D7C0E98D8442} + {60E86F7F-16E4-4F3C-91A5-F8E202386F10} $(MSBuildProjectName) Debug Win32 - {1794254B-AC98-41EB-A845-110FCD1AA932} + {04E1BD24-A9C6-471E-942D-B4A4F77125FE} diff --git a/filesys/miniFilter/change/change.vcxproj.Filters b/filesys/miniFilter/change/change.vcxproj.Filters index 1bca247f..ebad34d5 100644 --- a/filesys/miniFilter/change/change.vcxproj.Filters +++ b/filesys/miniFilter/change/change.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {D9D46B85-B0A5-4C33-8BE4-28566220F42D} + {68724F11-A0FA-48CE-85FD-A786F328F757} h;hpp;hxx;hm;inl;inc;xsd - {B66FFE81-FB9C-4422-BF7B-795BA16B48F1} + {FEAB8F27-1AD0-4230-BB82-A9FA8EF7DF67} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {78FB7669-0DC6-4483-9EAB-571950829035} + {E66AFE53-4910-4644-A9A4-63861F5375BF} inf;inv;inx;mof;mc; - {2E70873B-AF69-4324-ACF7-7318A567F6B3} + {380AD108-3AC4-428B-8916-067667866507} diff --git a/filesys/miniFilter/ctx/ctx.sln b/filesys/miniFilter/ctx/ctx.sln index 316647ca..8dfec33a 100644 --- a/filesys/miniFilter/ctx/ctx.sln +++ b/filesys/miniFilter/ctx/ctx.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ctx", "ctx.vcxproj", "{8A826E76-F53C-4951-B81A-8653A4FC7BF0}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ctx", "ctx.vcxproj", "{D00E3EDA-0BA1-428E-8DBE-D3D1DD586CD0}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +13,14 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {8A826E76-F53C-4951-B81A-8653A4FC7BF0}.Debug|Win32.ActiveCfg = Debug|Win32 - {8A826E76-F53C-4951-B81A-8653A4FC7BF0}.Debug|Win32.Build.0 = Debug|Win32 - {8A826E76-F53C-4951-B81A-8653A4FC7BF0}.Release|Win32.ActiveCfg = Release|Win32 - {8A826E76-F53C-4951-B81A-8653A4FC7BF0}.Release|Win32.Build.0 = Release|Win32 - {8A826E76-F53C-4951-B81A-8653A4FC7BF0}.Debug|x64.ActiveCfg = Debug|x64 - {8A826E76-F53C-4951-B81A-8653A4FC7BF0}.Debug|x64.Build.0 = Debug|x64 - {8A826E76-F53C-4951-B81A-8653A4FC7BF0}.Release|x64.ActiveCfg = Release|x64 - {8A826E76-F53C-4951-B81A-8653A4FC7BF0}.Release|x64.Build.0 = Release|x64 + {D00E3EDA-0BA1-428E-8DBE-D3D1DD586CD0}.Debug|Win32.ActiveCfg = Debug|Win32 + {D00E3EDA-0BA1-428E-8DBE-D3D1DD586CD0}.Debug|Win32.Build.0 = Debug|Win32 + {D00E3EDA-0BA1-428E-8DBE-D3D1DD586CD0}.Release|Win32.ActiveCfg = Release|Win32 + {D00E3EDA-0BA1-428E-8DBE-D3D1DD586CD0}.Release|Win32.Build.0 = Release|Win32 + {D00E3EDA-0BA1-428E-8DBE-D3D1DD586CD0}.Debug|x64.ActiveCfg = Debug|x64 + {D00E3EDA-0BA1-428E-8DBE-D3D1DD586CD0}.Debug|x64.Build.0 = Debug|x64 + {D00E3EDA-0BA1-428E-8DBE-D3D1DD586CD0}.Release|x64.ActiveCfg = Release|x64 + {D00E3EDA-0BA1-428E-8DBE-D3D1DD586CD0}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/filesys/miniFilter/ctx/ctx.vcxproj b/filesys/miniFilter/ctx/ctx.vcxproj index 65ce09b0..02105e0a 100644 --- a/filesys/miniFilter/ctx/ctx.vcxproj +++ b/filesys/miniFilter/ctx/ctx.vcxproj @@ -19,11 +19,11 @@ - {8A826E76-F53C-4951-B81A-8653A4FC7BF0} + {D00E3EDA-0BA1-428E-8DBE-D3D1DD586CD0} $(MSBuildProjectName) Debug Win32 - {E0BB0921-D467-4DDA-82CD-8B1FAADDBC55} + {EA561ABD-0088-4EF5-875C-CE05C0BC76D4} diff --git a/filesys/miniFilter/ctx/ctx.vcxproj.Filters b/filesys/miniFilter/ctx/ctx.vcxproj.Filters index 4eef3fc4..22a08147 100644 --- a/filesys/miniFilter/ctx/ctx.vcxproj.Filters +++ b/filesys/miniFilter/ctx/ctx.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {872ED434-D252-450B-ACD5-B7DDB6FF6D4E} + {36F385EE-28D4-41AE-A395-DD2DDE392541} h;hpp;hxx;hm;inl;inc;xsd - {FC7A2108-DAAB-43D9-AEFA-120FC32876D7} + {B72DF203-BB8E-4EA1-AAA9-F25126CC8C2B} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {C1AC955C-1C1A-4B66-8AA8-C6173E6B2EDD} + {6968CBCC-DC1D-49E1-BCBE-1FBAC7ED57E6} inf;inv;inx;mof;mc; - {1E203714-FFC5-4465-BC3D-2ED22ED46D83} + {C038C42C-4536-4CB3-8645-69BE91B63491} diff --git a/filesys/miniFilter/delete/delete.sln b/filesys/miniFilter/delete/delete.sln index 3af04bb5..2c13b91b 100644 --- a/filesys/miniFilter/delete/delete.sln +++ b/filesys/miniFilter/delete/delete.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "delete", "delete.vcxproj", "{A872AE22-1A64-4531-A85F-03361BE73894}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "delete", "delete.vcxproj", "{70924271-22E0-474E-BB48-4176AB921E8F}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +13,14 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {A872AE22-1A64-4531-A85F-03361BE73894}.Debug|Win32.ActiveCfg = Debug|Win32 - {A872AE22-1A64-4531-A85F-03361BE73894}.Debug|Win32.Build.0 = Debug|Win32 - {A872AE22-1A64-4531-A85F-03361BE73894}.Release|Win32.ActiveCfg = Release|Win32 - {A872AE22-1A64-4531-A85F-03361BE73894}.Release|Win32.Build.0 = Release|Win32 - {A872AE22-1A64-4531-A85F-03361BE73894}.Debug|x64.ActiveCfg = Debug|x64 - {A872AE22-1A64-4531-A85F-03361BE73894}.Debug|x64.Build.0 = Debug|x64 - {A872AE22-1A64-4531-A85F-03361BE73894}.Release|x64.ActiveCfg = Release|x64 - {A872AE22-1A64-4531-A85F-03361BE73894}.Release|x64.Build.0 = Release|x64 + {70924271-22E0-474E-BB48-4176AB921E8F}.Debug|Win32.ActiveCfg = Debug|Win32 + {70924271-22E0-474E-BB48-4176AB921E8F}.Debug|Win32.Build.0 = Debug|Win32 + {70924271-22E0-474E-BB48-4176AB921E8F}.Release|Win32.ActiveCfg = Release|Win32 + {70924271-22E0-474E-BB48-4176AB921E8F}.Release|Win32.Build.0 = Release|Win32 + {70924271-22E0-474E-BB48-4176AB921E8F}.Debug|x64.ActiveCfg = Debug|x64 + {70924271-22E0-474E-BB48-4176AB921E8F}.Debug|x64.Build.0 = Debug|x64 + {70924271-22E0-474E-BB48-4176AB921E8F}.Release|x64.ActiveCfg = Release|x64 + {70924271-22E0-474E-BB48-4176AB921E8F}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/filesys/miniFilter/delete/delete.vcxproj b/filesys/miniFilter/delete/delete.vcxproj index c2863872..b827a7f2 100644 --- a/filesys/miniFilter/delete/delete.vcxproj +++ b/filesys/miniFilter/delete/delete.vcxproj @@ -19,11 +19,11 @@ - {A872AE22-1A64-4531-A85F-03361BE73894} + {70924271-22E0-474E-BB48-4176AB921E8F} $(MSBuildProjectName) Debug Win32 - {DDF5DA16-05BC-4E87-9743-B11BFFA79395} + {983B8DC5-A107-4899-88AE-7E3EF643B95B} diff --git a/filesys/miniFilter/delete/delete.vcxproj.Filters b/filesys/miniFilter/delete/delete.vcxproj.Filters index 994af6a4..2502ad88 100644 --- a/filesys/miniFilter/delete/delete.vcxproj.Filters +++ b/filesys/miniFilter/delete/delete.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {0433160E-D11D-43E0-962A-F91BE56E9913} + {18043465-F44B-4DEF-8BAE-4836B5B96347} h;hpp;hxx;hm;inl;inc;xsd - {1BDAC8A0-7CBD-4CC1-9BC9-531A473E2C93} + {1305C3BE-0E2E-4103-8DFB-4B06F55C5FD5} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {391C5CBD-0397-4FCB-AFAE-CBDE3F118A7F} + {C66CE925-8A7F-4B95-B92B-E3EC6C00BD69} inf;inv;inx;mof;mc; - {1791F586-ED65-4309-8E44-3A9A74B4E2D7} + {D2AA6CEC-4B22-4779-B62F-D83B3AB88B56} diff --git a/filesys/miniFilter/minispy/filter/minispy.vcxproj b/filesys/miniFilter/minispy/filter/minispy.vcxproj index de6dac81..a75aceb5 100644 --- a/filesys/miniFilter/minispy/filter/minispy.vcxproj +++ b/filesys/miniFilter/minispy/filter/minispy.vcxproj @@ -19,11 +19,11 @@ - {99B46F3E-1CC2-4689-8D3E-80CCBD448E39} + {F59D1435-1559-4BFF-90FF-F6B2E081ADBA} $(MSBuildProjectName) Debug Win32 - {88181562-E49D-4E01-B470-89CECAA14E2E} + {B0F09019-3767-45D4-87E2-FF17FA11652A} diff --git a/filesys/miniFilter/minispy/filter/minispy.vcxproj.Filters b/filesys/miniFilter/minispy/filter/minispy.vcxproj.Filters index 7425e30c..4c51d4ff 100644 --- a/filesys/miniFilter/minispy/filter/minispy.vcxproj.Filters +++ b/filesys/miniFilter/minispy/filter/minispy.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {3973B07F-3667-4849-9D74-E6225E72C259} + {ADEB4B1F-7275-4D86-A8AC-1268384B7530} h;hpp;hxx;hm;inl;inc;xsd - {7BA4662B-3492-4B81-8081-ACA773397EA2} + {AF75460A-0706-4819-B584-BA557565BD9E} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {7C19E51C-41FA-46DE-9B69-35A11D9989A7} + {57EBC54C-C6CD-46B7-8093-C4810A40C233} inf;inv;inx;mof;mc; - {E81C4500-8F1F-45E5-92F1-B012E4D9FEB7} + {32B54034-2B3E-4AE9-9F0D-2D256FC4276D} diff --git a/filesys/miniFilter/minispy/minispy.sln b/filesys/miniFilter/minispy/minispy.sln index f6bc3c1c..22ea2743 100644 --- a/filesys/miniFilter/minispy/minispy.sln +++ b/filesys/miniFilter/minispy/minispy.sln @@ -3,13 +3,13 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Filter", "Filter", "{3B396921-0231-4B6C-B5E5-C7695F992BA7}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Filter", "Filter", "{39A7F6C2-D480-4C5C-B6FB-48ACDDA45B59}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "User", "User", "{32B4D5F7-B865-467E-9344-627DDBB25267}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "User", "User", "{42CC0135-35A4-4AD0-97D5-140EA747A3CD}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "minispy", "filter\minispy.vcxproj", "{99B46F3E-1CC2-4689-8D3E-80CCBD448E39}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "minispy", "filter\minispy.vcxproj", "{F59D1435-1559-4BFF-90FF-F6B2E081ADBA}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "minispy", "user\minispy.vcxproj", "{3EFB308B-ED6C-42FE-9140-9883674EA0A2}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "minispy", "user\minispy.vcxproj", "{8193E678-7717-4820-BBA6-A15A283160B1}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -19,28 +19,28 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {99B46F3E-1CC2-4689-8D3E-80CCBD448E39}.Debug|Win32.ActiveCfg = Debug|Win32 - {99B46F3E-1CC2-4689-8D3E-80CCBD448E39}.Debug|Win32.Build.0 = Debug|Win32 - {99B46F3E-1CC2-4689-8D3E-80CCBD448E39}.Release|Win32.ActiveCfg = Release|Win32 - {99B46F3E-1CC2-4689-8D3E-80CCBD448E39}.Release|Win32.Build.0 = Release|Win32 - {99B46F3E-1CC2-4689-8D3E-80CCBD448E39}.Debug|x64.ActiveCfg = Debug|x64 - {99B46F3E-1CC2-4689-8D3E-80CCBD448E39}.Debug|x64.Build.0 = Debug|x64 - {99B46F3E-1CC2-4689-8D3E-80CCBD448E39}.Release|x64.ActiveCfg = Release|x64 - {99B46F3E-1CC2-4689-8D3E-80CCBD448E39}.Release|x64.Build.0 = Release|x64 - {3EFB308B-ED6C-42FE-9140-9883674EA0A2}.Debug|Win32.ActiveCfg = Debug|Win32 - {3EFB308B-ED6C-42FE-9140-9883674EA0A2}.Debug|Win32.Build.0 = Debug|Win32 - {3EFB308B-ED6C-42FE-9140-9883674EA0A2}.Release|Win32.ActiveCfg = Release|Win32 - {3EFB308B-ED6C-42FE-9140-9883674EA0A2}.Release|Win32.Build.0 = Release|Win32 - {3EFB308B-ED6C-42FE-9140-9883674EA0A2}.Debug|x64.ActiveCfg = Debug|x64 - {3EFB308B-ED6C-42FE-9140-9883674EA0A2}.Debug|x64.Build.0 = Debug|x64 - {3EFB308B-ED6C-42FE-9140-9883674EA0A2}.Release|x64.ActiveCfg = Release|x64 - {3EFB308B-ED6C-42FE-9140-9883674EA0A2}.Release|x64.Build.0 = Release|x64 + {F59D1435-1559-4BFF-90FF-F6B2E081ADBA}.Debug|Win32.ActiveCfg = Debug|Win32 + {F59D1435-1559-4BFF-90FF-F6B2E081ADBA}.Debug|Win32.Build.0 = Debug|Win32 + {F59D1435-1559-4BFF-90FF-F6B2E081ADBA}.Release|Win32.ActiveCfg = Release|Win32 + {F59D1435-1559-4BFF-90FF-F6B2E081ADBA}.Release|Win32.Build.0 = Release|Win32 + {F59D1435-1559-4BFF-90FF-F6B2E081ADBA}.Debug|x64.ActiveCfg = Debug|x64 + {F59D1435-1559-4BFF-90FF-F6B2E081ADBA}.Debug|x64.Build.0 = Debug|x64 + {F59D1435-1559-4BFF-90FF-F6B2E081ADBA}.Release|x64.ActiveCfg = Release|x64 + {F59D1435-1559-4BFF-90FF-F6B2E081ADBA}.Release|x64.Build.0 = Release|x64 + {8193E678-7717-4820-BBA6-A15A283160B1}.Debug|Win32.ActiveCfg = Debug|Win32 + {8193E678-7717-4820-BBA6-A15A283160B1}.Debug|Win32.Build.0 = Debug|Win32 + {8193E678-7717-4820-BBA6-A15A283160B1}.Release|Win32.ActiveCfg = Release|Win32 + {8193E678-7717-4820-BBA6-A15A283160B1}.Release|Win32.Build.0 = Release|Win32 + {8193E678-7717-4820-BBA6-A15A283160B1}.Debug|x64.ActiveCfg = Debug|x64 + {8193E678-7717-4820-BBA6-A15A283160B1}.Debug|x64.Build.0 = Debug|x64 + {8193E678-7717-4820-BBA6-A15A283160B1}.Release|x64.ActiveCfg = Release|x64 + {8193E678-7717-4820-BBA6-A15A283160B1}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {99B46F3E-1CC2-4689-8D3E-80CCBD448E39} = {3B396921-0231-4B6C-B5E5-C7695F992BA7} - {3EFB308B-ED6C-42FE-9140-9883674EA0A2} = {32B4D5F7-B865-467E-9344-627DDBB25267} + {F59D1435-1559-4BFF-90FF-F6B2E081ADBA} = {39A7F6C2-D480-4C5C-B6FB-48ACDDA45B59} + {8193E678-7717-4820-BBA6-A15A283160B1} = {42CC0135-35A4-4AD0-97D5-140EA747A3CD} EndGlobalSection EndGlobal diff --git a/filesys/miniFilter/minispy/user/minispy.vcxproj b/filesys/miniFilter/minispy/user/minispy.vcxproj index 7903c881..14af62cc 100644 --- a/filesys/miniFilter/minispy/user/minispy.vcxproj +++ b/filesys/miniFilter/minispy/user/minispy.vcxproj @@ -19,11 +19,11 @@ - {3EFB308B-ED6C-42FE-9140-9883674EA0A2} + {8193E678-7717-4820-BBA6-A15A283160B1} $(MSBuildProjectName) Debug Win32 - {66B7506B-24F4-4F68-9941-68114AD91305} + {FF833B16-7C46-43F5-911C-228791B84F56} diff --git a/filesys/miniFilter/minispy/user/minispy.vcxproj.Filters b/filesys/miniFilter/minispy/user/minispy.vcxproj.Filters index dff75ebd..e9cd4bba 100644 --- a/filesys/miniFilter/minispy/user/minispy.vcxproj.Filters +++ b/filesys/miniFilter/minispy/user/minispy.vcxproj.Filters @@ -3,15 +3,15 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {FE182DA6-B396-42B5-BA36-09DA649AD386} + {1FD3EC74-2C96-4C1D-BB60-19DC7C1F0008} h;hpp;hxx;hm;inl;inc;xsd - {72009667-0B4E-4D0D-9548-CB2182BD6769} + {0B6C07D3-9F4A-499D-B097-2BC02C31091A} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {9B01DDB6-745D-4785-BD95-F02013721E53} + {36CB183B-6EAB-4767-957A-87186CA11D68} diff --git a/filesys/miniFilter/nullFilter/nullFilter.sln b/filesys/miniFilter/nullFilter/nullFilter.sln index 9af52d43..1a5db6f9 100644 --- a/filesys/miniFilter/nullFilter/nullFilter.sln +++ b/filesys/miniFilter/nullFilter/nullFilter.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nullFilter", "nullFilter.vcxproj", "{83F8E913-4ED0-4CB2-ACF2-5411AC436CC5}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nullFilter", "nullFilter.vcxproj", "{50FE4D46-70DC-4104-8360-9E84D58B1ABD}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +13,14 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {83F8E913-4ED0-4CB2-ACF2-5411AC436CC5}.Debug|Win32.ActiveCfg = Debug|Win32 - {83F8E913-4ED0-4CB2-ACF2-5411AC436CC5}.Debug|Win32.Build.0 = Debug|Win32 - {83F8E913-4ED0-4CB2-ACF2-5411AC436CC5}.Release|Win32.ActiveCfg = Release|Win32 - {83F8E913-4ED0-4CB2-ACF2-5411AC436CC5}.Release|Win32.Build.0 = Release|Win32 - {83F8E913-4ED0-4CB2-ACF2-5411AC436CC5}.Debug|x64.ActiveCfg = Debug|x64 - {83F8E913-4ED0-4CB2-ACF2-5411AC436CC5}.Debug|x64.Build.0 = Debug|x64 - {83F8E913-4ED0-4CB2-ACF2-5411AC436CC5}.Release|x64.ActiveCfg = Release|x64 - {83F8E913-4ED0-4CB2-ACF2-5411AC436CC5}.Release|x64.Build.0 = Release|x64 + {50FE4D46-70DC-4104-8360-9E84D58B1ABD}.Debug|Win32.ActiveCfg = Debug|Win32 + {50FE4D46-70DC-4104-8360-9E84D58B1ABD}.Debug|Win32.Build.0 = Debug|Win32 + {50FE4D46-70DC-4104-8360-9E84D58B1ABD}.Release|Win32.ActiveCfg = Release|Win32 + {50FE4D46-70DC-4104-8360-9E84D58B1ABD}.Release|Win32.Build.0 = Release|Win32 + {50FE4D46-70DC-4104-8360-9E84D58B1ABD}.Debug|x64.ActiveCfg = Debug|x64 + {50FE4D46-70DC-4104-8360-9E84D58B1ABD}.Debug|x64.Build.0 = Debug|x64 + {50FE4D46-70DC-4104-8360-9E84D58B1ABD}.Release|x64.ActiveCfg = Release|x64 + {50FE4D46-70DC-4104-8360-9E84D58B1ABD}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/filesys/miniFilter/nullFilter/nullFilter.vcxproj b/filesys/miniFilter/nullFilter/nullFilter.vcxproj index 7e24749f..68b1d5da 100644 --- a/filesys/miniFilter/nullFilter/nullFilter.vcxproj +++ b/filesys/miniFilter/nullFilter/nullFilter.vcxproj @@ -19,11 +19,11 @@ - {83F8E913-4ED0-4CB2-ACF2-5411AC436CC5} + {50FE4D46-70DC-4104-8360-9E84D58B1ABD} $(MSBuildProjectName) Debug Win32 - {6431C66E-F38F-45F1-BE1E-D06503CE7799} + {0B2B36C6-26D3-49D5-962E-C42C0A37B0D7} diff --git a/filesys/miniFilter/nullFilter/nullFilter.vcxproj.Filters b/filesys/miniFilter/nullFilter/nullFilter.vcxproj.Filters index a199c829..33afb077 100644 --- a/filesys/miniFilter/nullFilter/nullFilter.vcxproj.Filters +++ b/filesys/miniFilter/nullFilter/nullFilter.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {AC14DB33-6BC1-44EC-AAB1-816BA496A388} + {F188061D-FE31-43EE-A670-3276C6F0AD16} h;hpp;hxx;hm;inl;inc;xsd - {F9EA13FF-7409-4FCD-B877-4F877D4E24BF} + {11EA27C6-A0E0-4F0A-8981-6592E27784D9} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {365A22DE-D53C-4640-8237-5E79E158A537} + {03863453-B4FD-4A2F-AA85-A2448B28F0DC} inf;inv;inx;mof;mc; - {8F416348-B401-4C11-9DD0-4D79812667AD} + {714F8ED5-D3FD-4FDF-9650-251E97E2D0B6} diff --git a/filesys/miniFilter/passThrough/passThrough.sln b/filesys/miniFilter/passThrough/passThrough.sln index 26698330..1d49e685 100644 --- a/filesys/miniFilter/passThrough/passThrough.sln +++ b/filesys/miniFilter/passThrough/passThrough.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "passThrough", "passThrough.vcxproj", "{6925DFEC-4D62-4106-9465-F4BFC1CA280B}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "passThrough", "passThrough.vcxproj", "{8CE4EFE9-8B8E-4785-A3AF-7DD92E105868}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +13,14 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {6925DFEC-4D62-4106-9465-F4BFC1CA280B}.Debug|Win32.ActiveCfg = Debug|Win32 - {6925DFEC-4D62-4106-9465-F4BFC1CA280B}.Debug|Win32.Build.0 = Debug|Win32 - {6925DFEC-4D62-4106-9465-F4BFC1CA280B}.Release|Win32.ActiveCfg = Release|Win32 - {6925DFEC-4D62-4106-9465-F4BFC1CA280B}.Release|Win32.Build.0 = Release|Win32 - {6925DFEC-4D62-4106-9465-F4BFC1CA280B}.Debug|x64.ActiveCfg = Debug|x64 - {6925DFEC-4D62-4106-9465-F4BFC1CA280B}.Debug|x64.Build.0 = Debug|x64 - {6925DFEC-4D62-4106-9465-F4BFC1CA280B}.Release|x64.ActiveCfg = Release|x64 - {6925DFEC-4D62-4106-9465-F4BFC1CA280B}.Release|x64.Build.0 = Release|x64 + {8CE4EFE9-8B8E-4785-A3AF-7DD92E105868}.Debug|Win32.ActiveCfg = Debug|Win32 + {8CE4EFE9-8B8E-4785-A3AF-7DD92E105868}.Debug|Win32.Build.0 = Debug|Win32 + {8CE4EFE9-8B8E-4785-A3AF-7DD92E105868}.Release|Win32.ActiveCfg = Release|Win32 + {8CE4EFE9-8B8E-4785-A3AF-7DD92E105868}.Release|Win32.Build.0 = Release|Win32 + {8CE4EFE9-8B8E-4785-A3AF-7DD92E105868}.Debug|x64.ActiveCfg = Debug|x64 + {8CE4EFE9-8B8E-4785-A3AF-7DD92E105868}.Debug|x64.Build.0 = Debug|x64 + {8CE4EFE9-8B8E-4785-A3AF-7DD92E105868}.Release|x64.ActiveCfg = Release|x64 + {8CE4EFE9-8B8E-4785-A3AF-7DD92E105868}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/filesys/miniFilter/passThrough/passThrough.vcxproj b/filesys/miniFilter/passThrough/passThrough.vcxproj index 66521b00..cef246fc 100644 --- a/filesys/miniFilter/passThrough/passThrough.vcxproj +++ b/filesys/miniFilter/passThrough/passThrough.vcxproj @@ -19,11 +19,11 @@ - {6925DFEC-4D62-4106-9465-F4BFC1CA280B} + {8CE4EFE9-8B8E-4785-A3AF-7DD92E105868} $(MSBuildProjectName) Debug Win32 - {D0990CEE-D681-43CD-9797-60AB0D628853} + {43A19993-BF9D-4DAD-A4CB-892DA37962D9} diff --git a/filesys/miniFilter/passThrough/passThrough.vcxproj.Filters b/filesys/miniFilter/passThrough/passThrough.vcxproj.Filters index 24e2fc4c..53c358b3 100644 --- a/filesys/miniFilter/passThrough/passThrough.vcxproj.Filters +++ b/filesys/miniFilter/passThrough/passThrough.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {D8FC9FC6-EBA8-4607-B388-0F5F1CACBA9C} + {A3FF7F10-8FB5-4702-A04E-1FB975F5F7BC} h;hpp;hxx;hm;inl;inc;xsd - {968D5F4E-042F-4EB1-89CA-8A4DC5FAD3B8} + {A60ED505-D6D8-4912-8E60-31F9A98408D4} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {BD7D5A5F-EEB5-43CF-AEF9-602F292252B7} + {6E1D373B-63DD-434D-9219-9E9F06913A45} inf;inv;inx;mof;mc; - {6C7310BB-F3EA-4F55-A624-111FE5C6DF8D} + {48A890C1-A2B2-447D-8746-A08B9C046052} diff --git a/filesys/miniFilter/scanner/filter/scanner.vcxproj b/filesys/miniFilter/scanner/filter/scanner.vcxproj index 99432692..9f737bb8 100644 --- a/filesys/miniFilter/scanner/filter/scanner.vcxproj +++ b/filesys/miniFilter/scanner/filter/scanner.vcxproj @@ -19,11 +19,11 @@ - {6F2E7887-B782-4624-A03A-7AC8CB1D6AB3} + {6DA01722-898E-478D-AA5D-7477B31F2E3C} $(MSBuildProjectName) Debug Win32 - {82607450-8E93-44E4-9EDC-AA0C310E0E64} + {3C220F60-96A1-444C-A61D-4CD384F249A2} diff --git a/filesys/miniFilter/scanner/filter/scanner.vcxproj.Filters b/filesys/miniFilter/scanner/filter/scanner.vcxproj.Filters index 37511409..f33f5037 100644 --- a/filesys/miniFilter/scanner/filter/scanner.vcxproj.Filters +++ b/filesys/miniFilter/scanner/filter/scanner.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {714BE986-D639-4C08-B0B5-CEDD7F5A24B3} + {21DA36D6-0604-456B-948A-ED26A6DE69DE} h;hpp;hxx;hm;inl;inc;xsd - {8E4DEA17-46F6-459E-91CA-8EB73909B60A} + {4DE93ED6-CF7E-4EED-90C7-AFED0DC52266} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {A4702A45-F819-43D0-B05B-56FFCA504075} + {59D2E5FD-012C-4647-A2E2-61A3E8E63CA5} inf;inv;inx;mof;mc; - {A873A433-3F6A-4828-9BDA-9FDF6C9D4726} + {CDB9F3CF-9FAB-4B3D-A857-7D6FA6680A05} diff --git a/filesys/miniFilter/scanner/scanner.sln b/filesys/miniFilter/scanner/scanner.sln index f79705b4..5414efd7 100644 --- a/filesys/miniFilter/scanner/scanner.sln +++ b/filesys/miniFilter/scanner/scanner.sln @@ -3,13 +3,13 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Filter", "Filter", "{826E5DA7-B03B-43C0-9CFF-E0B6E29942A3}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Filter", "Filter", "{FD39AB44-4D29-4235-AF0B-25A200E98950}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "User", "User", "{B27B6441-52BC-4DFD-9A25-1BC5972664F4}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "User", "User", "{38839ABD-FCE8-455C-AFAC-3AF46756066C}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "scanner", "filter\scanner.vcxproj", "{6F2E7887-B782-4624-A03A-7AC8CB1D6AB3}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "scanner", "filter\scanner.vcxproj", "{6DA01722-898E-478D-AA5D-7477B31F2E3C}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "scanuser", "user\scanuser.vcxproj", "{EF224A50-E448-4767-AD5E-1EEF058D0E50}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "scanuser", "user\scanuser.vcxproj", "{F5A0D233-ABA9-41FE-A4FE-3EA88CDE90BB}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -19,28 +19,28 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {6F2E7887-B782-4624-A03A-7AC8CB1D6AB3}.Debug|Win32.ActiveCfg = Debug|Win32 - {6F2E7887-B782-4624-A03A-7AC8CB1D6AB3}.Debug|Win32.Build.0 = Debug|Win32 - {6F2E7887-B782-4624-A03A-7AC8CB1D6AB3}.Release|Win32.ActiveCfg = Release|Win32 - {6F2E7887-B782-4624-A03A-7AC8CB1D6AB3}.Release|Win32.Build.0 = Release|Win32 - {6F2E7887-B782-4624-A03A-7AC8CB1D6AB3}.Debug|x64.ActiveCfg = Debug|x64 - {6F2E7887-B782-4624-A03A-7AC8CB1D6AB3}.Debug|x64.Build.0 = Debug|x64 - {6F2E7887-B782-4624-A03A-7AC8CB1D6AB3}.Release|x64.ActiveCfg = Release|x64 - {6F2E7887-B782-4624-A03A-7AC8CB1D6AB3}.Release|x64.Build.0 = Release|x64 - {EF224A50-E448-4767-AD5E-1EEF058D0E50}.Debug|Win32.ActiveCfg = Debug|Win32 - {EF224A50-E448-4767-AD5E-1EEF058D0E50}.Debug|Win32.Build.0 = Debug|Win32 - {EF224A50-E448-4767-AD5E-1EEF058D0E50}.Release|Win32.ActiveCfg = Release|Win32 - {EF224A50-E448-4767-AD5E-1EEF058D0E50}.Release|Win32.Build.0 = Release|Win32 - {EF224A50-E448-4767-AD5E-1EEF058D0E50}.Debug|x64.ActiveCfg = Debug|x64 - {EF224A50-E448-4767-AD5E-1EEF058D0E50}.Debug|x64.Build.0 = Debug|x64 - {EF224A50-E448-4767-AD5E-1EEF058D0E50}.Release|x64.ActiveCfg = Release|x64 - {EF224A50-E448-4767-AD5E-1EEF058D0E50}.Release|x64.Build.0 = Release|x64 + {6DA01722-898E-478D-AA5D-7477B31F2E3C}.Debug|Win32.ActiveCfg = Debug|Win32 + {6DA01722-898E-478D-AA5D-7477B31F2E3C}.Debug|Win32.Build.0 = Debug|Win32 + {6DA01722-898E-478D-AA5D-7477B31F2E3C}.Release|Win32.ActiveCfg = Release|Win32 + {6DA01722-898E-478D-AA5D-7477B31F2E3C}.Release|Win32.Build.0 = Release|Win32 + {6DA01722-898E-478D-AA5D-7477B31F2E3C}.Debug|x64.ActiveCfg = Debug|x64 + {6DA01722-898E-478D-AA5D-7477B31F2E3C}.Debug|x64.Build.0 = Debug|x64 + {6DA01722-898E-478D-AA5D-7477B31F2E3C}.Release|x64.ActiveCfg = Release|x64 + {6DA01722-898E-478D-AA5D-7477B31F2E3C}.Release|x64.Build.0 = Release|x64 + {F5A0D233-ABA9-41FE-A4FE-3EA88CDE90BB}.Debug|Win32.ActiveCfg = Debug|Win32 + {F5A0D233-ABA9-41FE-A4FE-3EA88CDE90BB}.Debug|Win32.Build.0 = Debug|Win32 + {F5A0D233-ABA9-41FE-A4FE-3EA88CDE90BB}.Release|Win32.ActiveCfg = Release|Win32 + {F5A0D233-ABA9-41FE-A4FE-3EA88CDE90BB}.Release|Win32.Build.0 = Release|Win32 + {F5A0D233-ABA9-41FE-A4FE-3EA88CDE90BB}.Debug|x64.ActiveCfg = Debug|x64 + {F5A0D233-ABA9-41FE-A4FE-3EA88CDE90BB}.Debug|x64.Build.0 = Debug|x64 + {F5A0D233-ABA9-41FE-A4FE-3EA88CDE90BB}.Release|x64.ActiveCfg = Release|x64 + {F5A0D233-ABA9-41FE-A4FE-3EA88CDE90BB}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {6F2E7887-B782-4624-A03A-7AC8CB1D6AB3} = {826E5DA7-B03B-43C0-9CFF-E0B6E29942A3} - {EF224A50-E448-4767-AD5E-1EEF058D0E50} = {B27B6441-52BC-4DFD-9A25-1BC5972664F4} + {6DA01722-898E-478D-AA5D-7477B31F2E3C} = {FD39AB44-4D29-4235-AF0B-25A200E98950} + {F5A0D233-ABA9-41FE-A4FE-3EA88CDE90BB} = {38839ABD-FCE8-455C-AFAC-3AF46756066C} EndGlobalSection EndGlobal diff --git a/filesys/miniFilter/scanner/user/scanuser.vcxproj b/filesys/miniFilter/scanner/user/scanuser.vcxproj index a60beb42..dbab3266 100644 --- a/filesys/miniFilter/scanner/user/scanuser.vcxproj +++ b/filesys/miniFilter/scanner/user/scanuser.vcxproj @@ -19,11 +19,11 @@ - {EF224A50-E448-4767-AD5E-1EEF058D0E50} + {F5A0D233-ABA9-41FE-A4FE-3EA88CDE90BB} $(MSBuildProjectName) Debug Win32 - {2640B41E-C043-4A8E-B6EE-136BFFA9D855} + {F6714426-3D4C-4E07-AF32-F6C97BB4E3A6} diff --git a/filesys/miniFilter/scanner/user/scanuser.vcxproj.Filters b/filesys/miniFilter/scanner/user/scanuser.vcxproj.Filters index 468b6701..0a7635cc 100644 --- a/filesys/miniFilter/scanner/user/scanuser.vcxproj.Filters +++ b/filesys/miniFilter/scanner/user/scanuser.vcxproj.Filters @@ -3,15 +3,15 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {2CE1DA5C-939F-4E19-AECC-C2BF08201270} + {2CC6A14A-A1EB-4502-B4F5-DEC93B1962CD} h;hpp;hxx;hm;inl;inc;xsd - {5E1F3D4B-5B51-4AD3-937E-D0FD3FC41DEC} + {FC5F9B5A-4DE1-4EFB-A76D-C4E632BF4E43} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {FCEF13F3-09F2-4ED0-9EA6-455F60759ED5} + {F349C8BC-1724-4FC6-AB45-98CE70B47971} diff --git a/filesys/miniFilter/simrep/simrep.sln b/filesys/miniFilter/simrep/simrep.sln index 179a1e3c..f2a7496b 100644 --- a/filesys/miniFilter/simrep/simrep.sln +++ b/filesys/miniFilter/simrep/simrep.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "simrep", "simrep.vcxproj", "{8CA1286B-6F29-4AF8-90C9-C6CD8B5F9B6B}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "simrep", "simrep.vcxproj", "{6B29B971-97ED-48CF-BFE0-D1F1E77D75BD}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +13,14 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {8CA1286B-6F29-4AF8-90C9-C6CD8B5F9B6B}.Debug|Win32.ActiveCfg = Debug|Win32 - {8CA1286B-6F29-4AF8-90C9-C6CD8B5F9B6B}.Debug|Win32.Build.0 = Debug|Win32 - {8CA1286B-6F29-4AF8-90C9-C6CD8B5F9B6B}.Release|Win32.ActiveCfg = Release|Win32 - {8CA1286B-6F29-4AF8-90C9-C6CD8B5F9B6B}.Release|Win32.Build.0 = Release|Win32 - {8CA1286B-6F29-4AF8-90C9-C6CD8B5F9B6B}.Debug|x64.ActiveCfg = Debug|x64 - {8CA1286B-6F29-4AF8-90C9-C6CD8B5F9B6B}.Debug|x64.Build.0 = Debug|x64 - {8CA1286B-6F29-4AF8-90C9-C6CD8B5F9B6B}.Release|x64.ActiveCfg = Release|x64 - {8CA1286B-6F29-4AF8-90C9-C6CD8B5F9B6B}.Release|x64.Build.0 = Release|x64 + {6B29B971-97ED-48CF-BFE0-D1F1E77D75BD}.Debug|Win32.ActiveCfg = Debug|Win32 + {6B29B971-97ED-48CF-BFE0-D1F1E77D75BD}.Debug|Win32.Build.0 = Debug|Win32 + {6B29B971-97ED-48CF-BFE0-D1F1E77D75BD}.Release|Win32.ActiveCfg = Release|Win32 + {6B29B971-97ED-48CF-BFE0-D1F1E77D75BD}.Release|Win32.Build.0 = Release|Win32 + {6B29B971-97ED-48CF-BFE0-D1F1E77D75BD}.Debug|x64.ActiveCfg = Debug|x64 + {6B29B971-97ED-48CF-BFE0-D1F1E77D75BD}.Debug|x64.Build.0 = Debug|x64 + {6B29B971-97ED-48CF-BFE0-D1F1E77D75BD}.Release|x64.ActiveCfg = Release|x64 + {6B29B971-97ED-48CF-BFE0-D1F1E77D75BD}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/filesys/miniFilter/simrep/simrep.vcxproj b/filesys/miniFilter/simrep/simrep.vcxproj index 41f903f0..c9005083 100644 --- a/filesys/miniFilter/simrep/simrep.vcxproj +++ b/filesys/miniFilter/simrep/simrep.vcxproj @@ -19,11 +19,11 @@ - {8CA1286B-6F29-4AF8-90C9-C6CD8B5F9B6B} + {6B29B971-97ED-48CF-BFE0-D1F1E77D75BD} $(MSBuildProjectName) Debug Win32 - {E65EC005-19A7-464F-8CA6-C0A78FD9F8C8} + {1A3F112D-0CEE-4178-81FF-E9B1C64AF142} diff --git a/filesys/miniFilter/simrep/simrep.vcxproj.Filters b/filesys/miniFilter/simrep/simrep.vcxproj.Filters index e5b8f9ad..290230b8 100644 --- a/filesys/miniFilter/simrep/simrep.vcxproj.Filters +++ b/filesys/miniFilter/simrep/simrep.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {D5037E9C-B07A-4282-8BD3-F0F1852E3411} + {FB7CDB88-6130-4057-81D1-930F6AC33A28} h;hpp;hxx;hm;inl;inc;xsd - {793B13DB-7C30-4334-A398-EA998A473206} + {9D798EBC-3174-4AE0-921F-1AD1C2FC42EE} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {65B4A597-DA92-4875-BC82-E7B93DBCAA49} + {0DA2AD7A-574E-4412-8DBB-2C95DCFAF0C2} inf;inv;inx;mof;mc; - {37180E6D-5204-4358-98A7-E348F7EBB425} + {D53692A7-3396-456F-B5EA-DDB999B67D80} diff --git a/filesys/miniFilter/swapBuffers/swapBuffers.c b/filesys/miniFilter/swapBuffers/swapBuffers.c index 47893870..8773fde2 100644 --- a/filesys/miniFilter/swapBuffers/swapBuffers.c +++ b/filesys/miniFilter/swapBuffers/swapBuffers.c @@ -428,8 +428,7 @@ Return Value: // an allocated name buffer. If not, it will be NULL // -#pragma prefast(suppress:__WARNING_USE_OTHER_FUNCTION, "Used to maintain compatability with Win 2k") - status = RtlVolumeDeviceToDosName( devObj, &ctx->Name ); + status = IoVolumeDeviceToDosName( devObj, &ctx->Name ); } // diff --git a/filesys/miniFilter/swapBuffers/swapBuffers.sln b/filesys/miniFilter/swapBuffers/swapBuffers.sln index 88ca2992..bfb94841 100644 --- a/filesys/miniFilter/swapBuffers/swapBuffers.sln +++ b/filesys/miniFilter/swapBuffers/swapBuffers.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "swapBuffers", "swapBuffers.vcxproj", "{A7B7D32A-A301-4497-A68B-349341047B69}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "swapBuffers", "swapBuffers.vcxproj", "{BF51955F-EC2D-4746-9F6D-A38D203F2AB6}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +13,14 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {A7B7D32A-A301-4497-A68B-349341047B69}.Debug|Win32.ActiveCfg = Debug|Win32 - {A7B7D32A-A301-4497-A68B-349341047B69}.Debug|Win32.Build.0 = Debug|Win32 - {A7B7D32A-A301-4497-A68B-349341047B69}.Release|Win32.ActiveCfg = Release|Win32 - {A7B7D32A-A301-4497-A68B-349341047B69}.Release|Win32.Build.0 = Release|Win32 - {A7B7D32A-A301-4497-A68B-349341047B69}.Debug|x64.ActiveCfg = Debug|x64 - {A7B7D32A-A301-4497-A68B-349341047B69}.Debug|x64.Build.0 = Debug|x64 - {A7B7D32A-A301-4497-A68B-349341047B69}.Release|x64.ActiveCfg = Release|x64 - {A7B7D32A-A301-4497-A68B-349341047B69}.Release|x64.Build.0 = Release|x64 + {BF51955F-EC2D-4746-9F6D-A38D203F2AB6}.Debug|Win32.ActiveCfg = Debug|Win32 + {BF51955F-EC2D-4746-9F6D-A38D203F2AB6}.Debug|Win32.Build.0 = Debug|Win32 + {BF51955F-EC2D-4746-9F6D-A38D203F2AB6}.Release|Win32.ActiveCfg = Release|Win32 + {BF51955F-EC2D-4746-9F6D-A38D203F2AB6}.Release|Win32.Build.0 = Release|Win32 + {BF51955F-EC2D-4746-9F6D-A38D203F2AB6}.Debug|x64.ActiveCfg = Debug|x64 + {BF51955F-EC2D-4746-9F6D-A38D203F2AB6}.Debug|x64.Build.0 = Debug|x64 + {BF51955F-EC2D-4746-9F6D-A38D203F2AB6}.Release|x64.ActiveCfg = Release|x64 + {BF51955F-EC2D-4746-9F6D-A38D203F2AB6}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/filesys/miniFilter/swapBuffers/swapBuffers.vcxproj b/filesys/miniFilter/swapBuffers/swapBuffers.vcxproj index 3c7b7151..d3925754 100644 --- a/filesys/miniFilter/swapBuffers/swapBuffers.vcxproj +++ b/filesys/miniFilter/swapBuffers/swapBuffers.vcxproj @@ -19,11 +19,11 @@ - {A7B7D32A-A301-4497-A68B-349341047B69} + {BF51955F-EC2D-4746-9F6D-A38D203F2AB6} $(MSBuildProjectName) Debug Win32 - {3AA28CE9-14ED-49C0-9FC7-A918130F15DA} + {0B907EAE-2E1A-4640-BF08-A4CB8D10A921} diff --git a/filesys/miniFilter/swapBuffers/swapBuffers.vcxproj.Filters b/filesys/miniFilter/swapBuffers/swapBuffers.vcxproj.Filters index eba4de22..362bb7b1 100644 --- a/filesys/miniFilter/swapBuffers/swapBuffers.vcxproj.Filters +++ b/filesys/miniFilter/swapBuffers/swapBuffers.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {35572264-BD73-4FA0-88AC-7FCC7C0917C7} + {547C6A8B-43E4-4D52-86E9-F04019916975} h;hpp;hxx;hm;inl;inc;xsd - {FF6920BD-0267-4DBD-B420-DED4DD132F5C} + {43DE78CC-2ACC-400B-9144-EFB61C1A7E2E} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {2BAFD988-E41F-4DB0-A580-19F92CFFE2F4} + {54FF1AAF-29C0-4B36-A01E-964EC486668A} inf;inv;inx;mof;mc; - {0D9FC8FE-1009-48A7-8A94-DD71E176AEE9} + {DB21CD94-ADB1-4062-9C3D-0063158FA18F} diff --git a/general/PLX9x5x/PLX9x5x.sln b/general/PLX9x5x/PLX9x5x.sln index c54db7f0..cfe73a66 100644 --- a/general/PLX9x5x/PLX9x5x.sln +++ b/general/PLX9x5x/PLX9x5x.sln @@ -3,13 +3,13 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Sys", "Sys", "{C3251AB4-8086-4862-985F-35302E40A027}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Sys", "Sys", "{78FB30BE-39D1-4BE2-A805-515DFEC13B00}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{954C16D2-23E1-4D8C-A040-5D4FB830D689}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{12DE6B87-7F07-4817-98D9-7F9CB6CDB946}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Pci9x5x", "sys\Pci9x5x.vcxproj", "{12A2C4C0-856A-49BE-9F54-30D4D040C3E9}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Pci9x5x", "sys\Pci9x5x.vcxproj", "{116683DC-66A4-4386-93D3-32A935D96B37}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "plx", "test\plx.vcxproj", "{BF101CB1-B147-40AC-8F84-13AC122A2D37}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "plx", "test\plx.vcxproj", "{235EA7C6-B4BC-4762-B7C6-F519089D31B8}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -19,28 +19,28 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {12A2C4C0-856A-49BE-9F54-30D4D040C3E9}.Debug|Win32.ActiveCfg = Debug|Win32 - {12A2C4C0-856A-49BE-9F54-30D4D040C3E9}.Debug|Win32.Build.0 = Debug|Win32 - {12A2C4C0-856A-49BE-9F54-30D4D040C3E9}.Release|Win32.ActiveCfg = Release|Win32 - {12A2C4C0-856A-49BE-9F54-30D4D040C3E9}.Release|Win32.Build.0 = Release|Win32 - {12A2C4C0-856A-49BE-9F54-30D4D040C3E9}.Debug|x64.ActiveCfg = Debug|x64 - {12A2C4C0-856A-49BE-9F54-30D4D040C3E9}.Debug|x64.Build.0 = Debug|x64 - {12A2C4C0-856A-49BE-9F54-30D4D040C3E9}.Release|x64.ActiveCfg = Release|x64 - {12A2C4C0-856A-49BE-9F54-30D4D040C3E9}.Release|x64.Build.0 = Release|x64 - {BF101CB1-B147-40AC-8F84-13AC122A2D37}.Debug|Win32.ActiveCfg = Debug|Win32 - {BF101CB1-B147-40AC-8F84-13AC122A2D37}.Debug|Win32.Build.0 = Debug|Win32 - {BF101CB1-B147-40AC-8F84-13AC122A2D37}.Release|Win32.ActiveCfg = Release|Win32 - {BF101CB1-B147-40AC-8F84-13AC122A2D37}.Release|Win32.Build.0 = Release|Win32 - {BF101CB1-B147-40AC-8F84-13AC122A2D37}.Debug|x64.ActiveCfg = Debug|x64 - {BF101CB1-B147-40AC-8F84-13AC122A2D37}.Debug|x64.Build.0 = Debug|x64 - {BF101CB1-B147-40AC-8F84-13AC122A2D37}.Release|x64.ActiveCfg = Release|x64 - {BF101CB1-B147-40AC-8F84-13AC122A2D37}.Release|x64.Build.0 = Release|x64 + {116683DC-66A4-4386-93D3-32A935D96B37}.Debug|Win32.ActiveCfg = Debug|Win32 + {116683DC-66A4-4386-93D3-32A935D96B37}.Debug|Win32.Build.0 = Debug|Win32 + {116683DC-66A4-4386-93D3-32A935D96B37}.Release|Win32.ActiveCfg = Release|Win32 + {116683DC-66A4-4386-93D3-32A935D96B37}.Release|Win32.Build.0 = Release|Win32 + {116683DC-66A4-4386-93D3-32A935D96B37}.Debug|x64.ActiveCfg = Debug|x64 + {116683DC-66A4-4386-93D3-32A935D96B37}.Debug|x64.Build.0 = Debug|x64 + {116683DC-66A4-4386-93D3-32A935D96B37}.Release|x64.ActiveCfg = Release|x64 + {116683DC-66A4-4386-93D3-32A935D96B37}.Release|x64.Build.0 = Release|x64 + {235EA7C6-B4BC-4762-B7C6-F519089D31B8}.Debug|Win32.ActiveCfg = Debug|Win32 + {235EA7C6-B4BC-4762-B7C6-F519089D31B8}.Debug|Win32.Build.0 = Debug|Win32 + {235EA7C6-B4BC-4762-B7C6-F519089D31B8}.Release|Win32.ActiveCfg = Release|Win32 + {235EA7C6-B4BC-4762-B7C6-F519089D31B8}.Release|Win32.Build.0 = Release|Win32 + {235EA7C6-B4BC-4762-B7C6-F519089D31B8}.Debug|x64.ActiveCfg = Debug|x64 + {235EA7C6-B4BC-4762-B7C6-F519089D31B8}.Debug|x64.Build.0 = Debug|x64 + {235EA7C6-B4BC-4762-B7C6-F519089D31B8}.Release|x64.ActiveCfg = Release|x64 + {235EA7C6-B4BC-4762-B7C6-F519089D31B8}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {12A2C4C0-856A-49BE-9F54-30D4D040C3E9} = {C3251AB4-8086-4862-985F-35302E40A027} - {BF101CB1-B147-40AC-8F84-13AC122A2D37} = {954C16D2-23E1-4D8C-A040-5D4FB830D689} + {116683DC-66A4-4386-93D3-32A935D96B37} = {78FB30BE-39D1-4BE2-A805-515DFEC13B00} + {235EA7C6-B4BC-4762-B7C6-F519089D31B8} = {12DE6B87-7F07-4817-98D9-7F9CB6CDB946} EndGlobalSection EndGlobal diff --git a/general/PLX9x5x/sys/Pci9x5x.vcxproj b/general/PLX9x5x/sys/Pci9x5x.vcxproj index 7493d098..8922ce83 100644 --- a/general/PLX9x5x/sys/Pci9x5x.vcxproj +++ b/general/PLX9x5x/sys/Pci9x5x.vcxproj @@ -19,13 +19,13 @@ - {12A2C4C0-856A-49BE-9F54-30D4D040C3E9} + {116683DC-66A4-4386-93D3-32A935D96B37} $(MSBuildProjectName) 1 9 Debug Win32 - {0DB7EDF4-ADCA-4623-A75A-2D53E0B95D89} + {BE8B0450-C794-43FB-8906-0F2F924845CC} diff --git a/general/PLX9x5x/sys/Pci9x5x.vcxproj.Filters b/general/PLX9x5x/sys/Pci9x5x.vcxproj.Filters index 1cf6e8b2..ece7bbbf 100644 --- a/general/PLX9x5x/sys/Pci9x5x.vcxproj.Filters +++ b/general/PLX9x5x/sys/Pci9x5x.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {CFE8A049-4352-4797-A933-02B2457B9660} + {FB26A925-4DA1-470E-9D80-9D5F544E0DDD} h;hpp;hxx;hm;inl;inc;xsd - {EA19AC8F-5C37-4641-AAFA-4924984AF0F7} + {140FC8D5-2FBF-4CA2-8DE1-1ABF15927EF7} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {D407D40B-9D6E-4731-85DE-808B502FF92E} + {2C3C95FB-9EC1-4B9A-B35E-A8534768915B} inf;inv;inx;mof;mc; - {39E92CE4-17AE-463E-B0CB-746990AE72D1} + {D48F873E-36BD-45C1-A62F-4D9C8745F283} diff --git a/general/PLX9x5x/sys/pci9x5x.inx b/general/PLX9x5x/sys/pci9x5x.inx index 3904344b..43bd8dec 100644 --- a/general/PLX9x5x/sys/pci9x5x.inx +++ b/general/PLX9x5x/sys/pci9x5x.inx @@ -53,13 +53,6 @@ Pci9x5x.sys=1 [SourceDisksNames] 1=%DISK_NAME%, -; For Win2K -[MSFT] -; DisplayName Section DeviceId -; ----------- ------- -------- -%Pci9056.DRVDESC%= Pci9x5x_Inst, PCI\VEN_10b5&DEV_5601 -%Pci9656.DRVDESC%= Pci9x5x_Inst, PCI\VEN_10b5&DEV_9601 - ; For XP and later [MSFT.NT$ARCH$] ; DisplayName Section DeviceId diff --git a/general/PLX9x5x/test/plx.vcxproj b/general/PLX9x5x/test/plx.vcxproj index 3dcbd6f3..8634bd39 100644 --- a/general/PLX9x5x/test/plx.vcxproj +++ b/general/PLX9x5x/test/plx.vcxproj @@ -19,11 +19,11 @@ - {BF101CB1-B147-40AC-8F84-13AC122A2D37} + {235EA7C6-B4BC-4762-B7C6-F519089D31B8} $(MSBuildProjectName) Debug Win32 - {F475764B-7D1A-49E4-8FA0-B4153BB184E4} + {8C1C6BDF-C1D1-4007-A1EB-5D3354422309} diff --git a/general/PLX9x5x/test/plx.vcxproj.Filters b/general/PLX9x5x/test/plx.vcxproj.Filters index b74b5937..daeb5b79 100644 --- a/general/PLX9x5x/test/plx.vcxproj.Filters +++ b/general/PLX9x5x/test/plx.vcxproj.Filters @@ -3,15 +3,15 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {0B47F4CC-B263-41C6-86AF-E5D9448601A6} + {6D507CB2-9D2C-4ACA-9A1B-E26E912641A7} h;hpp;hxx;hm;inl;inc;xsd - {802D6182-3D0F-4A06-9D94-F6E77BA24FFD} + {A2D15E88-BFAF-4AC4-90C6-D28A212C15E6} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {F55A15F1-EBAB-45A9-AD99-9AA00FA8DA01} + {063653C5-4B37-4C7C-BB1B-92BFD43D344F} diff --git a/general/SystemDma/wdm/SystemDma.sln b/general/SystemDma/wdm/SystemDma.sln index 1df1c8b0..baa7294c 100644 --- a/general/SystemDma/wdm/SystemDma.sln +++ b/general/SystemDma/wdm/SystemDma.sln @@ -3,13 +3,13 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Exe", "Exe", "{91E3EEC7-4EBF-4BE0-A947-5C7C164EF77D}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Exe", "Exe", "{5C97DEF5-8A33-4405-AC60-96F0EC22ABEC}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Sys", "Sys", "{6C0D6BEB-2BA2-4769-BD10-476085814CAE}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Sys", "Sys", "{07DEA55E-F7CF-45F9-B169-834815EC1AFD}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SystemDmaApp", "exe\SystemDmaApp.vcxproj", "{3B7F8119-C721-4322-894C-0D3B49A38FFB}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SystemDmaApp", "exe\SystemDmaApp.vcxproj", "{23E9BB4A-11FD-4BC6-9CA7-0BE6A4188C1F}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SDma", "sys\SDma.vcxproj", "{42AC88BC-11CC-4FC0-B2EF-50B6CA8DDBCE}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SDma", "sys\SDma.vcxproj", "{3FE750B5-4CAD-4ECD-B443-12E16404FB11}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -19,28 +19,28 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {3B7F8119-C721-4322-894C-0D3B49A38FFB}.Debug|Win32.ActiveCfg = Debug|Win32 - {3B7F8119-C721-4322-894C-0D3B49A38FFB}.Debug|Win32.Build.0 = Debug|Win32 - {3B7F8119-C721-4322-894C-0D3B49A38FFB}.Release|Win32.ActiveCfg = Release|Win32 - {3B7F8119-C721-4322-894C-0D3B49A38FFB}.Release|Win32.Build.0 = Release|Win32 - {3B7F8119-C721-4322-894C-0D3B49A38FFB}.Debug|x64.ActiveCfg = Debug|x64 - {3B7F8119-C721-4322-894C-0D3B49A38FFB}.Debug|x64.Build.0 = Debug|x64 - {3B7F8119-C721-4322-894C-0D3B49A38FFB}.Release|x64.ActiveCfg = Release|x64 - {3B7F8119-C721-4322-894C-0D3B49A38FFB}.Release|x64.Build.0 = Release|x64 - {42AC88BC-11CC-4FC0-B2EF-50B6CA8DDBCE}.Debug|Win32.ActiveCfg = Debug|Win32 - {42AC88BC-11CC-4FC0-B2EF-50B6CA8DDBCE}.Debug|Win32.Build.0 = Debug|Win32 - {42AC88BC-11CC-4FC0-B2EF-50B6CA8DDBCE}.Release|Win32.ActiveCfg = Release|Win32 - {42AC88BC-11CC-4FC0-B2EF-50B6CA8DDBCE}.Release|Win32.Build.0 = Release|Win32 - {42AC88BC-11CC-4FC0-B2EF-50B6CA8DDBCE}.Debug|x64.ActiveCfg = Debug|x64 - {42AC88BC-11CC-4FC0-B2EF-50B6CA8DDBCE}.Debug|x64.Build.0 = Debug|x64 - {42AC88BC-11CC-4FC0-B2EF-50B6CA8DDBCE}.Release|x64.ActiveCfg = Release|x64 - {42AC88BC-11CC-4FC0-B2EF-50B6CA8DDBCE}.Release|x64.Build.0 = Release|x64 + {23E9BB4A-11FD-4BC6-9CA7-0BE6A4188C1F}.Debug|Win32.ActiveCfg = Debug|Win32 + {23E9BB4A-11FD-4BC6-9CA7-0BE6A4188C1F}.Debug|Win32.Build.0 = Debug|Win32 + {23E9BB4A-11FD-4BC6-9CA7-0BE6A4188C1F}.Release|Win32.ActiveCfg = Release|Win32 + {23E9BB4A-11FD-4BC6-9CA7-0BE6A4188C1F}.Release|Win32.Build.0 = Release|Win32 + {23E9BB4A-11FD-4BC6-9CA7-0BE6A4188C1F}.Debug|x64.ActiveCfg = Debug|x64 + {23E9BB4A-11FD-4BC6-9CA7-0BE6A4188C1F}.Debug|x64.Build.0 = Debug|x64 + {23E9BB4A-11FD-4BC6-9CA7-0BE6A4188C1F}.Release|x64.ActiveCfg = Release|x64 + {23E9BB4A-11FD-4BC6-9CA7-0BE6A4188C1F}.Release|x64.Build.0 = Release|x64 + {3FE750B5-4CAD-4ECD-B443-12E16404FB11}.Debug|Win32.ActiveCfg = Debug|Win32 + {3FE750B5-4CAD-4ECD-B443-12E16404FB11}.Debug|Win32.Build.0 = Debug|Win32 + {3FE750B5-4CAD-4ECD-B443-12E16404FB11}.Release|Win32.ActiveCfg = Release|Win32 + {3FE750B5-4CAD-4ECD-B443-12E16404FB11}.Release|Win32.Build.0 = Release|Win32 + {3FE750B5-4CAD-4ECD-B443-12E16404FB11}.Debug|x64.ActiveCfg = Debug|x64 + {3FE750B5-4CAD-4ECD-B443-12E16404FB11}.Debug|x64.Build.0 = Debug|x64 + {3FE750B5-4CAD-4ECD-B443-12E16404FB11}.Release|x64.ActiveCfg = Release|x64 + {3FE750B5-4CAD-4ECD-B443-12E16404FB11}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {3B7F8119-C721-4322-894C-0D3B49A38FFB} = {91E3EEC7-4EBF-4BE0-A947-5C7C164EF77D} - {42AC88BC-11CC-4FC0-B2EF-50B6CA8DDBCE} = {6C0D6BEB-2BA2-4769-BD10-476085814CAE} + {23E9BB4A-11FD-4BC6-9CA7-0BE6A4188C1F} = {5C97DEF5-8A33-4405-AC60-96F0EC22ABEC} + {3FE750B5-4CAD-4ECD-B443-12E16404FB11} = {07DEA55E-F7CF-45F9-B169-834815EC1AFD} EndGlobalSection EndGlobal diff --git a/general/SystemDma/wdm/exe/SystemDmaApp.vcxproj b/general/SystemDma/wdm/exe/SystemDmaApp.vcxproj index 25803eb1..7f966315 100644 --- a/general/SystemDma/wdm/exe/SystemDmaApp.vcxproj +++ b/general/SystemDma/wdm/exe/SystemDmaApp.vcxproj @@ -19,11 +19,11 @@ - {3B7F8119-C721-4322-894C-0D3B49A38FFB} + {23E9BB4A-11FD-4BC6-9CA7-0BE6A4188C1F} $(MSBuildProjectName) Debug Win32 - {91239967-1454-4D74-8730-73372B2E0C94} + {24697793-CB49-4265-8991-872727B15BC3} diff --git a/general/SystemDma/wdm/exe/SystemDmaApp.vcxproj.Filters b/general/SystemDma/wdm/exe/SystemDmaApp.vcxproj.Filters index 6d4320c9..39258507 100644 --- a/general/SystemDma/wdm/exe/SystemDmaApp.vcxproj.Filters +++ b/general/SystemDma/wdm/exe/SystemDmaApp.vcxproj.Filters @@ -3,15 +3,15 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {83BDC4AF-E38F-41A3-AE52-10470851D503} + {F3AEB441-C240-4DAC-894F-32249F376A28} h;hpp;hxx;hm;inl;inc;xsd - {3C82C17E-76AD-4F6A-A677-A4591BB22A00} + {8B83FC49-81EA-4DD1-BD8E-ED4F3858F05B} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {0D5328D1-97B0-4961-BF49-FB8CA3B73228} + {84E5DCD8-475D-4896-90D3-9F4398A303DB} diff --git a/general/SystemDma/wdm/sys/SDma.vcxproj b/general/SystemDma/wdm/sys/SDma.vcxproj index fb50d847..35bf5531 100644 --- a/general/SystemDma/wdm/sys/SDma.vcxproj +++ b/general/SystemDma/wdm/sys/SDma.vcxproj @@ -19,11 +19,11 @@ - {42AC88BC-11CC-4FC0-B2EF-50B6CA8DDBCE} + {3FE750B5-4CAD-4ECD-B443-12E16404FB11} $(MSBuildProjectName) Debug Win32 - {BB0473B0-289C-4FA0-9E81-C6EA8C79707D} + {19364197-D291-4DC9-B08E-DD477FD42358} diff --git a/general/SystemDma/wdm/sys/SDma.vcxproj.Filters b/general/SystemDma/wdm/sys/SDma.vcxproj.Filters index 259eadd5..7926613e 100644 --- a/general/SystemDma/wdm/sys/SDma.vcxproj.Filters +++ b/general/SystemDma/wdm/sys/SDma.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {7F208255-EDD4-4E3B-83EC-EBB1682D21C8} + {98D22585-F401-429B-BDB2-B5C6F436A255} h;hpp;hxx;hm;inl;inc;xsd - {B5677F44-0B89-43F0-91FB-984AB0713883} + {0B161BA1-4402-4873-9564-A47349B20298} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {82A0D909-8651-4045-8729-2AF8321AB2BB} + {B1F31E58-0465-4A38-BBB2-DF6F4EF598D8} inf;inv;inx;mof;mc; - {7D13F81D-2971-47FA-9382-E4CF95208FA4} + {5C6DF922-F9E0-48E6-B4D9-B472082A0400} diff --git a/general/SystemDma/wdm/systemdma.htm b/general/SystemDma/wdm/systemdma.htm new file mode 100644 index 00000000..301dead7 --- /dev/null +++ b/general/SystemDma/wdm/systemdma.htm @@ -0,0 +1,741 @@ + + + + + + + + + + + + + + + + + + + + +
+ +

SDMA +

+ +

SUMMARY

+ +

This +sample demonstrates the usage of V3 System DMA. It shows how a driver +could use a system DMA controller supported by Windows to +write data to a hardware location using DMA.

+ +

The sample +consists of a legacy device driver and a Win32 console mode test application. +The test application opens a handle to the device exposed by the driver and makes +a DeviceIoControl call to initiate the example system DMA. To understand how +the V3 system DMA calls are invoked please study SDmaWrite() in SDma.c.

+ +

This +driver will work on Windows 2000 and later operating systems.

+ +

This +sample driver is not a PnP driver. This is a minimal driver meant to +demonstrate an OS feature. Neither it nor its sample programs are intended for +use in a production environment. Rather, they are intended for educational +purposes and as a skeleton driver.

+ +

BUILDING THE SAMPLE

+ +

Click the +Free Build Environment or Checked Build Environment icon under Development Kits +program group to set basic environment variables.

+ +

Change to +the directory containing the sample source code, such as CD Src\General\sdma\wdm. +

+ +

Run build +-ceZ, or use the macro BLD. This command invokes the Microsoft make routines to +build the components. If the build succeeds, you will find the driver, +sdma.sys, and the test application, SystemDmaApp.exe, in the binary output +directory specified for the build environment. You can get the output path from +the buildxxx.log file (for example, buildfre_win7_arm.log). If the build fails +you can find errors and warnings in the buildxxx.err and buildxxx.wrn respectively, +where xxx is either chk or fre depending on the build environment.

+ +

TESTING

+ +

To test +this driver, copy the test app, SystemDmaApp.exe, and the driver to the same +directory, and run the application. The application will automatically load the +driver if it's not already loaded and interact with the driver. When you exit +the app, the driver will be stopped, unloaded and removed. Because no system DMA +controller exists for Windows which uses the advertised DRQ, the sample driver +will not proceed any further than failing to acquire a system DMA adapter.

+ +

CODE TOUR

+ +

File Manifest

+ +
File           Description
 
SystemDma.htm  Sample Tour documentation for this sample (this file).
Sources        Generic file that lists source files and all the build options.
SDma.c         Source file of the sample driver.
SDma.h         Header file for defining ioctls; included by driver and the test application.
Testapp.c      Source file of the test application. Contains routines to send one IOCTL to the driver.
Install.c      Source file of the test application. Contains routines to load and unload the driver.
SDma.rc        Resource file that specifies information such as file type, version, etc.
Makefile       This file merely indirects to the real makefile that is shared by all the driver components of the Windows NT DDK.
 
+ +

Top +of page +

+ + + + + +
+ +

© 1998 Microsoft +Corporation +

+ +
+ + + + diff --git a/general/cancel/cancel.htm b/general/cancel/cancel.htm new file mode 100644 index 00000000..cac03a7f --- /dev/null +++ b/general/cancel/cancel.htm @@ -0,0 +1,302 @@ + + + + + + + + +CANCEL + + + + + + + + + +
+ +

CANCEL

+ +

SUMMARY

+ +

This sample demonstrates +the use of new  cancel-safe +queue (IoCsqInitialize, IoCsqInsertIrp, +IoCsqRemoveIrp, IoCsqRemoveNextIrp) +APIs introduced on Windows XP for queuing IRPs in the +driver's internal device queue. By using these APIs, driver writers do not have +to worry about any IRP cancellation race condition issues. A common problem +with cancellation of IRPs in a driver is +synchronization between the cancel lock or the InterlockedExchange in the I/O Manager with the driver's +queue lock. These APIs abstract the cancel logic while allowing the driver to +implement the queue and associated synchronization.

+ +

The sample is accompanied +by a simple multithreaded Win32 console application to stress-test the driver's +cancel and cleanup routines.

+ +

This driver is written +for an hypothetical data acquisition device that +requires polling at a regular interval. The device has some settling period +between two reads. Upon user request the driver reads data and records the +time. When the next read request comes in, it checks the interval to see if +it's reading the device too soon. If so, it pends the +IRP and sleeps for a while and tries again. Upon arrival, IRPs +are queued in a cancel-safe queue and a semaphore is signaled. A polling thread +waiting indefinitely on the semaphore wakes up to the signal and processes queued IRPs sequentially.

+ +

This sample is adapted +from the original cancel sample +(http://support.microsoft.com/support/kb/articles/Q188/2/76.asp) written for +NT4.0.

+ +

The building and +installation instructions given here apply to Windows® 2000 and later operating systems.

+ +

This sample driver is not +a PnP driver. This is a minimal driver meant to demonstrate an OS feature. +Neither it nor its sample programs are intended for use in a production +environment. Rather, they are intended for educational purposes and as a +skeleton driver.

+ +

BUILDING THE SAMPLE

+ +

Click the Free Build +Environment or Checked Build Environment icon under Development Kits program +group to set basic environment variables.

+ +

Change to the directory +containing the device source code, such as CD Src\General\Cancel. +

+ +

Run build -ceZ, or use the macro BLD. This command invokes +the Microsoft make routines to build the components. If the build succeeds, you will find the driver, +cancel.sys, and the test application, canclapp.exe, +in the binary output directory specified for the build environment. You can get the output path from the buildxxx.log file. If it fails you can find errors and warnings in the buildxxx.err +and buildxxx.err respectively, where xxx is either chk or fre depending on the build +environment.

+ +

STARTIO IMPLEMENTATION

+ +

In the startio directory is another version of the sample driver +that shows how to use the  cancel-safe queues to implement IO +queuing functionality similar to the IoStartPacket/IoStartNextPacket +APIs. The same test application works with this driver as well.

+ +

TESTING

+ +

To test this driver, run +Testapp.exe, a simple Win32 multithreaded console mode application. The driver +will be automatically loaded and started. When you exit the app, the driver +will stopped and removed.

+ +

Usage:testapp (NumberOfThreads)

+ +

Note: NumberOfThreads +is limited to a maximum of 10 threads; the default value if run without the option +is 1. The main thread waits for user input. If you press Q, the application +exits gracefully; otherwise it exits the process abruptly forcing all the +threads to be terminated and all pending I/Os to be canceled. Other threads +perform I/O asynchronously in a loop. After every overlapped read, the thread +goes into an alertable sleep and wakes as soon as +completion routines is executed, when the read IRP gets completed by the +driver. You should run multiple instances of the application to stress test the +driver.

+ +

CODE TOUR

+ +

File Manifest

+ +
File           Description
 
Cancel.htm     Documentation for this sample (this file).
Cancel.c       Source file of the sample driver.
Sources        Generic file that lists source files and all the build options.
Testapp.c      Source file of the test application.
Install.c      Contains functions to load/start/stop/remove the driver.
Testapp.h      Header file for common definitions and function prototypes.
Cancel.rc      Resource file that specify information such as file type, version, etc.
Makefile       This file merely indirects to the real makefile that is shared by all the driver components of the Windows NT DDK.
+ +

Top of page

+ + + + + +
+

 

+
+ +

© 2004 Microsoft +Corporation

+ +
+ + + + diff --git a/general/cancel/cancel.sln b/general/cancel/cancel.sln index a9836742..fe8e9757 100644 --- a/general/cancel/cancel.sln +++ b/general/cancel/cancel.sln @@ -3,17 +3,17 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Sys", "Sys", "{DBD7C2B7-C00F-4FFE-84D4-B05886013873}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Sys", "Sys", "{FF154CE0-9DFD-405E-B895-7B7705DBB3BC}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Exe", "Exe", "{0B6A483D-D5F5-4F95-96E7-281FD7EA600F}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Exe", "Exe", "{A5E4BBE9-6842-4F12-91FD-1038D7FE8288}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Startio", "Startio", "{234DCAD4-F351-4964-9C3B-0B59C944B70D}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Startio", "Startio", "{B061A5AB-4CE5-4B99-A993-BF1AA7FD9A7A}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cancel", "sys\cancel.vcxproj", "{3363DCA3-7873-4ECB-BA98-F243C2E8FDA0}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cancel", "sys\cancel.vcxproj", "{D9569E28-5AA8-422B-8909-3B52E3A9E0A2}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "canclapp", "exe\canclapp.vcxproj", "{C8925B47-FB65-4E3E-89E4-2B45E3C10509}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "canclapp", "exe\canclapp.vcxproj", "{181B9B9A-1D10-4DF8-8864-2F2CD58AAACD}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cancel", "startio\cancel.vcxproj", "{1392C861-BA6F-4423-8C33-A8C771BAF473}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cancel", "startio\cancel.vcxproj", "{9123CC18-82D4-477B-B20E-6EA2D454E046}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -23,37 +23,37 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {3363DCA3-7873-4ECB-BA98-F243C2E8FDA0}.Debug|Win32.ActiveCfg = Debug|Win32 - {3363DCA3-7873-4ECB-BA98-F243C2E8FDA0}.Debug|Win32.Build.0 = Debug|Win32 - {3363DCA3-7873-4ECB-BA98-F243C2E8FDA0}.Release|Win32.ActiveCfg = Release|Win32 - {3363DCA3-7873-4ECB-BA98-F243C2E8FDA0}.Release|Win32.Build.0 = Release|Win32 - {3363DCA3-7873-4ECB-BA98-F243C2E8FDA0}.Debug|x64.ActiveCfg = Debug|x64 - {3363DCA3-7873-4ECB-BA98-F243C2E8FDA0}.Debug|x64.Build.0 = Debug|x64 - {3363DCA3-7873-4ECB-BA98-F243C2E8FDA0}.Release|x64.ActiveCfg = Release|x64 - {3363DCA3-7873-4ECB-BA98-F243C2E8FDA0}.Release|x64.Build.0 = Release|x64 - {C8925B47-FB65-4E3E-89E4-2B45E3C10509}.Debug|Win32.ActiveCfg = Debug|Win32 - {C8925B47-FB65-4E3E-89E4-2B45E3C10509}.Debug|Win32.Build.0 = Debug|Win32 - {C8925B47-FB65-4E3E-89E4-2B45E3C10509}.Release|Win32.ActiveCfg = Release|Win32 - {C8925B47-FB65-4E3E-89E4-2B45E3C10509}.Release|Win32.Build.0 = Release|Win32 - {C8925B47-FB65-4E3E-89E4-2B45E3C10509}.Debug|x64.ActiveCfg = Debug|x64 - {C8925B47-FB65-4E3E-89E4-2B45E3C10509}.Debug|x64.Build.0 = Debug|x64 - {C8925B47-FB65-4E3E-89E4-2B45E3C10509}.Release|x64.ActiveCfg = Release|x64 - {C8925B47-FB65-4E3E-89E4-2B45E3C10509}.Release|x64.Build.0 = Release|x64 - {1392C861-BA6F-4423-8C33-A8C771BAF473}.Debug|Win32.ActiveCfg = Debug|Win32 - {1392C861-BA6F-4423-8C33-A8C771BAF473}.Debug|Win32.Build.0 = Debug|Win32 - {1392C861-BA6F-4423-8C33-A8C771BAF473}.Release|Win32.ActiveCfg = Release|Win32 - {1392C861-BA6F-4423-8C33-A8C771BAF473}.Release|Win32.Build.0 = Release|Win32 - {1392C861-BA6F-4423-8C33-A8C771BAF473}.Debug|x64.ActiveCfg = Debug|x64 - {1392C861-BA6F-4423-8C33-A8C771BAF473}.Debug|x64.Build.0 = Debug|x64 - {1392C861-BA6F-4423-8C33-A8C771BAF473}.Release|x64.ActiveCfg = Release|x64 - {1392C861-BA6F-4423-8C33-A8C771BAF473}.Release|x64.Build.0 = Release|x64 + {D9569E28-5AA8-422B-8909-3B52E3A9E0A2}.Debug|Win32.ActiveCfg = Debug|Win32 + {D9569E28-5AA8-422B-8909-3B52E3A9E0A2}.Debug|Win32.Build.0 = Debug|Win32 + {D9569E28-5AA8-422B-8909-3B52E3A9E0A2}.Release|Win32.ActiveCfg = Release|Win32 + {D9569E28-5AA8-422B-8909-3B52E3A9E0A2}.Release|Win32.Build.0 = Release|Win32 + {D9569E28-5AA8-422B-8909-3B52E3A9E0A2}.Debug|x64.ActiveCfg = Debug|x64 + {D9569E28-5AA8-422B-8909-3B52E3A9E0A2}.Debug|x64.Build.0 = Debug|x64 + {D9569E28-5AA8-422B-8909-3B52E3A9E0A2}.Release|x64.ActiveCfg = Release|x64 + {D9569E28-5AA8-422B-8909-3B52E3A9E0A2}.Release|x64.Build.0 = Release|x64 + {181B9B9A-1D10-4DF8-8864-2F2CD58AAACD}.Debug|Win32.ActiveCfg = Debug|Win32 + {181B9B9A-1D10-4DF8-8864-2F2CD58AAACD}.Debug|Win32.Build.0 = Debug|Win32 + {181B9B9A-1D10-4DF8-8864-2F2CD58AAACD}.Release|Win32.ActiveCfg = Release|Win32 + {181B9B9A-1D10-4DF8-8864-2F2CD58AAACD}.Release|Win32.Build.0 = Release|Win32 + {181B9B9A-1D10-4DF8-8864-2F2CD58AAACD}.Debug|x64.ActiveCfg = Debug|x64 + {181B9B9A-1D10-4DF8-8864-2F2CD58AAACD}.Debug|x64.Build.0 = Debug|x64 + {181B9B9A-1D10-4DF8-8864-2F2CD58AAACD}.Release|x64.ActiveCfg = Release|x64 + {181B9B9A-1D10-4DF8-8864-2F2CD58AAACD}.Release|x64.Build.0 = Release|x64 + {9123CC18-82D4-477B-B20E-6EA2D454E046}.Debug|Win32.ActiveCfg = Debug|Win32 + {9123CC18-82D4-477B-B20E-6EA2D454E046}.Debug|Win32.Build.0 = Debug|Win32 + {9123CC18-82D4-477B-B20E-6EA2D454E046}.Release|Win32.ActiveCfg = Release|Win32 + {9123CC18-82D4-477B-B20E-6EA2D454E046}.Release|Win32.Build.0 = Release|Win32 + {9123CC18-82D4-477B-B20E-6EA2D454E046}.Debug|x64.ActiveCfg = Debug|x64 + {9123CC18-82D4-477B-B20E-6EA2D454E046}.Debug|x64.Build.0 = Debug|x64 + {9123CC18-82D4-477B-B20E-6EA2D454E046}.Release|x64.ActiveCfg = Release|x64 + {9123CC18-82D4-477B-B20E-6EA2D454E046}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {3363DCA3-7873-4ECB-BA98-F243C2E8FDA0} = {DBD7C2B7-C00F-4FFE-84D4-B05886013873} - {C8925B47-FB65-4E3E-89E4-2B45E3C10509} = {0B6A483D-D5F5-4F95-96E7-281FD7EA600F} - {1392C861-BA6F-4423-8C33-A8C771BAF473} = {234DCAD4-F351-4964-9C3B-0B59C944B70D} + {D9569E28-5AA8-422B-8909-3B52E3A9E0A2} = {FF154CE0-9DFD-405E-B895-7B7705DBB3BC} + {181B9B9A-1D10-4DF8-8864-2F2CD58AAACD} = {A5E4BBE9-6842-4F12-91FD-1038D7FE8288} + {9123CC18-82D4-477B-B20E-6EA2D454E046} = {B061A5AB-4CE5-4B99-A993-BF1AA7FD9A7A} EndGlobalSection EndGlobal diff --git a/general/cancel/exe/canclapp.vcxproj b/general/cancel/exe/canclapp.vcxproj index 63333b9c..0271461a 100644 --- a/general/cancel/exe/canclapp.vcxproj +++ b/general/cancel/exe/canclapp.vcxproj @@ -19,11 +19,11 @@
- {C8925B47-FB65-4E3E-89E4-2B45E3C10509} + {181B9B9A-1D10-4DF8-8864-2F2CD58AAACD} $(MSBuildProjectName) Debug Win32 - {1EB28B67-703E-42CB-AEEF-4871909ACBE4} + {BEFC1AEC-4158-4133-B070-197A3BCB3324} diff --git a/general/cancel/exe/canclapp.vcxproj.Filters b/general/cancel/exe/canclapp.vcxproj.Filters index fa02af34..630a370d 100644 --- a/general/cancel/exe/canclapp.vcxproj.Filters +++ b/general/cancel/exe/canclapp.vcxproj.Filters @@ -3,15 +3,15 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {8E80D4A1-56AB-4705-840F-3971E3C35CC4} + {A9970D5F-6A08-4685-BCB3-BC7260733555} h;hpp;hxx;hm;inl;inc;xsd - {F05A42DC-3C1C-4B0B-BB8A-980D8BDD8C12} + {751D0E38-6054-404C-9749-DE882ACAACF4} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {DB77EDC2-6072-41D9-B58F-42B9EECC5702} + {D2D88B2C-9B81-4181-8BF9-3F8E289E770D} diff --git a/general/cancel/startio/cancel.vcxproj b/general/cancel/startio/cancel.vcxproj index 8cdbf0ce..da4a61db 100644 --- a/general/cancel/startio/cancel.vcxproj +++ b/general/cancel/startio/cancel.vcxproj @@ -19,11 +19,11 @@ - {1392C861-BA6F-4423-8C33-A8C771BAF473} + {9123CC18-82D4-477B-B20E-6EA2D454E046} $(MSBuildProjectName) Debug Win32 - {2FA77D27-524D-4C63-81CD-62E054676D96} + {64C91FEC-568F-4B05-A91E-F6B96212BA27} diff --git a/general/cancel/startio/cancel.vcxproj.Filters b/general/cancel/startio/cancel.vcxproj.Filters index 015f96b7..7184abaf 100644 --- a/general/cancel/startio/cancel.vcxproj.Filters +++ b/general/cancel/startio/cancel.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {DBC52094-6726-43E4-8D3A-1E52EB8592CA} + {2B25101E-8842-4A6A-8AFE-E6EE3BB048FD} h;hpp;hxx;hm;inl;inc;xsd - {12A618AD-2EC7-4EF1-B1F8-F14652DE50D0} + {274A07A9-D5CD-40E9-A368-7B2405C97AAF} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {01F4B40C-7AC7-4573-A236-526D211FE249} + {46F2B62E-AC82-4992-8A9F-472BA3B4912D} inf;inv;inx;mof;mc; - {C63E5134-5856-4331-9141-C85F75D697B9} + {D0E05008-9870-4B85-88BD-6F86F9D5E37F} diff --git a/general/cancel/sys/cancel.vcxproj b/general/cancel/sys/cancel.vcxproj index 6227a13d..8ec42428 100644 --- a/general/cancel/sys/cancel.vcxproj +++ b/general/cancel/sys/cancel.vcxproj @@ -19,11 +19,11 @@ - {3363DCA3-7873-4ECB-BA98-F243C2E8FDA0} + {D9569E28-5AA8-422B-8909-3B52E3A9E0A2} $(MSBuildProjectName) Debug Win32 - {3003AE7E-3AA2-458A-B349-64E4A921061B} + {DA39B940-2FD0-474D-86EE-DF9796879A51} diff --git a/general/cancel/sys/cancel.vcxproj.Filters b/general/cancel/sys/cancel.vcxproj.Filters index bdf2e015..5e786985 100644 --- a/general/cancel/sys/cancel.vcxproj.Filters +++ b/general/cancel/sys/cancel.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {6BC3B1BF-F875-48B1-9E49-07CB6AE2FED1} + {3711485D-9620-4878-846C-DE26288C24AA} h;hpp;hxx;hm;inl;inc;xsd - {646CC6F7-384E-44CB-B55D-2CF7427232F2} + {02DB91A6-1A11-484A-A01E-212829E426DE} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {A3ADD9F6-E06C-4974-AD86-F265759792E2} + {643643F8-399E-478C-9A56-C0948E4C4562} inf;inv;inx;mof;mc; - {4BC75BD1-ADE8-40F5-91AF-0002A740EF8C} + {22E6AE16-CFAD-4ED0-BE35-3664BF6E578B} diff --git a/general/echo/kmdf/ReadMe.md b/general/echo/kmdf/ReadMe.md index 05f41f49..ec2244c8 100644 --- a/general/echo/kmdf/ReadMe.md +++ b/general/echo/kmdf/ReadMe.md @@ -8,6 +8,9 @@ It also shows how to synchronize execution of these events with other asynchrono ## Universal Compliant This sample builds a Windows Universal driver. It uses only APIs and DDIs that are included in Windows Core. +**Note** +Due to a known bug in the current Windows Driver Kit tools, when building this sample in Debug mode, the exe project may report some ApiValidator warnings. These can be safely ignored. + Related technologies -------------------- diff --git a/general/echo/kmdf/driver/AutoSync/device.c b/general/echo/kmdf/driver/AutoSync/device.c index ee20447f..e30ae723 100644 --- a/general/echo/kmdf/driver/AutoSync/device.c +++ b/general/echo/kmdf/driver/AutoSync/device.c @@ -60,7 +60,10 @@ Return Value: pnpPowerCallbacks.EvtDeviceSelfManagedIoInit = EchoEvtDeviceSelfManagedIoStart; pnpPowerCallbacks.EvtDeviceSelfManagedIoSuspend = EchoEvtDeviceSelfManagedIoSuspend; - #pragma prefast(suppress: 28024, "Function used for both Init and Restart Callbacks") + // + // Function used for both Init and Restart Callbacks + // + #pragma warning(suppress: 28024) pnpPowerCallbacks.EvtDeviceSelfManagedIoRestart = EchoEvtDeviceSelfManagedIoStart; // diff --git a/general/echo/kmdf/driver/AutoSync/echo.vcxproj b/general/echo/kmdf/driver/AutoSync/echo.vcxproj index fcaaf0ac..4dd50d31 100644 --- a/general/echo/kmdf/driver/AutoSync/echo.vcxproj +++ b/general/echo/kmdf/driver/AutoSync/echo.vcxproj @@ -19,12 +19,12 @@ - {C8F9A776-3675-459B-A0A3-BA17D003C70B} + {CDC025E9-1761-4E64-A166-BD45DE3FECDC} $(MSBuildProjectName) 1 Debug Win32 - {8063717F-2826-44B9-BCF2-23ACCAF2C1FA} + {1A19D04A-789A-4E5E-B6CB-8267327D49B2} diff --git a/general/echo/kmdf/driver/AutoSync/echo.vcxproj.Filters b/general/echo/kmdf/driver/AutoSync/echo.vcxproj.Filters index ba649423..e16a90eb 100644 --- a/general/echo/kmdf/driver/AutoSync/echo.vcxproj.Filters +++ b/general/echo/kmdf/driver/AutoSync/echo.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {C301082A-56B5-43D9-AF50-C90CDBB830DA} + {5315796E-E2AE-40C4-88D3-37088B83F7D8} h;hpp;hxx;hm;inl;inc;xsd - {E8E22922-FDB4-496F-9D8B-0E5930795BAC} + {F294BBB0-2191-4523-82C7-31490BDD8A37} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {78CA938F-ABD5-4BA1-A021-7E751E09B367} + {00A6B984-C7C3-4E03-9616-073B2F83B7A3} inf;inv;inx;mof;mc; - {A5E77DC1-258D-4E61-AA8D-1879410AE785} + {0046A610-D3DC-4635-AF3C-395E2E6D2900} diff --git a/general/echo/kmdf/driver/AutoSync/queue.c b/general/echo/kmdf/driver/AutoSync/queue.c index cb02a965..4906e067 100644 --- a/general/echo/kmdf/driver/AutoSync/queue.c +++ b/general/echo/kmdf/driver/AutoSync/queue.c @@ -301,7 +301,7 @@ Return Value: _Analysis_assume_(Length > 0); - KdPrint(("EchoEvtIoRead Called! Queue 0x%p, Request 0x%p Length %d\n", + KdPrint(("EchoEvtIoRead Called! Queue 0x%p, Request 0x%p Length %Iu\n", Queue,Request,Length)); // // No data to read @@ -396,11 +396,11 @@ Return Value: _Analysis_assume_(Length > 0); - KdPrint(("EchoEvtIoWrite Called! Queue 0x%p, Request 0x%p Length %d\n", + KdPrint(("EchoEvtIoWrite Called! Queue 0x%p, Request 0x%p Length %Iu\n", Queue,Request,Length)); if( Length > MAX_WRITE_LENGTH ) { - KdPrint(("EchoEvtIoWrite Buffer Length to big %d, Max is %d\n", + KdPrint(("EchoEvtIoWrite Buffer Length to big %Iu, Max is %d\n", Length,MAX_WRITE_LENGTH)); WdfRequestCompleteWithInformation(Request, STATUS_BUFFER_OVERFLOW, 0L); return; @@ -425,7 +425,7 @@ Return Value: queueContext->Buffer = ExAllocatePoolWithTag(NonPagedPool, Length, 'sam1'); if( queueContext->Buffer == NULL ) { - KdPrint(("EchoEvtIoWrite: Could not allocate %d byte buffer\n", Length)); + KdPrint(("EchoEvtIoWrite: Could not allocate %Iu byte buffer\n", Length)); WdfRequestComplete(Request, STATUS_INSUFFICIENT_RESOURCES); return; } diff --git a/general/echo/kmdf/driver/DriverSync/device.c b/general/echo/kmdf/driver/DriverSync/device.c index eb37eaf2..c9dbcbb4 100644 --- a/general/echo/kmdf/driver/DriverSync/device.c +++ b/general/echo/kmdf/driver/DriverSync/device.c @@ -59,7 +59,11 @@ Return Value: // pnpPowerCallbacks.EvtDeviceSelfManagedIoInit = EchoEvtDeviceSelfManagedIoStart; pnpPowerCallbacks.EvtDeviceSelfManagedIoSuspend = EchoEvtDeviceSelfManagedIoSuspend; - #pragma prefast(suppress: 28024, "Function used for both Init and Restart Callbacks") + + // + // Function used for both Init and Restart Callbacks + // + #pragma warning(suppress: 28024) pnpPowerCallbacks.EvtDeviceSelfManagedIoRestart = EchoEvtDeviceSelfManagedIoStart; // diff --git a/general/echo/kmdf/driver/DriverSync/echo_2.vcxproj b/general/echo/kmdf/driver/DriverSync/echo_2.vcxproj index a96b9b73..893895a1 100644 --- a/general/echo/kmdf/driver/DriverSync/echo_2.vcxproj +++ b/general/echo/kmdf/driver/DriverSync/echo_2.vcxproj @@ -19,12 +19,12 @@ - {968447B1-9A4F-4D2D-B81B-7BCB9240F5E3} + {349EBD20-0306-46A9-8921-622D7C07D20B} $(MSBuildProjectName) 1 Debug Win32 - {0F2B6094-D739-411B-B15C-D0ABD3ACF20E} + {76F69B56-EF56-432F-8691-1C773793EB51} diff --git a/general/echo/kmdf/driver/DriverSync/echo_2.vcxproj.Filters b/general/echo/kmdf/driver/DriverSync/echo_2.vcxproj.Filters index 2fac5833..cc1cf7de 100644 --- a/general/echo/kmdf/driver/DriverSync/echo_2.vcxproj.Filters +++ b/general/echo/kmdf/driver/DriverSync/echo_2.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {5AF6C435-D6C0-4812-A1B9-A231D60FF6A3} + {C1DDA8F3-CE1F-4E9F-B893-ABD8D39FA214} h;hpp;hxx;hm;inl;inc;xsd - {52F80479-DCAD-49B9-9A2F-BB7363EEEBAF} + {9EBBB66D-9D37-402F-833E-2CCF7E34CCD5} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {1EC49F54-AC4E-447D-B4EA-B9859C16E917} + {53508F5F-9B47-4922-91FF-3A0BB6BF6D49} inf;inv;inx;mof;mc; - {9CFF80B0-15ED-408B-B629-91208E5966C3} + {59652897-649C-440A-B1AA-1AE8A8038E8E} diff --git a/general/echo/kmdf/driver/DriverSync/queue.c b/general/echo/kmdf/driver/DriverSync/queue.c index 89d47fa2..6017294e 100644 --- a/general/echo/kmdf/driver/DriverSync/queue.c +++ b/general/echo/kmdf/driver/DriverSync/queue.c @@ -516,7 +516,7 @@ Return Value: _Analysis_assume_(Length > 0); - KdPrint(("EchoEvtIoRead Called! Queue 0x%p, Request 0x%p Length %d\n", + KdPrint(("EchoEvtIoRead Called! Queue 0x%p, Request 0x%p Length %Iu\n", Queue,Request,Length)); // // No data to read @@ -611,11 +611,11 @@ Return Value: _Analysis_assume_(Length > 0); - KdPrint(("EchoEvtIoWrite Called! Queue 0x%p, Request 0x%p Length %d\n", + KdPrint(("EchoEvtIoWrite Called! Queue 0x%p, Request 0x%p Length %Iu\n", Queue,Request,Length)); if( Length > MAX_WRITE_LENGTH ) { - KdPrint(("EchoEvtIoWrite Buffer Length to big %d, Max is %d\n", + KdPrint(("EchoEvtIoWrite Buffer Length to big %Iu, Max is %d\n", Length,MAX_WRITE_LENGTH)); WdfRequestCompleteWithInformation(Request, STATUS_BUFFER_OVERFLOW, 0L); return; @@ -640,7 +640,7 @@ Return Value: queueContext->Buffer = ExAllocatePoolWithTag(NonPagedPool, Length, 'sam1'); if( queueContext->Buffer == NULL ) { - KdPrint(("EchoEvtIoWrite: Could not allocate %d byte buffer\n",Length)); + KdPrint(("EchoEvtIoWrite: Could not allocate %Iu byte buffer\n",Length)); WdfRequestComplete(Request, STATUS_INSUFFICIENT_RESOURCES); return; } diff --git a/general/echo/kmdf/exe/echoapp.cpp b/general/echo/kmdf/exe/echoapp.cpp index 9649a407..2383db2c 100644 --- a/general/echo/kmdf/exe/echoapp.cpp +++ b/general/echo/kmdf/exe/echoapp.cpp @@ -4,11 +4,11 @@ Copyright (c) Microsoft Corporation Module Name: - ioctl.cpp + EchoApp.cpp Abstract: - A simple asynch test for usb driver. + An application to exercise the WDF "echo" sample driver. Environment: @@ -25,7 +25,7 @@ _Analysis_mode_(_Analysis_code_type_user_code_) #include #include -#include +#include #include #include #include "public.h" @@ -41,7 +41,7 @@ _Analysis_mode_(_Analysis_code_type_user_code_) BOOLEAN G_PerformAsyncIo; BOOLEAN G_LimitedLoops; ULONG G_AsyncIoLoopsNum; -CHAR G_DevicePath[MAX_DEVPATH_LENGTH]; +WCHAR G_DevicePath[MAX_DEVPATH_LENGTH]; ULONG @@ -58,7 +58,7 @@ PerformWriteReadTest( BOOL GetDevicePath( IN LPGUID InterfaceGuid, - _Out_writes_(BufLen) PCHAR DevicePath, + _Out_writes_(BufLen) PWCHAR DevicePath, _In_ size_t BufLen ); @@ -105,7 +105,7 @@ main( goto exit; } - printf("DevicePath: %s\n", G_DevicePath); + printf("DevicePath: %ws\n", G_DevicePath); hDevice = CreateFile(G_DevicePath, GENERIC_READ|GENERIC_WRITE, @@ -352,8 +352,6 @@ Cleanup: return result; } - - ULONG AsyncIo( PVOID ThreadParameter @@ -384,7 +382,7 @@ AsyncIo( if (hDevice == INVALID_HANDLE_VALUE) { - printf("Cannot open %s error %d\n", G_DevicePath, GetLastError()); + printf("Cannot open %ws error %d\n", G_DevicePath, GetLastError()); result = FALSE; goto Error; } @@ -579,122 +577,76 @@ Error: } - BOOL GetDevicePath( - IN LPGUID InterfaceGuid, - _Out_writes_(BufLen) PCHAR DevicePath, + _In_ LPGUID InterfaceGuid, + _Out_writes_(BufLen) PWCHAR 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), - (LPSTR) &lpMsgBuf, - 0, - NULL - )) { - - printf("SetupDiEnumDeviceInterfaces failed: %s", (LPTSTR)lpMsgBuf); - LocalFree(lpMsgBuf); - } - - printf("SetupDiEnumDeviceInterfaces failed.\n"); - SetupDiDestroyDeviceInfoList(HardwareDeviceInfo); - return FALSE; + CONFIGRET cr = CR_SUCCESS; + PWSTR deviceInterfaceList = NULL; + ULONG deviceInterfaceListLength = 0; + PWSTR nextInterface; + HRESULT hr = E_FAIL; + BOOL bRet = TRUE; + + cr = CM_Get_Device_Interface_List_Size( + &deviceInterfaceListLength, + InterfaceGuid, + NULL, + CM_GET_DEVICE_INTERFACE_LIST_PRESENT); + if (cr != CR_SUCCESS) { + printf("Error 0x%x retrieving device interface list size.\n", cr); + goto clean0; } - 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; + if (deviceInterfaceListLength <= 1) { + bRet = FALSE; + printf("Error: No active device interfaces found.\n" + " Is the sample driver loaded?"); + goto clean0; } - 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), - (LPSTR) &lpMsgBuf, - 0, - NULL - ); + deviceInterfaceList = (PWSTR)malloc(deviceInterfaceListLength * sizeof(WCHAR)); + if (deviceInterfaceList == NULL) { + printf("Error allocating memory for device interface list.\n"); + goto clean0; + } + ZeroMemory(deviceInterfaceList, deviceInterfaceListLength * sizeof(WCHAR)); + + cr = CM_Get_Device_Interface_List( + InterfaceGuid, + NULL, + deviceInterfaceList, + deviceInterfaceListLength, + CM_GET_DEVICE_INTERFACE_LIST_PRESENT); + if (cr != CR_SUCCESS) { + printf("Error 0x%x retrieving device interface list.\n", cr); + goto clean0; + } - SetupDiDestroyDeviceInfoList(HardwareDeviceInfo); - printf("Error in SetupDiGetDeviceInterfaceDetail: %s\n", (LPTSTR)lpMsgBuf); - LocalFree(DeviceInterfaceDetailData); - LocalFree(lpMsgBuf); - return FALSE; + nextInterface = deviceInterfaceList + wcslen(deviceInterfaceList) + 1; + if (*nextInterface != UNICODE_NULL) { + printf("Warning: More than one device interface instance found. \n" + "Selecting first matching device.\n\n"); } - hr = StringCchCopy(DevicePath, - BufLen, - DeviceInterfaceDetailData->DevicePath) ; + hr = StringCchCopy(DevicePath, BufLen, deviceInterfaceList); + if (FAILED(hr)) { + bRet = FALSE; + printf("Error: StringCchCopy failed with HRESULT 0x%x", hr); + goto clean0; + } - SetupDiDestroyDeviceInfoList(HardwareDeviceInfo); // It must be executed in both success and failure traces - LocalFree(DeviceInterfaceDetailData); +clean0: + if (deviceInterfaceList != NULL) { + free(deviceInterfaceList); + } + if (CR_SUCCESS != cr) { + bRet = FALSE; + } - return ( !FAILED(hr) ); // Result depends on StringCchCopy() + return bRet; } diff --git a/general/echo/kmdf/exe/echoapp.vcxproj b/general/echo/kmdf/exe/echoapp.vcxproj index 11b3eb4c..62821146 100644 --- a/general/echo/kmdf/exe/echoapp.vcxproj +++ b/general/echo/kmdf/exe/echoapp.vcxproj @@ -19,17 +19,17 @@ - {684264A6-91C1-4046-AD23-BD823E13EB60} + {84FCC75B-B284-4321-8108-140360BF56AA} $(MSBuildProjectName) Debug Win32 - {C342DB0F-934F-4A0A-90A7-02650E906732} + {5D8FBCFF-DE4D-4607-9577-F4D8A83F971D} Windows10 False - Desktop + Universal WindowsApplicationForDrivers10.0 Application @@ -37,7 +37,7 @@ Windows10 True - Desktop + Universal WindowsApplicationForDrivers10.0 Application @@ -45,7 +45,7 @@ Windows10 False - Desktop + Universal WindowsApplicationForDrivers10.0 Application @@ -53,7 +53,7 @@ Windows10 True - Desktop + Universal WindowsApplicationForDrivers10.0 Application @@ -89,66 +89,78 @@ - %(AdditionalDependencies);setupapi.lib;user32.lib + %(AdditionalDependencies);mincore.lib - %(AdditionalIncludeDirectories);$(DDK_INC_PATH) + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH) + %(PreprocessorDefinitions);UNICODE;_UNICODE - %(AdditionalIncludeDirectories);$(DDK_INC_PATH) + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH) + %(PreprocessorDefinitions);UNICODE;_UNICODE - %(AdditionalIncludeDirectories);$(DDK_INC_PATH) + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH) + %(PreprocessorDefinitions);UNICODE;_UNICODE - %(AdditionalDependencies);setupapi.lib;user32.lib + %(AdditionalDependencies);mincore.lib - %(AdditionalIncludeDirectories);$(DDK_INC_PATH) + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH) + %(PreprocessorDefinitions);UNICODE;_UNICODE - %(AdditionalIncludeDirectories);$(DDK_INC_PATH) + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH) + %(PreprocessorDefinitions);UNICODE;_UNICODE - %(AdditionalIncludeDirectories);$(DDK_INC_PATH) + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH) + %(PreprocessorDefinitions);UNICODE;_UNICODE - %(AdditionalDependencies);setupapi.lib;user32.lib + %(AdditionalDependencies);mincore.lib - %(AdditionalIncludeDirectories);$(DDK_INC_PATH) + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH) + %(PreprocessorDefinitions);UNICODE;_UNICODE - %(AdditionalIncludeDirectories);$(DDK_INC_PATH) + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH) + %(PreprocessorDefinitions);UNICODE;_UNICODE - %(AdditionalIncludeDirectories);$(DDK_INC_PATH) + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH) + %(PreprocessorDefinitions);UNICODE;_UNICODE - %(AdditionalDependencies);setupapi.lib;user32.lib + %(AdditionalDependencies);mincore.lib - %(AdditionalIncludeDirectories);$(DDK_INC_PATH) + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH) + %(PreprocessorDefinitions);UNICODE;_UNICODE - %(AdditionalIncludeDirectories);$(DDK_INC_PATH) + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH) + %(PreprocessorDefinitions);UNICODE;_UNICODE - %(AdditionalIncludeDirectories);$(DDK_INC_PATH) + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH) + %(PreprocessorDefinitions);UNICODE;_UNICODE diff --git a/general/echo/kmdf/exe/echoapp.vcxproj.Filters b/general/echo/kmdf/exe/echoapp.vcxproj.Filters index 7e14cf46..51d35517 100644 --- a/general/echo/kmdf/exe/echoapp.vcxproj.Filters +++ b/general/echo/kmdf/exe/echoapp.vcxproj.Filters @@ -3,15 +3,15 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {A120A502-9177-430F-BAEB-BBE51661EDDD} + {66A85886-4DDE-45CB-9A3F-E641ACCDBA7E} h;hpp;hxx;hm;inl;inc;xsd - {967C5907-C8A7-46F3-B2B7-E3A0BFF110EE} + {A498F6A0-D3A5-4F4B-8D99-056B439FB180} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {53BEED44-2F74-4E8F-B7B8-D0BDDB11BEB6} + {0B82D018-961F-414C-8BBC-6D96DAEA3805} diff --git a/general/echo/kmdf/kmdfecho.sln b/general/echo/kmdf/kmdfecho.sln index b9c25c6c..4cc77bf9 100644 --- a/general/echo/kmdf/kmdfecho.sln +++ b/general/echo/kmdf/kmdfecho.sln @@ -3,19 +3,19 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Exe", "Exe", "{1DD2F948-0799-49E3-A880-35A6215F8479}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Exe", "Exe", "{52FB1641-AFB0-4F37-8BE9-4138A77068CB}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "AutoSync", "AutoSync", "{B52DE63E-ED02-41DD-9DAB-53ACE0286663}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "AutoSync", "AutoSync", "{D05198DA-5478-4E5A-B530-5412FDB8A1DD}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Driver", "Driver", "{AE9E09B7-46C1-4AA3-9411-F125D9188EFD}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Driver", "Driver", "{4713DF3C-3B4C-4E76-9FB3-111280705220}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "DriverSync", "DriverSync", "{F01C6D5C-982E-4AE2-8DDC-0666F3905135}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "DriverSync", "DriverSync", "{7010B108-FC52-4EC9-B504-AF41533C82A7}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "echoapp", "exe\echoapp.vcxproj", "{684264A6-91C1-4046-AD23-BD823E13EB60}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "echoapp", "exe\echoapp.vcxproj", "{84FCC75B-B284-4321-8108-140360BF56AA}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "echo", "driver\AutoSync\echo.vcxproj", "{C8F9A776-3675-459B-A0A3-BA17D003C70B}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "echo", "driver\AutoSync\echo.vcxproj", "{CDC025E9-1761-4E64-A166-BD45DE3FECDC}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "echo_2", "driver\DriverSync\echo_2.vcxproj", "{968447B1-9A4F-4D2D-B81B-7BCB9240F5E3}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "echo_2", "driver\DriverSync\echo_2.vcxproj", "{349EBD20-0306-46A9-8921-622D7C07D20B}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -25,39 +25,39 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {684264A6-91C1-4046-AD23-BD823E13EB60}.Debug|Win32.ActiveCfg = Debug|Win32 - {684264A6-91C1-4046-AD23-BD823E13EB60}.Debug|Win32.Build.0 = Debug|Win32 - {684264A6-91C1-4046-AD23-BD823E13EB60}.Release|Win32.ActiveCfg = Release|Win32 - {684264A6-91C1-4046-AD23-BD823E13EB60}.Release|Win32.Build.0 = Release|Win32 - {684264A6-91C1-4046-AD23-BD823E13EB60}.Debug|x64.ActiveCfg = Debug|x64 - {684264A6-91C1-4046-AD23-BD823E13EB60}.Debug|x64.Build.0 = Debug|x64 - {684264A6-91C1-4046-AD23-BD823E13EB60}.Release|x64.ActiveCfg = Release|x64 - {684264A6-91C1-4046-AD23-BD823E13EB60}.Release|x64.Build.0 = Release|x64 - {C8F9A776-3675-459B-A0A3-BA17D003C70B}.Debug|Win32.ActiveCfg = Debug|Win32 - {C8F9A776-3675-459B-A0A3-BA17D003C70B}.Debug|Win32.Build.0 = Debug|Win32 - {C8F9A776-3675-459B-A0A3-BA17D003C70B}.Release|Win32.ActiveCfg = Release|Win32 - {C8F9A776-3675-459B-A0A3-BA17D003C70B}.Release|Win32.Build.0 = Release|Win32 - {C8F9A776-3675-459B-A0A3-BA17D003C70B}.Debug|x64.ActiveCfg = Debug|x64 - {C8F9A776-3675-459B-A0A3-BA17D003C70B}.Debug|x64.Build.0 = Debug|x64 - {C8F9A776-3675-459B-A0A3-BA17D003C70B}.Release|x64.ActiveCfg = Release|x64 - {C8F9A776-3675-459B-A0A3-BA17D003C70B}.Release|x64.Build.0 = Release|x64 - {968447B1-9A4F-4D2D-B81B-7BCB9240F5E3}.Debug|Win32.ActiveCfg = Debug|Win32 - {968447B1-9A4F-4D2D-B81B-7BCB9240F5E3}.Debug|Win32.Build.0 = Debug|Win32 - {968447B1-9A4F-4D2D-B81B-7BCB9240F5E3}.Release|Win32.ActiveCfg = Release|Win32 - {968447B1-9A4F-4D2D-B81B-7BCB9240F5E3}.Release|Win32.Build.0 = Release|Win32 - {968447B1-9A4F-4D2D-B81B-7BCB9240F5E3}.Debug|x64.ActiveCfg = Debug|x64 - {968447B1-9A4F-4D2D-B81B-7BCB9240F5E3}.Debug|x64.Build.0 = Debug|x64 - {968447B1-9A4F-4D2D-B81B-7BCB9240F5E3}.Release|x64.ActiveCfg = Release|x64 - {968447B1-9A4F-4D2D-B81B-7BCB9240F5E3}.Release|x64.Build.0 = Release|x64 + {84FCC75B-B284-4321-8108-140360BF56AA}.Debug|Win32.ActiveCfg = Debug|Win32 + {84FCC75B-B284-4321-8108-140360BF56AA}.Debug|Win32.Build.0 = Debug|Win32 + {84FCC75B-B284-4321-8108-140360BF56AA}.Release|Win32.ActiveCfg = Release|Win32 + {84FCC75B-B284-4321-8108-140360BF56AA}.Release|Win32.Build.0 = Release|Win32 + {84FCC75B-B284-4321-8108-140360BF56AA}.Debug|x64.ActiveCfg = Debug|x64 + {84FCC75B-B284-4321-8108-140360BF56AA}.Debug|x64.Build.0 = Debug|x64 + {84FCC75B-B284-4321-8108-140360BF56AA}.Release|x64.ActiveCfg = Release|x64 + {84FCC75B-B284-4321-8108-140360BF56AA}.Release|x64.Build.0 = Release|x64 + {CDC025E9-1761-4E64-A166-BD45DE3FECDC}.Debug|Win32.ActiveCfg = Debug|Win32 + {CDC025E9-1761-4E64-A166-BD45DE3FECDC}.Debug|Win32.Build.0 = Debug|Win32 + {CDC025E9-1761-4E64-A166-BD45DE3FECDC}.Release|Win32.ActiveCfg = Release|Win32 + {CDC025E9-1761-4E64-A166-BD45DE3FECDC}.Release|Win32.Build.0 = Release|Win32 + {CDC025E9-1761-4E64-A166-BD45DE3FECDC}.Debug|x64.ActiveCfg = Debug|x64 + {CDC025E9-1761-4E64-A166-BD45DE3FECDC}.Debug|x64.Build.0 = Debug|x64 + {CDC025E9-1761-4E64-A166-BD45DE3FECDC}.Release|x64.ActiveCfg = Release|x64 + {CDC025E9-1761-4E64-A166-BD45DE3FECDC}.Release|x64.Build.0 = Release|x64 + {349EBD20-0306-46A9-8921-622D7C07D20B}.Debug|Win32.ActiveCfg = Debug|Win32 + {349EBD20-0306-46A9-8921-622D7C07D20B}.Debug|Win32.Build.0 = Debug|Win32 + {349EBD20-0306-46A9-8921-622D7C07D20B}.Release|Win32.ActiveCfg = Release|Win32 + {349EBD20-0306-46A9-8921-622D7C07D20B}.Release|Win32.Build.0 = Release|Win32 + {349EBD20-0306-46A9-8921-622D7C07D20B}.Debug|x64.ActiveCfg = Debug|x64 + {349EBD20-0306-46A9-8921-622D7C07D20B}.Debug|x64.Build.0 = Debug|x64 + {349EBD20-0306-46A9-8921-622D7C07D20B}.Release|x64.ActiveCfg = Release|x64 + {349EBD20-0306-46A9-8921-622D7C07D20B}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {684264A6-91C1-4046-AD23-BD823E13EB60} = {1DD2F948-0799-49E3-A880-35A6215F8479} - {C8F9A776-3675-459B-A0A3-BA17D003C70B} = {B52DE63E-ED02-41DD-9DAB-53ACE0286663} - {968447B1-9A4F-4D2D-B81B-7BCB9240F5E3} = {F01C6D5C-982E-4AE2-8DDC-0666F3905135} - {B52DE63E-ED02-41DD-9DAB-53ACE0286663} = {AE9E09B7-46C1-4AA3-9411-F125D9188EFD} - {F01C6D5C-982E-4AE2-8DDC-0666F3905135} = {AE9E09B7-46C1-4AA3-9411-F125D9188EFD} + {84FCC75B-B284-4321-8108-140360BF56AA} = {52FB1641-AFB0-4F37-8BE9-4138A77068CB} + {CDC025E9-1761-4E64-A166-BD45DE3FECDC} = {D05198DA-5478-4E5A-B530-5412FDB8A1DD} + {349EBD20-0306-46A9-8921-622D7C07D20B} = {7010B108-FC52-4EC9-B504-AF41533C82A7} + {D05198DA-5478-4E5A-B530-5412FDB8A1DD} = {4713DF3C-3B4C-4E76-9FB3-111280705220} + {7010B108-FC52-4EC9-B504-AF41533C82A7} = {4713DF3C-3B4C-4E76-9FB3-111280705220} EndGlobalSection EndGlobal diff --git a/general/echo/umdf/WUDFEchoDriver.inx b/general/echo/umdf/WUDFEchoDriver.inx index 6279783e..b2fb16aa 100644 --- a/general/echo/umdf/WUDFEchoDriver.inx +++ b/general/echo/umdf/WUDFEchoDriver.inx @@ -75,7 +75,7 @@ UMDriverCopy=12,UMDF ; copy to drivers\UMDF CoInstallers_CopyFiles=11 [UMDriverCopy] -WUDFEchoDriver.dll +WUDFEchoDriver.dll,,,0x00004000 ; COPYFLG_IN_USE_RENAME ; =================== Generic ================================== diff --git a/general/echo/umdf/WUDFEchoDriver.vcxproj b/general/echo/umdf/WUDFEchoDriver.vcxproj index 242f1dda..0b231b04 100644 --- a/general/echo/umdf/WUDFEchoDriver.vcxproj +++ b/general/echo/umdf/WUDFEchoDriver.vcxproj @@ -19,12 +19,12 @@ - {9E7A6816-063C-4560-A31F-C5472D1CE345} + {E9829567-BB6F-432B-A8A1-4B4971928159} $(MSBuildProjectName) 1 Debug Win32 - {164B0F80-BB88-48C9-A03F-3F3937D8CCB6} + {6143696E-E68A-4B3D-87FA-ADE6B7E50DB4} diff --git a/general/echo/umdf/WUDFEchoDriver.vcxproj.Filters b/general/echo/umdf/WUDFEchoDriver.vcxproj.Filters index b702fb21..c3a10478 100644 --- a/general/echo/umdf/WUDFEchoDriver.vcxproj.Filters +++ b/general/echo/umdf/WUDFEchoDriver.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {0FBE107F-4905-4E97-BFF9-8C2A6B03AED8} + {78D910D7-E92B-4734-A811-EE671E018AD7} h;hpp;hxx;hm;inl;inc;xsd - {9534FE43-2493-4430-A335-97FC2BE106BD} + {D9527C10-A566-4A05-839C-005DACECC7AF} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {A96A2015-2537-47ED-B43D-8C379EDEC69F} + {F244522B-A2AF-46A0-BF42-64F811F1646C} inf;inv;inx;mof;mc; - {203FBCD2-49E2-491E-9D3F-03A028ED6CEE} + {D6D8C255-A574-4240-9F8E-EDE56A98BC63} diff --git a/general/echo/umdf/echo.sln b/general/echo/umdf/echo.sln index 853b7d55..e749b313 100644 --- a/general/echo/umdf/echo.sln +++ b/general/echo/umdf/echo.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WUDFEchoDriver", "WUDFEchoDriver.vcxproj", "{9E7A6816-063C-4560-A31F-C5472D1CE345}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WUDFEchoDriver", "WUDFEchoDriver.vcxproj", "{E9829567-BB6F-432B-A8A1-4B4971928159}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +13,14 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {9E7A6816-063C-4560-A31F-C5472D1CE345}.Debug|Win32.ActiveCfg = Debug|Win32 - {9E7A6816-063C-4560-A31F-C5472D1CE345}.Debug|Win32.Build.0 = Debug|Win32 - {9E7A6816-063C-4560-A31F-C5472D1CE345}.Release|Win32.ActiveCfg = Release|Win32 - {9E7A6816-063C-4560-A31F-C5472D1CE345}.Release|Win32.Build.0 = Release|Win32 - {9E7A6816-063C-4560-A31F-C5472D1CE345}.Debug|x64.ActiveCfg = Debug|x64 - {9E7A6816-063C-4560-A31F-C5472D1CE345}.Debug|x64.Build.0 = Debug|x64 - {9E7A6816-063C-4560-A31F-C5472D1CE345}.Release|x64.ActiveCfg = Release|x64 - {9E7A6816-063C-4560-A31F-C5472D1CE345}.Release|x64.Build.0 = Release|x64 + {E9829567-BB6F-432B-A8A1-4B4971928159}.Debug|Win32.ActiveCfg = Debug|Win32 + {E9829567-BB6F-432B-A8A1-4B4971928159}.Debug|Win32.Build.0 = Debug|Win32 + {E9829567-BB6F-432B-A8A1-4B4971928159}.Release|Win32.ActiveCfg = Release|Win32 + {E9829567-BB6F-432B-A8A1-4B4971928159}.Release|Win32.Build.0 = Release|Win32 + {E9829567-BB6F-432B-A8A1-4B4971928159}.Debug|x64.ActiveCfg = Debug|x64 + {E9829567-BB6F-432B-A8A1-4B4971928159}.Debug|x64.Build.0 = Debug|x64 + {E9829567-BB6F-432B-A8A1-4B4971928159}.Release|x64.ActiveCfg = Release|x64 + {E9829567-BB6F-432B-A8A1-4B4971928159}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/general/echo/umdf2/ReadMe.md b/general/echo/umdf2/ReadMe.md index e037a8b5..18fc9b23 100644 --- a/general/echo/umdf2/ReadMe.md +++ b/general/echo/umdf2/ReadMe.md @@ -8,6 +8,9 @@ It also shows how to synchronize execution of these events with other asynchrono ## Universal Compliant This sample builds a Windows Universal driver. It uses only APIs and DDIs that are included in Windows Core. +**Note** +Due to a known bug in the current Windows Driver Kit tools, when building this sample in Debug mode, the exe project may report some ApiValidator warnings. These can be safely ignored. + Related technologies -------------------- diff --git a/general/echo/umdf2/driver/AutoSync/echo.vcxproj b/general/echo/umdf2/driver/AutoSync/echo.vcxproj index defa7b4d..1a42c503 100644 --- a/general/echo/umdf2/driver/AutoSync/echo.vcxproj +++ b/general/echo/umdf2/driver/AutoSync/echo.vcxproj @@ -19,12 +19,12 @@ - {95360722-8B66-4DD4-957A-DF8B7CA700FB} + {7B51533F-3B85-437B-843B-FEC865C81376} $(MSBuildProjectName) 2 Debug Win32 - {F03689D2-F1BC-4D18-B99E-286CA22656D5} + {7014B7B7-69CF-441E-9264-AD0DBCCA6690} diff --git a/general/echo/umdf2/driver/AutoSync/echo.vcxproj.Filters b/general/echo/umdf2/driver/AutoSync/echo.vcxproj.Filters index 75ab6a0f..be4e54d6 100644 --- a/general/echo/umdf2/driver/AutoSync/echo.vcxproj.Filters +++ b/general/echo/umdf2/driver/AutoSync/echo.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {EF21C647-A675-40F9-981A-364CC77BFA4D} + {9B3693A5-EB57-4FA2-8C1B-F85253695D04} h;hpp;hxx;hm;inl;inc;xsd - {DC1E303A-60D0-45E3-AD8E-FA903A23C932} + {E32C0D43-4943-449E-82C0-2596D5D3BCEE} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {04F193A8-1C9D-45EC-ADDB-918233FB151D} + {ADEC5939-ED9C-4182-879E-AD54FFCB84ED} inf;inv;inx;mof;mc; - {C0846D78-C3A3-42B0-AFDD-5D33B6AAE456} + {216463FB-3A2F-40C2-A52E-263D862032D6} diff --git a/general/echo/umdf2/driver/AutoSync/echoum.inx b/general/echo/umdf2/driver/AutoSync/echoum.inx index 287c05df..fa5d29a9 100644 --- a/general/echo/umdf2/driver/AutoSync/echoum.inx +++ b/general/echo/umdf2/driver/AutoSync/echoum.inx @@ -55,7 +55,7 @@ Echo.dll = 1,, CopyFiles=UMDriverCopy [UMDriverCopy] -ECHO.dll +ECHO.dll,,,0x00004000 ; COPYFLG_IN_USE_RENAME [DestinationDirs] UMDriverCopy=12,UMDF ; copy to driversMdf diff --git a/general/echo/umdf2/exe/echoapp.cpp b/general/echo/umdf2/exe/echoapp.cpp index 9649a407..2383db2c 100644 --- a/general/echo/umdf2/exe/echoapp.cpp +++ b/general/echo/umdf2/exe/echoapp.cpp @@ -4,11 +4,11 @@ Copyright (c) Microsoft Corporation Module Name: - ioctl.cpp + EchoApp.cpp Abstract: - A simple asynch test for usb driver. + An application to exercise the WDF "echo" sample driver. Environment: @@ -25,7 +25,7 @@ _Analysis_mode_(_Analysis_code_type_user_code_) #include #include -#include +#include #include #include #include "public.h" @@ -41,7 +41,7 @@ _Analysis_mode_(_Analysis_code_type_user_code_) BOOLEAN G_PerformAsyncIo; BOOLEAN G_LimitedLoops; ULONG G_AsyncIoLoopsNum; -CHAR G_DevicePath[MAX_DEVPATH_LENGTH]; +WCHAR G_DevicePath[MAX_DEVPATH_LENGTH]; ULONG @@ -58,7 +58,7 @@ PerformWriteReadTest( BOOL GetDevicePath( IN LPGUID InterfaceGuid, - _Out_writes_(BufLen) PCHAR DevicePath, + _Out_writes_(BufLen) PWCHAR DevicePath, _In_ size_t BufLen ); @@ -105,7 +105,7 @@ main( goto exit; } - printf("DevicePath: %s\n", G_DevicePath); + printf("DevicePath: %ws\n", G_DevicePath); hDevice = CreateFile(G_DevicePath, GENERIC_READ|GENERIC_WRITE, @@ -352,8 +352,6 @@ Cleanup: return result; } - - ULONG AsyncIo( PVOID ThreadParameter @@ -384,7 +382,7 @@ AsyncIo( if (hDevice == INVALID_HANDLE_VALUE) { - printf("Cannot open %s error %d\n", G_DevicePath, GetLastError()); + printf("Cannot open %ws error %d\n", G_DevicePath, GetLastError()); result = FALSE; goto Error; } @@ -579,122 +577,76 @@ Error: } - BOOL GetDevicePath( - IN LPGUID InterfaceGuid, - _Out_writes_(BufLen) PCHAR DevicePath, + _In_ LPGUID InterfaceGuid, + _Out_writes_(BufLen) PWCHAR 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), - (LPSTR) &lpMsgBuf, - 0, - NULL - )) { - - printf("SetupDiEnumDeviceInterfaces failed: %s", (LPTSTR)lpMsgBuf); - LocalFree(lpMsgBuf); - } - - printf("SetupDiEnumDeviceInterfaces failed.\n"); - SetupDiDestroyDeviceInfoList(HardwareDeviceInfo); - return FALSE; + CONFIGRET cr = CR_SUCCESS; + PWSTR deviceInterfaceList = NULL; + ULONG deviceInterfaceListLength = 0; + PWSTR nextInterface; + HRESULT hr = E_FAIL; + BOOL bRet = TRUE; + + cr = CM_Get_Device_Interface_List_Size( + &deviceInterfaceListLength, + InterfaceGuid, + NULL, + CM_GET_DEVICE_INTERFACE_LIST_PRESENT); + if (cr != CR_SUCCESS) { + printf("Error 0x%x retrieving device interface list size.\n", cr); + goto clean0; } - 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; + if (deviceInterfaceListLength <= 1) { + bRet = FALSE; + printf("Error: No active device interfaces found.\n" + " Is the sample driver loaded?"); + goto clean0; } - 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), - (LPSTR) &lpMsgBuf, - 0, - NULL - ); + deviceInterfaceList = (PWSTR)malloc(deviceInterfaceListLength * sizeof(WCHAR)); + if (deviceInterfaceList == NULL) { + printf("Error allocating memory for device interface list.\n"); + goto clean0; + } + ZeroMemory(deviceInterfaceList, deviceInterfaceListLength * sizeof(WCHAR)); + + cr = CM_Get_Device_Interface_List( + InterfaceGuid, + NULL, + deviceInterfaceList, + deviceInterfaceListLength, + CM_GET_DEVICE_INTERFACE_LIST_PRESENT); + if (cr != CR_SUCCESS) { + printf("Error 0x%x retrieving device interface list.\n", cr); + goto clean0; + } - SetupDiDestroyDeviceInfoList(HardwareDeviceInfo); - printf("Error in SetupDiGetDeviceInterfaceDetail: %s\n", (LPTSTR)lpMsgBuf); - LocalFree(DeviceInterfaceDetailData); - LocalFree(lpMsgBuf); - return FALSE; + nextInterface = deviceInterfaceList + wcslen(deviceInterfaceList) + 1; + if (*nextInterface != UNICODE_NULL) { + printf("Warning: More than one device interface instance found. \n" + "Selecting first matching device.\n\n"); } - hr = StringCchCopy(DevicePath, - BufLen, - DeviceInterfaceDetailData->DevicePath) ; + hr = StringCchCopy(DevicePath, BufLen, deviceInterfaceList); + if (FAILED(hr)) { + bRet = FALSE; + printf("Error: StringCchCopy failed with HRESULT 0x%x", hr); + goto clean0; + } - SetupDiDestroyDeviceInfoList(HardwareDeviceInfo); // It must be executed in both success and failure traces - LocalFree(DeviceInterfaceDetailData); +clean0: + if (deviceInterfaceList != NULL) { + free(deviceInterfaceList); + } + if (CR_SUCCESS != cr) { + bRet = FALSE; + } - return ( !FAILED(hr) ); // Result depends on StringCchCopy() + return bRet; } diff --git a/general/echo/umdf2/exe/echoapp.vcxproj b/general/echo/umdf2/exe/echoapp.vcxproj index c8b2000b..213947f1 100644 --- a/general/echo/umdf2/exe/echoapp.vcxproj +++ b/general/echo/umdf2/exe/echoapp.vcxproj @@ -19,17 +19,17 @@ - {2744B9D7-C918-4979-AF41-3DC6B305BA72} + {312B4737-78DE-40B0-AEFB-D20A133B2A99} $(MSBuildProjectName) Debug Win32 - {725C57DF-D40D-4503-ADBE-A694D0AC15A8} + {1AEE3F20-6611-4775-ACF4-2871153EE1BF} Windows10 False - Desktop + Universal WindowsApplicationForDrivers10.0 Application @@ -37,7 +37,7 @@ Windows10 True - Desktop + Universal WindowsApplicationForDrivers10.0 Application @@ -45,7 +45,7 @@ Windows10 False - Desktop + Universal WindowsApplicationForDrivers10.0 Application @@ -53,7 +53,7 @@ Windows10 True - Desktop + Universal WindowsApplicationForDrivers10.0 Application @@ -89,66 +89,78 @@ - %(AdditionalDependencies);setupapi.lib;user32.lib + %(AdditionalDependencies);mincore.lib - %(AdditionalIncludeDirectories);$(DDK_INC_PATH) + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH) + %(PreprocessorDefinitions);UNICODE;_UNICODE - %(AdditionalIncludeDirectories);$(DDK_INC_PATH) + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH) + %(PreprocessorDefinitions);UNICODE;_UNICODE - %(AdditionalIncludeDirectories);$(DDK_INC_PATH) + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH) + %(PreprocessorDefinitions);UNICODE;_UNICODE - %(AdditionalDependencies);setupapi.lib;user32.lib + %(AdditionalDependencies);mincore.lib - %(AdditionalIncludeDirectories);$(DDK_INC_PATH) + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH) + %(PreprocessorDefinitions);UNICODE;_UNICODE - %(AdditionalIncludeDirectories);$(DDK_INC_PATH) + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH) + %(PreprocessorDefinitions);UNICODE;_UNICODE - %(AdditionalIncludeDirectories);$(DDK_INC_PATH) + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH) + %(PreprocessorDefinitions);UNICODE;_UNICODE - %(AdditionalDependencies);setupapi.lib;user32.lib + %(AdditionalDependencies);mincore.lib - %(AdditionalIncludeDirectories);$(DDK_INC_PATH) + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH) + %(PreprocessorDefinitions);UNICODE;_UNICODE - %(AdditionalIncludeDirectories);$(DDK_INC_PATH) + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH) + %(PreprocessorDefinitions);UNICODE;_UNICODE - %(AdditionalIncludeDirectories);$(DDK_INC_PATH) + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH) + %(PreprocessorDefinitions);UNICODE;_UNICODE - %(AdditionalDependencies);setupapi.lib;user32.lib + %(AdditionalDependencies);mincore.lib - %(AdditionalIncludeDirectories);$(DDK_INC_PATH) + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH) + %(PreprocessorDefinitions);UNICODE;_UNICODE - %(AdditionalIncludeDirectories);$(DDK_INC_PATH) + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH) + %(PreprocessorDefinitions);UNICODE;_UNICODE - %(AdditionalIncludeDirectories);$(DDK_INC_PATH) + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH) + %(PreprocessorDefinitions);UNICODE;_UNICODE diff --git a/general/echo/umdf2/exe/echoapp.vcxproj.Filters b/general/echo/umdf2/exe/echoapp.vcxproj.Filters index 1b67a921..8e64dba6 100644 --- a/general/echo/umdf2/exe/echoapp.vcxproj.Filters +++ b/general/echo/umdf2/exe/echoapp.vcxproj.Filters @@ -3,15 +3,15 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {A27E5252-132E-4B45-BC34-E21958A5A7B8} + {E47A65CC-C272-4052-B8E3-DFA70BFA5CE8} h;hpp;hxx;hm;inl;inc;xsd - {21C62558-1F78-4174-BB6A-42FE9F273912} + {49E408BF-7F56-41B9-BC23-1B36BFACD38A} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {D51D868F-D9FD-45A5-B7C1-50CBFF474959} + {4C476049-FA54-4F33-86B7-650A8CCB4500} diff --git a/general/echo/umdf2/umdf2echo.sln b/general/echo/umdf2/umdf2echo.sln index f7467745..2e4f7d20 100644 --- a/general/echo/umdf2/umdf2echo.sln +++ b/general/echo/umdf2/umdf2echo.sln @@ -3,15 +3,15 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Exe", "Exe", "{5B8D0286-7445-4569-84C3-D5616997F792}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Exe", "Exe", "{E72CA533-5276-42E4-B2B2-B64188523BD4}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "AutoSync", "AutoSync", "{DAEA5A04-51AB-46D0-B95C-25DA1FEB0B70}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "AutoSync", "AutoSync", "{F31A130C-2441-4FE4-95D6-BB7071D6D69A}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Driver", "Driver", "{0E50C291-4877-4FE5-A66C-EDEFF747DA75}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Driver", "Driver", "{86AE3BF7-2160-454A-90FB-454DAF617943}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "echoapp", "exe\echoapp.vcxproj", "{2744B9D7-C918-4979-AF41-3DC6B305BA72}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "echoapp", "exe\echoapp.vcxproj", "{312B4737-78DE-40B0-AEFB-D20A133B2A99}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "echo", "driver\AutoSync\echo.vcxproj", "{95360722-8B66-4DD4-957A-DF8B7CA700FB}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "echo", "driver\AutoSync\echo.vcxproj", "{7B51533F-3B85-437B-843B-FEC865C81376}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -21,29 +21,29 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {2744B9D7-C918-4979-AF41-3DC6B305BA72}.Debug|Win32.ActiveCfg = Debug|Win32 - {2744B9D7-C918-4979-AF41-3DC6B305BA72}.Debug|Win32.Build.0 = Debug|Win32 - {2744B9D7-C918-4979-AF41-3DC6B305BA72}.Release|Win32.ActiveCfg = Release|Win32 - {2744B9D7-C918-4979-AF41-3DC6B305BA72}.Release|Win32.Build.0 = Release|Win32 - {2744B9D7-C918-4979-AF41-3DC6B305BA72}.Debug|x64.ActiveCfg = Debug|x64 - {2744B9D7-C918-4979-AF41-3DC6B305BA72}.Debug|x64.Build.0 = Debug|x64 - {2744B9D7-C918-4979-AF41-3DC6B305BA72}.Release|x64.ActiveCfg = Release|x64 - {2744B9D7-C918-4979-AF41-3DC6B305BA72}.Release|x64.Build.0 = Release|x64 - {95360722-8B66-4DD4-957A-DF8B7CA700FB}.Debug|Win32.ActiveCfg = Debug|Win32 - {95360722-8B66-4DD4-957A-DF8B7CA700FB}.Debug|Win32.Build.0 = Debug|Win32 - {95360722-8B66-4DD4-957A-DF8B7CA700FB}.Release|Win32.ActiveCfg = Release|Win32 - {95360722-8B66-4DD4-957A-DF8B7CA700FB}.Release|Win32.Build.0 = Release|Win32 - {95360722-8B66-4DD4-957A-DF8B7CA700FB}.Debug|x64.ActiveCfg = Debug|x64 - {95360722-8B66-4DD4-957A-DF8B7CA700FB}.Debug|x64.Build.0 = Debug|x64 - {95360722-8B66-4DD4-957A-DF8B7CA700FB}.Release|x64.ActiveCfg = Release|x64 - {95360722-8B66-4DD4-957A-DF8B7CA700FB}.Release|x64.Build.0 = Release|x64 + {312B4737-78DE-40B0-AEFB-D20A133B2A99}.Debug|Win32.ActiveCfg = Debug|Win32 + {312B4737-78DE-40B0-AEFB-D20A133B2A99}.Debug|Win32.Build.0 = Debug|Win32 + {312B4737-78DE-40B0-AEFB-D20A133B2A99}.Release|Win32.ActiveCfg = Release|Win32 + {312B4737-78DE-40B0-AEFB-D20A133B2A99}.Release|Win32.Build.0 = Release|Win32 + {312B4737-78DE-40B0-AEFB-D20A133B2A99}.Debug|x64.ActiveCfg = Debug|x64 + {312B4737-78DE-40B0-AEFB-D20A133B2A99}.Debug|x64.Build.0 = Debug|x64 + {312B4737-78DE-40B0-AEFB-D20A133B2A99}.Release|x64.ActiveCfg = Release|x64 + {312B4737-78DE-40B0-AEFB-D20A133B2A99}.Release|x64.Build.0 = Release|x64 + {7B51533F-3B85-437B-843B-FEC865C81376}.Debug|Win32.ActiveCfg = Debug|Win32 + {7B51533F-3B85-437B-843B-FEC865C81376}.Debug|Win32.Build.0 = Debug|Win32 + {7B51533F-3B85-437B-843B-FEC865C81376}.Release|Win32.ActiveCfg = Release|Win32 + {7B51533F-3B85-437B-843B-FEC865C81376}.Release|Win32.Build.0 = Release|Win32 + {7B51533F-3B85-437B-843B-FEC865C81376}.Debug|x64.ActiveCfg = Debug|x64 + {7B51533F-3B85-437B-843B-FEC865C81376}.Debug|x64.Build.0 = Debug|x64 + {7B51533F-3B85-437B-843B-FEC865C81376}.Release|x64.ActiveCfg = Release|x64 + {7B51533F-3B85-437B-843B-FEC865C81376}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {2744B9D7-C918-4979-AF41-3DC6B305BA72} = {5B8D0286-7445-4569-84C3-D5616997F792} - {95360722-8B66-4DD4-957A-DF8B7CA700FB} = {DAEA5A04-51AB-46D0-B95C-25DA1FEB0B70} - {DAEA5A04-51AB-46D0-B95C-25DA1FEB0B70} = {0E50C291-4877-4FE5-A66C-EDEFF747DA75} + {312B4737-78DE-40B0-AEFB-D20A133B2A99} = {E72CA533-5276-42E4-B2B2-B64188523BD4} + {7B51533F-3B85-437B-843B-FEC865C81376} = {F31A130C-2441-4FE4-95D6-BB7071D6D69A} + {F31A130C-2441-4FE4-95D6-BB7071D6D69A} = {86AE3BF7-2160-454A-90FB-454DAF617943} EndGlobalSection EndGlobal diff --git a/general/echo/umdfSocketEcho/Driver/SocketEcho.vcxproj b/general/echo/umdfSocketEcho/Driver/SocketEcho.vcxproj index d9930170..d46fb4f5 100644 --- a/general/echo/umdfSocketEcho/Driver/SocketEcho.vcxproj +++ b/general/echo/umdfSocketEcho/Driver/SocketEcho.vcxproj @@ -19,13 +19,13 @@ - {ABEFFAA1-36CF-4F78-9A6B-10EAEC11B3E3} + {A6553663-4D94-47EA-A6D7-EF2A81C8FB48} $(MSBuildProjectName) 1 1 Debug Win32 - {DA04694B-6179-416F-83FF-53A671E51B26} + {7817F01F-7524-4D2D-A443-8DDE220A0F02} diff --git a/general/echo/umdfSocketEcho/Driver/SocketEcho.vcxproj.Filters b/general/echo/umdfSocketEcho/Driver/SocketEcho.vcxproj.Filters index 539cbe3b..0cfba6a8 100644 --- a/general/echo/umdfSocketEcho/Driver/SocketEcho.vcxproj.Filters +++ b/general/echo/umdfSocketEcho/Driver/SocketEcho.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {BEDB1CCE-4E58-4AE0-B5B6-C54C6159232D} + {ED119046-004F-4EA8-88D2-ED4E43A285D2} h;hpp;hxx;hm;inl;inc;xsd - {07B8152F-B3FA-4EA1-BBCD-EABDD1B7FCAB} + {81E40625-7071-4159-B4B0-94DC1ECBC3F8} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {61C11142-602D-496E-B9EB-516ED5D7685B} + {BF6D7038-8154-4206-84CC-15F05F014BCC} inf;inv;inx;mof;mc; - {2BB65E51-CB92-4484-AD29-5ED2A6007684} + {8574D23A-10D4-4701-885F-95D7059BCA72} diff --git a/general/echo/umdfSocketEcho/Exe/socketechoserver.vcxproj b/general/echo/umdfSocketEcho/Exe/socketechoserver.vcxproj index ea299161..4017bff4 100644 --- a/general/echo/umdfSocketEcho/Exe/socketechoserver.vcxproj +++ b/general/echo/umdfSocketEcho/Exe/socketechoserver.vcxproj @@ -19,11 +19,11 @@ - {4237BF5F-1426-45DD-96E0-74DEADFA24C6} + {6230EF04-CC9D-47CA-ACB4-90D68F65BC09} $(MSBuildProjectName) Debug Win32 - {13151EE8-4C58-4284-BA01-C4B9431C6B06} + {CCBB9F0B-704E-4DDF-BDB4-ED2B2EB0330A} diff --git a/general/echo/umdfSocketEcho/Exe/socketechoserver.vcxproj.Filters b/general/echo/umdfSocketEcho/Exe/socketechoserver.vcxproj.Filters index 035fba1a..b75a0709 100644 --- a/general/echo/umdfSocketEcho/Exe/socketechoserver.vcxproj.Filters +++ b/general/echo/umdfSocketEcho/Exe/socketechoserver.vcxproj.Filters @@ -3,15 +3,15 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {1BEC8228-FE60-4512-B036-885F56208A4B} + {B299C82C-4620-4309-92E4-590D9694D4C7} h;hpp;hxx;hm;inl;inc;xsd - {E4060FEA-373E-4AE6-94B7-FF878D406EAE} + {E30D2942-24C0-4E0F-9BE4-069374516060} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {181042B8-D282-46BA-B9D7-BDEE33402D00} + {7F4BBF43-DCE0-4376-A01F-F47446EFE8B0} diff --git a/general/echo/umdfSocketEcho/umdfsocketecho.sln b/general/echo/umdfSocketEcho/umdfsocketecho.sln index 9cd8f76d..ff9d14cf 100644 --- a/general/echo/umdfSocketEcho/umdfsocketecho.sln +++ b/general/echo/umdfSocketEcho/umdfsocketecho.sln @@ -3,13 +3,13 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Driver", "Driver", "{C4B24CED-B58F-47D1-8FC0-778610EF84CF}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Driver", "Driver", "{2CC915B5-4289-4A00-9330-BC299F498C6B}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Exe", "Exe", "{AFCDA28A-1D07-410D-BA77-47E637336CA6}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Exe", "Exe", "{326CD5AE-45A8-4C81-BA8C-42FF5CAE00D8}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SocketEcho", "Driver\SocketEcho.vcxproj", "{ABEFFAA1-36CF-4F78-9A6B-10EAEC11B3E3}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SocketEcho", "Driver\SocketEcho.vcxproj", "{A6553663-4D94-47EA-A6D7-EF2A81C8FB48}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "socketechoserver", "Exe\socketechoserver.vcxproj", "{4237BF5F-1426-45DD-96E0-74DEADFA24C6}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "socketechoserver", "Exe\socketechoserver.vcxproj", "{6230EF04-CC9D-47CA-ACB4-90D68F65BC09}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -19,28 +19,28 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {ABEFFAA1-36CF-4F78-9A6B-10EAEC11B3E3}.Debug|Win32.ActiveCfg = Debug|Win32 - {ABEFFAA1-36CF-4F78-9A6B-10EAEC11B3E3}.Debug|Win32.Build.0 = Debug|Win32 - {ABEFFAA1-36CF-4F78-9A6B-10EAEC11B3E3}.Release|Win32.ActiveCfg = Release|Win32 - {ABEFFAA1-36CF-4F78-9A6B-10EAEC11B3E3}.Release|Win32.Build.0 = Release|Win32 - {ABEFFAA1-36CF-4F78-9A6B-10EAEC11B3E3}.Debug|x64.ActiveCfg = Debug|x64 - {ABEFFAA1-36CF-4F78-9A6B-10EAEC11B3E3}.Debug|x64.Build.0 = Debug|x64 - {ABEFFAA1-36CF-4F78-9A6B-10EAEC11B3E3}.Release|x64.ActiveCfg = Release|x64 - {ABEFFAA1-36CF-4F78-9A6B-10EAEC11B3E3}.Release|x64.Build.0 = Release|x64 - {4237BF5F-1426-45DD-96E0-74DEADFA24C6}.Debug|Win32.ActiveCfg = Debug|Win32 - {4237BF5F-1426-45DD-96E0-74DEADFA24C6}.Debug|Win32.Build.0 = Debug|Win32 - {4237BF5F-1426-45DD-96E0-74DEADFA24C6}.Release|Win32.ActiveCfg = Release|Win32 - {4237BF5F-1426-45DD-96E0-74DEADFA24C6}.Release|Win32.Build.0 = Release|Win32 - {4237BF5F-1426-45DD-96E0-74DEADFA24C6}.Debug|x64.ActiveCfg = Debug|x64 - {4237BF5F-1426-45DD-96E0-74DEADFA24C6}.Debug|x64.Build.0 = Debug|x64 - {4237BF5F-1426-45DD-96E0-74DEADFA24C6}.Release|x64.ActiveCfg = Release|x64 - {4237BF5F-1426-45DD-96E0-74DEADFA24C6}.Release|x64.Build.0 = Release|x64 + {A6553663-4D94-47EA-A6D7-EF2A81C8FB48}.Debug|Win32.ActiveCfg = Debug|Win32 + {A6553663-4D94-47EA-A6D7-EF2A81C8FB48}.Debug|Win32.Build.0 = Debug|Win32 + {A6553663-4D94-47EA-A6D7-EF2A81C8FB48}.Release|Win32.ActiveCfg = Release|Win32 + {A6553663-4D94-47EA-A6D7-EF2A81C8FB48}.Release|Win32.Build.0 = Release|Win32 + {A6553663-4D94-47EA-A6D7-EF2A81C8FB48}.Debug|x64.ActiveCfg = Debug|x64 + {A6553663-4D94-47EA-A6D7-EF2A81C8FB48}.Debug|x64.Build.0 = Debug|x64 + {A6553663-4D94-47EA-A6D7-EF2A81C8FB48}.Release|x64.ActiveCfg = Release|x64 + {A6553663-4D94-47EA-A6D7-EF2A81C8FB48}.Release|x64.Build.0 = Release|x64 + {6230EF04-CC9D-47CA-ACB4-90D68F65BC09}.Debug|Win32.ActiveCfg = Debug|Win32 + {6230EF04-CC9D-47CA-ACB4-90D68F65BC09}.Debug|Win32.Build.0 = Debug|Win32 + {6230EF04-CC9D-47CA-ACB4-90D68F65BC09}.Release|Win32.ActiveCfg = Release|Win32 + {6230EF04-CC9D-47CA-ACB4-90D68F65BC09}.Release|Win32.Build.0 = Release|Win32 + {6230EF04-CC9D-47CA-ACB4-90D68F65BC09}.Debug|x64.ActiveCfg = Debug|x64 + {6230EF04-CC9D-47CA-ACB4-90D68F65BC09}.Debug|x64.Build.0 = Debug|x64 + {6230EF04-CC9D-47CA-ACB4-90D68F65BC09}.Release|x64.ActiveCfg = Release|x64 + {6230EF04-CC9D-47CA-ACB4-90D68F65BC09}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {ABEFFAA1-36CF-4F78-9A6B-10EAEC11B3E3} = {C4B24CED-B58F-47D1-8FC0-778610EF84CF} - {4237BF5F-1426-45DD-96E0-74DEADFA24C6} = {AFCDA28A-1D07-410D-BA77-47E637336CA6} + {A6553663-4D94-47EA-A6D7-EF2A81C8FB48} = {2CC915B5-4289-4A00-9330-BC299F498C6B} + {6230EF04-CC9D-47CA-ACB4-90D68F65BC09} = {326CD5AE-45A8-4C81-BA8C-42FF5CAE00D8} EndGlobalSection EndGlobal diff --git a/general/event/event.htm b/general/event/event.htm new file mode 100644 index 00000000..32485d9a --- /dev/null +++ b/general/event/event.htm @@ -0,0 +1,229 @@ + + + + + +EVENT + + + + + + + +
+ +

EVENT

+ +

SUMMARY

+ +

This +sample demonstrates two different ways a Windows NT kernel-mode driver can +notify an application about a hardware event. One is event based method and the +other is an IRP based method. Since the sample driver is not talking to any +real hardware, it uses a timer DPC to simulate hardware events. The test +application informs the driver whether it wants to be notified by signaling an +event or by completing the pending IRP and also gives a relative time at which +the DPC timer has to fire.

+ +

Event +based approach: +The application creates an event using CreateEvent(). It then passes the event +handle to the driver in a private ioctl IOCTL_REGISTER_EVENT. Since the driver +is a monolithic toplevel driver, its IRP dispatch routines run in the +application process context and as a result the event handle is still valid in +the driver. The driver dereferences the user-mode handle into system space +& saves the event object pointer for later use and queues a custom timer +DPC. When the DPC fires, the driver signals the event via KeSetEvent() at +DISPATCH_LEVEL and deletes the references to the event object. You can't use +this approach if your driver is not a monolithic - toplevel driver, because you +can't guarantee the process context in a multi-level driver stack if you are +not at the top.

+ +

Pending +IRP based approach: +The application make a synchronous ioctl(IOCTL_REGISTER_EVENT) request. The +driver marks the device I/O control IRP pending and queues a timer DPC and +returns STATUS_PENDING. When the timer fires to indicate a hardware event, the +driver completes the pending IRP to notify the application about the hardware +event.

+ +

There are +two advantages of this method over the event based approach. One is that you +can send a message to the application along with your notification and other +one is that the driver routines don't have to be in the context of the process +that made the request. The application can do a synchronous or asynchronous +(overlapped) ioctl to the driver.

+ +

This +sample driver is not a PnP driver. This is a minimal driver meant to +demonstrate an OS feature. Neither it nor its sample programs are intended for +use in a production environment. Rather, they are intended for educational +purposes and as a skeleton driver.

+ +

This driver +will work on Windows NT 4.0, Windows 2000 and later operating systems.

+ +

BUILDING THE SAMPLE

+ +

Click the +Free Build Environment or Checked Build Environment icon under Development Kits +program group to set basic environment variables.

+ +

Change to +the directory containing the device source code, such as CD Src\General\Event.

+ +

Run build +-ceZ, or use the macro BLD. This command invokes the Microsoft make +routines to build the components. If the build succeeds, you will find the +driver, event.sys, and the test application, event.exe, in the binary output directory specified for the build environment. You can get the output path from the buildxxx.log file. If the build +fails you can find errors and warnings in the buildxxx.err and buildxxx.err +respectively, where xxx is eithr chk or fre depending on the build environment. +

+ +

TESTING

+ +

To test +this driver, copy the test app, event.exe, and the driver to the same +directory, and run the application. The application will automatically load the +driver if it's not already loaded and interact with the driver. When you exit +the app, the driver will be stopped, unloaded and removed.

+ +

c:\>Event.exe +DELAY <0/1>

+ +

where +DELAY equals the time to delay the Event signal in seconds.

+ +

Specify O +for IRP based notification and 1 for event based notification.

+ +

CODE TOUR

+ +

File Manifest

+ +
File           Description
 
 
Event.htm      Documentation for the sample (this file)
 
Exe\Sources    Generic file for building the test app
Exe\Eventtest.c Simple console test application
Exe\install.c  Code for registering and starting the driver service
 
Wdm\Sources    Generic file for building the driver
Wdm\Event.h    Header file private to the driver
Wdm\public.h   Common header file between app and driver
Wdm\Event.c    Main driver file
Wdm\Event.rc   Driver resource file
 
+ +

Top +of page +

+ +
 
+ + + + + +
+ +
 
 
+ +

© 1998 +Microsoft Corporation +

+ +
+ + + + diff --git a/general/event/eventsample.sln b/general/event/eventsample.sln index 1b533282..cc831cd5 100644 --- a/general/event/eventsample.sln +++ b/general/event/eventsample.sln @@ -3,13 +3,13 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Exe", "Exe", "{AD60DF57-AE60-4857-9CAE-41B96E1E0789}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Exe", "Exe", "{69B6F5B9-DDF7-400F-BE17-476DE539E4DA}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Wdm", "Wdm", "{1403EA42-4F69-4B63-B15F-3447F44A500A}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Wdm", "Wdm", "{E4DA1FA9-CAA1-4781-B138-3EA4166B922B}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "event", "exe\event.vcxproj", "{19EFCD7C-6C7A-427A-84D2-A62D9073146A}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "event", "exe\event.vcxproj", "{D5CE2F64-0EB5-420B-A867-31106AFA3731}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "event", "wdm\event.vcxproj", "{99CD8B5D-2961-44A5-ACB4-CC1CCCEE096B}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "event", "wdm\event.vcxproj", "{FBF7BF86-1A35-46BB-8BC6-67B2C1E431A6}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -19,28 +19,28 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {19EFCD7C-6C7A-427A-84D2-A62D9073146A}.Debug|Win32.ActiveCfg = Debug|Win32 - {19EFCD7C-6C7A-427A-84D2-A62D9073146A}.Debug|Win32.Build.0 = Debug|Win32 - {19EFCD7C-6C7A-427A-84D2-A62D9073146A}.Release|Win32.ActiveCfg = Release|Win32 - {19EFCD7C-6C7A-427A-84D2-A62D9073146A}.Release|Win32.Build.0 = Release|Win32 - {19EFCD7C-6C7A-427A-84D2-A62D9073146A}.Debug|x64.ActiveCfg = Debug|x64 - {19EFCD7C-6C7A-427A-84D2-A62D9073146A}.Debug|x64.Build.0 = Debug|x64 - {19EFCD7C-6C7A-427A-84D2-A62D9073146A}.Release|x64.ActiveCfg = Release|x64 - {19EFCD7C-6C7A-427A-84D2-A62D9073146A}.Release|x64.Build.0 = Release|x64 - {99CD8B5D-2961-44A5-ACB4-CC1CCCEE096B}.Debug|Win32.ActiveCfg = Debug|Win32 - {99CD8B5D-2961-44A5-ACB4-CC1CCCEE096B}.Debug|Win32.Build.0 = Debug|Win32 - {99CD8B5D-2961-44A5-ACB4-CC1CCCEE096B}.Release|Win32.ActiveCfg = Release|Win32 - {99CD8B5D-2961-44A5-ACB4-CC1CCCEE096B}.Release|Win32.Build.0 = Release|Win32 - {99CD8B5D-2961-44A5-ACB4-CC1CCCEE096B}.Debug|x64.ActiveCfg = Debug|x64 - {99CD8B5D-2961-44A5-ACB4-CC1CCCEE096B}.Debug|x64.Build.0 = Debug|x64 - {99CD8B5D-2961-44A5-ACB4-CC1CCCEE096B}.Release|x64.ActiveCfg = Release|x64 - {99CD8B5D-2961-44A5-ACB4-CC1CCCEE096B}.Release|x64.Build.0 = Release|x64 + {D5CE2F64-0EB5-420B-A867-31106AFA3731}.Debug|Win32.ActiveCfg = Debug|Win32 + {D5CE2F64-0EB5-420B-A867-31106AFA3731}.Debug|Win32.Build.0 = Debug|Win32 + {D5CE2F64-0EB5-420B-A867-31106AFA3731}.Release|Win32.ActiveCfg = Release|Win32 + {D5CE2F64-0EB5-420B-A867-31106AFA3731}.Release|Win32.Build.0 = Release|Win32 + {D5CE2F64-0EB5-420B-A867-31106AFA3731}.Debug|x64.ActiveCfg = Debug|x64 + {D5CE2F64-0EB5-420B-A867-31106AFA3731}.Debug|x64.Build.0 = Debug|x64 + {D5CE2F64-0EB5-420B-A867-31106AFA3731}.Release|x64.ActiveCfg = Release|x64 + {D5CE2F64-0EB5-420B-A867-31106AFA3731}.Release|x64.Build.0 = Release|x64 + {FBF7BF86-1A35-46BB-8BC6-67B2C1E431A6}.Debug|Win32.ActiveCfg = Debug|Win32 + {FBF7BF86-1A35-46BB-8BC6-67B2C1E431A6}.Debug|Win32.Build.0 = Debug|Win32 + {FBF7BF86-1A35-46BB-8BC6-67B2C1E431A6}.Release|Win32.ActiveCfg = Release|Win32 + {FBF7BF86-1A35-46BB-8BC6-67B2C1E431A6}.Release|Win32.Build.0 = Release|Win32 + {FBF7BF86-1A35-46BB-8BC6-67B2C1E431A6}.Debug|x64.ActiveCfg = Debug|x64 + {FBF7BF86-1A35-46BB-8BC6-67B2C1E431A6}.Debug|x64.Build.0 = Debug|x64 + {FBF7BF86-1A35-46BB-8BC6-67B2C1E431A6}.Release|x64.ActiveCfg = Release|x64 + {FBF7BF86-1A35-46BB-8BC6-67B2C1E431A6}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {19EFCD7C-6C7A-427A-84D2-A62D9073146A} = {AD60DF57-AE60-4857-9CAE-41B96E1E0789} - {99CD8B5D-2961-44A5-ACB4-CC1CCCEE096B} = {1403EA42-4F69-4B63-B15F-3447F44A500A} + {D5CE2F64-0EB5-420B-A867-31106AFA3731} = {69B6F5B9-DDF7-400F-BE17-476DE539E4DA} + {FBF7BF86-1A35-46BB-8BC6-67B2C1E431A6} = {E4DA1FA9-CAA1-4781-B138-3EA4166B922B} EndGlobalSection EndGlobal diff --git a/general/event/exe/event.vcxproj b/general/event/exe/event.vcxproj index 1ec7b921..e670d808 100644 --- a/general/event/exe/event.vcxproj +++ b/general/event/exe/event.vcxproj @@ -19,11 +19,11 @@
- {19EFCD7C-6C7A-427A-84D2-A62D9073146A} + {D5CE2F64-0EB5-420B-A867-31106AFA3731} $(MSBuildProjectName) Debug Win32 - {B020889A-CDA3-4F73-AA14-45C800A49925} + {1DA134F1-988F-4D83-8663-343393FCF8DD} diff --git a/general/event/exe/event.vcxproj.Filters b/general/event/exe/event.vcxproj.Filters index 7cdaec8b..1536b3e3 100644 --- a/general/event/exe/event.vcxproj.Filters +++ b/general/event/exe/event.vcxproj.Filters @@ -3,15 +3,15 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {F62E2250-4375-47E7-8996-8B59DCFCFCF8} + {3F33EAAB-7921-43F5-9263-4D4F98669ACE} h;hpp;hxx;hm;inl;inc;xsd - {B34D45F9-19AD-4EA0-A3AA-ABDD239D4829} + {E071C862-9C8B-4C31-8B57-CDB34DF842FD} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {F9F32DF2-C4E0-45E6-9964-FE9DAA47CC64} + {3C9792F4-01B3-4045-A0CB-4E09CE0A28AD} diff --git a/general/event/wdm/event.vcxproj b/general/event/wdm/event.vcxproj index 3dd391d5..fefc851e 100644 --- a/general/event/wdm/event.vcxproj +++ b/general/event/wdm/event.vcxproj @@ -19,11 +19,11 @@ - {99CD8B5D-2961-44A5-ACB4-CC1CCCEE096B} + {FBF7BF86-1A35-46BB-8BC6-67B2C1E431A6} $(MSBuildProjectName) Debug Win32 - {463697D8-488D-488E-A7DF-ECB602F46DD2} + {060F5D78-0639-46D2-82D0-178EDF598138} diff --git a/general/event/wdm/event.vcxproj.Filters b/general/event/wdm/event.vcxproj.Filters index c876bb5b..f3fdde44 100644 --- a/general/event/wdm/event.vcxproj.Filters +++ b/general/event/wdm/event.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {68A8B3BF-BA74-401E-A54C-A5D84A227969} + {64E2D106-4544-49A8-91BA-6151D707621E} h;hpp;hxx;hm;inl;inc;xsd - {F899D68E-E4E7-4168-9636-254BF3CDC360} + {E819D815-E057-47BD-BBEB-7A4BD55F9D61} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {0DFB698C-60E9-4C46-A9DD-76D3E4A63C45} + {C45F0550-45D7-404C-98DB-F9916B5185A5} inf;inv;inx;mof;mc; - {705F4A1B-5DF2-4182-BCEA-69C62EC7ED04} + {50C64871-D47E-47D2-99E0-6AF3BFC203C5} diff --git a/general/filehistory/exe/fhsetup.vcxproj b/general/filehistory/exe/fhsetup.vcxproj index 29151c50..ba08d0f6 100644 --- a/general/filehistory/exe/fhsetup.vcxproj +++ b/general/filehistory/exe/fhsetup.vcxproj @@ -19,11 +19,11 @@ - {5ED52C3F-4CA6-4E04-82DD-404CA008EE8B} + {4F3542D9-0265-46EF-AC1C-E9077754389D} $(MSBuildProjectName) Debug Win32 - {19CB999A-197D-4EAB-85F1-C4230C32B26E} + {7C399721-D8AC-42CB-AFD9-8A6F4507D84D} diff --git a/general/filehistory/exe/fhsetup.vcxproj.Filters b/general/filehistory/exe/fhsetup.vcxproj.Filters index 8b773bab..828bbfdd 100644 --- a/general/filehistory/exe/fhsetup.vcxproj.Filters +++ b/general/filehistory/exe/fhsetup.vcxproj.Filters @@ -3,15 +3,15 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {86ABC263-8E1E-48CB-8D3E-368CE3C22885} + {4A29C27D-C667-4A42-8519-09FCF0137B81} h;hpp;hxx;hm;inl;inc;xsd - {E466B712-D4BD-4268-8FDB-FB7BDDAC7FB4} + {36854BB1-3791-4B72-BAFE-F63E471284B3} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {C3E2505A-EA9E-4B2A-B2B1-1AF968556961} + {08ADDCDC-38B0-425F-8E1A-15E9B3A9B7D5} diff --git a/general/filehistory/filehistory.sln b/general/filehistory/filehistory.sln index 055780ce..1df30962 100644 --- a/general/filehistory/filehistory.sln +++ b/general/filehistory/filehistory.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fhsetup", "exe\fhsetup.vcxproj", "{5ED52C3F-4CA6-4E04-82DD-404CA008EE8B}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fhsetup", "exe\fhsetup.vcxproj", "{4F3542D9-0265-46EF-AC1C-E9077754389D}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +13,14 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {5ED52C3F-4CA6-4E04-82DD-404CA008EE8B}.Debug|Win32.ActiveCfg = Debug|Win32 - {5ED52C3F-4CA6-4E04-82DD-404CA008EE8B}.Debug|Win32.Build.0 = Debug|Win32 - {5ED52C3F-4CA6-4E04-82DD-404CA008EE8B}.Release|Win32.ActiveCfg = Release|Win32 - {5ED52C3F-4CA6-4E04-82DD-404CA008EE8B}.Release|Win32.Build.0 = Release|Win32 - {5ED52C3F-4CA6-4E04-82DD-404CA008EE8B}.Debug|x64.ActiveCfg = Debug|x64 - {5ED52C3F-4CA6-4E04-82DD-404CA008EE8B}.Debug|x64.Build.0 = Debug|x64 - {5ED52C3F-4CA6-4E04-82DD-404CA008EE8B}.Release|x64.ActiveCfg = Release|x64 - {5ED52C3F-4CA6-4E04-82DD-404CA008EE8B}.Release|x64.Build.0 = Release|x64 + {4F3542D9-0265-46EF-AC1C-E9077754389D}.Debug|Win32.ActiveCfg = Debug|Win32 + {4F3542D9-0265-46EF-AC1C-E9077754389D}.Debug|Win32.Build.0 = Debug|Win32 + {4F3542D9-0265-46EF-AC1C-E9077754389D}.Release|Win32.ActiveCfg = Release|Win32 + {4F3542D9-0265-46EF-AC1C-E9077754389D}.Release|Win32.Build.0 = Release|Win32 + {4F3542D9-0265-46EF-AC1C-E9077754389D}.Debug|x64.ActiveCfg = Debug|x64 + {4F3542D9-0265-46EF-AC1C-E9077754389D}.Debug|x64.Build.0 = Debug|x64 + {4F3542D9-0265-46EF-AC1C-E9077754389D}.Release|x64.ActiveCfg = Release|x64 + {4F3542D9-0265-46EF-AC1C-E9077754389D}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/general/installwdf/InstallWdf.vcxproj b/general/installwdf/InstallWdf.vcxproj index 566e44b1..4629b895 100644 --- a/general/installwdf/InstallWdf.vcxproj +++ b/general/installwdf/InstallWdf.vcxproj @@ -19,11 +19,11 @@ - {242C8F74-1471-4876-ABE9-F9B3798F7537} + {33B59758-52DF-4853-B3EF-10AB314C0B4F} $(MSBuildProjectName) Debug Win32 - {EC6592EB-25EF-40EB-8E93-87FABB3C6085} + {E35D4009-C471-4212-97F4-BB773763DCBC} diff --git a/general/installwdf/InstallWdf.vcxproj.Filters b/general/installwdf/InstallWdf.vcxproj.Filters index aded6d8a..876d73d9 100644 --- a/general/installwdf/InstallWdf.vcxproj.Filters +++ b/general/installwdf/InstallWdf.vcxproj.Filters @@ -3,15 +3,15 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {5F54DABF-B262-4C6D-922E-4458AB12ED8C} + {B14F5D40-7162-4516-827A-BDEDFCC8051D} h;hpp;hxx;hm;inl;inc;xsd - {7D22CB0D-9813-4E12-B539-5F8A9BCC71F1} + {D3DD2DE2-BCB4-4D09-8C7E-0EAE804C69ED} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {13558A71-E018-47D4-B9A5-45A8C27B32B1} + {C6E040CC-8B14-482F-8D7E-8DC793538B92} diff --git a/general/installwdf/installwdf.sln b/general/installwdf/installwdf.sln index e520c1dc..9c1dc0dd 100644 --- a/general/installwdf/installwdf.sln +++ b/general/installwdf/installwdf.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "InstallWdf", "InstallWdf.vcxproj", "{242C8F74-1471-4876-ABE9-F9B3798F7537}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "InstallWdf", "InstallWdf.vcxproj", "{33B59758-52DF-4853-B3EF-10AB314C0B4F}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +13,14 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {242C8F74-1471-4876-ABE9-F9B3798F7537}.Debug|Win32.ActiveCfg = Debug|Win32 - {242C8F74-1471-4876-ABE9-F9B3798F7537}.Debug|Win32.Build.0 = Debug|Win32 - {242C8F74-1471-4876-ABE9-F9B3798F7537}.Release|Win32.ActiveCfg = Release|Win32 - {242C8F74-1471-4876-ABE9-F9B3798F7537}.Release|Win32.Build.0 = Release|Win32 - {242C8F74-1471-4876-ABE9-F9B3798F7537}.Debug|x64.ActiveCfg = Debug|x64 - {242C8F74-1471-4876-ABE9-F9B3798F7537}.Debug|x64.Build.0 = Debug|x64 - {242C8F74-1471-4876-ABE9-F9B3798F7537}.Release|x64.ActiveCfg = Release|x64 - {242C8F74-1471-4876-ABE9-F9B3798F7537}.Release|x64.Build.0 = Release|x64 + {33B59758-52DF-4853-B3EF-10AB314C0B4F}.Debug|Win32.ActiveCfg = Debug|Win32 + {33B59758-52DF-4853-B3EF-10AB314C0B4F}.Debug|Win32.Build.0 = Debug|Win32 + {33B59758-52DF-4853-B3EF-10AB314C0B4F}.Release|Win32.ActiveCfg = Release|Win32 + {33B59758-52DF-4853-B3EF-10AB314C0B4F}.Release|Win32.Build.0 = Release|Win32 + {33B59758-52DF-4853-B3EF-10AB314C0B4F}.Debug|x64.ActiveCfg = Debug|x64 + {33B59758-52DF-4853-B3EF-10AB314C0B4F}.Debug|x64.Build.0 = Debug|x64 + {33B59758-52DF-4853-B3EF-10AB314C0B4F}.Release|x64.ActiveCfg = Release|x64 + {33B59758-52DF-4853-B3EF-10AB314C0B4F}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/general/ioctl/wdm/exe/ioctlapp.vcxproj b/general/ioctl/wdm/exe/ioctlapp.vcxproj index 976df289..a4fe1dc9 100644 --- a/general/ioctl/wdm/exe/ioctlapp.vcxproj +++ b/general/ioctl/wdm/exe/ioctlapp.vcxproj @@ -19,11 +19,11 @@ - {76D71F31-1E96-453B-B624-603110936517} + {0F1154FD-BDCC-4DCD-A452-C04E4AD94CEA} $(MSBuildProjectName) Debug Win32 - {F11B90FF-7C0F-4187-A69C-B3D2C6FA36BD} + {A8666C84-4408-4F56-834E-989B3B03ED5A} diff --git a/general/ioctl/wdm/exe/ioctlapp.vcxproj.Filters b/general/ioctl/wdm/exe/ioctlapp.vcxproj.Filters index 6698bc65..af420f3f 100644 --- a/general/ioctl/wdm/exe/ioctlapp.vcxproj.Filters +++ b/general/ioctl/wdm/exe/ioctlapp.vcxproj.Filters @@ -3,15 +3,15 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {A6129EF0-0D42-48B8-B0C4-C484D8CB1BEC} + {96F80F7E-43A8-4FF2-833B-0F4E0B486149} h;hpp;hxx;hm;inl;inc;xsd - {7C1B93C7-3641-4D37-AF76-8B4E72FB0E36} + {49685EE8-840B-4F1C-92CA-EF94838E1143} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {4E2B024A-1EF5-41B1-A019-C74272815D2A} + {F87C331A-2013-470A-A6AC-100426820F7F} diff --git a/general/ioctl/wdm/ioctl.htm b/general/ioctl/wdm/ioctl.htm new file mode 100644 index 00000000..bfce1a9e --- /dev/null +++ b/general/ioctl/wdm/ioctl.htm @@ -0,0 +1,742 @@ + + + + + + + + + + + + + + + + + + + + +
+ +

IOCTL +

+ +

SUMMARY

+ +

This +sample demonstrates the usage of four different types of IOCTLs +(METHOD_IN_DIRECT, METHOD_OUT_DIRECT, METHOD_NEITHER, and METHOD_BUFFERED) +supported by Windows, and how the user input & output buffer specified in +the DeviceControl function is handled by the I/O subsystem and the driver in +each case.

+ +

The sample +consists of a legacy device driver and a Win32 console mode test application. +The test application opens a handle to the device exposed by the driver and makes +all four different DeviceIoControl calls one after another. To understand how +the IRP fields are set the I/O manager, you should run the checked build version +of the driver and see the debug output.

+ +

This +driver will work on Windows 2000 and later operating systems.

+ +

This +sample driver is not a PnP driver. This is a minimal driver meant to +demonstrate an OS feature. Neither it nor its sample programs are intended for +use in a production environment. Rather, they are intended for educational +purposes and as a skeleton driver.

+ +

BUILDING THE SAMPLE

+ +

Click the +Free Build Environment or Checked Build Environment icon under Development Kits +program group to set basic environment variables.

+ +

Change to +the directory containing the sample source code, such as CD Src\General\ioctl\wdm. +

+ +

Run build +-ceZ, or use the macro BLD. This command invokes the Microsoft make routines to +build the components. If the build succeeds, you will find the driver, +sioctl.sys, and the test application, ioctlapp.exe, in the binary output +directory specified for the build environment. You can get the output path from +the buildxxx.log file (for example, buildfre_win7_x86.log). If the build fails +you can find errors and warnings in the buildxxx.err and buildxxx.wrn respectively, +where xxx is either chk or fre depending on the build environment.

+ +

TESTING

+ +

To test +this driver, copy the test app, ioctlapp.exe, and the driver to the same +directory, and run the application. The application will automatically load the +driver if it's not already loaded and interact with the driver. When you exit +the app, the driver will be stopped, unloaded and removed.

+ +

CODE TOUR

+ +

File Manifest

+ +
File           Description
 
Ioctl.htm      Sample Tour documentation for this sample (this file).
Sources        Generic file that lists source files and all the build options.
Sioctl.c       Source file of the sample driver.
Sioctl.h       Header file for defining ioctls; included by driver and the test application.
Testapp.c      Source file of the test application. Contains routines to send IOCTLs to the driver.
Install.c      Source file of the test application. Contains routines to load and unload the driver.
Sioctl.rc      Resource file that specifies information such as file type, version, etc.
Makefile       This file merely indirects to the real makefile that is shared by all the driver components of the Windows NT DDK.
 
+ +

Top +of page +

+ + + + + +
+ +

© 1998 Microsoft +Corporation +

+ +
+ + + + diff --git a/general/ioctl/wdm/ioctl.sln b/general/ioctl/wdm/ioctl.sln index ba787f9d..ff5233dc 100644 --- a/general/ioctl/wdm/ioctl.sln +++ b/general/ioctl/wdm/ioctl.sln @@ -3,13 +3,13 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Exe", "Exe", "{91C983A9-7E97-4964-A924-F019A135772F}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Exe", "Exe", "{784A1AB1-AE41-4D83-99A8-82848B129B48}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Sys", "Sys", "{9D017694-F9BE-450B-BF96-67F46D45BE81}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Sys", "Sys", "{8D7246D9-D426-4517-9631-BCDC343A98A5}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ioctlapp", "exe\ioctlapp.vcxproj", "{76D71F31-1E96-453B-B624-603110936517}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ioctlapp", "exe\ioctlapp.vcxproj", "{0F1154FD-BDCC-4DCD-A452-C04E4AD94CEA}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sioctl", "sys\sioctl.vcxproj", "{EFC79CFC-9D17-4830-90C1-1825B6CFE1AD}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sioctl", "sys\sioctl.vcxproj", "{7B626BD2-8EA8-42C1-BCC4-BBBBF52E5E68}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -19,28 +19,28 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {76D71F31-1E96-453B-B624-603110936517}.Debug|Win32.ActiveCfg = Debug|Win32 - {76D71F31-1E96-453B-B624-603110936517}.Debug|Win32.Build.0 = Debug|Win32 - {76D71F31-1E96-453B-B624-603110936517}.Release|Win32.ActiveCfg = Release|Win32 - {76D71F31-1E96-453B-B624-603110936517}.Release|Win32.Build.0 = Release|Win32 - {76D71F31-1E96-453B-B624-603110936517}.Debug|x64.ActiveCfg = Debug|x64 - {76D71F31-1E96-453B-B624-603110936517}.Debug|x64.Build.0 = Debug|x64 - {76D71F31-1E96-453B-B624-603110936517}.Release|x64.ActiveCfg = Release|x64 - {76D71F31-1E96-453B-B624-603110936517}.Release|x64.Build.0 = Release|x64 - {EFC79CFC-9D17-4830-90C1-1825B6CFE1AD}.Debug|Win32.ActiveCfg = Debug|Win32 - {EFC79CFC-9D17-4830-90C1-1825B6CFE1AD}.Debug|Win32.Build.0 = Debug|Win32 - {EFC79CFC-9D17-4830-90C1-1825B6CFE1AD}.Release|Win32.ActiveCfg = Release|Win32 - {EFC79CFC-9D17-4830-90C1-1825B6CFE1AD}.Release|Win32.Build.0 = Release|Win32 - {EFC79CFC-9D17-4830-90C1-1825B6CFE1AD}.Debug|x64.ActiveCfg = Debug|x64 - {EFC79CFC-9D17-4830-90C1-1825B6CFE1AD}.Debug|x64.Build.0 = Debug|x64 - {EFC79CFC-9D17-4830-90C1-1825B6CFE1AD}.Release|x64.ActiveCfg = Release|x64 - {EFC79CFC-9D17-4830-90C1-1825B6CFE1AD}.Release|x64.Build.0 = Release|x64 + {0F1154FD-BDCC-4DCD-A452-C04E4AD94CEA}.Debug|Win32.ActiveCfg = Debug|Win32 + {0F1154FD-BDCC-4DCD-A452-C04E4AD94CEA}.Debug|Win32.Build.0 = Debug|Win32 + {0F1154FD-BDCC-4DCD-A452-C04E4AD94CEA}.Release|Win32.ActiveCfg = Release|Win32 + {0F1154FD-BDCC-4DCD-A452-C04E4AD94CEA}.Release|Win32.Build.0 = Release|Win32 + {0F1154FD-BDCC-4DCD-A452-C04E4AD94CEA}.Debug|x64.ActiveCfg = Debug|x64 + {0F1154FD-BDCC-4DCD-A452-C04E4AD94CEA}.Debug|x64.Build.0 = Debug|x64 + {0F1154FD-BDCC-4DCD-A452-C04E4AD94CEA}.Release|x64.ActiveCfg = Release|x64 + {0F1154FD-BDCC-4DCD-A452-C04E4AD94CEA}.Release|x64.Build.0 = Release|x64 + {7B626BD2-8EA8-42C1-BCC4-BBBBF52E5E68}.Debug|Win32.ActiveCfg = Debug|Win32 + {7B626BD2-8EA8-42C1-BCC4-BBBBF52E5E68}.Debug|Win32.Build.0 = Debug|Win32 + {7B626BD2-8EA8-42C1-BCC4-BBBBF52E5E68}.Release|Win32.ActiveCfg = Release|Win32 + {7B626BD2-8EA8-42C1-BCC4-BBBBF52E5E68}.Release|Win32.Build.0 = Release|Win32 + {7B626BD2-8EA8-42C1-BCC4-BBBBF52E5E68}.Debug|x64.ActiveCfg = Debug|x64 + {7B626BD2-8EA8-42C1-BCC4-BBBBF52E5E68}.Debug|x64.Build.0 = Debug|x64 + {7B626BD2-8EA8-42C1-BCC4-BBBBF52E5E68}.Release|x64.ActiveCfg = Release|x64 + {7B626BD2-8EA8-42C1-BCC4-BBBBF52E5E68}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {76D71F31-1E96-453B-B624-603110936517} = {91C983A9-7E97-4964-A924-F019A135772F} - {EFC79CFC-9D17-4830-90C1-1825B6CFE1AD} = {9D017694-F9BE-450B-BF96-67F46D45BE81} + {0F1154FD-BDCC-4DCD-A452-C04E4AD94CEA} = {784A1AB1-AE41-4D83-99A8-82848B129B48} + {7B626BD2-8EA8-42C1-BCC4-BBBBF52E5E68} = {8D7246D9-D426-4517-9631-BCDC343A98A5} EndGlobalSection EndGlobal diff --git a/general/ioctl/wdm/sys/sioctl.vcxproj b/general/ioctl/wdm/sys/sioctl.vcxproj index 7340c780..7941eb1d 100644 --- a/general/ioctl/wdm/sys/sioctl.vcxproj +++ b/general/ioctl/wdm/sys/sioctl.vcxproj @@ -19,11 +19,11 @@
- {EFC79CFC-9D17-4830-90C1-1825B6CFE1AD} + {7B626BD2-8EA8-42C1-BCC4-BBBBF52E5E68} $(MSBuildProjectName) Debug Win32 - {733A9BE6-EB74-47AD-9701-2DB93FD4B2AC} + {FCA3A913-3152-480C-8F1A-78460EBE1F76} diff --git a/general/ioctl/wdm/sys/sioctl.vcxproj.Filters b/general/ioctl/wdm/sys/sioctl.vcxproj.Filters index 3b5a4633..2c4c9583 100644 --- a/general/ioctl/wdm/sys/sioctl.vcxproj.Filters +++ b/general/ioctl/wdm/sys/sioctl.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {68FEC55D-22E4-4CC8-86A7-C923C2AB8F07} + {0293F632-CB51-45F8-8DF6-6CE8AB8DEB1D} h;hpp;hxx;hm;inl;inc;xsd - {9D595192-13EA-4968-AFE4-63BECD7EDD64} + {8214575D-756B-4919-88AE-CDECEFA1921F} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {644100AF-059B-48EE-B8B9-280BA8724FF6} + {7306FA3C-F664-4252-9566-E061F0301808} inf;inv;inx;mof;mc; - {41B8EECC-BA42-433E-9150-6D2D385CC021} + {8721C5CF-CC9A-4480-B324-73C98BFD444A} diff --git a/general/obcallback/control/ObCallbackTestCtrl.vcxproj b/general/obcallback/control/ObCallbackTestCtrl.vcxproj index d9ea7f08..2f9a4a43 100644 --- a/general/obcallback/control/ObCallbackTestCtrl.vcxproj +++ b/general/obcallback/control/ObCallbackTestCtrl.vcxproj @@ -19,11 +19,11 @@ - {8B053BEE-EA21-4D12-984B-6C93FE6D4992} + {DB8864B4-169E-4815-9922-F552FAA028AF} $(MSBuildProjectName) Debug Win32 - {BED8786D-3B67-42D0-AC7B-D7D2F45E551E} + {CE20F975-1A88-43A5-8976-68A8BEBDC3ED} diff --git a/general/obcallback/control/ObCallbackTestCtrl.vcxproj.Filters b/general/obcallback/control/ObCallbackTestCtrl.vcxproj.Filters index b9258c52..0850a135 100644 --- a/general/obcallback/control/ObCallbackTestCtrl.vcxproj.Filters +++ b/general/obcallback/control/ObCallbackTestCtrl.vcxproj.Filters @@ -3,15 +3,15 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {5FCF0F0F-49FE-446D-9A27-490CBE156E8F} + {C20EE14F-B2D9-4FBF-BC7E-0DF705B150AD} h;hpp;hxx;hm;inl;inc;xsd - {F9488019-A49A-430B-818A-BB8ADC3106D1} + {8C949FC8-F2A5-423F-8F4F-D215168CEC6C} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {DBBA22E4-2B2D-4D16-8C9A-26B358D8752E} + {0FB11462-6C7F-4485-9D39-632D8C9CF2FD} diff --git a/general/obcallback/driver/ObCallbackTest.vcxproj b/general/obcallback/driver/ObCallbackTest.vcxproj index e781eb3a..2e6348ae 100644 --- a/general/obcallback/driver/ObCallbackTest.vcxproj +++ b/general/obcallback/driver/ObCallbackTest.vcxproj @@ -19,11 +19,11 @@ - {C696D115-0970-4E9C-8FED-31A99E039ED5} + {2C2188DF-F19F-4886-B4C1-5DD95909A64A} $(MSBuildProjectName) Debug Win32 - {F7152E7D-34B2-4B88-A5D9-17D68B786DFC} + {BBA1F9F1-637A-40C4-A643-A0766AB87027} diff --git a/general/obcallback/driver/ObCallbackTest.vcxproj.Filters b/general/obcallback/driver/ObCallbackTest.vcxproj.Filters index 6fb49bed..621e0f79 100644 --- a/general/obcallback/driver/ObCallbackTest.vcxproj.Filters +++ b/general/obcallback/driver/ObCallbackTest.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {5962AF0C-70AA-4F9A-870A-9CA844475924} + {030D466C-6D17-4995-AC90-E04818AEEA75} h;hpp;hxx;hm;inl;inc;xsd - {B9BBA35B-98FC-4830-9A01-41A3227755C9} + {D351C05E-ED86-4240-946A-9CCAA4B2916A} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {75DE6DD6-44CF-4D1B-BC2C-1EF556200FC9} + {6381A0AA-76E1-4A9F-B058-3F7A67153834} inf;inv;inx;mof;mc; - {593EF94F-8BBC-4C56-999C-5D894DD5456F} + {35FB336D-920E-4CCB-A47B-72D212D86AB0} diff --git a/general/obcallback/obcallback.sln b/general/obcallback/obcallback.sln index ed5a27b9..3ede4fc0 100644 --- a/general/obcallback/obcallback.sln +++ b/general/obcallback/obcallback.sln @@ -3,13 +3,13 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Control", "Control", "{D429EFC9-09E8-495C-81B0-32340C75C2BA}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Control", "Control", "{70CADFEA-4EA6-46ED-8C0E-966D4F3E7280}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Driver", "Driver", "{5DA38202-119A-41F8-B5A6-CB8D38191147}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Driver", "Driver", "{4A168675-E825-4328-87A1-46ADBFB75DB5}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ObCallbackTestCtrl", "control\ObCallbackTestCtrl.vcxproj", "{8B053BEE-EA21-4D12-984B-6C93FE6D4992}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ObCallbackTestCtrl", "control\ObCallbackTestCtrl.vcxproj", "{DB8864B4-169E-4815-9922-F552FAA028AF}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ObCallbackTest", "driver\ObCallbackTest.vcxproj", "{C696D115-0970-4E9C-8FED-31A99E039ED5}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ObCallbackTest", "driver\ObCallbackTest.vcxproj", "{2C2188DF-F19F-4886-B4C1-5DD95909A64A}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -19,28 +19,28 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {8B053BEE-EA21-4D12-984B-6C93FE6D4992}.Debug|Win32.ActiveCfg = Debug|Win32 - {8B053BEE-EA21-4D12-984B-6C93FE6D4992}.Debug|Win32.Build.0 = Debug|Win32 - {8B053BEE-EA21-4D12-984B-6C93FE6D4992}.Release|Win32.ActiveCfg = Release|Win32 - {8B053BEE-EA21-4D12-984B-6C93FE6D4992}.Release|Win32.Build.0 = Release|Win32 - {8B053BEE-EA21-4D12-984B-6C93FE6D4992}.Debug|x64.ActiveCfg = Debug|x64 - {8B053BEE-EA21-4D12-984B-6C93FE6D4992}.Debug|x64.Build.0 = Debug|x64 - {8B053BEE-EA21-4D12-984B-6C93FE6D4992}.Release|x64.ActiveCfg = Release|x64 - {8B053BEE-EA21-4D12-984B-6C93FE6D4992}.Release|x64.Build.0 = Release|x64 - {C696D115-0970-4E9C-8FED-31A99E039ED5}.Debug|Win32.ActiveCfg = Debug|Win32 - {C696D115-0970-4E9C-8FED-31A99E039ED5}.Debug|Win32.Build.0 = Debug|Win32 - {C696D115-0970-4E9C-8FED-31A99E039ED5}.Release|Win32.ActiveCfg = Release|Win32 - {C696D115-0970-4E9C-8FED-31A99E039ED5}.Release|Win32.Build.0 = Release|Win32 - {C696D115-0970-4E9C-8FED-31A99E039ED5}.Debug|x64.ActiveCfg = Debug|x64 - {C696D115-0970-4E9C-8FED-31A99E039ED5}.Debug|x64.Build.0 = Debug|x64 - {C696D115-0970-4E9C-8FED-31A99E039ED5}.Release|x64.ActiveCfg = Release|x64 - {C696D115-0970-4E9C-8FED-31A99E039ED5}.Release|x64.Build.0 = Release|x64 + {DB8864B4-169E-4815-9922-F552FAA028AF}.Debug|Win32.ActiveCfg = Debug|Win32 + {DB8864B4-169E-4815-9922-F552FAA028AF}.Debug|Win32.Build.0 = Debug|Win32 + {DB8864B4-169E-4815-9922-F552FAA028AF}.Release|Win32.ActiveCfg = Release|Win32 + {DB8864B4-169E-4815-9922-F552FAA028AF}.Release|Win32.Build.0 = Release|Win32 + {DB8864B4-169E-4815-9922-F552FAA028AF}.Debug|x64.ActiveCfg = Debug|x64 + {DB8864B4-169E-4815-9922-F552FAA028AF}.Debug|x64.Build.0 = Debug|x64 + {DB8864B4-169E-4815-9922-F552FAA028AF}.Release|x64.ActiveCfg = Release|x64 + {DB8864B4-169E-4815-9922-F552FAA028AF}.Release|x64.Build.0 = Release|x64 + {2C2188DF-F19F-4886-B4C1-5DD95909A64A}.Debug|Win32.ActiveCfg = Debug|Win32 + {2C2188DF-F19F-4886-B4C1-5DD95909A64A}.Debug|Win32.Build.0 = Debug|Win32 + {2C2188DF-F19F-4886-B4C1-5DD95909A64A}.Release|Win32.ActiveCfg = Release|Win32 + {2C2188DF-F19F-4886-B4C1-5DD95909A64A}.Release|Win32.Build.0 = Release|Win32 + {2C2188DF-F19F-4886-B4C1-5DD95909A64A}.Debug|x64.ActiveCfg = Debug|x64 + {2C2188DF-F19F-4886-B4C1-5DD95909A64A}.Debug|x64.Build.0 = Debug|x64 + {2C2188DF-F19F-4886-B4C1-5DD95909A64A}.Release|x64.ActiveCfg = Release|x64 + {2C2188DF-F19F-4886-B4C1-5DD95909A64A}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {8B053BEE-EA21-4D12-984B-6C93FE6D4992} = {D429EFC9-09E8-495C-81B0-32340C75C2BA} - {C696D115-0970-4E9C-8FED-31A99E039ED5} = {5DA38202-119A-41F8-B5A6-CB8D38191147} + {DB8864B4-169E-4815-9922-F552FAA028AF} = {70CADFEA-4EA6-46ED-8C0E-966D4F3E7280} + {2C2188DF-F19F-4886-B4C1-5DD95909A64A} = {4A168675-E825-4328-87A1-46ADBFB75DB5} EndGlobalSection EndGlobal diff --git a/general/pcidrv/kmdf/HW/PCIDRV.vcxproj b/general/pcidrv/kmdf/HW/PCIDRV.vcxproj index ca2cff13..353263b8 100644 --- a/general/pcidrv/kmdf/HW/PCIDRV.vcxproj +++ b/general/pcidrv/kmdf/HW/PCIDRV.vcxproj @@ -19,12 +19,12 @@ - {2221261F-E1E2-4562-A15D-2EF8BF7D878E} + {981ADEB0-2F42-4F65-B118-8553CD64ACFD} $(MSBuildProjectName) 1 Debug Win32 - {EAA7F2DD-6EAB-48CE-80E1-46A17BF21F72} + {4FF76CFE-2641-4D5A-983A-622FA892000D} diff --git a/general/pcidrv/kmdf/HW/PCIDRV.vcxproj.Filters b/general/pcidrv/kmdf/HW/PCIDRV.vcxproj.Filters index a15b9d16..98b4bbfe 100644 --- a/general/pcidrv/kmdf/HW/PCIDRV.vcxproj.Filters +++ b/general/pcidrv/kmdf/HW/PCIDRV.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {8FC125AF-15BD-4DCD-9D5E-C7FE9A6ACD75} + {6D6B3E6C-B12D-41CD-B77E-CFE7772C651E} h;hpp;hxx;hm;inl;inc;xsd - {938C7F7B-13A2-43D1-A1CF-4B02B581687C} + {C3F0DB26-8DB1-4AC1-BAAF-D84FAA82A17A} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {75E794A5-28E0-464A-A171-8AD7F2A1DEAA} + {2BDDF51F-F342-422D-8E77-6D18E65A4FE3} inf;inv;inx;mof;mc; - {EDAC3101-0378-4793-BEA6-FC4E036C130B} + {9B95345C-42E1-4A98-8A1F-71F76466D9AF} diff --git a/general/pcidrv/kmdf/genpci.inx b/general/pcidrv/kmdf/genpci.inx index b1f30a6c..c66464ed 100644 --- a/general/pcidrv/kmdf/genpci.inx +++ b/general/pcidrv/kmdf/genpci.inx @@ -54,15 +54,6 @@ pcidrv.sys = 1 [SourceDisksNames] 1=%DISK_NAME%, -; For Win2K -[MSFT] -; DisplayName Section DeviceId -; ----------- ------- -------- -%GenPCI.DRVDESC%=GenPCI_Inst, PCI\VEN_8086&DEV_1229 -%GenPCI.DRVDESC%=GenPCI_Inst, PCI\VEN_8086&DEV_103D -%GenPCI.DRVDESC%=GenPCI_Inst, PCI\VEN_8086&DEV_1031 -%GenPCI.DRVDESC%=GenPCI_Inst, PCI\VEN_8086&DEV_1038 - ; For XP and later [MSFT.NT$ARCH$] ; DisplayName Section DeviceId diff --git a/general/pcidrv/pcidrv.sln b/general/pcidrv/pcidrv.sln index e6607b8a..cfbe21e5 100644 --- a/general/pcidrv/pcidrv.sln +++ b/general/pcidrv/pcidrv.sln @@ -3,15 +3,15 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{EFA400EA-F405-4FB2-AC59-22D52ED1C479}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{1177EB4D-108A-42D1-86E1-323626CD6975}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "HW", "HW", "{8CBB3334-12D6-42CE-BD7A-A6F00E08FE45}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "HW", "HW", "{D8F67AFA-F8CE-4531-A387-DB50915BB347}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Kmdf", "Kmdf", "{A8847B95-FC0F-4553-9D94-354FE3C0A56E}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Kmdf", "Kmdf", "{9FD6367B-8E6E-4F7D-B260-D93B3D0150B6}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "myping", "test\myping.vcxproj", "{AAB2FA59-187D-45F7-A84F-09C7089848B3}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "myping", "test\myping.vcxproj", "{E270A551-A250-4432-975F-99FC5C7271D0}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PCIDRV", "kmdf\HW\PCIDRV.vcxproj", "{2221261F-E1E2-4562-A15D-2EF8BF7D878E}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PCIDRV", "kmdf\HW\PCIDRV.vcxproj", "{981ADEB0-2F42-4F65-B118-8553CD64ACFD}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -21,29 +21,29 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {AAB2FA59-187D-45F7-A84F-09C7089848B3}.Debug|Win32.ActiveCfg = Debug|Win32 - {AAB2FA59-187D-45F7-A84F-09C7089848B3}.Debug|Win32.Build.0 = Debug|Win32 - {AAB2FA59-187D-45F7-A84F-09C7089848B3}.Release|Win32.ActiveCfg = Release|Win32 - {AAB2FA59-187D-45F7-A84F-09C7089848B3}.Release|Win32.Build.0 = Release|Win32 - {AAB2FA59-187D-45F7-A84F-09C7089848B3}.Debug|x64.ActiveCfg = Debug|x64 - {AAB2FA59-187D-45F7-A84F-09C7089848B3}.Debug|x64.Build.0 = Debug|x64 - {AAB2FA59-187D-45F7-A84F-09C7089848B3}.Release|x64.ActiveCfg = Release|x64 - {AAB2FA59-187D-45F7-A84F-09C7089848B3}.Release|x64.Build.0 = Release|x64 - {2221261F-E1E2-4562-A15D-2EF8BF7D878E}.Debug|Win32.ActiveCfg = Debug|Win32 - {2221261F-E1E2-4562-A15D-2EF8BF7D878E}.Debug|Win32.Build.0 = Debug|Win32 - {2221261F-E1E2-4562-A15D-2EF8BF7D878E}.Release|Win32.ActiveCfg = Release|Win32 - {2221261F-E1E2-4562-A15D-2EF8BF7D878E}.Release|Win32.Build.0 = Release|Win32 - {2221261F-E1E2-4562-A15D-2EF8BF7D878E}.Debug|x64.ActiveCfg = Debug|x64 - {2221261F-E1E2-4562-A15D-2EF8BF7D878E}.Debug|x64.Build.0 = Debug|x64 - {2221261F-E1E2-4562-A15D-2EF8BF7D878E}.Release|x64.ActiveCfg = Release|x64 - {2221261F-E1E2-4562-A15D-2EF8BF7D878E}.Release|x64.Build.0 = Release|x64 + {E270A551-A250-4432-975F-99FC5C7271D0}.Debug|Win32.ActiveCfg = Debug|Win32 + {E270A551-A250-4432-975F-99FC5C7271D0}.Debug|Win32.Build.0 = Debug|Win32 + {E270A551-A250-4432-975F-99FC5C7271D0}.Release|Win32.ActiveCfg = Release|Win32 + {E270A551-A250-4432-975F-99FC5C7271D0}.Release|Win32.Build.0 = Release|Win32 + {E270A551-A250-4432-975F-99FC5C7271D0}.Debug|x64.ActiveCfg = Debug|x64 + {E270A551-A250-4432-975F-99FC5C7271D0}.Debug|x64.Build.0 = Debug|x64 + {E270A551-A250-4432-975F-99FC5C7271D0}.Release|x64.ActiveCfg = Release|x64 + {E270A551-A250-4432-975F-99FC5C7271D0}.Release|x64.Build.0 = Release|x64 + {981ADEB0-2F42-4F65-B118-8553CD64ACFD}.Debug|Win32.ActiveCfg = Debug|Win32 + {981ADEB0-2F42-4F65-B118-8553CD64ACFD}.Debug|Win32.Build.0 = Debug|Win32 + {981ADEB0-2F42-4F65-B118-8553CD64ACFD}.Release|Win32.ActiveCfg = Release|Win32 + {981ADEB0-2F42-4F65-B118-8553CD64ACFD}.Release|Win32.Build.0 = Release|Win32 + {981ADEB0-2F42-4F65-B118-8553CD64ACFD}.Debug|x64.ActiveCfg = Debug|x64 + {981ADEB0-2F42-4F65-B118-8553CD64ACFD}.Debug|x64.Build.0 = Debug|x64 + {981ADEB0-2F42-4F65-B118-8553CD64ACFD}.Release|x64.ActiveCfg = Release|x64 + {981ADEB0-2F42-4F65-B118-8553CD64ACFD}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {AAB2FA59-187D-45F7-A84F-09C7089848B3} = {EFA400EA-F405-4FB2-AC59-22D52ED1C479} - {2221261F-E1E2-4562-A15D-2EF8BF7D878E} = {8CBB3334-12D6-42CE-BD7A-A6F00E08FE45} - {8CBB3334-12D6-42CE-BD7A-A6F00E08FE45} = {A8847B95-FC0F-4553-9D94-354FE3C0A56E} + {E270A551-A250-4432-975F-99FC5C7271D0} = {1177EB4D-108A-42D1-86E1-323626CD6975} + {981ADEB0-2F42-4F65-B118-8553CD64ACFD} = {D8F67AFA-F8CE-4531-A387-DB50915BB347} + {D8F67AFA-F8CE-4531-A387-DB50915BB347} = {9FD6367B-8E6E-4F7D-B260-D93B3D0150B6} EndGlobalSection EndGlobal diff --git a/general/pcidrv/test/myping.vcxproj b/general/pcidrv/test/myping.vcxproj index 182ebe8c..9bea4622 100644 --- a/general/pcidrv/test/myping.vcxproj +++ b/general/pcidrv/test/myping.vcxproj @@ -19,11 +19,11 @@ - {AAB2FA59-187D-45F7-A84F-09C7089848B3} + {E270A551-A250-4432-975F-99FC5C7271D0} $(MSBuildProjectName) Debug Win32 - {E28A6724-75F7-4959-8204-0A5787BBF7B9} + {10CF0CFF-7ED4-4C36-B12F-E6AE18422A4E} diff --git a/general/pcidrv/test/myping.vcxproj.Filters b/general/pcidrv/test/myping.vcxproj.Filters index 32295c73..cf2b75b4 100644 --- a/general/pcidrv/test/myping.vcxproj.Filters +++ b/general/pcidrv/test/myping.vcxproj.Filters @@ -3,15 +3,15 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {B8B1F2DC-5ED4-4A1F-BFEE-587F0F5312D5} + {0D2B8F8A-7DF3-4F12-8A73-720F90D3AD69} h;hpp;hxx;hm;inl;inc;xsd - {8259798A-8FE0-4AE5-B848-77626974747D} + {CF7CB9C0-EAFC-44C5-8277-390F35F3D21E} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {48C95CA9-FD65-42C9-8FAF-C20DEB7390E8} + {A6BEDE27-A5E1-46BF-BA34-C345F92F4873} diff --git a/general/perfcounters/kcs/kcs.htm b/general/perfcounters/kcs/kcs.htm new file mode 100644 index 00000000..4349388b --- /dev/null +++ b/general/perfcounters/kcs/kcs.htm @@ -0,0 +1,757 @@ + + + + + + + + +Sample Name + + + + + + + + + +
+ +

Kernel Counter Sample (Kcs)

+ +

SUMMARY

+ +

kcs is a +sample to demonstrate the use of kernel mode perflib +API. The driver does not control any hardware; it simple provides counters. The +code contains comments to explain what each function does.

+ +

USING THE SAMPLE

+ +

To test the Kcs counter provider, +use the following procedure.

+ +
    +
  1. Copy kcs.sys and kcs.man files in %windir%\system32 dir, and kcs.sys.mui in %windir%\system32\en-US + dir if kcs.sys.mui was + generated.
    +
    +
  2. +
  3. Sign the sample driver. For + details about how to sign the driver, see "SIGNNING THE SAMPLE + DRIVER" section.
    +
    +
  4. +
  5. Install the counters.
  6. +
+ +

lodctr.exe /m:kcs.man

+ +
    +
  1. Create a service to control + the driver.
  2. +
+ +

sc create kcs +binpath= %windir%\system32\kcs.sys +type= kernel start= demand

+ +
    +
  1. Start the service
  2. +
+ +

net start kcs

+ +
    +
  1. Run perfmon + and add Geometric Wave and Trignometric Wave + Counter Sets
  2. +
+ +

perfmon.exe

+ +
    +
  1. To stop the service, run
  2. +
+ +

net stop kcs

+ +
    +
  1. To un-install the counters, + run
  2. +
+ +

unlodctr.exe /m:kcs.man

+ +

BUILD THE SAMPLE

+ +

To get the simple driver (kcs.sys), use the following +procedure.

+ +
    +
  1. Click kcs.vcxproj + to open the sample.
  2. +
  3. Right click project, select + Properties, goto Linker -> Manifest File, make sure "Generate Manifest" is "No".
  4. +
  5. Build the project.
  6. +
      +
    1. You can press "F7" + or choose Build->Build Solution.
    2. +
    +
+ +

LIMITATIONS

+ +

This sample driver should not be used in a production +environment.

+ +

 

+ +

Kcs is designed for Windows 7 +and later versions of Windows.

+ +

 

+ +

FILE LIST

+ +

kcs.h

+ +

makefile

+ +

sources

+ +

kcs.c

+ +

kcs.rc

+ +

 

+ +

LOCATION

+ +

The files that comprise Kcs are +included in the Windows DDK in the \src\general\perfcounters\kcs directory.

+ +

 

+ +

FEEDBACK

+ +

Top of page

+ + + + + +
+

 

+
+ +

© +Microsoft Corporation +

+ +
+ + + + diff --git a/general/perfcounters/kcs/kcs.sln b/general/perfcounters/kcs/kcs.sln index 6630e582..2d6fe420 100644 --- a/general/perfcounters/kcs/kcs.sln +++ b/general/perfcounters/kcs/kcs.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "kcs", "kcs.vcxproj", "{FA4BC0C3-DA1C-46DA-BFF4-AA448B5D0A0A}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "kcs", "kcs.vcxproj", "{7596269F-A8F8-465D-A627-3B5878A73DDF}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +13,14 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {FA4BC0C3-DA1C-46DA-BFF4-AA448B5D0A0A}.Debug|Win32.ActiveCfg = Debug|Win32 - {FA4BC0C3-DA1C-46DA-BFF4-AA448B5D0A0A}.Debug|Win32.Build.0 = Debug|Win32 - {FA4BC0C3-DA1C-46DA-BFF4-AA448B5D0A0A}.Release|Win32.ActiveCfg = Release|Win32 - {FA4BC0C3-DA1C-46DA-BFF4-AA448B5D0A0A}.Release|Win32.Build.0 = Release|Win32 - {FA4BC0C3-DA1C-46DA-BFF4-AA448B5D0A0A}.Debug|x64.ActiveCfg = Debug|x64 - {FA4BC0C3-DA1C-46DA-BFF4-AA448B5D0A0A}.Debug|x64.Build.0 = Debug|x64 - {FA4BC0C3-DA1C-46DA-BFF4-AA448B5D0A0A}.Release|x64.ActiveCfg = Release|x64 - {FA4BC0C3-DA1C-46DA-BFF4-AA448B5D0A0A}.Release|x64.Build.0 = Release|x64 + {7596269F-A8F8-465D-A627-3B5878A73DDF}.Debug|Win32.ActiveCfg = Debug|Win32 + {7596269F-A8F8-465D-A627-3B5878A73DDF}.Debug|Win32.Build.0 = Debug|Win32 + {7596269F-A8F8-465D-A627-3B5878A73DDF}.Release|Win32.ActiveCfg = Release|Win32 + {7596269F-A8F8-465D-A627-3B5878A73DDF}.Release|Win32.Build.0 = Release|Win32 + {7596269F-A8F8-465D-A627-3B5878A73DDF}.Debug|x64.ActiveCfg = Debug|x64 + {7596269F-A8F8-465D-A627-3B5878A73DDF}.Debug|x64.Build.0 = Debug|x64 + {7596269F-A8F8-465D-A627-3B5878A73DDF}.Release|x64.ActiveCfg = Release|x64 + {7596269F-A8F8-465D-A627-3B5878A73DDF}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/general/perfcounters/kcs/kcs.vcxproj b/general/perfcounters/kcs/kcs.vcxproj index c58a9026..1dcd38af 100644 --- a/general/perfcounters/kcs/kcs.vcxproj +++ b/general/perfcounters/kcs/kcs.vcxproj @@ -19,11 +19,11 @@
- {FA4BC0C3-DA1C-46DA-BFF4-AA448B5D0A0A} + {7596269F-A8F8-465D-A627-3B5878A73DDF} $(MSBuildProjectName) Debug Win32 - {C44D3FE1-3E60-4619-A1F9-E34A55C6FCA7} + {69F72AB3-96CC-43AD-A68F-CB688463DDA0} diff --git a/general/perfcounters/kcs/kcs.vcxproj.Filters b/general/perfcounters/kcs/kcs.vcxproj.Filters index fedf64ea..fc8b9ec1 100644 --- a/general/perfcounters/kcs/kcs.vcxproj.Filters +++ b/general/perfcounters/kcs/kcs.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {1E487FA6-DCB9-4A49-A9B9-3A1C9D75EB43} + {355E458C-12D5-4C11-ADC3-406D93CFB8A8} h;hpp;hxx;hm;inl;inc;xsd - {E4CC3C2E-1709-47A1-A48A-1EB157A1251C} + {EDE44450-36F4-47D8-B151-48C17BDF62DD} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {3D42F00B-B811-48EC-BB7A-2D8047551422} + {ADDD9180-1AB7-4BDB-931B-6D108B189EB5} inf;inv;inx;mof;mc; - {4AE0C581-1388-4311-8C6C-9087111D70F5} + {36374B68-325A-4EE5-B9E7-523B2544F1D3} diff --git a/general/registry/regfltr/exe/regctrl.vcxproj b/general/registry/regfltr/exe/regctrl.vcxproj index a0a9e234..60d7f41c 100644 --- a/general/registry/regfltr/exe/regctrl.vcxproj +++ b/general/registry/regfltr/exe/regctrl.vcxproj @@ -19,11 +19,11 @@ - {F3CBF3E0-E60F-409E-9402-A508C8008EB7} + {C1237DB4-2E21-436F-A4E7-7C5B7632D1A2} $(MSBuildProjectName) Debug Win32 - {7DBA6C3C-01A4-4CB0-A5A2-0D1E014C3F17} + {D3AEFA3D-C8F6-4B1F-9977-D2D0D6A8B318} diff --git a/general/registry/regfltr/exe/regctrl.vcxproj.Filters b/general/registry/regfltr/exe/regctrl.vcxproj.Filters index 33b9e1e1..176ee63c 100644 --- a/general/registry/regfltr/exe/regctrl.vcxproj.Filters +++ b/general/registry/regfltr/exe/regctrl.vcxproj.Filters @@ -3,15 +3,15 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {9713D19A-A900-45FB-AA68-19BDFD105192} + {9E122CD6-5345-418A-AFA8-B17887197386} h;hpp;hxx;hm;inl;inc;xsd - {8A005B43-A062-4866-BEC2-037F5820B234} + {95638411-9C24-4D8D-955D-26586E3BD517} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {768BFEC7-A3C9-42EA-BCB0-30162CB4DA90} + {E8182A13-CD10-438C-A333-32F784173C22} diff --git a/general/registry/regfltr/regfltr.sln b/general/registry/regfltr/regfltr.sln index 1b1e31c3..59193da5 100644 --- a/general/registry/regfltr/regfltr.sln +++ b/general/registry/regfltr/regfltr.sln @@ -3,13 +3,13 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Exe", "Exe", "{C7CD81BA-CF73-4628-909C-77E4B3370C77}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Exe", "Exe", "{FADD4059-9BCA-43E7-93E1-D841DDC3359C}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Sys", "Sys", "{700EF2F6-A93B-4398-AE93-EFA0C49511C6}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Sys", "Sys", "{10003933-73CE-44B3-BB13-A248CD5862A8}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "regctrl", "exe\regctrl.vcxproj", "{F3CBF3E0-E60F-409E-9402-A508C8008EB7}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "regctrl", "exe\regctrl.vcxproj", "{C1237DB4-2E21-436F-A4E7-7C5B7632D1A2}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "regfltr", "sys\regfltr.vcxproj", "{12666DFF-2CD6-4000-AFE6-0796D9B6D330}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "regfltr", "sys\regfltr.vcxproj", "{5FA7255C-4B69-42A2-8511-FA5CF23789C1}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -19,28 +19,28 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {F3CBF3E0-E60F-409E-9402-A508C8008EB7}.Debug|Win32.ActiveCfg = Debug|Win32 - {F3CBF3E0-E60F-409E-9402-A508C8008EB7}.Debug|Win32.Build.0 = Debug|Win32 - {F3CBF3E0-E60F-409E-9402-A508C8008EB7}.Release|Win32.ActiveCfg = Release|Win32 - {F3CBF3E0-E60F-409E-9402-A508C8008EB7}.Release|Win32.Build.0 = Release|Win32 - {F3CBF3E0-E60F-409E-9402-A508C8008EB7}.Debug|x64.ActiveCfg = Debug|x64 - {F3CBF3E0-E60F-409E-9402-A508C8008EB7}.Debug|x64.Build.0 = Debug|x64 - {F3CBF3E0-E60F-409E-9402-A508C8008EB7}.Release|x64.ActiveCfg = Release|x64 - {F3CBF3E0-E60F-409E-9402-A508C8008EB7}.Release|x64.Build.0 = Release|x64 - {12666DFF-2CD6-4000-AFE6-0796D9B6D330}.Debug|Win32.ActiveCfg = Debug|Win32 - {12666DFF-2CD6-4000-AFE6-0796D9B6D330}.Debug|Win32.Build.0 = Debug|Win32 - {12666DFF-2CD6-4000-AFE6-0796D9B6D330}.Release|Win32.ActiveCfg = Release|Win32 - {12666DFF-2CD6-4000-AFE6-0796D9B6D330}.Release|Win32.Build.0 = Release|Win32 - {12666DFF-2CD6-4000-AFE6-0796D9B6D330}.Debug|x64.ActiveCfg = Debug|x64 - {12666DFF-2CD6-4000-AFE6-0796D9B6D330}.Debug|x64.Build.0 = Debug|x64 - {12666DFF-2CD6-4000-AFE6-0796D9B6D330}.Release|x64.ActiveCfg = Release|x64 - {12666DFF-2CD6-4000-AFE6-0796D9B6D330}.Release|x64.Build.0 = Release|x64 + {C1237DB4-2E21-436F-A4E7-7C5B7632D1A2}.Debug|Win32.ActiveCfg = Debug|Win32 + {C1237DB4-2E21-436F-A4E7-7C5B7632D1A2}.Debug|Win32.Build.0 = Debug|Win32 + {C1237DB4-2E21-436F-A4E7-7C5B7632D1A2}.Release|Win32.ActiveCfg = Release|Win32 + {C1237DB4-2E21-436F-A4E7-7C5B7632D1A2}.Release|Win32.Build.0 = Release|Win32 + {C1237DB4-2E21-436F-A4E7-7C5B7632D1A2}.Debug|x64.ActiveCfg = Debug|x64 + {C1237DB4-2E21-436F-A4E7-7C5B7632D1A2}.Debug|x64.Build.0 = Debug|x64 + {C1237DB4-2E21-436F-A4E7-7C5B7632D1A2}.Release|x64.ActiveCfg = Release|x64 + {C1237DB4-2E21-436F-A4E7-7C5B7632D1A2}.Release|x64.Build.0 = Release|x64 + {5FA7255C-4B69-42A2-8511-FA5CF23789C1}.Debug|Win32.ActiveCfg = Debug|Win32 + {5FA7255C-4B69-42A2-8511-FA5CF23789C1}.Debug|Win32.Build.0 = Debug|Win32 + {5FA7255C-4B69-42A2-8511-FA5CF23789C1}.Release|Win32.ActiveCfg = Release|Win32 + {5FA7255C-4B69-42A2-8511-FA5CF23789C1}.Release|Win32.Build.0 = Release|Win32 + {5FA7255C-4B69-42A2-8511-FA5CF23789C1}.Debug|x64.ActiveCfg = Debug|x64 + {5FA7255C-4B69-42A2-8511-FA5CF23789C1}.Debug|x64.Build.0 = Debug|x64 + {5FA7255C-4B69-42A2-8511-FA5CF23789C1}.Release|x64.ActiveCfg = Release|x64 + {5FA7255C-4B69-42A2-8511-FA5CF23789C1}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {F3CBF3E0-E60F-409E-9402-A508C8008EB7} = {C7CD81BA-CF73-4628-909C-77E4B3370C77} - {12666DFF-2CD6-4000-AFE6-0796D9B6D330} = {700EF2F6-A93B-4398-AE93-EFA0C49511C6} + {C1237DB4-2E21-436F-A4E7-7C5B7632D1A2} = {FADD4059-9BCA-43E7-93E1-D841DDC3359C} + {5FA7255C-4B69-42A2-8511-FA5CF23789C1} = {10003933-73CE-44B3-BB13-A248CD5862A8} EndGlobalSection EndGlobal diff --git a/general/registry/regfltr/sys/regfltr.vcxproj b/general/registry/regfltr/sys/regfltr.vcxproj index 6bddb5e4..bd877cee 100644 --- a/general/registry/regfltr/sys/regfltr.vcxproj +++ b/general/registry/regfltr/sys/regfltr.vcxproj @@ -19,11 +19,11 @@ - {12666DFF-2CD6-4000-AFE6-0796D9B6D330} + {5FA7255C-4B69-42A2-8511-FA5CF23789C1} $(MSBuildProjectName) Debug Win32 - {3973A2A5-EFFD-4997-985D-51731D2A58CA} + {72113749-69A5-4D2B-A747-75C97C239409} diff --git a/general/registry/regfltr/sys/regfltr.vcxproj.Filters b/general/registry/regfltr/sys/regfltr.vcxproj.Filters index 22722767..5c90e0f7 100644 --- a/general/registry/regfltr/sys/regfltr.vcxproj.Filters +++ b/general/registry/regfltr/sys/regfltr.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {2B50099F-1EBF-480D-9136-448FBDF31F1F} + {0AA7B9CC-6AAF-487B-9036-B939FD9A9B0E} h;hpp;hxx;hm;inl;inc;xsd - {1001336B-4543-45F1-A020-C5E84A980E24} + {BB821D94-5629-40BE-B5B8-809B58382931} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {9EEC1AF7-63F4-44AB-81FA-A0DAC270B821} + {28C582AD-3C88-4631-A980-E0EB0684D9FA} inf;inv;inx;mof;mc; - {AE93F2E1-863E-4BAE-BC5D-09810656976E} + {87216377-AE9B-47DE-995E-F11370E84553} diff --git a/general/toaster/toastpkg/toastapp/toastapp.vcxproj b/general/toaster/toastpkg/toastapp/toastapp.vcxproj index 9e71f3da..5deac4a6 100644 --- a/general/toaster/toastpkg/toastapp/toastapp.vcxproj +++ b/general/toaster/toastpkg/toastapp/toastapp.vcxproj @@ -19,11 +19,11 @@ - {1C818755-28B2-4C84-8623-FF84F3326B64} + {A8A63599-6EC4-4103-93F2-67403B310ECE} $(MSBuildProjectName) Debug Win32 - {42007D8E-51B7-469B-B5D0-45C7674BFFEF} + {52D1A92C-A8CF-4ED9-A4C5-DE0E54683CC9} diff --git a/general/toaster/toastpkg/toastapp/toastapp.vcxproj.Filters b/general/toaster/toastpkg/toastapp/toastapp.vcxproj.Filters index bcbb10b1..3bd997c3 100644 --- a/general/toaster/toastpkg/toastapp/toastapp.vcxproj.Filters +++ b/general/toaster/toastpkg/toastapp/toastapp.vcxproj.Filters @@ -3,15 +3,15 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {5B7E141F-3C1C-446C-B423-22D8F13BD05C} + {3CAB87A0-84A1-442D-A0DA-AFE6311FDF5F} h;hpp;hxx;hm;inl;inc;xsd - {21C18B76-71F9-4B0C-B377-B15E4821D9CD} + {5745867E-8275-4764-8224-38EDA6FF5215} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {67F5F556-F3BD-4452-88F3-806BDB94EB5F} + {A5E2F374-BB6F-4016-AAEA-BFBB7C4B7DE1} diff --git a/general/toaster/toastpkg/toastcd/tostx86.cat b/general/toaster/toastpkg/toastcd/tostx86.cat index 31450f2f..47a4fdf5 100644 Binary files a/general/toaster/toastpkg/toastcd/tostx86.cat and b/general/toaster/toastpkg/toastcd/tostx86.cat differ diff --git a/general/toaster/toastpkg/toastcd/tstamd64.cat b/general/toaster/toastpkg/toastcd/tstamd64.cat index f91fe53f..5d500130 100644 Binary files a/general/toaster/toastpkg/toastcd/tstamd64.cat and b/general/toaster/toastpkg/toastcd/tstamd64.cat differ diff --git a/general/toaster/toastpkg/toastco/tostrco2.vcxproj b/general/toaster/toastpkg/toastco/tostrco2.vcxproj index ee1a266f..e0cfe4d9 100644 --- a/general/toaster/toastpkg/toastco/tostrco2.vcxproj +++ b/general/toaster/toastpkg/toastco/tostrco2.vcxproj @@ -19,11 +19,11 @@ - {84F11D30-54EE-479A-8F8A-7FBFA8E6BE22} + {2C6F3F5F-06F7-4F86-8914-DB04CFDD9B19} $(MSBuildProjectName) Debug Win32 - {F4010EA2-CDEF-4E68-AF56-C0240162D712} + {E58D7499-1030-49A4-9FD8-CB60E7F71D05} diff --git a/general/toaster/toastpkg/toastco/tostrco2.vcxproj.Filters b/general/toaster/toastpkg/toastco/tostrco2.vcxproj.Filters index 5639c710..4766e098 100644 --- a/general/toaster/toastpkg/toastco/tostrco2.vcxproj.Filters +++ b/general/toaster/toastpkg/toastco/tostrco2.vcxproj.Filters @@ -3,15 +3,15 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {FF79EB36-D2F2-497B-9B3B-1F5D4BA911D4} + {0202E791-D56D-4726-BDAF-E96655EA47F7} h;hpp;hxx;hm;inl;inc;xsd - {A4BFE1CB-F5FD-4F98-8EA6-6B0F543535C6} + {C5D6053C-04B1-46D4-94A3-6DDCD2C1D19C} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {F4E6AFB3-5EF2-4D35-92BF-D0DAD16E87B5} + {ECD2A7C2-F1AA-4184-B6BE-7CD1E8BBBCAE} diff --git a/general/toaster/toastpkg/toastpkg.htm b/general/toaster/toastpkg/toastpkg.htm new file mode 100644 index 00000000..cd780261 --- /dev/null +++ b/general/toaster/toastpkg/toastpkg.htm @@ -0,0 +1,186 @@ + + + + +Toaster Installation Package + + + +

Toaster Installation Package

+
+ + +

SUMMARY

+This document discusses the different approaches that end users take when adding new hardware to their computer, and describes an approach that addresses these scenarios in a consistent, robust manner that works cooperatively with Plug and Play in Windows 2000 and Windows XP. It also outlines the mechanisms provided to facilitate additional vendor requirements such as the installation of value-added software. + +

INTRODUCTION

+The installation of software to support an instance of a given device (known as "device installation" or "driver installation") is done in a device-centric fashion in Windows operating systems. A device INF that matches up with one of the device's hardware or compatible IDs is used to identify the required driver file(s), registry modifications, etc., that are needed to make the device fully operational. This INF, along with the files copied thereby and a catalog that contains the digital signatures of the INF and these other files, constitute what is known as a "driver package". + +

+Because device installation is done for a specific instance of a device, the "natural" method of adding devices to a computer running a Plug and Play operating system is by plugging in the device first, letting Plug and Play find the device and automatically initiate an installation for that device. The device installation may then proceed using a driver package supplied with the OS, or a "3rd-party" driver package (supplied via CD-ROM, the Internet, or some other distribution mechanism). When the device installation is initiated by the addition of hardware, this is termed a "hardware-first" device +installation. + +

+Users may, however, take an alternate approach to adding hardware to their computer. In this scenario, they first run a setup program (perhaps launched as an autorun application when the vendor-supplied CD-ROM is inserted). This setup program may perform installation activities, and then prompt the user to insert their hardware. Upon the hardware's insertion, the vendor-supplied driver package (which was "pre-installed" by the setup program) is then found by Plug and Play, and the installation proceeds as in the hardware-first scenario. When the device installation is initiated by running a setup program, this is termed a "software-first" device installation. This approach to adding new hardware is just as valid as the hardware-first scenario, and some vendors may even instruct their users (via documentation that ships with the hardware) that this is the preferred method. + +

+Vendors must support the hardware-first scenario (by providing a driver package that may be supplied to the "Found New Hardware" wizard with no +"pre-configuration" performed by a setup program or other mechanism). Vendors may optionally support the software-first scenario as well, but the +actual installation of the device instance is done by Plug and Play upon the device's arrival, as described above. + +

+Vendors may also wish to perform additional activities as part of the device installation. For example, the vendor may want to allow the user to optionally install one or more applications that ship with the device (e.g., a scanner that ships with an image processing application). Such software is termed "value-added software". Value-added software is distinct from the files that comprise the driver package because, unlike the core driver files, the device does not require value-added software to function properly. In the previous example of a scanner, for instance, perhaps the user already has an image processing application that they prefer. The user should be given the option of whether or not they want to install any value-added software. Additional activities (such as allowing the user to select value-added software offerings) may be accomplished by using a vendor-supplied +device-specific co-installer. + + +

INTRODUCTION TO THE TOASTER INSTALLATION SAMPLE

+This sample contains inf, toastapp, toastcd, toastco, and toastva directories. The following summary describes the directories and key files. +

+ +inf +

+This directory contains the device INF (toastpkg.inf) that is used in device installation of toaster devices enumerated by the toaster bus enumerator. It registers a device-specific co-installer (tostrco2.dll) that provides additional functionality during the installation. + +

+Also contained in this directory is the autorun.inf file that would be placed in the root of the vendor's setup media (e.g., CD-ROM). This INF will launch the toastva.exe application (described below) when the media is inserted in an autorun-capable drive, or when the user double-clicks on the drive icon in Explorer. Additionally, this INF illustrates the [DeviceInstall] section that is a new feature introduced in Windows XP for +autorun INF files: + +

+

+[DeviceInstall] +

+DriverPath=\ +

+ +

+The DriverPath entry in a [DeviceInstall] section indicates to the Found New Hardware and Update Driver wizards that Plug and Play should search for +device INFs in the specified directory only. This provides a performance improvement for media layouts that contain many subdirectories, since the default +behavior is for Plug and Play to recursively search the entire CD. Additionally, specifying no DriverPath entry in this section indicates that the CD contains no drivers, thus Plug and Play can quickly determine that it can ignore this media. Absence of the [DeviceInstall] section will cause the media to be treated as it was in previous versions of Windows (e.g., as in Windows Me and Windows 2000, the entire media will be searched recursively for applicable INFs). +

+ +toastapp
+This directory contains the source code for the toastapp.exe program that is used as value-added software that may optionally be installed by the user as part of device installation. This program is installed via the InstallShield(tm) (Microsoft Installer-based) setup program in the toastcd\ToastApp directory. +
+ +toastcd
+This directory contains the CD image that would be used by the vendor to distribute the toaster package. In the root of the image, we have the +autorun.inf which launches either the x86 or ia64 version of toastva.exe (depending on platform). Also in the root we have the device INF, +toastpkg.inf, and the two associated catalogs, tostx86.cat and tostia64.cat, for the x86 and ia64 platforms respectively. Finally, +in the root we also have the zero-length tag file toastpkg.tag, which is used to identify the media in case it must be prompted for. This tagfile is +referenced in the SourceDisksNames sections of toastpkg.inf: + +
+

+[SourceDisksNames.x86] +

+1 = %DiskId1%, toastpkg.tag,,\i386 +

+[SourceDisksNames.ia64] +

+1 = %DiskId1%, toastpkg.tag,,\ia64 +

+ +

+The i386 and ia64 subdirectories contain the driver files that, along with the INF and CAT, constitute the driver package. These files are +toaster.sys, tostrcls.dll, and tostrco2.dll. Their corresponding debug (.PDB) files are located there as well, although +these aren’t installed. Additionally, as mentioned above, the toastva.exe program (and its .PDB file) is located here. Note that this +is not part of the driver package—it is merely used to facilitate software-first installation. Since this executable is not part of the driver +package, it may be modified without affecting the digital signature of the package. + +

+Finally, the ToastApp subdirectory contains the setup.exe program that installs the value-added software package, toastapp.exe. This +setup.exe is a standalone package that contains the files it installs within this single binary. This is meant to represent an example of the kind +of software that might be supplied to a vendor by an ISV for distribution with that vendor's hardware. While this particular setup program was authored +with InstallShield(tm), other installation methods are equally valid. For example, the setup program could have been written using C/C++, directly +leveraging the Microsoft Installer (MSI) application programming interfaces (API). + +

+The tostrco2.dll module is constructed so that there is no requirement on how the value-added software is installed--it simply creates a process to initiate the setup program, then waits for that process to terminate before continuing. For the sample, the description of the value-added software offerings and details of launching the value-added setup application are hard-coded, but in a real-world scenario, the value-added software supplied might be listed in some sort of data file (perhaps an INF file) and the value-added software selection page would be completely data driven, using the information contained in that data file. This would be advantageous, for example, because a vendor could submit just their core driver package for Windows Logo testing without any value-added software (and without this data file). The vendor could then construct setup media containing the core driver package plus value-added software as they see fit. The contents of their setup media could be modified at any time by adding or removing value-added software, and no changes to the core driver package would be required (hence, no need to re-submit for Windows Logo testing). This works because the data file containing details about the +value-added software offerings isn't a part of the driver package, and thus can be changed without affecting that package. A co-installer DLL written +to accommodate such a scheme could have default behavior that would not display the value-added software selection page in the absence of this data file. +

+ +toastco
+This directory contains the co-installer, tostrco2.dll, which is used during device installation of toaster devices enumerated by the toaster bus enumerator. This co-installer supplies a finish-install wizard page that allows the user to select the value-added software, if any, that they wish to install. It does not supply a finish-install wizard page if the user has previously responded to the wizard page (whether or not they opted to install value-added software) so that the user isn't prompted multiple times in the case where they plug in multiple toasters (or the same toaster is plugged into multiple ports, which will appear to Plug and Play as different instances of that device). + +

+This DLL also supplies the same value-added software selection page for use by the toastva.exe setup program. This avoids code duplication and ensures a consistent user experience for the hardware-first and software-first scenarios. + +

+Finally, this co-installer performs the same function as its version 1 counterpart (in the coinstaller directory under the main toaster directory). It provides a friendly name for the device that incorporates its serial number. However, this version retrieves the friendly name template from the INF, and since the template is stored in the [Strings] section, it may be localized for other languages. + +

+The reason this co-installer’s filename includes version number is to illustrate the technique that must be used when updating the driver for a device that may already have a previous version of the co-installer installed. If the name is not changed, then the old co-installer will be loaded early-on during the processing of DIF codes, and the updated version won’t be able to “get in the loop” to perform its new actions when installing the device. Thus, co-installers should include a version number in their filename, so that the new version can be copied and can participate in the device installation. +

+ +toastva
+This directory contains the autorun installation application, toastva.exe, which is launched when the user inserts the vendor-provided CD-ROM. This application is used to "pre-install" the necessary INF and catalog, along with any value-added software the user chooses. In addition, it uses the UpdateDriverForPlugAndPlayDevices API to update the existing installed drivers for any toasters that may already be present. Examples of scenarios where this would apply are: +
    +
  1. +The user previously plugged in a toaster, and there was no in-box support (i.e., no supporting driver was included with Windows) for it. The user didn't supply a vendor provided driver package at that time (perhaps because they didn't have the media), so no driver was installed for the device (this is sometimes referred to as a "null driver install"). +
  2. +The user previously plugged in a toaster, and there was in-box support for it (perhaps using an older or reduced-functionality driver). +
  3. +The user previously plugged in a toaster, and at that time supplied an older version of the driver provided by the vendor. + +

    +In all the above cases, the UpdateDriverForPlugAndPlayDevices API will seek out any toaster device instances matching the specified hardware or compatible ID, and determine whether the specified driver package is "better" (i.e., lower rank or newer). If so, the device instance will be updated with the specified driver package. +

+ +

BUILDING THE SAMPLE

+To build the Toaster Installation Sample components, you must first set up the DDK environment on your host machine. The “Installation and Release Notes” +topic in the Windows XP DDK has a complete description on how to do this. + +

+Run the build –cZ command in the toastpkg directory to build tostrco2.dll, toastapp.exe, and toastva.exe. Run the build –cZ +command in the classinstaller and func subdirectories of the main Toaster directory (parent of the toastpkg directory) to build +tostrcls.dll and toaster.sys. The toastcd directory contains all these components already built with full debugging information. The +reason is so that the sample could be digitally signed (thus exactly reproducing the ideal user experience). + +

+To experiment with certain behaviors of this package (e.g., toastva.exe launched via CD autorun), it is necessary to copy the entire contents of the toastcd tree onto a writeable CD. +

+ +

RUNNING THE SAMPLE

+The sample can be run in two different ways, corresponding to the hardware-first and software-first scenarios. +

+Hardware-First Device Installation Walk-Through +

+Simulate the plugging in of a toaster by typing the following at a command prompt (see the documentation for the toaster sample driver for more information on setting up the toaster bus enumerator and using the "enum" application to simulate plugging and unplugging of toaster devices): + +

+

+C:\>enum -p 1 +

+ +

+Since there is no in-box driver for this device, the Found New Hardware wizard will appear, prompting for a driver package. If you constructed the setup image on autorun-capable media (e.g., writeable CD or DVD), you may insert that media in the drive, and Windows XP will automatically initiate a driver search on that media. On Windows 2000, you must click "Next" to initiate the driver search on that media. If you constructed the setup image in a directory on your hard disk, then you must click the "Install from a list or specific location (Advanced)" radio button, then click "Next". On the next page, click the "Include this location in the search:" checkbox, and type the path to the directory. Clicking "Next" will then initiate a driver search in the directory you specified. + +

+The install will proceed using the toastpkg.inf file in the root of the install location. The co-installer, tostrco2.dll, will assign the device a friendly name during DIF_INSTALLDEVICE, and will supply a value-add software selection wizard page in response to DIF_NEWDEVICEWIZARD_FINISHINSTALL. This page will only be supplied if the user hasn’t been given the option previously of selecting value-added software (of if they’ve since uninstalled said software). This allows subsequent toasters to be installed server-side, without any user interaction whatsoever (even if a non-admin user or no user is logged in). + +

+Software-First Device Installation Walk-Through +

+If you constructed the setup image on auto-run capable media (e.g., writeable CD or DVD), you can simply insert the media, and the toastva.exe program will automatically launch. Note that toastva.exe suppresses itself when invoked while a device installation is in progress, which is why this application doesn’t appear during the hardware-first scenario described above. + +

+After the Welcome page, the wizard will attempt to update the driver for any existing toaster devices (via the UpdateDriverForPlugAndPlayDevices) API. +If there aren’t any, it will instead “pre-install” the INF using the SetupCopyOEMInf API so that Plug and Play will automatically find a match when +the hardware is subsequently inserted. SetupCopyOEMInf also stores away information that allows Plug and Play to know where the INF came from, thus allowing the Found New Hardware wizard to prompt for media in the correct location if it ever needs to. In this scenario, it is presumed that the user will plug in their toaster upon completion of the wizard, when they’re instructed to do so. As such, they should never actually be prompted to reinsert the CD, since they wouldn’t have removed it. However, if they had removed it, Plug and Play would prompt them to reinsert it. It is possible to “pre-install” all the driver files as well so that the user would never be prompted, even if they did remove the CD. The Windows XP DDK has a discussion of this technique in the section titled “Writing a Device Installation Application” in the Device Installation chapter. + +

+Next, the wizard displays the same value-add software selection page as the user would receive if they’d performed a hardware-first install, as described above. After clicking “Next” on this page, any selected applications are installed (the wizard is hidden while these setup processes run), then the Finish wizard page appears. If the wizard didn’t find any devices during its call to UpdateDriverForPlugAndPlayDevices, it prompts the user to plug in their hardware now. When the user does plug in the hardware (i.e., by typing “enum –p 1” as described above), then the install will proceed without requiring any user interaction. + +

FEEDBACK

+

We welcome your comments, problem reports and wish-list requests. Please + submit them by pointing your Internet browser to http://www.microsoft.com/whdc/default.mspx. +

+ + +

+

© 2005 Microsoft Corporation

+ diff --git a/general/toaster/toastpkg/toastpkg.sln b/general/toaster/toastpkg/toastpkg.sln index 13fee6ef..7fd13435 100644 --- a/general/toaster/toastpkg/toastpkg.sln +++ b/general/toaster/toastpkg/toastpkg.sln @@ -3,19 +3,19 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Toastapp", "Toastapp", "{BFAE4A6A-CD41-4052-AC38-EAC4DB8494DF}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Toastapp", "Toastapp", "{9A41588C-FCFB-4217-9153-99D10B0829EB}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Toastco", "Toastco", "{4C142C9D-56A8-44C0-84F1-D4ABBFA3E9F8}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Toastco", "Toastco", "{F540D936-4986-46C1-94C2-EB4E7172BBEA}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Toastva", "Toastva", "{47FE1DB3-FA82-4F24-96B1-C6798AA08C61}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Toastva", "Toastva", "{E02E6DD1-0612-4CEE-A1F2-566FA71FB390}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "toastapp", "toastapp\toastapp.vcxproj", "{1C818755-28B2-4C84-8623-FF84F3326B64}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "toastapp", "toastapp\toastapp.vcxproj", "{A8A63599-6EC4-4103-93F2-67403B310ECE}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tostrco2", "toastco\tostrco2.vcxproj", "{84F11D30-54EE-479A-8F8A-7FBFA8E6BE22}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tostrco2", "toastco\tostrco2.vcxproj", "{2C6F3F5F-06F7-4F86-8914-DB04CFDD9B19}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "toastva", "toastva\toastva.vcxproj", "{7A49D840-4E82-477B-8105-CF546E4FD034}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "toastva", "toastva\toastva.vcxproj", "{85967D7E-7E0A-4DEC-950F-19C263C05B6A}" ProjectSection(ProjectDependencies) = postProject - {84F11D30-54EE-479A-8F8A-7FBFA8E6BE22} = {84F11D30-54EE-479A-8F8A-7FBFA8E6BE22} + {2C6F3F5F-06F7-4F86-8914-DB04CFDD9B19} = {2C6F3F5F-06F7-4F86-8914-DB04CFDD9B19} EndProjectSection EndProject Global @@ -26,37 +26,37 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {1C818755-28B2-4C84-8623-FF84F3326B64}.Debug|Win32.ActiveCfg = Debug|Win32 - {1C818755-28B2-4C84-8623-FF84F3326B64}.Debug|Win32.Build.0 = Debug|Win32 - {1C818755-28B2-4C84-8623-FF84F3326B64}.Release|Win32.ActiveCfg = Release|Win32 - {1C818755-28B2-4C84-8623-FF84F3326B64}.Release|Win32.Build.0 = Release|Win32 - {1C818755-28B2-4C84-8623-FF84F3326B64}.Debug|x64.ActiveCfg = Debug|x64 - {1C818755-28B2-4C84-8623-FF84F3326B64}.Debug|x64.Build.0 = Debug|x64 - {1C818755-28B2-4C84-8623-FF84F3326B64}.Release|x64.ActiveCfg = Release|x64 - {1C818755-28B2-4C84-8623-FF84F3326B64}.Release|x64.Build.0 = Release|x64 - {84F11D30-54EE-479A-8F8A-7FBFA8E6BE22}.Debug|Win32.ActiveCfg = Debug|Win32 - {84F11D30-54EE-479A-8F8A-7FBFA8E6BE22}.Debug|Win32.Build.0 = Debug|Win32 - {84F11D30-54EE-479A-8F8A-7FBFA8E6BE22}.Release|Win32.ActiveCfg = Release|Win32 - {84F11D30-54EE-479A-8F8A-7FBFA8E6BE22}.Release|Win32.Build.0 = Release|Win32 - {84F11D30-54EE-479A-8F8A-7FBFA8E6BE22}.Debug|x64.ActiveCfg = Debug|x64 - {84F11D30-54EE-479A-8F8A-7FBFA8E6BE22}.Debug|x64.Build.0 = Debug|x64 - {84F11D30-54EE-479A-8F8A-7FBFA8E6BE22}.Release|x64.ActiveCfg = Release|x64 - {84F11D30-54EE-479A-8F8A-7FBFA8E6BE22}.Release|x64.Build.0 = Release|x64 - {7A49D840-4E82-477B-8105-CF546E4FD034}.Debug|Win32.ActiveCfg = Debug|Win32 - {7A49D840-4E82-477B-8105-CF546E4FD034}.Debug|Win32.Build.0 = Debug|Win32 - {7A49D840-4E82-477B-8105-CF546E4FD034}.Release|Win32.ActiveCfg = Release|Win32 - {7A49D840-4E82-477B-8105-CF546E4FD034}.Release|Win32.Build.0 = Release|Win32 - {7A49D840-4E82-477B-8105-CF546E4FD034}.Debug|x64.ActiveCfg = Debug|x64 - {7A49D840-4E82-477B-8105-CF546E4FD034}.Debug|x64.Build.0 = Debug|x64 - {7A49D840-4E82-477B-8105-CF546E4FD034}.Release|x64.ActiveCfg = Release|x64 - {7A49D840-4E82-477B-8105-CF546E4FD034}.Release|x64.Build.0 = Release|x64 + {A8A63599-6EC4-4103-93F2-67403B310ECE}.Debug|Win32.ActiveCfg = Debug|Win32 + {A8A63599-6EC4-4103-93F2-67403B310ECE}.Debug|Win32.Build.0 = Debug|Win32 + {A8A63599-6EC4-4103-93F2-67403B310ECE}.Release|Win32.ActiveCfg = Release|Win32 + {A8A63599-6EC4-4103-93F2-67403B310ECE}.Release|Win32.Build.0 = Release|Win32 + {A8A63599-6EC4-4103-93F2-67403B310ECE}.Debug|x64.ActiveCfg = Debug|x64 + {A8A63599-6EC4-4103-93F2-67403B310ECE}.Debug|x64.Build.0 = Debug|x64 + {A8A63599-6EC4-4103-93F2-67403B310ECE}.Release|x64.ActiveCfg = Release|x64 + {A8A63599-6EC4-4103-93F2-67403B310ECE}.Release|x64.Build.0 = Release|x64 + {2C6F3F5F-06F7-4F86-8914-DB04CFDD9B19}.Debug|Win32.ActiveCfg = Debug|Win32 + {2C6F3F5F-06F7-4F86-8914-DB04CFDD9B19}.Debug|Win32.Build.0 = Debug|Win32 + {2C6F3F5F-06F7-4F86-8914-DB04CFDD9B19}.Release|Win32.ActiveCfg = Release|Win32 + {2C6F3F5F-06F7-4F86-8914-DB04CFDD9B19}.Release|Win32.Build.0 = Release|Win32 + {2C6F3F5F-06F7-4F86-8914-DB04CFDD9B19}.Debug|x64.ActiveCfg = Debug|x64 + {2C6F3F5F-06F7-4F86-8914-DB04CFDD9B19}.Debug|x64.Build.0 = Debug|x64 + {2C6F3F5F-06F7-4F86-8914-DB04CFDD9B19}.Release|x64.ActiveCfg = Release|x64 + {2C6F3F5F-06F7-4F86-8914-DB04CFDD9B19}.Release|x64.Build.0 = Release|x64 + {85967D7E-7E0A-4DEC-950F-19C263C05B6A}.Debug|Win32.ActiveCfg = Debug|Win32 + {85967D7E-7E0A-4DEC-950F-19C263C05B6A}.Debug|Win32.Build.0 = Debug|Win32 + {85967D7E-7E0A-4DEC-950F-19C263C05B6A}.Release|Win32.ActiveCfg = Release|Win32 + {85967D7E-7E0A-4DEC-950F-19C263C05B6A}.Release|Win32.Build.0 = Release|Win32 + {85967D7E-7E0A-4DEC-950F-19C263C05B6A}.Debug|x64.ActiveCfg = Debug|x64 + {85967D7E-7E0A-4DEC-950F-19C263C05B6A}.Debug|x64.Build.0 = Debug|x64 + {85967D7E-7E0A-4DEC-950F-19C263C05B6A}.Release|x64.ActiveCfg = Release|x64 + {85967D7E-7E0A-4DEC-950F-19C263C05B6A}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {1C818755-28B2-4C84-8623-FF84F3326B64} = {BFAE4A6A-CD41-4052-AC38-EAC4DB8494DF} - {84F11D30-54EE-479A-8F8A-7FBFA8E6BE22} = {4C142C9D-56A8-44C0-84F1-D4ABBFA3E9F8} - {7A49D840-4E82-477B-8105-CF546E4FD034} = {47FE1DB3-FA82-4F24-96B1-C6798AA08C61} + {A8A63599-6EC4-4103-93F2-67403B310ECE} = {9A41588C-FCFB-4217-9153-99D10B0829EB} + {2C6F3F5F-06F7-4F86-8914-DB04CFDD9B19} = {F540D936-4986-46C1-94C2-EB4E7172BBEA} + {85967D7E-7E0A-4DEC-950F-19C263C05B6A} = {E02E6DD1-0612-4CEE-A1F2-566FA71FB390} EndGlobalSection EndGlobal diff --git a/general/toaster/toastpkg/toastva/toastva.vcxproj b/general/toaster/toastpkg/toastva/toastva.vcxproj index 1a25ac8c..e9aa4432 100644 --- a/general/toaster/toastpkg/toastva/toastva.vcxproj +++ b/general/toaster/toastpkg/toastva/toastva.vcxproj @@ -19,11 +19,11 @@
- {7A49D840-4E82-477B-8105-CF546E4FD034} + {85967D7E-7E0A-4DEC-950F-19C263C05B6A} $(MSBuildProjectName) Debug Win32 - {2DF87D9A-363B-4C6B-9E31-BE2BF60898DF} + {D7B39220-AA74-4EA0-B07C-59CA1E85D809} diff --git a/general/toaster/toastpkg/toastva/toastva.vcxproj.Filters b/general/toaster/toastpkg/toastva/toastva.vcxproj.Filters index 8ae9e8e3..bc07fd8a 100644 --- a/general/toaster/toastpkg/toastva/toastva.vcxproj.Filters +++ b/general/toaster/toastpkg/toastva/toastva.vcxproj.Filters @@ -3,15 +3,15 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {C874EFAD-3886-466E-97CC-4A852797DC29} + {A355FE6D-8F54-4AE5-BB0A-8097742C6850} h;hpp;hxx;hm;inl;inc;xsd - {4A7A3632-2660-49C4-9B04-6BD51BEA6316} + {D196262B-5F82-4ABA-AC81-0469C32AA57A} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {CDCE6E71-5F53-4E60-99F1-ABD1D5819475} + {2A7EB223-FB84-4B57-A4F3-78C1D05435A6} diff --git a/general/toaster/umdf2/Package/package.VcxProj b/general/toaster/umdf2/Package/package.VcxProj deleted file mode 100644 index d03cefec..00000000 --- a/general/toaster/umdf2/Package/package.VcxProj +++ /dev/null @@ -1,91 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - WindowsKernelModeDriver10.0 - Utility - Package - true - Debug - - - - {52EEA7C4-68B9-4AE9-B3EC-881A49E9E1E5} - {7F090110-1487-4DA8-8CEA-3C1A43F8C119} - $(MSBuildProjectName) - - - Windows10 - true - - - Windows10 - false - - - Windows10 - true - - - Windows10 - false - - - - - - - - - - - DbgengRemoteDebugger - False - None - - - - - - %PathToInf% - False - False - True - - 133563 - - - - - - - - - - {A60F76D2-C512-4DA6-8C80-263F1B506267} - - - {4867F54B-D8EF-45B0-984E-D571D987174A} - - - - - - \ No newline at end of file diff --git a/general/toaster/umdf2/Package/package.VcxProj.Filters b/general/toaster/umdf2/Package/package.VcxProj.Filters deleted file mode 100644 index 8153ab30..00000000 --- a/general/toaster/umdf2/Package/package.VcxProj.Filters +++ /dev/null @@ -1,21 +0,0 @@ - - - - - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {1B3C45DA-0194-4257-B308-970F7B2AB7C0} - - - h;hpp;hxx;hm;inl;inc;xsd - {84FCFB7D-58FA-4617-9482-C1BD332BCC31} - - - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {824C0178-16B0-4768-B411-CE9BDD79D690} - - - inf;inv;inx;mof;mc; - {9C6B14B3-304F-491F-B5F1-C14CA36EC7E8} - - - \ No newline at end of file diff --git a/general/toaster/umdf2/ReadMe.md b/general/toaster/umdf2/ReadMe.md deleted file mode 100644 index 8bd9dada..00000000 --- a/general/toaster/umdf2/ReadMe.md +++ /dev/null @@ -1,58 +0,0 @@ -Toaster Sample (UMDF Version 2) -=============================== - -The Toaster (UMDF version 2) sample is an iterative series of samples that demonstrate fundamental aspects of Windows driver development. - -The Toaster sample collection is comprised of driver projects (.vcxproj files) that are contained in the umdf2toaster.sln solution file. - -For related information, see the [Toaster Sample](http://code.msdn.microsoft.com/windowshardware/Toaster-7d256224). - -## Universal Compliant -This sample builds a Windows Universal driver. It uses only APIs and DDIs that are included in Windows Core. - -Related technologies --------------------- - -[User-Mode Driver Framework](http://msdn.microsoft.com/en-us/library/windows/hardware/ff560456) - -Run the sample --------------- - -The computer where you install the driver is called the *target computer* or the *test computer*. Typically this is a separate computer from where you develop and build the driver package. The computer where you develop and build the driver is called the *host computer*. - -The process of moving the driver package to the target computer and installing the driver is called *deploying the driver*. You can deploy a driver sample automatically or manually. - -### Automatic deployment (root enumerated) - -Before you automatically deploy a driver, you must provision the target computer. For instructions, see [Configuring a Computer for Driver Deployment, Testing, and Debugging](http://msdn.microsoft.com/en-us/library/windows/hardware/). - -1. On the host computer, in Visual Studio, in Solution Explorer, right click **package** (lower case), and choose **Properties**. Navigate to **Configuration Properties \> Driver Install \> Deployment**. -2. Check **Enable deployment**, and check **Remove previous driver versions before deployment**. For **Target Computer Name**, select the name of a target computer that you provisioned previously. Select **Hardware ID Driver Update**, and enter **root\\toaster** for the hardware ID. Click **OK**. -3. Because this solution contains many projects, you may find it easier to remove some of them before you build and deploy a driver package. To do so, right click **package** (lower case), and choose **Properties**. Navigate to **Common Properties-\>References** and click **Remove Reference** to remove projects you don't want. (You can add them back later by using **Add New Reference**.) Click **OK**. -4. On the **Build** menu, choose **Build Solution** or **Rebuild Solution** (if you removed references). -5. If you removed references and deployment does not succeed, try deleting the contents of the c:\\DriverTest\\Drivers folder on the target machine, and then retry deployment. - -### Manual deployment (root enumerated) - -Before you manually deploy a driver, you must turn on test signing and install a certificate on the target computer. You also need to copy the [DevCon](http://msdn.microsoft.com/en-us/library/windows/hardware/ff544707) tool to the target computer. For instructions, see [Preparing a Computer for Manual Driver Deployment](http://msdn.microsoft.com/en-us/library/windows/hardware/dn265571). - -1. Copy all of the files in your driver package to a folder on the target computer (for example, c:\\Umdf2toaster). -2. On the target computer, open a Command Prompt window as Administrator. Navigate to your driver package folder, and enter a command such as: - - **devcon install wdfsimpleum.inf root\\toaster** - -### View the root enumerated driver in Device Manager - -On the target computer, in a Command Prompt window, enter **devmgmt** to open Device Manager. In Device Manager, on the **View** menu, choose **Devices by type**. In the device tree, locate **Sample WDF Toaster Service + Filter** (for example, this might be under the **Toaster** node). - -In Device Manager, on the **View** menu, choose **Devices by connection**. Locate **Sample WDF Toaster Service + Filter** as a child of the root node of the device tree. - -Build the sample using MSBuild ------------------------------- - -As an alternative to building the driver sample in Visual Studio, you can build it in a Visual Studio Command Prompt window. In Visual Studio, on the **Tools** menu, choose **Visual Studio Command Prompt**. In the Visual Studio Command Prompt window, navigate to the folder that has the solution file, Umdf2toaster.sln. Use the MSBuild command to build the solution. Here is an example: - -**msbuild /p:configuration=â€Win8 Release†/p:platform=â€Win32†Umdf2toaster.sln** - -For more information about using MSBuild to build a driver package, see [Building a Driver](http://msdn.microsoft.com/en-us/library/windows/hardware/ff554644). - diff --git a/general/toaster/umdf2/exe/enum/Enum.vcxproj b/general/toaster/umdf2/exe/enum/Enum.vcxproj deleted file mode 100644 index 822a36c7..00000000 --- a/general/toaster/umdf2/exe/enum/Enum.vcxproj +++ /dev/null @@ -1,171 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - {6E1593D4-08A1-45E4-A77F-AF34AC6F0D69} - $(MSBuildProjectName) - Debug - Win32 - {2F2E0D4F-031E-4B76-983A-ED7F18562A15} - - - - Windows10 - False - Desktop - - WindowsApplicationForDrivers10.0 - Application - - - Windows10 - True - Desktop - - WindowsApplicationForDrivers10.0 - Application - - - Windows10 - False - Desktop - - WindowsApplicationForDrivers10.0 - Application - - - Windows10 - True - Desktop - - WindowsApplicationForDrivers10.0 - Application - - - - $(IntDir) - - - - - - - - - - - - - - - - Enum - - - Enum - - - Enum - - - Enum - - - - %(AdditionalIncludeDirectories);..\..\inc - - - %(AdditionalIncludeDirectories);..\..\inc - - - - - %(AdditionalIncludeDirectories);..\..\inc - - - %(AdditionalDependencies);setupapi.lib - - - - - %(AdditionalIncludeDirectories);..\..\inc - - - %(AdditionalIncludeDirectories);..\..\inc - - - - - %(AdditionalIncludeDirectories);..\..\inc - - - %(AdditionalDependencies);setupapi.lib - - - - - %(AdditionalIncludeDirectories);..\..\inc - - - %(AdditionalIncludeDirectories);..\..\inc - - - - - %(AdditionalIncludeDirectories);..\..\inc - - - %(AdditionalDependencies);setupapi.lib - - - - - %(AdditionalIncludeDirectories);..\..\inc - - - %(AdditionalIncludeDirectories);..\..\inc - - - - - %(AdditionalIncludeDirectories);..\..\inc - - - %(AdditionalDependencies);setupapi.lib - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/general/toaster/umdf2/exe/enum/Enum.vcxproj.Filters b/general/toaster/umdf2/exe/enum/Enum.vcxproj.Filters deleted file mode 100644 index c84e1e9f..00000000 --- a/general/toaster/umdf2/exe/enum/Enum.vcxproj.Filters +++ /dev/null @@ -1,22 +0,0 @@ - - - - - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {58C64BCB-5021-4790-BBB0-C1AB7A443B79} - - - h;hpp;hxx;hm;inl;inc;xsd - {17570C2B-4A49-4EB7-9BC8-219A1CDD870D} - - - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {B5B13117-98BA-4E65-833F-2DB49A70E1DF} - - - - - Source Files - - - \ No newline at end of file diff --git a/general/toaster/umdf2/exe/enum/enum.c b/general/toaster/umdf2/exe/enum/enum.c deleted file mode 100644 index ac285115..00000000 --- a/general/toaster/umdf2/exe/enum/enum.c +++ /dev/null @@ -1,317 +0,0 @@ -/*++ - -Copyright (c) Microsoft Corporation. All rights reserved. - - THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY - KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR - PURPOSE. - -Module Name: - - Enum.c - -Abstract: - This application simulates the plugin, unplug or ejection - of devices. - -Environment: - - usermode console application - -Revision History: - - Eliyas Yakub Oct 14, 1998 - - ---*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "public.h" -#include - -// -// Prototypes -// - -BOOLEAN -OpenBusInterface ( - _In_ HDEVINFO HardwareDeviceInfo, - _In_ PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData - ); - - - -#define USAGE \ -"Usage: Enum [-p SerialNo] Plugs in a device. SerialNo must be greater than zero.\n\ - [-u SerialNo or 0] Unplugs device(s) - specify 0 to unplug all \ - the devices enumerated so far.\n\ - [-e SerialNo or 0] Ejects device(s) - specify 0 to eject all \ - the devices enumerated so far.\n" - -BOOLEAN bPlugIn, bUnplug, bEject; -ULONG SerialNo; - -INT __cdecl -main( - _In_ ULONG argc, - _In_reads_(argc) PCHAR argv[] - ) -{ - HDEVINFO hardwareDeviceInfo; - SP_DEVICE_INTERFACE_DATA deviceInterfaceData; - - bPlugIn = bUnplug = bEject = FALSE; - - if(argc <3) { - goto usage; - } - - if(argv[1][0] == '-') { - if(tolower(argv[1][1]) == 'p') { - if(argv[2]) - SerialNo = (USHORT)atol(argv[2]); - bPlugIn = TRUE; - } - else if(tolower(argv[1][1]) == 'u') { - if(argv[2]) - SerialNo = (ULONG)atol(argv[2]); - bUnplug = TRUE; - } - else if(tolower(argv[1][1]) == 'e') { - if(argv[2]) - SerialNo = (ULONG)atol(argv[2]); - bEject = TRUE; - } - else { - goto usage; - } - } - else - goto usage; - - if(bPlugIn && 0 == SerialNo) - goto usage; - // - // Open a handle to the device interface information set of all - // present toaster bus enumerator interfaces. - // - - hardwareDeviceInfo = SetupDiGetClassDevs ( - (LPGUID)&GUID_DEVINTERFACE_BUSENUM_TOASTER, - NULL, // Define no enumerator (global) - NULL, // Define no - (DIGCF_PRESENT | // Only Devices present - DIGCF_DEVICEINTERFACE)); // Function class devices. - - if(INVALID_HANDLE_VALUE == hardwareDeviceInfo) - { - printf("SetupDiGetClassDevs failed: %x\n", GetLastError()); - return 0; - } - - deviceInterfaceData.cbSize = sizeof (SP_DEVICE_INTERFACE_DATA); - - if (SetupDiEnumDeviceInterfaces (hardwareDeviceInfo, - 0, // No care about specific PDOs - (LPGUID)&GUID_DEVINTERFACE_BUSENUM_TOASTER, - 0, // - &deviceInterfaceData)) { - - OpenBusInterface(hardwareDeviceInfo, &deviceInterfaceData); - } else if (ERROR_NO_MORE_ITEMS == GetLastError()) { - - printf( - "Error:Interface GUID_DEVINTERFACE_BUSENUM_TOASTER is not registered\n"); - } - - SetupDiDestroyDeviceInfoList (hardwareDeviceInfo); - return 0; -usage: - printf(USAGE); - exit(0); -} - -BOOLEAN -OpenBusInterface ( - _In_ HDEVINFO HardwareDeviceInfo, - _In_ PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData - ) -{ - HANDLE file; - PSP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailData = NULL; - ULONG predictedLength = 0; - ULONG requiredLength = 0; - ULONG bytes; - BUSENUM_UNPLUG_HARDWARE unplug; - BUSENUM_EJECT_HARDWARE eject; - PBUSENUM_PLUGIN_HARDWARE hardware; - BOOLEAN bSuccess; - - // - // Allocate a function class device data structure to receive the - // information about this particular device. - // - - SetupDiGetDeviceInterfaceDetail ( - HardwareDeviceInfo, - DeviceInterfaceData, - NULL, // probing so no output buffer yet - 0, // probing so output buffer length of zero - &requiredLength, - NULL); // not interested in the specific dev-node - - if(ERROR_INSUFFICIENT_BUFFER != GetLastError()) { - printf("Error in SetupDiGetDeviceInterfaceDetail%d\n", - GetLastError()); - return FALSE; - } - - predictedLength = requiredLength; - - deviceInterfaceDetailData = malloc (predictedLength); - - if(deviceInterfaceDetailData) { - deviceInterfaceDetailData->cbSize = - sizeof (SP_DEVICE_INTERFACE_DETAIL_DATA); - } else { - printf("Couldn't allocate %d bytes for device interface details.\n", predictedLength); - return FALSE; - } - - - if (! SetupDiGetDeviceInterfaceDetail ( - HardwareDeviceInfo, - DeviceInterfaceData, - deviceInterfaceDetailData, - predictedLength, - &requiredLength, - NULL)) { - printf("Error in SetupDiGetDeviceInterfaceDetail\n"); - free (deviceInterfaceDetailData); - return FALSE; - } - - printf("Opening %s\n", deviceInterfaceDetailData->DevicePath); - - file = CreateFile ( deviceInterfaceDetailData->DevicePath, - GENERIC_READ, // Only read access - 0, // FILE_SHARE_READ | FILE_SHARE_WRITE - NULL, // no SECURITY_ATTRIBUTES structure - OPEN_EXISTING, // No special create flags - 0, // No special attributes - NULL); // No template file - - if (INVALID_HANDLE_VALUE == file) { - printf("CreateFile failed: 0x%x", GetLastError()); - free (deviceInterfaceDetailData); - return FALSE; - } - - printf("Bus interface opened!!!\n"); - - // - // From this point on, we need to jump to the end of the routine for - // common clean-up. Keep track of whether we succeeded or failed, so - // we'll know what to return to the caller. - // - bSuccess = FALSE; - - // - // Enumerate Devices - // - - if(bPlugIn) { - - printf("SerialNo. of the device to be enumerated: %d\n", SerialNo); - - hardware = malloc (bytes = (sizeof (BUSENUM_PLUGIN_HARDWARE) + - BUS_HARDWARE_IDS_LENGTH)); - - if(hardware) { - hardware->Size = sizeof (BUSENUM_PLUGIN_HARDWARE); - hardware->SerialNo = SerialNo; - } else { - printf("Couldn't allocate %d bytes for busenum plugin hardware structure.\n", bytes); - goto End; - } - - // - // Allocate storage for the Device ID - // - - memcpy (hardware->HardwareIDs, - BUS_HARDWARE_IDS, - BUS_HARDWARE_IDS_LENGTH); - - if (!DeviceIoControl (file, - IOCTL_BUSENUM_PLUGIN_HARDWARE , - hardware, bytes, - NULL, 0, - &bytes, NULL)) { - free (hardware); - printf("PlugIn failed:0x%x\n", GetLastError()); - goto End; - } - - free (hardware); - } - - // - // Removes a device if given the specific Id of the device. Otherwise this - // ioctls removes all the devices that are enumerated so far. - // - - if(bUnplug) { - printf("Unplugging device(s)....\n"); - - unplug.Size = bytes = sizeof (unplug); - unplug.SerialNo = SerialNo; - if (!DeviceIoControl (file, - IOCTL_BUSENUM_UNPLUG_HARDWARE, - &unplug, bytes, - NULL, 0, - &bytes, NULL)) { - printf("Unplug failed: 0x%x\n", GetLastError()); - goto End; - } - } - - // - // Ejects a device if given the specific Id of the device. Otherwise this - // ioctls ejects all the devices that are enumerated so far. - // - - if(bEject) - { - printf("Ejecting Device(s)\n"); - - eject.Size = bytes = sizeof (eject); - eject.SerialNo = SerialNo; - if (!DeviceIoControl (file, - IOCTL_BUSENUM_EJECT_HARDWARE, - &eject, bytes, - NULL, 0, - &bytes, NULL)) { - printf("Eject failed: 0x%x\n", GetLastError()); - goto End; - } - } - - printf("Success!!!\n"); - bSuccess = TRUE; - -End: - CloseHandle(file); - free (deviceInterfaceDetailData); - return bSuccess; -} - - diff --git a/general/toaster/umdf2/exe/notify/notify.c b/general/toaster/umdf2/exe/notify/notify.c deleted file mode 100644 index 3362ce3d..00000000 --- a/general/toaster/umdf2/exe/notify/notify.c +++ /dev/null @@ -1,1244 +0,0 @@ -/*++ - -Copyright (c) Microsoft Corporation. All rights reserved. - - THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY - KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR - PURPOSE. - -Module Name: notify.c - - -Abstract: - - -Author: - - Eliyas Yakub Nov 23, 1999 - -Environment: - - User mode only. - -Revision History: - - Modified to use linked list for deviceInfo - instead of arrays. (5/12/2000) - ---*/ -#define UNICODE -#define _UNICODE -#define INITGUID - -// -// Annotation to indicate to prefast that this is nondriver user-mode code. -// -#include -_Analysis_mode_(_Analysis_code_type_user_code_) - -#include -#include -#include -#include -#include -#include -#include -#include "public.h" -#include "notify.h" -#include - -BOOL -HandlePowerBroadcast( - HWND hWnd, - WPARAM wParam, - LPARAM lParam); - -// -// Global variables -// -HINSTANCE hInst; -HWND hWndList; -TCHAR szTitle[]=TEXT("Toaster Package Test Application"); -LIST_ENTRY ListHead; -HDEVNOTIFY hInterfaceNotification; -TCHAR OutText[500]; -UINT ListBoxIndex = 0; -GUID InterfaceGuid;// = GUID_DEVINTERFACE_TOASTER; -BOOLEAN Verbose= FALSE; - -_inline BOOLEAN -IsValid( - ULONG No - ) -{ - PLIST_ENTRY thisEntry; - PDEVICE_INFO deviceInfo; - - if(0==(No)) return TRUE; //special case - - for(thisEntry = ListHead.Flink; thisEntry != &ListHead; - thisEntry = thisEntry->Flink) - { - deviceInfo = CONTAINING_RECORD(thisEntry, DEVICE_INFO, ListEntry); - if((No) == deviceInfo->SerialNo) { - return TRUE; - } - } - return FALSE; -} - -VOID -Display( - _In_ LPWSTR pstrFormat, // @parm A printf style format string - ... // @parm | ... | Variable paramters based on

- ) -{ - HRESULT hr; - va_list va; - - va_start(va, pstrFormat); - // - // Truncation is acceptable. - // - hr = StringCbVPrintf(OutText, sizeof(OutText)-sizeof(WCHAR), pstrFormat, va); - va_end(va); - - if(FAILED(hr)){ - return; - } - - SendMessage(hWndList, LB_INSERTSTRING, ListBoxIndex, (LPARAM)OutText); - SendMessage(hWndList, LB_SETCURSEL, ListBoxIndex, 0); - ListBoxIndex++; - -} - -VOID -DisplayV( - _In_ LPWSTR pstrFormat, // @parm A printf style format string - ... // @parm | ... | Variable paramters based on

- ) -{ - va_list va; - - if (Verbose) - { - va_start(va, pstrFormat); - Display(pstrFormat, va); - va_end(va); - } -} -int PASCAL -WinMain ( - _In_ HINSTANCE hInstance, - _In_opt_ HINSTANCE hPrevInstance, - _In_ LPSTR lpCmdLine, - _In_ int nShowCmd - ) -{ - static TCHAR szAppName[]=TEXT("Toaster Notify"); - HWND hWnd; - MSG msg; - WNDCLASS wndclass; - - UNREFERENCED_PARAMETER( lpCmdLine ); - - InterfaceGuid = GUID_DEVINTERFACE_TOASTER; - hInst=hInstance; - - if (!hPrevInstance) - { - wndclass.style = CS_HREDRAW | CS_VREDRAW; - wndclass.lpfnWndProc = WndProc; - wndclass.cbClsExtra = 0; - wndclass.cbWndExtra = 0; - wndclass.hInstance = hInstance; - wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION); - wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); - wndclass.hbrBackground= GetStockObject(WHITE_BRUSH); - wndclass.lpszMenuName = TEXT("GenericMenu"); - wndclass.lpszClassName= szAppName; - - RegisterClass(&wndclass); - } - - hWnd = CreateWindow (szAppName, - szTitle, - WS_OVERLAPPEDWINDOW, - CW_USEDEFAULT, - CW_USEDEFAULT, - CW_USEDEFAULT, - CW_USEDEFAULT, - NULL, - NULL, - hInstance, - NULL); - - ShowWindow (hWnd, nShowCmd); - UpdateWindow(hWnd); - - while (GetMessage (&msg, NULL, 0,0)) - { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - - return (0); -} - - -LRESULT -FAR PASCAL -WndProc ( - HWND hWnd, - UINT message, - WPARAM wParam, - LPARAM lParam - ) -{ - DWORD nEventType = (DWORD)wParam; - PDEV_BROADCAST_HDR p = (PDEV_BROADCAST_HDR) lParam; - DEV_BROADCAST_DEVICEINTERFACE filter; - - switch (message) - { - - case WM_COMMAND: - HandleCommands(hWnd, message, wParam, lParam); - return 0; - - case WM_CREATE: - - // - // Load and set the icon of the program - // - SetClassLongPtr(hWnd, GCLP_HICON, - (LONG_PTR)LoadIcon((HINSTANCE)lParam,MAKEINTRESOURCE(IDI_CLASS_ICON))); - - hWndList = CreateWindow (TEXT("listbox"), - NULL, - WS_CHILD|WS_VISIBLE|LBS_NOTIFY | - WS_VSCROLL | WS_BORDER, - CW_USEDEFAULT, - CW_USEDEFAULT, - CW_USEDEFAULT, - CW_USEDEFAULT, - hWnd, - (HMENU)ID_EDIT, - hInst, - NULL); - - filter.dbcc_size = sizeof(filter); - filter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; - filter.dbcc_classguid = InterfaceGuid; - hInterfaceNotification = RegisterDeviceNotification(hWnd, &filter, 0); - - InitializeListHead(&ListHead); - EnumExistingDevices(hWnd); - - return 0; - - case WM_SIZE: - - MoveWindow(hWndList, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE); - return 0; - - case WM_SETFOCUS: - SetFocus(hWndList); - return 0; - - case WM_DEVICECHANGE: - - // - // The DBT_DEVNODES_CHANGED broadcast message is sent - // everytime a device is added or removed. This message - // is typically handled by Device Manager kind of apps, - // which uses it to refresh window whenever something changes. - // The lParam is always NULL in this case. - // - if(DBT_DEVNODES_CHANGED == wParam) { - DisplayV(TEXT("Received DBT_DEVNODES_CHANGED broadcast message")); - return 0; - } - - // - // All the events we're interested in come with lParam pointing to - // a structure headed by a DEV_BROADCAST_HDR. This is denoted by - // bit 15 of wParam being set, and bit 14 being clear. - // - if((wParam & 0xC000) == 0x8000) { - - if (!p) - return 0; - - if (p->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) { - - HandleDeviceInterfaceChange(hWnd, nEventType, (PDEV_BROADCAST_DEVICEINTERFACE) p); - } else if (p->dbch_devicetype == DBT_DEVTYP_HANDLE) { - - HandleDeviceChange(hWnd, nEventType, (PDEV_BROADCAST_HANDLE) p); - } - } - return 0; - - case WM_POWERBROADCAST: - HandlePowerBroadcast(hWnd, wParam, lParam); - return 0; - - case WM_CLOSE: - Cleanup(hWnd); - UnregisterDeviceNotification(hInterfaceNotification); - return DefWindowProc(hWnd,message, wParam, lParam); - - case WM_DESTROY: - PostQuitMessage(0); - return 0; - } - return DefWindowProc(hWnd,message, wParam, lParam); - } - - -LRESULT -HandleCommands( - HWND hWnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam - ) - -{ - PDIALOG_RESULT result = NULL; - - UNREFERENCED_PARAMETER( uMsg ); - UNREFERENCED_PARAMETER( lParam ); - - switch (wParam) { - - case IDM_OPEN: - Cleanup(hWnd); // close all open handles - EnumExistingDevices(hWnd); - break; - - case IDM_CLOSE: - Cleanup(hWnd); - break; - - case IDM_HIDE: - result = (PDIALOG_RESULT)DialogBox(hInst, MAKEINTRESOURCE(IDD_DIALOG1), hWnd, DlgProc); - if(result && result->SerialNo && IsValid(result->SerialNo)) { - DWORD bytes; - PDEVICE_INFO deviceInfo = NULL; - PLIST_ENTRY thisEntry; - - // - // Find out the deviceInfo that matches this SerialNo. - // We need the deviceInfo to get the handle to the device. - // - for(thisEntry = ListHead.Flink; thisEntry != &ListHead; - thisEntry = thisEntry->Flink) - { - deviceInfo = CONTAINING_RECORD(thisEntry, DEVICE_INFO, ListEntry); - if(result->SerialNo == deviceInfo->SerialNo) { - break; - } - deviceInfo = NULL; - } - - // - // If found send I/O control - // - - if (deviceInfo && !DeviceIoControl (deviceInfo->hDevice, - IOCTL_TOASTER_DONT_DISPLAY_IN_UI_DEVICE, - NULL, 0, - NULL, 0, - &bytes, NULL)) { - MessageBox(hWnd, TEXT("Request Failed or Invalid Serial No"), - TEXT("Error"), MB_OK); - } - } - break; - case IDM_PLUGIN: - - result = (PDIALOG_RESULT)DialogBox(hInst, MAKEINTRESOURCE(IDD_DIALOG), hWnd, DlgProc); - if(result) { - if(!result->SerialNo || !OpenBusInterface(result->SerialNo, result->DeviceId, PLUGIN)){ - MessageBox(hWnd, TEXT("Invalid Serial Number or OpenBusInterface Failed"), TEXT("Error"), MB_OK); - } - } - break; - case IDM_UNPLUG: - result = (PDIALOG_RESULT)DialogBox(hInst, MAKEINTRESOURCE(IDD_DIALOG1), hWnd, DlgProc); - - if(result && IsValid(result->SerialNo)) { - if(!OpenBusInterface(result->SerialNo, NULL, UNPLUG)) { - MessageBox(hWnd, TEXT("Invalid Serial Number or OpenBusInterface Failed"), TEXT("Error"), MB_OK); - } - } - break; - case IDM_EJECT: - result = (PDIALOG_RESULT)DialogBox(hInst, MAKEINTRESOURCE(IDD_DIALOG1), hWnd, DlgProc); - if(result && IsValid(result->SerialNo)) { - if(!OpenBusInterface(result->SerialNo, NULL, EJECT)) { - MessageBox(hWnd, TEXT("Invalid Serial Number or OpenBusInterface Failed"), TEXT("Error"), MB_OK); - } - } - break; - - case IDM_CLEAR: - SendMessage(hWndList, LB_RESETCONTENT, 0, 0); - ListBoxIndex = 0; - break; - - case IDM_IOCTL: - SendIoctlToFilterDevice(); - break; - - case IDM_VERBOSE: { - - HMENU hMenu = GetMenu(hWnd); - Verbose = !Verbose; - if(Verbose) { - CheckMenuItem(hMenu, (UINT)wParam, MF_CHECKED); - } else { - CheckMenuItem(hMenu, (UINT)wParam, MF_UNCHECKED); - } - } - break; - - case IDM_EXIT: - PostQuitMessage(0); - break; - - default: - break; - } - - if(result) { - HeapFree (GetProcessHeap(), 0, result); - } - return TRUE; -} - -INT_PTR CALLBACK -DlgProc( - HWND hDlg, - UINT message, - WPARAM wParam, - LPARAM lParam -) -{ - BOOL success; - PDIALOG_RESULT dialogResult = NULL; - - UNREFERENCED_PARAMETER( lParam ); - - switch(message) - { - case WM_INITDIALOG: - SetDlgItemText(hDlg, IDC_DEVICEID, BUS_HARDWARE_IDS); - return TRUE; - - case WM_COMMAND: - switch( wParam) - { - case ID_OK: - dialogResult = HeapAlloc(GetProcessHeap(), - HEAP_ZERO_MEMORY, - (sizeof(DIALOG_RESULT) + MAX_PATH * sizeof(WCHAR))); - if(dialogResult) { - dialogResult->DeviceId = (PWCHAR)((PCHAR)dialogResult + sizeof(DIALOG_RESULT)); - dialogResult->SerialNo = GetDlgItemInt(hDlg,IDC_SERIALNO, &success, FALSE ); - GetDlgItemText(hDlg, IDC_DEVICEID, dialogResult->DeviceId, MAX_PATH-1 ); - } - EndDialog(hDlg, (UINT_PTR)dialogResult); - return TRUE; - case ID_CANCEL: - EndDialog(hDlg, 0); - return TRUE; - - } - break; - - } - return FALSE; -} - - -BOOL -HandleDeviceInterfaceChange( - HWND hWnd, - DWORD evtype, - PDEV_BROADCAST_DEVICEINTERFACE dip - ) -{ - DEV_BROADCAST_HANDLE filter; - PDEVICE_INFO deviceInfo = NULL; - HRESULT hr; - - switch (evtype) - { - case DBT_DEVICEARRIVAL: - // - // New device arrived. Open handle to the device - // and register notification of type DBT_DEVTYP_HANDLE - // - - deviceInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DEVICE_INFO)); - if(!deviceInfo) - return FALSE; - - InitializeListHead(&deviceInfo->ListEntry); - InsertTailList(&ListHead, &deviceInfo->ListEntry); - - - if(!GetDeviceDescription(dip->dbcc_name, - (PBYTE)deviceInfo->DeviceName, - sizeof(deviceInfo->DeviceName), - &deviceInfo->SerialNo)) { - MessageBox(hWnd, TEXT("GetDeviceDescription failed"), TEXT("Error!"), MB_OK); - } - - Display(TEXT("New device Arrived (Interface Change Notification): %ws"), - deviceInfo->DeviceName); - - hr = StringCchCopy(deviceInfo->DevicePath, MAX_PATH, dip->dbcc_name); - if(FAILED(hr)){ - // DeviceInfo will be freed later by the cleanup routine. - break; - } - - deviceInfo->hDevice = CreateFile(dip->dbcc_name, - GENERIC_READ |GENERIC_WRITE, 0, NULL, - OPEN_EXISTING, 0, NULL); - if(deviceInfo->hDevice == INVALID_HANDLE_VALUE) { - Display(TEXT("Failed to open the device: %ws"), deviceInfo->DeviceName); - break; - } - - Display(TEXT("Opened handled to the device: %ws"), deviceInfo->DeviceName); - memset (&filter, 0, sizeof(filter)); //zero the structure - filter.dbch_size = sizeof(filter); - filter.dbch_devicetype = DBT_DEVTYP_HANDLE; - filter.dbch_handle = deviceInfo->hDevice; - - deviceInfo->hHandleNotification = - RegisterDeviceNotification(hWnd, &filter, 0); - break; - - case DBT_DEVICEREMOVECOMPLETE: - Display(TEXT("Remove Complete (Interface Change Notification)")); - break; - - // - // Device Removed. - // - - default: - Display(TEXT("Unknown (Interface Change Notification)")); - break; - } - return TRUE; -} - -BOOL -HandleDeviceChange( - HWND hWnd, - DWORD evtype, - PDEV_BROADCAST_HANDLE dhp - ) -{ - DEV_BROADCAST_HANDLE filter; - PDEVICE_INFO deviceInfo = NULL; - PLIST_ENTRY thisEntry; - - // - // Walk the list to get the deviceInfo for this device - // by matching the handle given in the notification. - // - for(thisEntry = ListHead.Flink; thisEntry != &ListHead; - thisEntry = thisEntry->Flink) - { - deviceInfo = CONTAINING_RECORD(thisEntry, DEVICE_INFO, ListEntry); - if(dhp->dbch_hdevnotify == deviceInfo->hHandleNotification) { - break; - } - deviceInfo = NULL; - } - - if(!deviceInfo) { - Display(TEXT("Error: spurious message, Event Type %x, Device Type %x"), - evtype, dhp->dbch_devicetype); - return FALSE; - } - - switch (evtype) - { - - case DBT_DEVICEQUERYREMOVE: - - Display(TEXT("Query Remove (Handle Notification)"), deviceInfo->DeviceName); - - // User is trying to disable, uninstall, or eject our device. - // Close the handle to the device so that the target device can - // get removed. Do not unregister the notification - // at this point, because we want to know whether - // the device is successfully removed or not. - // - if (deviceInfo->hDevice != INVALID_HANDLE_VALUE) { - - CloseHandle(deviceInfo->hDevice); - deviceInfo->hDevice = INVALID_HANDLE_VALUE; - Display(TEXT("Closed handle to device %ws"), deviceInfo->DeviceName ); - } - break; - - case DBT_DEVICEREMOVECOMPLETE: - - Display(TEXT("Remove Complete (Handle Notification):%ws"), - deviceInfo->DeviceName); - // - // Device is getting surprise removed. So close - // the handle to device and unregister the PNP notification. - // - - if (deviceInfo->hHandleNotification) { - UnregisterDeviceNotification(deviceInfo->hHandleNotification); - deviceInfo->hHandleNotification = NULL; - } - if (deviceInfo->hDevice != INVALID_HANDLE_VALUE) { - - CloseHandle(deviceInfo->hDevice); - deviceInfo->hDevice = INVALID_HANDLE_VALUE; - Display(TEXT("Closed handle to device %ws"), deviceInfo->DeviceName ); - } - // - // Unlink this deviceInfo from the list and free the memory - // - RemoveEntryList(&deviceInfo->ListEntry); - HeapFree (GetProcessHeap(), 0, deviceInfo); - - break; - - case DBT_DEVICEREMOVEPENDING: - - Display(TEXT("Remove Pending (Handle Notification):%ws"), - deviceInfo->DeviceName); - // - // Device is successfully removed so unregister the notification - // and free the memory. - // - if (deviceInfo->hHandleNotification) { - UnregisterDeviceNotification(deviceInfo->hHandleNotification); - deviceInfo->hHandleNotification = NULL; - deviceInfo->hDevice = INVALID_HANDLE_VALUE; - } - // - // Unlink this deviceInfo from the list and free the memory - // - RemoveEntryList(&deviceInfo->ListEntry); - HeapFree (GetProcessHeap(), 0, deviceInfo); - - break; - - case DBT_DEVICEQUERYREMOVEFAILED : - Display(TEXT("Remove failed (Handle Notification):%ws"), - deviceInfo->DeviceName); - // - // Remove failed. So reopen the device and register for - // notification on the new handle. But first we should unregister - // the previous notification. - // - if (deviceInfo->hHandleNotification) { - UnregisterDeviceNotification(deviceInfo->hHandleNotification); - deviceInfo->hHandleNotification = NULL; - } - deviceInfo->hDevice = CreateFile(deviceInfo->DevicePath, - GENERIC_READ | GENERIC_WRITE, - 0, NULL, OPEN_EXISTING, 0, NULL); - if(deviceInfo->hDevice == INVALID_HANDLE_VALUE) { - Display(TEXT("Failed to reopen the device: %ws"), - deviceInfo->DeviceName); - HeapFree (GetProcessHeap(), 0, deviceInfo); - break; - } - - // - // Register handle based notification to receive pnp - // device change notification on the handle. - // - memset (&filter, 0, sizeof(filter)); //zero the structure - filter.dbch_size = sizeof(filter); - filter.dbch_devicetype = DBT_DEVTYP_HANDLE; - filter.dbch_handle = deviceInfo->hDevice; - - deviceInfo->hHandleNotification = - RegisterDeviceNotification(hWnd, &filter, 0); - Display(TEXT("Reopened device %ws"), deviceInfo->DeviceName); - break; - - default: - Display(TEXT("Unknown (Handle Notification)"), deviceInfo->DeviceName); - break; - - } - return TRUE; -} - - -BOOLEAN -EnumExistingDevices( - HWND hWnd -) -{ - HDEVINFO hardwareDeviceInfo; - SP_DEVICE_INTERFACE_DATA deviceInterfaceData; - PSP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailData = NULL; - ULONG predictedLength = 0; - ULONG requiredLength = 0; - DWORD error; - DEV_BROADCAST_HANDLE filter; - PDEVICE_INFO deviceInfo =NULL; - UINT i=0; - HRESULT hr; - - hardwareDeviceInfo = SetupDiGetClassDevs ( - (LPGUID)&InterfaceGuid, - NULL, // Define no enumerator (global) - NULL, // Define no - (DIGCF_PRESENT | // Only Devices present - DIGCF_DEVICEINTERFACE)); // Function class devices. - if(INVALID_HANDLE_VALUE == hardwareDeviceInfo) - { - goto Error; - } - - // - // Enumerate devices of toaster class - // - deviceInterfaceData.cbSize = sizeof(deviceInterfaceData); - - for(i=0; SetupDiEnumDeviceInterfaces (hardwareDeviceInfo, - 0, // No care about specific PDOs - (LPGUID)&InterfaceGuid, - i, // - &deviceInterfaceData); i++ ) { - - // - // Allocate a function class device data structure to - // receive the information about this particular device. - // - - // - // First find out required length of the buffer - // - if(deviceInterfaceDetailData) - { - HeapFree (GetProcessHeap(), 0, deviceInterfaceDetailData); - deviceInterfaceDetailData = NULL; - } - - if(!SetupDiGetDeviceInterfaceDetail ( - hardwareDeviceInfo, - &deviceInterfaceData, - NULL, // probing so no output buffer yet - 0, // probing so output buffer length of zero - &requiredLength, - NULL) && (error = GetLastError()) != ERROR_INSUFFICIENT_BUFFER) - { - goto Error; - } - predictedLength = requiredLength; - - deviceInterfaceDetailData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, - predictedLength); - if (deviceInterfaceDetailData == NULL) { - goto Error; - } - deviceInterfaceDetailData->cbSize = - sizeof (SP_DEVICE_INTERFACE_DETAIL_DATA); - - - if (! SetupDiGetDeviceInterfaceDetail ( - hardwareDeviceInfo, - &deviceInterfaceData, - deviceInterfaceDetailData, - predictedLength, - &requiredLength, - NULL)) { - goto Error; - } - - deviceInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof(DEVICE_INFO)); - if (deviceInfo == NULL) { - goto Error; - } - - InitializeListHead(&deviceInfo->ListEntry); - InsertTailList(&ListHead, &deviceInfo->ListEntry); - - // - // Get the device details such as friendly name and SerialNo - // - if(!GetDeviceDescription(deviceInterfaceDetailData->DevicePath, - (PBYTE)deviceInfo->DeviceName, - sizeof(deviceInfo->DeviceName), - &deviceInfo->SerialNo)){ - goto Error; - } - - Display(TEXT("Found device %ws"), deviceInfo->DeviceName ); - - hr = StringCchCopy(deviceInfo->DevicePath, MAX_PATH, deviceInterfaceDetailData->DevicePath); - if(FAILED(hr)){ - goto Error; - } - // - // Open an handle to the device. - // - deviceInfo->hDevice = CreateFile ( - deviceInterfaceDetailData->DevicePath, - GENERIC_READ | GENERIC_WRITE, - 0, - NULL, // no SECURITY_ATTRIBUTES structure - OPEN_EXISTING, // No special create flags - 0, // No special attributes - NULL); - - if (INVALID_HANDLE_VALUE == deviceInfo->hDevice) { - Display(TEXT("Failed to open the device: %ws"), deviceInfo->DeviceName); - continue; - } - - Display(TEXT("Opened handled to the device: %ws"), deviceInfo->DeviceName); - // - // Register handle based notification to receive pnp - // device change notification on the handle. - // - - memset (&filter, 0, sizeof(filter)); //zero the structure - filter.dbch_size = sizeof(filter); - filter.dbch_devicetype = DBT_DEVTYP_HANDLE; - filter.dbch_handle = deviceInfo->hDevice; - - deviceInfo->hHandleNotification = RegisterDeviceNotification(hWnd, &filter, 0); - - } - - if(deviceInterfaceDetailData) - HeapFree (GetProcessHeap(), 0, deviceInterfaceDetailData); - - SetupDiDestroyDeviceInfoList (hardwareDeviceInfo); - return 0; - -Error: - - MessageBox(hWnd, TEXT("EnumExisting Devices failed"), TEXT("Error!"), MB_OK); - if(deviceInterfaceDetailData) - HeapFree (GetProcessHeap(), 0, deviceInterfaceDetailData); - - SetupDiDestroyDeviceInfoList (hardwareDeviceInfo); - Cleanup(hWnd); - return 0; -} - -BOOLEAN Cleanup(HWND hWnd) -{ - PDEVICE_INFO deviceInfo =NULL; - PLIST_ENTRY thisEntry; - - UNREFERENCED_PARAMETER( hWnd ); - - while (!IsListEmpty(&ListHead)) { - thisEntry = RemoveHeadList(&ListHead); - deviceInfo = CONTAINING_RECORD(thisEntry, DEVICE_INFO, ListEntry); - if (deviceInfo->hHandleNotification) { - UnregisterDeviceNotification(deviceInfo->hHandleNotification); - deviceInfo->hHandleNotification = NULL; - } - if (deviceInfo->hDevice != INVALID_HANDLE_VALUE && - deviceInfo->hDevice != NULL) { - CloseHandle(deviceInfo->hDevice); - deviceInfo->hDevice = INVALID_HANDLE_VALUE; - Display(TEXT("Closed handle to device %ws"), deviceInfo->DeviceName ); - } - HeapFree (GetProcessHeap(), 0, deviceInfo); - } - return TRUE; -} - - -BOOL -GetDeviceDescription( - _In_ LPTSTR DevPath, - _Out_writes_bytes_(OutBufferLen) PBYTE OutBuffer, - _In_ ULONG OutBufferLen, - _In_ PULONG SerialNo -) -{ - HDEVINFO hardwareDeviceInfo; - SP_DEVICE_INTERFACE_DATA deviceInterfaceData; - SP_DEVINFO_DATA deviceInfoData; - DWORD dwRegType, error; - - hardwareDeviceInfo = SetupDiCreateDeviceInfoList(NULL, NULL); - if(INVALID_HANDLE_VALUE == hardwareDeviceInfo) - { - goto Error; - } - - // - // Enumerate devices of toaster class - // - deviceInterfaceData.cbSize = sizeof(deviceInterfaceData); - - SetupDiOpenDeviceInterface (hardwareDeviceInfo, DevPath, - 0, // - &deviceInterfaceData); - - deviceInfoData.cbSize = sizeof(deviceInfoData); - if(!SetupDiGetDeviceInterfaceDetail ( - hardwareDeviceInfo, - &deviceInterfaceData, - NULL, // probing so no output buffer yet - 0, // probing so output buffer length of zero - NULL, - &deviceInfoData) && (error = GetLastError()) != ERROR_INSUFFICIENT_BUFFER) - { - goto Error; - } - // - // Get the friendly name for this instance, if that fails - // try to get the device description. - // - - if(!SetupDiGetDeviceRegistryProperty(hardwareDeviceInfo, &deviceInfoData, - SPDRP_FRIENDLYNAME, - &dwRegType, - OutBuffer, - OutBufferLen, - NULL)) - { - if(!SetupDiGetDeviceRegistryProperty(hardwareDeviceInfo, &deviceInfoData, - SPDRP_DEVICEDESC, - &dwRegType, - OutBuffer, - OutBufferLen, - NULL)){ - goto Error; - - } - - - } - - // - // Get the serial number of the device. The bus driver reports - // the device serial number as UINumber in the devcaps. - // - if(!SetupDiGetDeviceRegistryProperty(hardwareDeviceInfo, - &deviceInfoData, - SPDRP_UI_NUMBER, - &dwRegType, - (BYTE*) SerialNo, - sizeof(ULONG), - NULL)) { - Display(TEXT("SerialNo is not available for device: %ws"), OutBuffer ); - } - - - SetupDiDestroyDeviceInfoList (hardwareDeviceInfo); - return TRUE; - -Error: - - SetupDiDestroyDeviceInfoList (hardwareDeviceInfo); - return FALSE; -} - - - -BOOLEAN -OpenBusInterface ( - _In_ ULONG SerialNo, - _When_ (Action == PLUGIN, _In_) LPWSTR DeviceId, - _In_ USER_ACTION_TYPE Action - ) -{ - HANDLE hDevice=INVALID_HANDLE_VALUE; - PSP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailData = NULL; - ULONG predictedLength = 0; - ULONG requiredLength = 0; - ULONG bytes; - BUSENUM_UNPLUG_HARDWARE unplug; - BUSENUM_EJECT_HARDWARE eject; - PBUSENUM_PLUGIN_HARDWARE hardware; - HDEVINFO hardwareDeviceInfo; - SP_DEVICE_INTERFACE_DATA deviceInterfaceData; - BOOLEAN status = FALSE; - HRESULT hr; - // - // Open a handle to the device interface information set of all - // present toaster bus enumerator interfaces. - // - - hardwareDeviceInfo = SetupDiGetClassDevs ( - (LPGUID)&GUID_DEVINTERFACE_BUSENUM_TOASTER, - NULL, // Define no enumerator (global) - NULL, // Define no - (DIGCF_PRESENT | // Only Devices present - DIGCF_DEVICEINTERFACE)); // Function class devices. - - if(INVALID_HANDLE_VALUE == hardwareDeviceInfo) - { - return FALSE; - } - - deviceInterfaceData.cbSize = sizeof (SP_DEVICE_INTERFACE_DATA); - - if (!SetupDiEnumDeviceInterfaces (hardwareDeviceInfo, - 0, // No care about specific PDOs - (LPGUID)&GUID_DEVINTERFACE_BUSENUM_TOASTER, - 0, // - &deviceInterfaceData)) { - goto Clean0; - } - - // - // Allocate a function class device data structure to receive the - // information about this particular device. - // - - SetupDiGetDeviceInterfaceDetail ( - hardwareDeviceInfo, - &deviceInterfaceData, - NULL, // probing so no output buffer yet - 0, // probing so output buffer length of zero - &requiredLength, - NULL);//not interested in the specific dev-node - - if(ERROR_INSUFFICIENT_BUFFER != GetLastError()) { - goto Clean0; - } - - - predictedLength = requiredLength; - - deviceInterfaceDetailData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, - predictedLength); - - if(deviceInterfaceDetailData) { - deviceInterfaceDetailData->cbSize = - sizeof (SP_DEVICE_INTERFACE_DETAIL_DATA); - } else { - goto Clean0; - } - - - if (! SetupDiGetDeviceInterfaceDetail ( - hardwareDeviceInfo, - &deviceInterfaceData, - deviceInterfaceDetailData, - predictedLength, - &requiredLength, - NULL)) { - goto Clean1; - } - - - hDevice = CreateFile ( deviceInterfaceDetailData->DevicePath, - GENERIC_READ, // Only read access - 0, // FILE_SHARE_READ | FILE_SHARE_WRITE - NULL, // no SECURITY_ATTRIBUTES structure - OPEN_EXISTING, // No special create flags - 0, // No special attributes - NULL); // No template file - - if (INVALID_HANDLE_VALUE == hDevice) { - goto Clean1; - } - - // - // Enumerate Devices - // - - if(Action == PLUGIN) { - int length = (int) (wcslen(DeviceId)+2)*sizeof(WCHAR); //in bytes - - bytes = sizeof (BUSENUM_PLUGIN_HARDWARE) + length; - hardware = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, bytes); - - if(hardware) { - memset(hardware, 0, bytes); - hardware->Size = sizeof (BUSENUM_PLUGIN_HARDWARE); - hardware->SerialNo = SerialNo; - } else { - goto Clean2; - } - - // - // copy the Device ID - // - hr = StringCchCopy(hardware->HardwareIDs, length/sizeof(WCHAR), DeviceId); - if (SUCCEEDED(hr) && DeviceIoControl (hDevice, - IOCTL_BUSENUM_PLUGIN_HARDWARE , - hardware, bytes, - NULL, 0, - &bytes, NULL)) { - status = TRUE; - } - - HeapFree (GetProcessHeap(), 0, hardware); - - } - - // - // Removes a device if given the specific Id of the device. Otherwise this - // ioctls removes all the devices that are enumerated so far. - // - - if(Action == UNPLUG) { - - unplug.Size = bytes = sizeof (unplug); - unplug.SerialNo = SerialNo; - if (DeviceIoControl (hDevice, - IOCTL_BUSENUM_UNPLUG_HARDWARE, - &unplug, bytes, - NULL, 0, - &bytes, NULL)) { - status = TRUE; - } - } - - // - // Ejects a device if given the specific Id of the device. Otherwise this - // ioctls ejects all the devices that are enumerated so far. - // - - if(Action == EJECT) - { - - eject.Size = bytes = sizeof (eject); - eject.SerialNo = SerialNo; - if (DeviceIoControl (hDevice, - IOCTL_BUSENUM_EJECT_HARDWARE, - &eject, bytes, - NULL, 0, - &bytes, NULL)) { - status = TRUE; - } - } - -Clean2: - CloseHandle(hDevice); -Clean1: - HeapFree (GetProcessHeap(), 0, deviceInterfaceDetailData); -Clean0: - SetupDiDestroyDeviceInfoList (hardwareDeviceInfo); - return status; -} - -BOOL -HandlePowerBroadcast( - HWND hWnd, - WPARAM wParam, - LPARAM lParam) -{ - BOOL fRet = TRUE; - - UNREFERENCED_PARAMETER( hWnd ); - UNREFERENCED_PARAMETER( lParam ); - - switch (wParam) - { - case PBT_APMQUERYSTANDBY: - DisplayV(TEXT("PBT_APMQUERYSTANDBY")); - break; - case PBT_APMQUERYSUSPEND: - DisplayV(TEXT("PBT_APMQUERYSUSPEND")); - break; - case PBT_APMSTANDBY : - DisplayV(TEXT("PBT_APMSTANDBY")); - break; - case PBT_APMSUSPEND : - DisplayV(TEXT("PBT_APMSUSPEND")); - break; - case PBT_APMQUERYSTANDBYFAILED: - DisplayV(TEXT("PBT_APMQUERYSTANDBYFAILED")); - break; - case PBT_APMRESUMESTANDBY: - DisplayV(TEXT("PBT_APMRESUMESTANDBY")); - break; - case PBT_APMQUERYSUSPENDFAILED: - DisplayV(TEXT("PBT_APMQUERYSUSPENDFAILED")); - break; - case PBT_APMRESUMESUSPEND: - DisplayV(TEXT("PBT_APMRESUMESUSPEND")); - break; - case PBT_APMBATTERYLOW: - DisplayV(TEXT("PBT_APMBATTERYLOW")); - break; - case PBT_APMOEMEVENT: - DisplayV(TEXT("PBT_APMOEMEVENT")); - break; - case PBT_APMRESUMEAUTOMATIC: - DisplayV(TEXT("PBT_APMRESUMEAUTOMATIC")); - break; - case PBT_APMRESUMECRITICAL: - DisplayV(TEXT("PBT_APMRESUMECRITICAL")); - break; - case PBT_APMPOWERSTATUSCHANGE: - DisplayV(TEXT("PBT_APMPOWERSTATUSCHANGE")); - break; - default: - DisplayV(TEXT("Default")); - break; - } - return fRet; -} - -void -SendIoctlToFilterDevice() -{ -#define IOCTL_CUSTOM_CODE CTL_CODE(FILE_DEVICE_UNKNOWN, 0, METHOD_BUFFERED, FILE_READ_DATA) - - HANDLE hControlDevice; - ULONG bytes; - - // - // Open handle to the control device. Please note that even - // a non-admin user can open handle to the device with - // FILE_READ_ATTRIBUTES | SYNCHRONIZE DesiredAccess and send IOCTLs if the - // IOCTL is defined with FILE_ANY_ACCESS. So for better security avoid - // specifying FILE_ANY_ACCESS in your IOCTL defintions. - // If the IOCTL is defined to have FILE_READ_DATA access rights, you can - // open the device with GENERIC_READ and call DeviceIoControl. - // If the IOCTL is defined to have FILE_WRITE_DATA access rights, you can - // open the device with GENERIC_WRITE and call DeviceIoControl. - // - hControlDevice = CreateFile ( TEXT("\\\\.\\ToasterFilter"), - GENERIC_READ, // Only read access - 0, // FILE_SHARE_READ | FILE_SHARE_WRITE - NULL, // no SECURITY_ATTRIBUTES structure - OPEN_EXISTING, // No special create flags - 0, // No special attributes - NULL); // No template file - - if (INVALID_HANDLE_VALUE == hControlDevice) { - Display(TEXT("Failed to open ToasterFilter device")); - } else { - if (!DeviceIoControl (hControlDevice, - IOCTL_CUSTOM_CODE, - NULL, 0, - NULL, 0, - &bytes, NULL)) { - Display(TEXT("Ioctl to ToasterFilter device failed")); - } else { - Display(TEXT("Ioctl to ToasterFilter device succeeded")); - } - CloseHandle(hControlDevice); - } - return; -} diff --git a/general/toaster/umdf2/exe/notify/notify.h b/general/toaster/umdf2/exe/notify/notify.h deleted file mode 100644 index 98db2918..00000000 --- a/general/toaster/umdf2/exe/notify/notify.h +++ /dev/null @@ -1,182 +0,0 @@ -/*++ -Copyright (c) 1990-2000 Microsoft Corporation All Rights Reserved - -Module Name: - - notify.h - -Abstract: - - -Author: - - Eliyas Yakub Nov 23, 1999 - -Environment: - - -Revision History: - - ---*/ - -#ifndef __NOTIFY_H -#define __NOTIFY_H - - -// -// Copied Macros from ntddk.h -// - -#define CONTAINING_RECORD(address, type, field) ((type *)( \ - (PCHAR)(address) - \ - (ULONG_PTR)(&((type *)0)->field))) - - -#define InitializeListHead(ListHead) (\ - (ListHead)->Flink = (ListHead)->Blink = (ListHead)) - -#define RemoveHeadList(ListHead) \ - (ListHead)->Flink;\ - {RemoveEntryList((ListHead)->Flink)} - -#define IsListEmpty(ListHead) \ - ((ListHead)->Flink == (ListHead)) - - -#define RemoveEntryList(Entry) {\ - PLIST_ENTRY _EX_Blink;\ - PLIST_ENTRY _EX_Flink;\ - _EX_Flink = (Entry)->Flink;\ - _EX_Blink = (Entry)->Blink;\ - _EX_Blink->Flink = _EX_Flink;\ - _EX_Flink->Blink = _EX_Blink;\ - } - -#define InsertTailList(ListHead,Entry) {\ - PLIST_ENTRY _EX_Blink;\ - PLIST_ENTRY _EX_ListHead;\ - _EX_ListHead = (ListHead);\ - _EX_Blink = _EX_ListHead->Blink;\ - (Entry)->Flink = _EX_ListHead;\ - (Entry)->Blink = _EX_Blink;\ - _EX_Blink->Flink = (Entry);\ - _EX_ListHead->Blink = (Entry);\ - } - -typedef struct _DEVICE_INFO -{ - HANDLE hDevice; // file handle - HDEVNOTIFY hHandleNotification; // notification handle - TCHAR DeviceName[MAX_PATH];// friendly name of device description - TCHAR DevicePath[MAX_PATH];// - ULONG SerialNo; // Serial number of the device. - LIST_ENTRY ListEntry; -} DEVICE_INFO, *PDEVICE_INFO; - - -typedef enum { - - PLUGIN = 1, - UNPLUG, - EJECT - -} USER_ACTION_TYPE; - -typedef struct _DIALOG_RESULT -{ - ULONG SerialNo; - PWCHAR DeviceId; -} DIALOG_RESULT, *PDIALOG_RESULT; - -#define ID_EDIT 1 - -#define IDM_OPEN 100 -#define IDM_CLOSE 101 -#define IDM_EXIT 102 -#define IDM_HIDE 103 -#define IDM_PLUGIN 104 -#define IDM_UNPLUG 105 -#define IDM_EJECT 106 -#define IDM_ENABLE 107 -#define IDM_DISABLE 108 -#define IDM_CLEAR 109 -#define IDM_IOCTL 110 -#define IDM_VERBOSE 111 - -#define IDD_DIALOG 115 -#define IDD_DIALOG1 116 -#define IDD_DIALOG2 117 -#define ID_OK 118 -#define ID_CANCEL 119 -#define IDC_SERIALNO 1000 -#define IDC_DEVICEID 1001 -#define IDC_STATIC -1 - -#define IDI_CLASS_ICON 200 - -LRESULT FAR PASCAL -WndProc ( - HWND hwnd, - UINT message, - WPARAM wParam, - LPARAM lParam - ); - -BOOLEAN EnumExistingDevices( - HWND hWnd - ); - -BOOL HandleDeviceInterfaceChange( - HWND hwnd, - DWORD evtype, - PDEV_BROADCAST_DEVICEINTERFACE dip - ); - -BOOL HandleDeviceChange( - HWND hwnd, - DWORD evtype, - PDEV_BROADCAST_HANDLE dhp - ); - -LRESULT -HandleCommands( - HWND hWnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam - ); - -BOOLEAN Cleanup( - HWND hWnd - ); - -BOOL -GetDeviceDescription( - _In_ LPTSTR DevPath, - _Out_writes_bytes_(OutBufferLen) PBYTE OutBuffer, - _In_ ULONG OutBufferLen, - _In_ PULONG SerialNo - ); - -BOOLEAN -OpenBusInterface ( - _In_ ULONG SerialNo, - _When_ (Action == PLUGIN, _In_) LPWSTR DeviceId, - _In_ USER_ACTION_TYPE Action - ); - - -INT_PTR CALLBACK -DlgProc( - HWND hDlg, - UINT message, - WPARAM wParam, - LPARAM lParam); - -void -SendIoctlToFilterDevice(); - - -#endif - diff --git a/general/toaster/umdf2/exe/notify/notify.rc b/general/toaster/umdf2/exe/notify/notify.rc deleted file mode 100644 index eb15657f..00000000 --- a/general/toaster/umdf2/exe/notify/notify.rc +++ /dev/null @@ -1,77 +0,0 @@ -#include "windows.h" - -#include "notify.h" - - -GenericMenu MENU - { - POPUP "&File" - { - MENUITEM "Clear &Display", IDM_CLEAR - MENUITEM "&Verbose Trace", IDM_VERBOSE - MENUITEM "E&xit", IDM_EXIT - } - POPUP "&Bus" - { - MENUITEM "&PlugIn", IDM_PLUGIN - MENUITEM "&UnPlug (Surprise Removal)", IDM_UNPLUG - MENUITEM "&Eject", IDM_EJECT - } - POPUP "&Function" - { - MENUITEM "&Open", IDM_OPEN - MENUITEM "&Close", IDM_CLOSE - MENUITEM "&Hide", IDM_HIDE - - } - POPUP "Fil&ter" - { - MENUITEM "&Ioctl to Control Device", IDM_IOCTL - } - } - - - -///////////////////////////////////////////////////////////////////////////// -// -// Dialog for plug in -// - -IDD_DIALOG DIALOG DISCARDABLE 0, 0, 289, 86 -STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Plug In Device" -FONT 8, "MS Shell Dlg" -BEGIN - DEFPUSHBUTTON "OK",ID_OK,72,61,50,14,BS_NOTIFY - PUSHBUTTON "CANCEL",ID_CANCEL,170,60,50,14,BS_NOTIFY - LTEXT "Serial Number :",IDC_STATIC,18,13,55,8 - LTEXT "Device ID :",IDC_STATIC,20,35,55,8 - EDITTEXT IDC_SERIALNO,75,11,24,14,ES_NUMBER - EDITTEXT IDC_DEVICEID,76,32,200,14,ES_AUTOHSCROLL -END - -///////////////////////////////////////////////////////////////////////////// -// -// Dialog for unplug/hide/enable/disable -// - -IDD_DIALOG1 DIALOG DISCARDABLE 0, 0, 232, 86 -STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Enter SerialNo of the device" -FONT 8, "MS Shell Dlg" -BEGIN - LTEXT "Serial Number :",IDC_STATIC,18,13,55,8 - EDITTEXT IDC_SERIALNO,75,11,24,14,ES_NUMBER - DEFPUSHBUTTON "OK",ID_OK,27,61,50,14,BS_NOTIFY - PUSHBUTTON "CANCEL",ID_CANCEL,121,60,50,14,BS_NOTIFY -END - - -///////////////////////////////////////////////////////////////////////////// -// -// Icon -// - -IDI_CLASS_ICON ICON DISCARDABLE "TOASTER.ICO" - - diff --git a/general/toaster/umdf2/exe/notify/notify.vcxproj b/general/toaster/umdf2/exe/notify/notify.vcxproj deleted file mode 100644 index 9d65f2f7..00000000 --- a/general/toaster/umdf2/exe/notify/notify.vcxproj +++ /dev/null @@ -1,172 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - {FEBBDE46-4BD4-462D-87BD-8FDC8C1ECB76} - $(MSBuildProjectName) - Debug - Win32 - {83E3E107-0EC1-44A8-BA29-BFBB6C43DC53} - - - - Windows10 - False - Desktop - - WindowsApplicationForDrivers10.0 - Application - - - Windows10 - True - Desktop - - WindowsApplicationForDrivers10.0 - Application - - - Windows10 - False - Desktop - - WindowsApplicationForDrivers10.0 - Application - - - Windows10 - True - Desktop - - WindowsApplicationForDrivers10.0 - Application - - - - $(IntDir) - - - - - - - - - - - - - - - - notify - - - notify - - - notify - - - notify - - - - %(AdditionalIncludeDirectories);..\..\inc - - - %(AdditionalIncludeDirectories);..\..\inc - - - - - %(AdditionalIncludeDirectories);..\..\inc - - - %(AdditionalDependencies);setupapi.lib - - - - - %(AdditionalIncludeDirectories);..\..\inc - - - %(AdditionalIncludeDirectories);..\..\inc - - - - - %(AdditionalIncludeDirectories);..\..\inc - - - %(AdditionalDependencies);setupapi.lib - - - - - %(AdditionalIncludeDirectories);..\..\inc - - - %(AdditionalIncludeDirectories);..\..\inc - - - - - %(AdditionalIncludeDirectories);..\..\inc - - - %(AdditionalDependencies);setupapi.lib - - - - - %(AdditionalIncludeDirectories);..\..\inc - - - %(AdditionalIncludeDirectories);..\..\inc - - - - - %(AdditionalIncludeDirectories);..\..\inc - - - %(AdditionalDependencies);setupapi.lib - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/general/toaster/umdf2/exe/notify/notify.vcxproj.Filters b/general/toaster/umdf2/exe/notify/notify.vcxproj.Filters deleted file mode 100644 index ccccf66b..00000000 --- a/general/toaster/umdf2/exe/notify/notify.vcxproj.Filters +++ /dev/null @@ -1,27 +0,0 @@ - - - - - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {26C90330-C836-4747-995F-76F38B79BDA9} - - - h;hpp;hxx;hm;inl;inc;xsd - {04722C15-5D21-4294-B1A9-004CFAF38D17} - - - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {600866EB-F078-4625-8B46-D93F60CD2380} - - - - - Source Files - - - - - Resource Files - - - \ No newline at end of file diff --git a/general/toaster/umdf2/exe/notify/toaster.ico b/general/toaster/umdf2/exe/notify/toaster.ico deleted file mode 100644 index 77ad2081..00000000 Binary files a/general/toaster/umdf2/exe/notify/toaster.ico and /dev/null differ diff --git a/general/toaster/umdf2/exe/toast/toast.c b/general/toaster/umdf2/exe/toast/toast.c deleted file mode 100644 index 4f0525c6..00000000 --- a/general/toaster/umdf2/exe/toast/toast.c +++ /dev/null @@ -1,343 +0,0 @@ -/*++ - -Copyright (c) Microsoft Corporation. All rights reserved. - - THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY - KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR - PURPOSE. - -Module Name: - - TOAST.C - -Abstract: - - Lists all the toaster device and interfaces present in the system - and opens the last interface to send an invalidate device Ioctl request - or read requests. - -Environment: - - usermode console application - -Revision History: - - Eliyas Yakub Nov 2, 1998 - - ---*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "public.h" -#include -#include - -#define USAGE \ -"Usage: Toast <-h> {-h option causes the device to hide from Device Manager UI}\n" - -BOOL PrintToasterDeviceInfo(); - -INT __cdecl -main( - _In_ ULONG argc, - _In_reads_(argc) PCHAR argv[] - ) -{ - HDEVINFO hardwareDeviceInfo; - SP_DEVICE_INTERFACE_DATA deviceInterfaceData; - PSP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailData = NULL; - ULONG predictedLength = 0; - ULONG requiredLength = 0, bytes=0; - HANDLE file; - int i, ch; - char buffer[10]; - BOOL bHide = FALSE; - - if(argc == 2) { - if(argv[1][0] == '-') { - if(argv[1][1] == 'h' || argv[1][1] == 'H') { - bHide = TRUE; - } else { - printf(USAGE); - exit(0); - } - } - else { - printf(USAGE); - exit(0); - } - } - - - // - // Print a list of devices of Toaster Class - // - if(!PrintToasterDeviceInfo()) - { - printf("No toaster devices present\n"); - return 0; - } - - // - // Open a handle to the device interface information set of all - // present toaster class interfaces. - // - - hardwareDeviceInfo = SetupDiGetClassDevs ( - (LPGUID)&GUID_DEVINTERFACE_TOASTER, - NULL, // Define no enumerator (global) - NULL, // Define no - (DIGCF_PRESENT | // Only Devices present - DIGCF_DEVICEINTERFACE)); // Function class devices. - if(INVALID_HANDLE_VALUE == hardwareDeviceInfo) - { - printf("SetupDiGetClassDevs failed: %x\n", GetLastError()); - return 0; - } - - deviceInterfaceData.cbSize = sizeof (SP_DEVICE_INTERFACE_DATA); - - printf("\nList of Toaster Device Interfaces\n"); - printf("---------------------------------\n"); - - i = 0; - - // - // Enumerate devices of toaster class - // - - for(;;) { - if (SetupDiEnumDeviceInterfaces (hardwareDeviceInfo, - 0, // No care about specific PDOs - (LPGUID)&GUID_DEVINTERFACE_TOASTER, - i, // - &deviceInterfaceData)) { - - if(deviceInterfaceDetailData) { - free (deviceInterfaceDetailData); - deviceInterfaceDetailData = NULL; - } - - // - // Allocate a function class device data structure to - // receive the information about this particular device. - // - - // - // First find out required length of the buffer - // - - if(!SetupDiGetDeviceInterfaceDetail ( - hardwareDeviceInfo, - &deviceInterfaceData, - NULL, // probing so no output buffer yet - 0, // probing so output buffer length of zero - &requiredLength, - NULL)) { // not interested in the specific dev-node - if(ERROR_INSUFFICIENT_BUFFER != GetLastError()) { - printf("SetupDiGetDeviceInterfaceDetail failed %d\n", GetLastError()); - SetupDiDestroyDeviceInfoList (hardwareDeviceInfo); - return FALSE; - } - - } - - predictedLength = requiredLength; - - deviceInterfaceDetailData = malloc (predictedLength); - - if(deviceInterfaceDetailData) { - deviceInterfaceDetailData->cbSize = - sizeof (SP_DEVICE_INTERFACE_DETAIL_DATA); - } else { - printf("Couldn't allocate %d bytes for device interface details.\n", predictedLength); - SetupDiDestroyDeviceInfoList (hardwareDeviceInfo); - return FALSE; - } - - - if (! SetupDiGetDeviceInterfaceDetail ( - hardwareDeviceInfo, - &deviceInterfaceData, - deviceInterfaceDetailData, - predictedLength, - &requiredLength, - NULL)) { - printf("Error in SetupDiGetDeviceInterfaceDetail\n"); - SetupDiDestroyDeviceInfoList (hardwareDeviceInfo); - free (deviceInterfaceDetailData); - return FALSE; - } - printf("%d) %s\n", ++i, - deviceInterfaceDetailData->DevicePath); - } - else if (ERROR_NO_MORE_ITEMS != GetLastError()) { - free (deviceInterfaceDetailData); - deviceInterfaceDetailData = NULL; - continue; - } - else - break; - - } - - - SetupDiDestroyDeviceInfoList (hardwareDeviceInfo); - - if(!deviceInterfaceDetailData) - { - printf("No device interfaces present\n"); - return 0; - } - - // - // Open the last toaster device interface - // - - printf("\nOpening the last interface:\n %s\n", - deviceInterfaceDetailData->DevicePath); - - file = CreateFile ( deviceInterfaceDetailData->DevicePath, - GENERIC_READ | GENERIC_WRITE, - 0, - NULL, // no SECURITY_ATTRIBUTES structure - OPEN_EXISTING, // No special create flags - 0, // No special attributes - NULL); - - if (INVALID_HANDLE_VALUE == file) { - printf("Error in CreateFile: %x", GetLastError()); - free (deviceInterfaceDetailData); - return 0; - } - - // - // Invalidate the Device State - // - - if(bHide) - { - if (!DeviceIoControl (file, - IOCTL_TOASTER_DONT_DISPLAY_IN_UI_DEVICE, - NULL, 0, - NULL, 0, - &bytes, NULL)) { - printf("Invalidate device request failed:0x%x\n", GetLastError()); - free (deviceInterfaceDetailData); - CloseHandle(file); - return 0; - } - printf("\nRequest to hide the device completed successfully\n"); - - } - - - // - // Read/Write to the toaster device. - // - - printf("\nPress 'q' to exit, any other key to read...\n"); - fflush(stdin); - ch = _getche(); - - while(tolower(ch) != 'q' ) - { - - if(!ReadFile(file, buffer, sizeof(buffer), &bytes, NULL)) - { - printf("Error in ReadFile: %x", GetLastError()); - break; - } - printf("Read Successful\n"); - ch = _getche(); - } - - free (deviceInterfaceDetailData); - CloseHandle(file); - return 0; -} - - - -BOOL -PrintToasterDeviceInfo() -{ - HDEVINFO hdi; - DWORD dwIndex=0; - SP_DEVINFO_DATA deid; - BOOL fSuccess=FALSE; - CHAR szCompInstanceId[MAX_PATH]; - CHAR szCompDescription[MAX_PATH]; - CHAR szFriendlyName[MAX_PATH]; - DWORD dwRegType; - BOOL fFound=FALSE; - - // get a list of all devices of class 'GUID_DEVCLASS_TOASTER' - hdi = SetupDiGetClassDevs(&GUID_DEVCLASS_TOASTER, NULL, NULL, - DIGCF_PRESENT); - - if (INVALID_HANDLE_VALUE != hdi) - { - - // enumerate over each device - while (deid.cbSize = sizeof(SP_DEVINFO_DATA), - SetupDiEnumDeviceInfo(hdi, dwIndex, &deid)) - { - dwIndex++; - - // the right thing to do here would be to call this function - // to get the size required to hold the instance ID and then - // to call it second time with a buffer large enough for that size. - // However, that would tend to obscure the control flow in - // the sample code. Lets keep things simple by keeping the - // buffer large enough. - - // get the device instance ID - fSuccess = SetupDiGetDeviceInstanceId(hdi, &deid, - szCompInstanceId, - MAX_PATH, NULL); - if (fSuccess) - { - // get the description for this instance - fSuccess = - SetupDiGetDeviceRegistryProperty(hdi, &deid, - SPDRP_DEVICEDESC, - &dwRegType, - (BYTE*) szCompDescription, - MAX_PATH, - NULL); - if (fSuccess) - { - memset(szFriendlyName, 0, MAX_PATH); - SetupDiGetDeviceRegistryProperty(hdi, &deid, - SPDRP_FRIENDLYNAME, - &dwRegType, - (BYTE*) szFriendlyName, - MAX_PATH, - NULL); - fFound = TRUE; - printf("Instance ID : %s\n", szCompInstanceId); - printf("Description : %s\n", szCompDescription); - printf("FriendlyName: %s\n\n", szFriendlyName); - } - } - } - - // release the device info list - SetupDiDestroyDeviceInfoList(hdi); - } - - if(fFound) - return TRUE; - else - return FALSE; -} - diff --git a/general/toaster/umdf2/exe/toast/toast.vcxproj b/general/toaster/umdf2/exe/toast/toast.vcxproj deleted file mode 100644 index 45a4ceb0..00000000 --- a/general/toaster/umdf2/exe/toast/toast.vcxproj +++ /dev/null @@ -1,171 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - {9BF4F988-D8B7-4E73-BC77-6658D413212F} - $(MSBuildProjectName) - Debug - Win32 - {5A95B864-3AA6-41E5-AF06-4FB9836D4219} - - - - Windows10 - False - Desktop - - WindowsApplicationForDrivers10.0 - Application - - - Windows10 - True - Desktop - - WindowsApplicationForDrivers10.0 - Application - - - Windows10 - False - Desktop - - WindowsApplicationForDrivers10.0 - Application - - - Windows10 - True - Desktop - - WindowsApplicationForDrivers10.0 - Application - - - - $(IntDir) - - - - - - - - - - - - - - - - toast - - - toast - - - toast - - - toast - - - - %(AdditionalIncludeDirectories);..\..\inc - - - %(AdditionalIncludeDirectories);..\..\inc - - - - - %(AdditionalIncludeDirectories);..\..\inc - - - %(AdditionalDependencies);setupapi.lib - - - - - %(AdditionalIncludeDirectories);..\..\inc - - - %(AdditionalIncludeDirectories);..\..\inc - - - - - %(AdditionalIncludeDirectories);..\..\inc - - - %(AdditionalDependencies);setupapi.lib - - - - - %(AdditionalIncludeDirectories);..\..\inc - - - %(AdditionalIncludeDirectories);..\..\inc - - - - - %(AdditionalIncludeDirectories);..\..\inc - - - %(AdditionalDependencies);setupapi.lib - - - - - %(AdditionalIncludeDirectories);..\..\inc - - - %(AdditionalIncludeDirectories);..\..\inc - - - - - %(AdditionalIncludeDirectories);..\..\inc - - - %(AdditionalDependencies);setupapi.lib - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/general/toaster/umdf2/exe/toast/toast.vcxproj.Filters b/general/toaster/umdf2/exe/toast/toast.vcxproj.Filters deleted file mode 100644 index b418a4e3..00000000 --- a/general/toaster/umdf2/exe/toast/toast.vcxproj.Filters +++ /dev/null @@ -1,22 +0,0 @@ - - - - - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {74122CFE-AC0A-405A-887C-C84F0A71602A} - - - h;hpp;hxx;hm;inl;inc;xsd - {BF44B779-EC06-4E53-8DA1-5B27378BE11C} - - - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {92FCEB4A-CD44-4D16-8B54-1B192FADB341} - - - - - Source Files - - - \ No newline at end of file diff --git a/general/toaster/umdf2/filter/generic/filter.c b/general/toaster/umdf2/filter/generic/filter.c deleted file mode 100644 index d245c2ba..00000000 --- a/general/toaster/umdf2/filter/generic/filter.c +++ /dev/null @@ -1,387 +0,0 @@ -/*++ - -Copyright (c) Microsoft Corporation. All rights reserved. - - THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY - KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR - PURPOSE. - -Module Name: - - filter.c - -Abstract: - - This module shows how to a write a generic filter driver. The driver demonstrates how - to support device I/O control requests through queues. All the I/O requests passed on to - the lower driver. This filter driver shows how to handle IRP postprocessing by forwarding - the requests with and without a completion routine. To forward with a completion routine - set the define FORWARD_REQUEST_WITH_COMPLETION to 1. - -Environment: - - User mode - ---*/ - -#include "filter.h" - - -#ifdef ALLOC_PRAGMA -#pragma alloc_text (INIT, DriverEntry) -#pragma alloc_text (PAGE, FilterEvtDeviceAdd) -#endif - - -NTSTATUS -DriverEntry( - IN PDRIVER_OBJECT DriverObject, - IN PUNICODE_STRING RegistryPath - ) -/*++ - -Routine Description: - - Installable driver initialization entry point. - This entry point is called directly by the I/O system. - -Arguments: - - DriverObject - pointer to the driver object - - RegistryPath - pointer to a unicode string representing the path, - to driver-specific key in the registry. - -Return Value: - - STATUS_SUCCESS if successful, - STATUS_UNSUCCESSFUL otherwise. - ---*/ -{ - WDF_DRIVER_CONFIG config; - NTSTATUS status; - WDFDRIVER hDriver; - - KdPrint(("Toaster Generic Filter Driver Sample - Driver Framework Edition.\n")); - - // - // Initiialize driver config to control the attributes that - // are global to the driver. Note that framework by default - // provides a driver unload routine. If you create any resources - // in the DriverEntry and want to be cleaned in driver unload, - // you can override that by manually setting the EvtDriverUnload in the - // config structure. In general xxx_CONFIG_INIT macros are provided to - // initialize most commonly used members. - // - - WDF_DRIVER_CONFIG_INIT( - &config, - FilterEvtDeviceAdd - ); - - // - // Create a framework driver object to represent our driver. - // - status = WdfDriverCreate(DriverObject, - RegistryPath, - WDF_NO_OBJECT_ATTRIBUTES, - &config, - &hDriver); - if (!NT_SUCCESS(status)) { - KdPrint( ("WdfDriverCreate failed with status 0x%x\n", status)); - } - - return status; -} - - -NTSTATUS -FilterEvtDeviceAdd( - IN WDFDRIVER Driver, - IN PWDFDEVICE_INIT DeviceInit - ) -/*++ -Routine Description: - - EvtDeviceAdd is called by the framework in response to AddDevice - call from the PnP manager. Here you can query the device properties - using WdfFdoInitWdmGetPhysicalDevice/IoGetDeviceProperty and based - on that, decide to create a filter device object and attach to the - function stack. If you are not interested in filtering this particular - instance of the device, you can just return STATUS_SUCCESS without creating - a framework device. - -Arguments: - - Driver - Handle to a framework driver object created in DriverEntry - - DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure. - -Return Value: - - NTSTATUS - ---*/ -{ - WDF_OBJECT_ATTRIBUTES deviceAttributes; - PFILTER_EXTENSION filterExt; - NTSTATUS status; - WDFDEVICE device; - WDF_IO_QUEUE_CONFIG ioQueueConfig; - - PAGED_CODE (); - - UNREFERENCED_PARAMETER(Driver); - - // - // Tell the framework that you are filter driver. Framework - // takes care of inherting all the device flags & characterstics - // from the lower device you are attaching to. - // - WdfFdoInitSetFilter(DeviceInit); - - // - // Specify the size of device extension where we track per device - // context. - // - - WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&deviceAttributes, FILTER_EXTENSION); - - // - // Create a framework device object.This call will inturn create - // a WDM deviceobject, attach to the lower stack and set the - // appropriate flags and attributes. - // - status = WdfDeviceCreate(&DeviceInit, &deviceAttributes, &device); - if (!NT_SUCCESS(status)) { - KdPrint( ("WdfDeviceCreate failed with status code 0x%x\n", status)); - return status; - } - - filterExt = FilterGetData(device); - - // - // Configure the default queue to be Parallel. - // - WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&ioQueueConfig, - WdfIoQueueDispatchParallel); - - // - // Framework by default creates non-power managed queues for - // filter drivers. - // - ioQueueConfig.EvtIoDeviceControl = FilterEvtIoDeviceControl; - - status = WdfIoQueueCreate(device, - &ioQueueConfig, - WDF_NO_OBJECT_ATTRIBUTES, - WDF_NO_HANDLE // pointer to default queue - ); - if (!NT_SUCCESS(status)) { - KdPrint( ("WdfIoQueueCreate failed 0x%x\n", status)); - return status; - } - - return status; -} - -VOID -FilterEvtIoDeviceControl( - IN WDFQUEUE Queue, - IN WDFREQUEST Request, - IN size_t OutputBufferLength, - IN size_t InputBufferLength, - IN ULONG IoControlCode - ) -/*++ - -Routine Description: - - This routine is the dispatch routine for internal device control requests. - -Arguments: - - Queue - Handle to the framework queue object that is associated - with the I/O request. - Request - Handle to a framework request object. - - OutputBufferLength - length of the request's output buffer, - if an output buffer is available. - InputBufferLength - length of the request's input buffer, - if an input buffer is available. - - IoControlCode - the driver-defined or system-defined I/O control code - (IOCTL) that is associated with the request. - -Return Value: - - VOID - ---*/ -{ - PFILTER_EXTENSION filterExt; - NTSTATUS status = STATUS_SUCCESS; - WDFDEVICE device; - - UNREFERENCED_PARAMETER(OutputBufferLength); - UNREFERENCED_PARAMETER(InputBufferLength); - - KdPrint(("Entered FilterEvtIoDeviceControl\n")); - - device = WdfIoQueueGetDevice(Queue); - - filterExt = FilterGetData(device); - - switch (IoControlCode) { - - // - // Put your cases for handling IOCTLs here - // - - default: - status = STATUS_SUCCESS; - } - - if (!NT_SUCCESS(status)) { - WdfRequestComplete(Request, status); - return; - } - - // - // Forward the request down. WdfDeviceGetIoTarget returns - // the default target, which represents the device attached to us below in - // the stack. - // -#if FORWARD_REQUEST_WITH_COMPLETION - // - // Use this routine to forward a request if you are interested in post - // processing the IRP. - // - FilterForwardRequestWithCompletionRoutine(Request, - WdfDeviceGetIoTarget(device)); -#else - FilterForwardRequest(Request, WdfDeviceGetIoTarget(device)); -#endif - - return; -} - -VOID -FilterForwardRequest( - IN WDFREQUEST Request, - IN WDFIOTARGET Target - ) -/*++ -Routine Description: - - Passes a request on to the lower driver. - ---*/ -{ - WDF_REQUEST_SEND_OPTIONS options; - BOOLEAN ret; - NTSTATUS status; - - // - // We are not interested in post processing the IRP so - // fire and forget. - // - WDF_REQUEST_SEND_OPTIONS_INIT(&options, - WDF_REQUEST_SEND_OPTION_SEND_AND_FORGET); - - ret = WdfRequestSend(Request, Target, &options); - - if (ret == FALSE) { - status = WdfRequestGetStatus (Request); - KdPrint( ("WdfRequestSend failed: 0x%x\n", status)); - WdfRequestComplete(Request, status); - } - - return; -} - -#if FORWARD_REQUEST_WITH_COMPLETION - -VOID -FilterForwardRequestWithCompletionRoutine( - IN WDFREQUEST Request, - IN WDFIOTARGET Target - ) -/*++ -Routine Description: - - This routine forwards the request to a lower driver with - a completion so that when the request is completed by the - lower driver, it can regain control of the request and look - at the result. - ---*/ -{ - BOOLEAN ret; - NTSTATUS status; - - // - // The following funciton essentially copies the content of - // current stack location of the underlying IRP to the next one. - // - WdfRequestFormatRequestUsingCurrentType(Request); - - WdfRequestSetCompletionRoutine(Request, - FilterRequestCompletionRoutine, - WDF_NO_CONTEXT); - - ret = WdfRequestSend(Request, - Target, - WDF_NO_SEND_OPTIONS); - - if (ret == FALSE) { - status = WdfRequestGetStatus (Request); - KdPrint( ("WdfRequestSend failed: 0x%x\n", status)); - WdfRequestComplete(Request, status); - } - - return; -} - -VOID -FilterRequestCompletionRoutine( - IN WDFREQUEST Request, - IN WDFIOTARGET Target, - PWDF_REQUEST_COMPLETION_PARAMS CompletionParams, - IN WDFCONTEXT Context - ) -/*++ - -Routine Description: - - Completion Routine - -Arguments: - - Target - Target handle - Request - Request handle - Params - request completion params - Context - Driver supplied context - - -Return Value: - - VOID - ---*/ -{ - UNREFERENCED_PARAMETER(Target); - UNREFERENCED_PARAMETER(Context); - - WdfRequestComplete(Request, CompletionParams->IoStatus.Status); - - return; -} - -#endif //FORWARD_REQUEST_WITH_COMPLETION - - - - diff --git a/general/toaster/umdf2/filter/generic/filter.h b/general/toaster/umdf2/filter/generic/filter.h deleted file mode 100644 index e9042c29..00000000 --- a/general/toaster/umdf2/filter/generic/filter.h +++ /dev/null @@ -1,85 +0,0 @@ -/*++ - -Copyright (c) Microsoft Corporation. All rights reserved. - - THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY - KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR - PURPOSE. - -Module Name: - - filter.h - -Abstract: - - Contains structure definitions and function prototypes for a generic filter driver. - -Environment: - - User mode - ---*/ - -#include -#include -#pragma warning( disable: 4201 ) // nonstandard extension used : nameless struct/union -#include -#include -#include -#include - -#if !defined(_FILTER_H_) -#define _FILTER_H_ - - -#define DRIVERNAME "Generic.sys: " - -// -// Change the following define to 1 if you want to forward -// the request with a completion routine. -// -#define FORWARD_REQUEST_WITH_COMPLETION 0 - - -typedef struct _FILTER_EXTENSION -{ - WDFDEVICE WdfDevice; - // More context data here - -}FILTER_EXTENSION, *PFILTER_EXTENSION; - - -WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(FILTER_EXTENSION, - FilterGetData) - -DRIVER_INITIALIZE DriverEntry; -EVT_WDF_DRIVER_DEVICE_ADD FilterEvtDeviceAdd; -EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL FilterEvtIoDeviceControl; - -VOID -FilterForwardRequest( - IN WDFREQUEST Request, - IN WDFIOTARGET Target - ); - -#if FORWARD_REQUEST_WITH_COMPLETION - -VOID -FilterForwardRequestWithCompletionRoutine( - IN WDFREQUEST Request, - IN WDFIOTARGET Target - ); - -VOID -FilterRequestCompletionRoutine( - IN WDFREQUEST Request, - IN WDFIOTARGET Target, - PWDF_REQUEST_COMPLETION_PARAMS CompletionParams, - IN WDFCONTEXT Context - ); - -#endif //FORWARD_REQUEST_WITH_COMPLETION - -#endif - diff --git a/general/toaster/umdf2/filter/generic/filter.rc b/general/toaster/umdf2/filter/generic/filter.rc deleted file mode 100644 index 0c108f44..00000000 --- a/general/toaster/umdf2/filter/generic/filter.rc +++ /dev/null @@ -1,12 +0,0 @@ -#include -#include -#include - -#define VER_FILETYPE VFT_DLL -#define VER_FILESUBTYPE VFT_UNKNOWN -#define VER_FILEDESCRIPTION_STR "UMDF 2.0 Filter Driver for the Toaster Stack" -#define VER_INTERNALNAME_STR DRIVERNAME -#define VER_ORIGINALFILENAME_STR DRIVERNAME - -#include "common.ver" - diff --git a/general/toaster/umdf2/filter/generic/filterum.inx b/general/toaster/umdf2/filter/generic/filterum.inx deleted file mode 100644 index 3e7013ae..00000000 --- a/general/toaster/umdf2/filter/generic/filterum.inx +++ /dev/null @@ -1,98 +0,0 @@ -;/*++ -; -;Copyright (c) Microsoft Corporation. All rights reserved. -; -;Module Name: -; -; filterum.INF -; -;--*/ - -[Version] -Signature="$WINDOWS NT$" -Class=TOASTER -ClassGuid={B85B7C50-6A01-11d2-B841-00C04FAD5171} -Provider=%MSFT% -DriverVer=06/16/1999,5.00.2064 -CatalogFile=wudf.cat - -[DestinationDirs] -DefaultDestDir = 12 - -; ================= Class section ===================== - -[ClassInstall32] -Addreg=ToasterClassReg - -[ToasterClassReg] -HKR,,,0,%ClassName% -HKR,,Icon,,100 -HKR,,DeviceCharacteristics,0x10001,0x100 ;Use same security checks on relative opens -HKR,,Security,,"D:P(A;;GA;;;SY)(A;;GA;;;BA)" ;Allow generic all access to system and built-in Admin. - ;This one overrides the security set by the driver - -;***************************************** -; Toaster Device Install Section -;***************************************** - -[Manufacturer] -%StdMfg%=Standard,NT$ARCH$ - - -; For XP and later -[Standard.NT$ARCH$] -%WdfSimpleDevice.DeviceDesc%=Toaster_Device, root\toaster - -[Toaster_Device.NT] -CopyFiles=UMDriverCopy - -; ---------------- file copy -[UMDriverCopy] -wdfsimpleum.dll,,,0x00004000 ; COPYFLG_IN_USE_RENAME -filterum.dll,,,0x00004000 ; COPYFLG_IN_USE_RENAME - -[DestinationDirs] -UMDriverCopy=12,UMDF ; copy to drivers/umdf - -[SourceDisksNames] -1 = %DiskId1%,,,"" - -[SourceDisksFiles] -wdfsimpleum.dll = 1,, -filterum.dll = 1,, - -;-------------- Service installation - -[Toaster_Device.NT.Services] -AddService=WUDFRd,0x000001fa,WUDFRD_ServiceInstall - -[WUDFRD_ServiceInstall] -DisplayName = %WudfRdDisplayName% -ServiceType = 1 -StartType = 3 -ErrorControl = 1 -ServiceBinary = %12%\WUDFRd.sys - -;-------------- WDF specific section ------------- -[Toaster_Device.NT.Wdf] -UmdfService=wdfsimpleum, wdfsimple_Install -UmdfService=filterum, filter_Install -UmdfServiceOrder=wdfsimpleum, filterum - -[wdfsimple_Install] -UmdfLibraryVersion=$UMDFVERSION$ -ServiceBinary=%12%\UMDF\wdfsimpleum.dll - -[filter_Install] -UmdfLibraryVersion=$UMDFVERSION$ -ServiceBinary=%12%\UMDF\filterum.dll - -[Strings] -SPSVCINST_ASSOCSERVICE= 0x00000002 -MSFT = "Microsoft" -StdMfg = "(Standard system devices)" -DiskId1 = "WDF Sample Toaster Installation Disk #1" -WdfSimpleDevice.DeviceDesc = "Sample WDF Toaster Service + Filter" -ClassName = "Toaster" -WudfRdDisplayName="Windows Driver Foundation - User-mode Driver Framework Reflector" - diff --git a/general/toaster/umdf2/filter/generic/filterum.vcxproj b/general/toaster/umdf2/filter/generic/filterum.vcxproj deleted file mode 100644 index d1f340e4..00000000 --- a/general/toaster/umdf2/filter/generic/filterum.vcxproj +++ /dev/null @@ -1,188 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - {A60F76D2-C512-4DA6-8C80-263F1B506267} - $(MSBuildProjectName) - 2 - false - true - Debug - Win32 - {0B7A9ABA-5822-49BC-84D3-571A2C7F009A} - - - - Windows10 - False - Universal - UMDF - WindowsUserModeDriver10.0 - DynamicLibrary - - - Windows10 - True - Universal - UMDF - WindowsUserModeDriver10.0 - DynamicLibrary - - - Windows10 - False - Universal - UMDF - WindowsUserModeDriver10.0 - DynamicLibrary - - - Windows10 - True - Universal - UMDF - WindowsUserModeDriver10.0 - DynamicLibrary - - - - $(IntDir) - - - - - - - - - - - - - - - - $(InfArch) - true - .\$(IntDir)\filterum.inf - - - - filterum - - - filterum - - - filterum - - - filterum - - - - true - Level4 - %(AdditionalIncludeDirectories);..\..\inc - - - - - %(AdditionalDependencies);$(SDK_LIB_PATH)\mincore.lib - - - %(AdditionalIncludeDirectories);..\..\inc - - - %(AdditionalIncludeDirectories);..\..\inc - - - - - true - Level4 - %(AdditionalIncludeDirectories);..\..\inc - - - - - %(AdditionalDependencies);$(SDK_LIB_PATH)\mincore.lib - - - %(AdditionalIncludeDirectories);..\..\inc - - - %(AdditionalIncludeDirectories);..\..\inc - - - - - true - Level4 - %(AdditionalIncludeDirectories);..\..\inc - - - - - %(AdditionalDependencies);$(SDK_LIB_PATH)\mincore.lib - - - %(AdditionalIncludeDirectories);..\..\inc - - - %(AdditionalIncludeDirectories);..\..\inc - - - - - true - Level4 - %(AdditionalIncludeDirectories);..\..\inc - - - - - %(AdditionalDependencies);$(SDK_LIB_PATH)\mincore.lib - - - %(AdditionalIncludeDirectories);..\..\inc - - - %(AdditionalIncludeDirectories);..\..\inc - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/general/toaster/umdf2/filter/generic/filterum.vcxproj.Filters b/general/toaster/umdf2/filter/generic/filterum.vcxproj.Filters deleted file mode 100644 index e36af926..00000000 --- a/general/toaster/umdf2/filter/generic/filterum.vcxproj.Filters +++ /dev/null @@ -1,34 +0,0 @@ - - - - - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {DD0D84E8-FA6D-4F21-A94F-490114347147} - - - h;hpp;hxx;hm;inl;inc;xsd - {D308818F-2345-4AAC-AE3A-51BD7F250DE2} - - - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {79C52444-6CA6-4417-BC6A-85DD2B63D65C} - - - inf;inv;inx;mof;mc; - {D5C7C2FC-CFB2-4B65-879D-EE3C6847D48D} - - - - - Driver Files - - - Driver Files - - - - - Source Files - - - \ No newline at end of file diff --git a/general/toaster/umdf2/func/featured/power.c b/general/toaster/umdf2/func/featured/power.c deleted file mode 100644 index 60b5df78..00000000 --- a/general/toaster/umdf2/func/featured/power.c +++ /dev/null @@ -1,385 +0,0 @@ -/*++ - -Copyright (c) Microsoft Corporation. All rights reserved. - - THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY - KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR - PURPOSE. - -Module Name: - - Power.C - -Abstract: - - Implements callbacks to manager power transition, wait-wake and selective - suspend. - -Environment: - - Kernel mode - ---*/ - -#include "toaster.h" - -#ifdef ALLOC_PRAGMA -#pragma alloc_text(PAGE, ToasterEvtDeviceD0Exit) -#pragma alloc_text(PAGE, ToasterEvtDeviceArmWakeFromS0) -#pragma alloc_text(PAGE, ToasterEvtDeviceArmWakeFromSx) -#pragma alloc_text(PAGE, ToasterEvtDeviceWakeFromS0Triggered) -#pragma alloc_text(PAGE, DbgDevicePowerString) -#endif // ALLOC_PRAGMA - - -NTSTATUS -ToasterEvtDeviceD0Entry( - IN WDFDEVICE Device, - IN WDF_POWER_DEVICE_STATE RecentPowerState - ) -/*++ -Routine Description: - - EvtDeviceD0Entry event is called to program the device to goto - D0, which is the working state. The framework calls the driver's - EvtDeviceD0Entry callback when the Power manager sends an - IRP_MN_SET_POWER-DevicePower request to the driver stack. The Power manager - sends this request when the power policy manager of this device stack - (probaby the FDO) requests a change in D-state by calling PoRequestPowerIrp. - - This function is not marked pageable because this function is in the - device power up path. When a function is marked pagable and the code - section is paged out, it will generate a page fault which could impact - the fast resume behavior because the client driver will have to wait - until the system drivers can service this page fault. - -Arguments: - - Device - handle to a framework device object. - - RecentPowerState - WDF_POWER_DEVICE_STATE-typed enumerator that identifies the - device power state that the device was in before this transition - to D0. - -Return Value: - - NTSTATUS - A failure here will indicate a fatal error in the driver. - The Framework will attempt to tear down the stack. - ---*/ -{ - UNREFERENCED_PARAMETER(Device); - UNREFERENCED_PARAMETER(RecentPowerState); - - KdPrint(("ToasterEvtDeviceD0Entry - coming from %s\n", - DbgDevicePowerString(RecentPowerState))); - - return STATUS_SUCCESS; -} - -NTSTATUS -ToasterEvtDeviceD0Exit( - IN WDFDEVICE Device, - IN WDF_POWER_DEVICE_STATE PowerState - ) -/*++ -Routine Description: - - EvtDeviceD0Entry event is called to program the device to goto - D1, D2 or D3, which are the low-power states. The framework calls the - driver's EvtDeviceD0Exit callback when the Power manager sends an - IRP_MN_SET_POWER-DevicePower request to the driver stack. The Power manager - sends this request when the power policy manager of this device stack - (probaby the FDO) requests a change in D-state by calling PoRequestPowerIrp. - -Arguments: - - Device - handle to a framework device object. - - DeviceState - WDF_POWER_DEVICE_STATE-typed enumerator that identifies the - device power state that the power policy owner (probably the - FDO) has decided is appropriate. - -Return Value: - - NTSTATUS - A failure here will indicate a fatal error in the driver. - The Framework will attempt to tear down the stack. ---*/ -{ - UNREFERENCED_PARAMETER(Device); - UNREFERENCED_PARAMETER(PowerState); - - PAGED_CODE(); - - KdPrint(("ToasterEvtDeviceD0Exit %s\n", - DbgDevicePowerString(PowerState))); - - return STATUS_SUCCESS; -} - -NTSTATUS -ToasterEvtDeviceArmWakeFromS0( - IN WDFDEVICE Device - ) -/*++ - -Routine Description: - - EvtDeviceArmWakeFromS0 is called when the Framework arms the device for - wake from S0. If there is any device-specific initialization - that needs to be done to arm internal wake signals, or to route internal - interrupt signals to the wake logic, it should be done here. The device - will be moved out of the D0 state soon after this callback is invoked. - - This function is pageable and it will run at PASSIVE_LEVEL. - -Arguments: - - Device - Handle to a Framework device object. - -Return Value: - - NTSTATUS - Failure will result in the device remaining in the D0 state. - ---*/ -{ - UNREFERENCED_PARAMETER(Device); - - PAGED_CODE(); - - KdPrint(( "--> ToasterEvtDeviceArmWakeFromS0\n")); - - KdPrint(( "<-- ToasterEvtDeviceArmWakeFromS0\n")); - - return STATUS_SUCCESS; -} - -NTSTATUS -ToasterEvtDeviceArmWakeFromSx( - IN WDFDEVICE Device - ) -/*++ - -Routine Description: - - EvtDeviceArmWakeFromSx is called when the Framework arms the device for - wake from Sx. If there is any device-specific initialization - that needs to be done to arm internal wake signals, or to route internal - interrupt signals to the wake logic, it should be done here. The device - will be moved out of the D0 state soon after this callback is invoked. - - This function is pageable and it will run at PASSIVE_LEVEL. - -Arguments: - - Device - Handle to a Framework device object. - -Return Value: - - NTSTATUS - Failure will result in the device remaining in the D0 state. - ---*/ -{ - UNREFERENCED_PARAMETER(Device); - - PAGED_CODE(); - - KdPrint(( "--> ToasterEvtDeviceArmWakeFromSx\n")); - - KdPrint(( "<-- ToasterEvtDeviceArmWakeFromSx\n")); - - return STATUS_SUCCESS; -} - -VOID -ToasterEvtDeviceDisarmWakeFromS0( - IN WDFDEVICE Device - ) -/*++ - -Routine Description: - - EvtDeviceDisarmWakeFromS0 reverses anything done in EvtDeviceArmWakeFromS0. - - This function is not marked pageable because this function is in the - device power up path. When a function is marked pagable and the code - section is paged out, it will generate a page fault which could impact - the fast resume behavior because the client driver will have to wait - until the system drivers can service this page fault. - -Arguments: - - Device - Handle to a Framework device object. - -Return Value: - - VOID. - ---*/ -{ - UNREFERENCED_PARAMETER(Device); - - KdPrint(( "--> ToasterEvtDeviceDisarmWakeFromS0\n")); - - KdPrint(( "<-- ToasterEvtDeviceDisarmWakeFromS0\n")); - - return ; -} - -VOID -ToasterEvtDeviceDisarmWakeFromSx( - IN WDFDEVICE Device - ) -/*++ - -Routine Description: - - EvtDeviceDisarmWakeFromSx reverses anything done in EvtDeviceArmWakeFromSx. - - This function will run at PASSIVE_LEVEL. - - This function is not marked pageable because this function is in the - device power up path. When a function is marked pagable and the code - section is paged out, it will generate a page fault which could impact - the fast resume behavior because the client driver will have to wait - until the system drivers can service this page fault. - -Arguments: - - Device - Handle to a Framework device object. - -Return Value: - - VOID. - ---*/ -{ - UNREFERENCED_PARAMETER(Device); - - KdPrint(( "--> ToasterEvtDeviceDisarmWakeFromSx\n")); - - KdPrint(( "<-- ToasterEvtDeviceDisarmWakeFromSx\n")); - - return ; -} - -VOID -ToasterEvtDeviceWakeFromS0Triggered( - IN WDFDEVICE Device - ) -/*++ - -Routine Description: - - EvtDeviceWakeFromS0Triggered will be called whenever the device triggers its - wake signal after being armed for wake. - - This function is pageable and runs at PASSIVE_LEVEL. - -Arguments: - - Device - Handle to a Framework device object. - -Return Value: - - VOID - ---*/ -{ - UNREFERENCED_PARAMETER(Device); - - PAGED_CODE(); - - KdPrint(( "--> ToasterEvtDeviceWakeFromS0Triggered\n")); - - - KdPrint(( "<-- ToasterEvtDeviceWakeFromS0Triggered\n")); - -} - -VOID -ToasterEvtDeviceWakeFromSxTriggered( - IN WDFDEVICE Device - ) -/*++ - -Routine Description: - - EvtDeviceWakeFromSxTriggered will be called whenever the device triggers its - wake signal after being armed for wake. - - This function runs at PASSIVE_LEVEL. - - This function is not marked pageable because this function is in the - device power up path. When a function is marked pagable and the code - section is paged out, it will generate a page fault which could impact - the fast resume behavior because the client driver will have to wait - until the system drivers can service this page fault. - -Arguments: - - Device - Handle to a Framework device object. - -Return Value: - - VOID - ---*/ -{ - UNREFERENCED_PARAMETER(Device); - - KdPrint(( "--> ToasterEvtDeviceWakeFromSxTriggered\n")); - - KdPrint(( "<-- ToasterEvtDeviceWakeFromSxTriggered\n")); - -} - -PCHAR -DbgDevicePowerString( - IN WDF_POWER_DEVICE_STATE Type - ) -/*++ - -New Routine Description: - DbgDevicePowerString converts the device power state code of a power IRP to a - text string that is helpful when tracing the execution of power IRPs. - -Parameters Description: - Type - Type specifies the device power state code of a power IRP. - -Return Value Description: - DbgDevicePowerString returns a pointer to a string that represents the - text description of the incoming device power state code. - ---*/ -{ - PAGED_CODE(); - - switch (Type) - { - case WdfPowerDeviceInvalid: - return "WdfPowerDeviceInvalid"; - case WdfPowerDeviceD0: - return "WdfPowerDeviceD0"; - case WdfPowerDeviceD1: - return "WdfPowerDeviceD1"; - case WdfPowerDeviceD2: - return "WdfPowerDeviceD2"; - case WdfPowerDeviceD3: - return "WdfPowerDeviceD3"; - case WdfPowerDeviceD3Final: - return "WdfPowerDeviceD3Final"; - case WdfPowerDevicePrepareForHibernation: - return "WdfPowerDevicePrepareForHibernation"; - case WdfPowerDeviceMaximum: - return "WdfPowerDeviceMaximum"; - default: - return "UnKnown Device Power State"; - } -} - - - - diff --git a/general/toaster/umdf2/func/featured/toaster.c b/general/toaster/umdf2/func/featured/toaster.c deleted file mode 100644 index c25eebd4..00000000 --- a/general/toaster/umdf2/func/featured/toaster.c +++ /dev/null @@ -1,862 +0,0 @@ -/*++ - -Copyright (c) Microsoft Corporation. All rights reserved. - - THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY - KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR - PURPOSE. - -Module Name: - - Toaster.c - -Abstract: - - This is a featured version of the toaster function driver. This version - shows how to register for PNP and Power events, handle create & close - file requests. - -Environment: - - Kernel mode - ---*/ - -#include "toaster.h" - -#ifdef ALLOC_PRAGMA -#pragma alloc_text (INIT, DriverEntry) -#pragma alloc_text (PAGE, ToasterEvtDeviceAdd) -#pragma alloc_text (PAGE, ToasterEvtDeviceFileCreate) -#pragma alloc_text (PAGE, ToasterEvtFileClose) -#pragma alloc_text (PAGE, ToasterEvtDevicePrepareHardware) -#pragma alloc_text (PAGE, ToasterEvtDeviceReleaseHardware) -#pragma alloc_text (PAGE, ToasterEvtDeviceContextCleanup) -#pragma alloc_text (PAGE, ToasterEvtIoDeviceControl) -#pragma alloc_text (PAGE, ToasterEvtIoRead) -#pragma alloc_text (PAGE, ToasterEvtIoWrite) -#endif - -NTSTATUS -DriverEntry( - IN PDRIVER_OBJECT DriverObject, - IN PUNICODE_STRING RegistryPath - ) -/*++ - -Routine Description: - DriverEntry initializes the driver and is the first routine called by the - system after the driver is loaded. DriverEntry specifies the other entry - points in the function driver, such as ToasterAddDevice and ToasterUnload. - -Parameters Description: - - DriverObject - represents the instance of the function driver that is loaded - into memory. DriverEntry must initialize members of DriverObject before it - returns to the caller. DriverObject is allocated by the system before the - driver is loaded, and it is released by the system after the system unloads - the function driver from memory. - - RegistryPath - represents the driver specific path in the Registry. - The function driver can use the path to store driver related data between - reboots. The path does not store hardware instance specific data. - -Return Value: - - STATUS_SUCCESS if successful, - STATUS_UNSUCCESSFUL otherwise. - ---*/ -{ - NTSTATUS status = STATUS_SUCCESS; - WDF_DRIVER_CONFIG config; - - KdPrint(("WDF Toaster Function Driver Sample - Featured version\n")); - - // - // Initiialize driver config to control the attributes that - // are global to the driver. Note that framework by default - // provides a driver unload routine. If you create any resources - // in the DriverEntry and want to be cleaned in driver unload, - // you can override that by manually setting the EvtDriverUnload in the - // config structure. In general xxx_CONFIG_INIT macros are provided to - // initialize most commonly used members. - // - - WDF_DRIVER_CONFIG_INIT( - &config, - ToasterEvtDeviceAdd - ); - - // - // Create a framework driver object to represent our driver. - // - status = WdfDriverCreate( - DriverObject, - RegistryPath, - WDF_NO_OBJECT_ATTRIBUTES, // Driver Attributes - &config, // Driver Config Info - WDF_NO_HANDLE - ); - - if (!NT_SUCCESS(status)) { - KdPrint( ("WdfDriverCreate failed with status 0x%x\n", status)); - } - - return status; -} - - -NTSTATUS -ToasterEvtDeviceAdd( - IN WDFDRIVER Driver, - IN PWDFDEVICE_INIT DeviceInit - ) -/*++ -Routine Description: - - ToasterEvtDeviceAdd is called by the framework in response to AddDevice - call from the PnP manager. We create and initialize a device object to - represent a new instance of toaster device. - -Arguments: - - Driver - Handle to a framework driver object created in DriverEntry - - DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure. - -Return Value: - - NTSTATUS - ---*/ -{ - NTSTATUS status = STATUS_SUCCESS; - WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks; - WDF_OBJECT_ATTRIBUTES fdoAttributes; - WDFDEVICE device; - WDF_FILEOBJECT_CONFIG fileConfig; - WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS idleSettings; - WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS wakeSettings; - WDF_POWER_POLICY_EVENT_CALLBACKS powerPolicyCallbacks; - WDF_IO_QUEUE_CONFIG queueConfig; - //PFDO_DATA fdoData; - WDFQUEUE queue; - - UNREFERENCED_PARAMETER(Driver); - - PAGED_CODE(); - - KdPrint(("ToasterEvtDeviceAdd called\n")); - - // - // Initialize the pnpPowerCallbacks structure. Callback events for PNP - // and Power are specified here. If you don't supply any callbacks, - // the Framework will take appropriate default actions based on whether - // DeviceInit is initialized to be an FDO, a PDO or a filter device - // object. - // - - WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks); - - // - // Register PNP callbacks. - // - pnpPowerCallbacks.EvtDevicePrepareHardware = ToasterEvtDevicePrepareHardware; - pnpPowerCallbacks.EvtDeviceReleaseHardware = ToasterEvtDeviceReleaseHardware; - pnpPowerCallbacks.EvtDeviceSelfManagedIoInit = ToasterEvtDeviceSelfManagedIoInit; - - // - // Register Power callbacks. - // - pnpPowerCallbacks.EvtDeviceD0Entry = ToasterEvtDeviceD0Entry; - pnpPowerCallbacks.EvtDeviceD0Exit = ToasterEvtDeviceD0Exit; - - - WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks); - - // - // Register power policy event callbacks so that we would know when to - // arm/disarm the hardware to handle wait-wake and when the wake event - // is triggered by the hardware. - // - WDF_POWER_POLICY_EVENT_CALLBACKS_INIT(&powerPolicyCallbacks); - - // - // This group of three callbacks allows this sample driver to manage - // arming the device for wake from the S0 or Sx state. We don't really - // differentiate between S0 and Sx state.. - // - powerPolicyCallbacks.EvtDeviceArmWakeFromS0 = ToasterEvtDeviceArmWakeFromS0; - powerPolicyCallbacks.EvtDeviceDisarmWakeFromS0 = ToasterEvtDeviceDisarmWakeFromS0; - powerPolicyCallbacks.EvtDeviceWakeFromS0Triggered = ToasterEvtDeviceWakeFromS0Triggered; - powerPolicyCallbacks.EvtDeviceArmWakeFromSx = ToasterEvtDeviceArmWakeFromSx; - powerPolicyCallbacks.EvtDeviceDisarmWakeFromSx = ToasterEvtDeviceDisarmWakeFromSx; - powerPolicyCallbacks.EvtDeviceWakeFromSxTriggered = ToasterEvtDeviceWakeFromSxTriggered; - - // - // Register the power policy callbacks. - // - WdfDeviceInitSetPowerPolicyEventCallbacks(DeviceInit, &powerPolicyCallbacks); - - // - // Initialize WDF_FILEOBJECT_CONFIG_INIT struct to tell the - // framework whether you are interested in handling Create, Close and - // Cleanup requests that gets genereate when an application or another - // kernel component opens an handle to the device. If you don't register, - // the framework default behaviour would be complete these requests - // with STATUS_SUCCESS. A driver might be interested in registering these - // events if it wants to do security validation and also wants to maintain - // per handle (fileobject) context. - // - - WDF_FILEOBJECT_CONFIG_INIT( - &fileConfig, - ToasterEvtDeviceFileCreate, - ToasterEvtFileClose, - WDF_NO_EVENT_CALLBACK // not interested in Cleanup - ); - - WdfDeviceInitSetFileObjectConfig(DeviceInit, - &fileConfig, - WDF_NO_OBJECT_ATTRIBUTES); - - // - // Now specify the size of device extension where we track per device - // context. Along with setting the context type as shown below, you should also - // specify the WDF_DECLARE_CONTEXT_TYPE_WITH_NAME in header to specify the - // accessor function name. - // - WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&fdoAttributes, FDO_DATA); - - // - // Set a context cleanup routine to cleanup any resources that are not - // parent to this device. This cleanup will be called in the context of - // pnp remove-device when the framework deletes the device object. - // - fdoAttributes.EvtCleanupCallback = ToasterEvtDeviceContextCleanup; - - // - // DeviceInit is completely initialized. So call the framework to create the - // device and attach it to the lower stack. - // - status = WdfDeviceCreate(&DeviceInit, &fdoAttributes, &device); - if (!NT_SUCCESS(status)) { - KdPrint( ("WdfDeviceCreate failed with Status code 0x%x\n", status)); - return status; - } - - // - // Get the device context by using accessor function specified in - // the WDF_DECLARE_CONTEXT_TYPE_WITH_NAME macro for FDO_DATA. - // - //fdoData = ToasterFdoGetData(device); - - // - // Tell the Framework that this device will need an interface so that - // application can find our device and talk to it. - // - status = WdfDeviceCreateDeviceInterface( - device, - (LPGUID) &GUID_DEVINTERFACE_TOASTER, - NULL - ); - - if (!NT_SUCCESS (status)) { - KdPrint( ("WdfDeviceCreateDeviceInterface failed 0x%x\n", status)); - return status; - } - - // - // Register I/O callbacks to tell the framework that you are interested - // in handling IRP_MJ_READ, IRP_MJ_WRITE, and IRP_MJ_DEVICE_CONTROL requests. - // In case a specific handler is not specified for one of these, - // the request will be dispatched to the EvtIoDefault handler, if any. - // If there is no EvtIoDefault handler, the request will be failed with - // STATUS_INVALID_DEVICE_REQUEST. - // WdfIoQueueDispatchParallel means that we are capable of handling - // all the I/O request simultaneously and we are responsible for protecting - // data that could be accessed by these callbacks simultaneously. - // A default queue gets all the requests that are not - // configure-fowarded using WdfDeviceConfigureRequestDispatching. - // - WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&queueConfig, - WdfIoQueueDispatchParallel); // EvtIoCancel - - queueConfig.EvtIoRead = ToasterEvtIoRead; - queueConfig.EvtIoWrite = ToasterEvtIoWrite; - queueConfig.EvtIoDeviceControl = ToasterEvtIoDeviceControl; - - // - // By default, Static Driver Verifier (SDV) displays a warning if it - // doesn't find the EvtIoStop callback on a power-managed queue. - // The 'assume' below causes SDV to suppress this warning. If the driver - // has not explicitly set PowerManaged to WdfFalse, the framework creates - // power-managed queues when the device is not a filter driver. Normally - // the EvtIoStop is required for power-managed queues, but for this driver - // it is not needed b/c the driver doesn't hold on to the requests or - // forward them to other drivers. This driver completes the requests - // directly in the queue's handlers. If the EvtIoStop callback is not - // implemented, the framework waits for all driver-owned requests to be - // done before moving in the Dx/sleep states or before removing the - // device, which is the correct behavior for this type of driver. - // If the requests were taking an indeterminate amount of time to complete, - // or if the driver forwarded the requests to a lower driver/another stack, - // the queue should have an EvtIoStop/EvtIoResume. - // - __analysis_assume(queueConfig.EvtIoStop != 0); - status = WdfIoQueueCreate(device, - &queueConfig, - WDF_NO_OBJECT_ATTRIBUTES, - &queue - ); - __analysis_assume(queueConfig.EvtIoStop == 0); - - if (!NT_SUCCESS (status)) { - - KdPrint( ("WdfIoQueueCreate failed 0x%x\n", status)); - return status; - } - - // - // Set the idle power policy to put the device to Dx if the device is not used - // for the specified IdleTimeout time. Since this is a virtual device we - // tell the framework that we cannot wake ourself if we sleep in S0. Only - // way the device can be brought to D0 is if the device recieves an I/O from - // the system. - // - WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_INIT(&idleSettings, IdleCannotWakeFromS0); - idleSettings.IdleTimeout = 60000; // 60 secs idle timeout - status = WdfDeviceAssignS0IdleSettings(device, &idleSettings); - if (!NT_SUCCESS(status)) { - KdPrint( ("WdfDeviceAssignS0IdleSettings failed 0x%x\n", status)); - return status; - } - - // - // Set the wait-wake policy. - // - - WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_INIT(&wakeSettings); - status = WdfDeviceAssignSxWakeSettings(device, &wakeSettings); - if (!NT_SUCCESS(status)) { - // - // We are probably enumerated on a bus that doesn't support Sx-wake. - // Let us not fail the device add just because we aren't able to support - // wait-wake. I will let the user of this sample decide how important it's - // to support wait-wake for their hardware and return appropriate status. - // - KdPrint( ("WdfDeviceAssignSxWakeSettings failed 0x%x\n", status)); - status = STATUS_SUCCESS; - } - - return status; -} - -NTSTATUS -ToasterEvtDevicePrepareHardware( - WDFDEVICE Device, - WDFCMRESLIST ResourcesRaw, - WDFCMRESLIST ResourcesTranslated - ) -/*++ - -Routine Description: - - EvtDevicePrepareHardware event callback performs operations that are - necessary to make the driver's device operational. The framework calls the - driver's EvtDevicePrepareHardware callback when the PnP manager sends an - IRP_MN_START_DEVICE request to the driver stack. - - Specifically, most drivers will use this callback to map resources. USB - drivers may use it to get device descriptors, config descriptors and to - select configs. - - Some drivers may choose to download firmware to a device in this callback, - but that is usually only a good choice if the device firmware won't be - destroyed by a D0 to D3 transition. If firmware will be gone after D3, - then firmware downloads should be done in EvtDeviceD0Entry, not here. - -Arguments: - - Device - Handle to a framework device object. - - ResourcesRaw - Handle to a collection of framework resource objects. - This collection identifies the raw (bus-relative) hardware - resources that have been assigned to the device. - - ResourcesTranslated - Handle to a collection of framework resource objects. - This collection identifies the translated (system-physical) - hardware resources that have been assigned to the device. - The resources appear from the CPU's point of view. - Use this list of resources to map I/O space and - device-accessible memory into virtual address space - -Return Value: - - WDF status code - ---*/ -{ - //PFDO_DATA fdoData; - NTSTATUS status = STATUS_SUCCESS; - ULONG i; - PCM_PARTIAL_RESOURCE_DESCRIPTOR descriptor; - - //fdoData = ToasterFdoGetData(Device); - - UNREFERENCED_PARAMETER(Device); - UNREFERENCED_PARAMETER(ResourcesRaw); - - KdPrint(("ToasterEvtDevicePrepareHardware called\n")); - - PAGED_CODE(); - // - // Get the number item that are currently in Resources collection and - // iterate thru as many times to get more information about the each items - // - for (i=0; i < WdfCmResourceListGetCount(ResourcesTranslated); i++) { - - descriptor = WdfCmResourceListGetDescriptor(ResourcesTranslated, i); - - switch(descriptor->Type) { - - case CmResourceTypePort: - - KdPrint(("I/O Port: (%x) Length: (%d)\n", - descriptor->u.Port.Start.LowPart, - descriptor->u.Port.Length)); - break; - - case CmResourceTypeMemory: - - KdPrint(("Memory: (%x) Length: (%d)\n", - descriptor->u.Memory.Start.LowPart, - descriptor->u.Memory.Length)); - break; - case CmResourceTypeInterrupt: - - KdPrint(("Interrupt level: 0x%0x, Vector: 0x%0x, Affinity: 0x%0Ix\n", - descriptor->u.Interrupt.Level, - descriptor->u.Interrupt.Vector, - descriptor->u.Interrupt.Affinity)); - break; - - default: - break; - } - - } - - return status; - -} - -NTSTATUS -ToasterEvtDeviceReleaseHardware( - IN WDFDEVICE Device, - IN WDFCMRESLIST ResourcesTranslated - ) -/*++ - -Routine Description: - - EvtDeviceReleaseHardware is called by the framework whenever the PnP manager - is revoking ownership of our resources. This may be in response to either - IRP_MN_STOP_DEVICE or IRP_MN_REMOVE_DEVICE. The callback is made before - passing down the IRP to the lower driver. - - In this callback, do anything necessary to free those resources. - -Arguments: - - Device - Handle to a framework device object. - - ResourcesTranslated - Handle to a collection of framework resource objects. - This collection identifies the translated (system-physical) - hardware resources that have been assigned to the device. - The resources appear from the CPU's point of view. - Use this list of resources to map I/O space and - device-accessible memory into virtual address space - -Return Value: - - NTSTATUS - Failures will be logged, but not acted on. - ---*/ -{ - //PFDO_DATA fdoData; - - UNREFERENCED_PARAMETER(Device); - UNREFERENCED_PARAMETER(ResourcesTranslated); - - KdPrint(("ToasterEvtDeviceReleaseHardware called\n")); - - PAGED_CODE(); - - //fdoData = ToasterFdoGetData(Device); - // - // Unmap any I/O ports, registers that you mapped in PrepareHardware. - // Disconnecting from the interrupt will be done automatically by the framework. - // - return STATUS_SUCCESS; -} - -NTSTATUS -ToasterEvtDeviceSelfManagedIoInit( - IN WDFDEVICE Device - ) -/*++ - -Routine Description: - - EvtDeviceSelfManagedIoInit is called it once for each device, - after the framework has called the driver's EvtDeviceD0Entry - callback function for the first time. The framework does not - call the EvtDeviceSelfManagedIoInit callback function again for - that device, unless the device is removed and reconnected, or - the drivers are reloaded. - - The EvtDeviceSelfManagedIoInit callback function must initialize - the self-managed I/O operations that the driver will handle - for the device. - - This function is not marked pageable because this function is in the - device power up path. When a function is marked pagable and the code - section is paged out, it will generate a page fault which could impact - the fast resume behavior because the client driver will have to wait - until the system drivers can service this page fault. - -Arguments: - - Device - Handle to a framework device object. - -Return Value: - - NTSTATUS - Failures will result in the device stack being torn down. - ---*/ -{ - UNREFERENCED_PARAMETER(Device); - - KdPrint(("ToasterEvtDeviceSelfManagedIoInit called\n")); - - return STATUS_SUCCESS; -} - - -VOID -ToasterEvtDeviceContextCleanup( - IN WDFOBJECT Device - ) -/*++ - -Routine Description: - - EvtDeviceContextCleanup event callback must perform any operations that are - necessary before the specified device is removed. The framework calls - the driver's EvtDeviceContextCleanup callback when the device is deleted in response - to IRP_MN_REMOVE_DEVICE request. - -Arguments: - - Device - Handle to a framework device object. - -Return Value: - - None - ---*/ -{ - //PFDO_DATA fdoData; - UNREFERENCED_PARAMETER(Device); - KdPrint( ("ToasterEvtDeviceContextCleanup called\n")); - - PAGED_CODE(); - - //fdoData = ToasterFdoGetData((WDFDEVICE)Device); - - return; -} - -VOID -ToasterEvtDeviceFileCreate ( - IN WDFDEVICE Device, - IN WDFREQUEST Request, - IN WDFFILEOBJECT FileObject - ) -/*++ - -Routine Description: - - The framework calls a driver's EvtDeviceFileCreate callback - when the framework receives an IRP_MJ_CREATE request. - The system sends this request when a user application opens the - device to perform an I/O operation, such as reading or writing to a device. - This callback is called in the context of the thread - that created the IRP_MJ_CREATE request. - -Arguments: - - Device - Handle to a framework device object. - FileObject - Pointer to fileobject that represents the open handle. - CreateParams - Parameters for create - -Return Value: - - None - ---*/ -{ - //PFDO_DATA fdoData; - - UNREFERENCED_PARAMETER(FileObject); - UNREFERENCED_PARAMETER(Device); - - KdPrint( ("ToasterEvtDeviceFileCreate %p\n", Device)); - - PAGED_CODE (); - - // - // Get the device context given the device handle. - // - //fdoData = ToasterFdoGetData(Device); - - WdfRequestComplete(Request, STATUS_SUCCESS); - - return; -} - - -VOID -ToasterEvtFileClose ( - IN WDFFILEOBJECT FileObject - ) - -/*++ - -Routine Description: - - EvtFileClose is called when all the handles represented by the FileObject - is closed and all the references to FileObject is removed. This callback - may get called in an arbitrary thread context instead of the thread that - called CloseHandle. If you want to delete any per FileObject context that - must be done in the context of the user thread that made the Create call, - you should do that in the EvtDeviceCleanp callback. - -Arguments: - - FileObject - Pointer to fileobject that represents the open handle. - -Return Value: - - None - ---*/ -{ - //PFDO_DATA fdoData; - UNREFERENCED_PARAMETER(FileObject); - PAGED_CODE (); - - //fdoData = ToasterFdoGetData(WdfFileObjectGetDevice(FileObject)); - - KdPrint( ("ToasterEvtFileClose\n")); - - return; -} - - - -VOID -ToasterEvtIoRead ( - WDFQUEUE Queue, - WDFREQUEST Request, - size_t Length - ) -/*++ - -Routine Description: - - Performs read to the toaster device. This event is called when the - framework receives IRP_MJ_READ requests. - -Arguments: - - Queue - Handle to the framework queue object that is associated with the - I/O request. - Request - Handle to a framework request object. - - Lenght - Length of the data buffer associated with the request. - The default property of the queue is to not dispatch - zero lenght read & write requests to the driver and - complete is with status success. So we will never get - a zero length request. - -Return Value: - - None - ---*/ -{ - NTSTATUS status; - ULONG_PTR bytesCopied =0; - WDFMEMORY memory; - - UNREFERENCED_PARAMETER(Length); - UNREFERENCED_PARAMETER(Queue); - - PAGED_CODE(); - - KdPrint(("ToasterEvtIoRead: Request: 0x%p, Queue: 0x%p\n", - Request, Queue)); - - // - // Get the request memory and perform read operation here - // - status = WdfRequestRetrieveOutputMemory(Request, &memory); - if(NT_SUCCESS(status) ) { - // - // Copy data into the memory buffer using WdfMemoryCopyFromBuffer - // - } - - WdfRequestCompleteWithInformation(Request, status, bytesCopied); - -} - -VOID -ToasterEvtIoWrite ( - WDFQUEUE Queue, - WDFREQUEST Request, - size_t Length - ) -/*++ - -Routine Description: - - Performs write to the toaster device. This event is called when the - framework receives IRP_MJ_WRITE requests. - -Arguments: - - Queue - Handle to the framework queue object that is associated with the - I/O request. - Request - Handle to a framework request object. - - Lenght - Length of the data buffer associated with the request. - The default property of the queue is to not dispatch - zero lenght read & write requests to the driver and - complete is with status success. So we will never get - a zero length request. - -Return Value: - - None - ---*/ - -{ - NTSTATUS status; - WDFMEMORY memory; - - UNREFERENCED_PARAMETER(Queue); - - KdPrint(("ToasterEvtIoWrite. Request: 0x%p, Queue: 0x%p\n", - Request, Queue)); - PAGED_CODE(); - - // - // Get the request buffer and perform write operation here - // - status = WdfRequestRetrieveInputMemory(Request, &memory); - if(NT_SUCCESS(status) ) { - // - // 1) Use WdfMemoryCopyToBuffer to copy data from the request - // to driver buffer. - // 2) Or get the buffer pointer from the request by calling - // WdfRequestRetrieveInputBuffer to transfer data to the hw - // 3) Or you can get the buffer pointer from the memory handle - // by calling WdfMemoryGetBuffer to transfer data to the hw. - // - } - - WdfRequestCompleteWithInformation(Request, status, Length); - -} - - -VOID -ToasterEvtIoDeviceControl( - IN WDFQUEUE Queue, - IN WDFREQUEST Request, - IN size_t OutputBufferLength, - IN size_t InputBufferLength, - IN ULONG IoControlCode - ) -/*++ -Routine Description: - - This event is called when the framework receives IRP_MJ_DEVICE_CONTROL - requests from the system. - -Arguments: - - Queue - Handle to the framework queue object that is associated - with the I/O request. - Request - Handle to a framework request object. - - OutputBufferLength - length of the request's output buffer, - if an output buffer is available. - InputBufferLength - length of the request's input buffer, - if an input buffer is available. - - IoControlCode - the driver-defined or system-defined I/O control code - (IOCTL) that is associated with the request. - -Return Value: - - None - ---*/ -{ - NTSTATUS status= STATUS_SUCCESS; - WDF_DEVICE_STATE deviceState; - WDFDEVICE hDevice = WdfIoQueueGetDevice(Queue); - - - UNREFERENCED_PARAMETER(OutputBufferLength); - UNREFERENCED_PARAMETER(InputBufferLength); - - KdPrint(("ToasterEvtIoDeviceControl called\n")); - - PAGED_CODE(); - - switch (IoControlCode) { - - case IOCTL_TOASTER_DONT_DISPLAY_IN_UI_DEVICE: - // - // This is just an example on how to hide your device in the - // device manager. Please remove this code when you adapt - // this sample for your hardware. - // - WDF_DEVICE_STATE_INIT(&deviceState); - deviceState.DontDisplayInUI = WdfTrue; - WdfDeviceSetDeviceState( - hDevice, - &deviceState - ); - break; - - default: - status = STATUS_INVALID_DEVICE_REQUEST; - } - - // - // Complete the Request. - // - WdfRequestCompleteWithInformation(Request, status, (ULONG_PTR) 0); - -} - - diff --git a/general/toaster/umdf2/func/featured/toaster.rc b/general/toaster/umdf2/func/featured/toaster.rc deleted file mode 100644 index e9ba2ea8..00000000 --- a/general/toaster/umdf2/func/featured/toaster.rc +++ /dev/null @@ -1,12 +0,0 @@ -#include - -#include - -#define VER_FILETYPE VFT_DLL -#define VER_FILESUBTYPE VFT_UNKNOWN -#define VER_FILEDESCRIPTION_STR "WDF UMDF2 Toaster Device Driver" -#define VER_INTERNALNAME_STR "wdftoaster.dll" -#define VER_ORIGINALFILENAME_STR "wdftoaster.dll" - -#include "common.ver" - diff --git a/general/toaster/umdf2/func/featured/wdffeaturedum.inx b/general/toaster/umdf2/func/featured/wdffeaturedum.inx deleted file mode 100644 index feae7a33..00000000 --- a/general/toaster/umdf2/func/featured/wdffeaturedum.inx +++ /dev/null @@ -1,98 +0,0 @@ -;/*++ -; -;Copyright (c) Microsoft Corporation. All rights reserved. -; -;Module Name: -; wdffeatured.INF -; -;Abstract: -; INF file for installing the UMDF2 Toaster Driver -; -;Installation Notes: -; Using Devcon: Type "devcon install wdffeaturedum.inf root\toaster" to install -; -;--*/ - -[Version] -Signature="$WINDOWS NT$" -Class=TOASTER -ClassGuid={B85B7C50-6A01-11d2-B841-00C04FAD5171} -Provider=%MSFT% -DriverVer=03/20/2003,5.00.3788 -CatalogFile=wudf.cat - -[DestinationDirs] -DefaultDestDir = 12 - -; ================= Class section ===================== - -[ClassInstall32] -Addreg=ToasterClassReg - -[ToasterClassReg] -HKR,,,0,%ClassName% -HKR,,Icon,,100 -HKR,,DeviceCharacteristics,0x10001,0x100 ;Use same security checks on relative opens -HKR,,Security,,"D:P(A;;GA;;;SY)(A;;GA;;;BA)" ;Allow generic all access to system and built-in Admin. - ;This one overrides the security set by the driver - -[SourceDisksNames] -1 = %DiskId1%,,,"" - -[SourceDisksFiles] -wdffeaturedum.dll = 1,, - -;***************************************** -; Toaster Install Section -;***************************************** - -[Manufacturer] -%StdMfg%=Standard,NT$ARCH$ - -; -; Hw Id is root\toaster -; -[Standard.NT$ARCH$] -%Toaster.DeviceDesc%=Toaster_Device, root\toaster - -;---------------- copy files - -[Toaster_Device.NT] -CopyFiles=UMDriverCopy - -[UMDriverCopy] -wdffeaturedum.dll,,,0x00004000 ; COPYFLG_IN_USE_RENAME - -[DestinationDirs] -UMDriverCopy=12,UMDF ; copy to drivers\umdf - -;-------------- Service installation -[Toaster_Device.NT.Services] -AddService=WUDFRd,0x000001fa,WUDFRD_ServiceInstall - -[WUDFRD_ServiceInstall] -DisplayName = %WudfRdDisplayName% -ServiceType = 1 -StartType = 3 -ErrorControl = 1 -ServiceBinary = %12%\WUDFRd.sys - -;-------------- WDF specific section ------------- -[Toaster_Device.NT.Wdf] -UmdfService=wdffeaturedum, Toaster_Install -UmdfServiceOrder=wdffeaturedum - -[Toaster_Install] -UmdfLibraryVersion=$UMDFVERSION$ -ServiceBinary=%12%\UMDF\wdffeaturedum.dll - -[Strings] -SPSVCINST_ASSOCSERVICE= 0x00000002 -MSFT = "Microsoft" -StdMfg = "(Standard system devices)" -DiskId1 = "WDF Sample Toaster Installation Disk #1" -Toaster.DeviceDesc = "Sample UMDF Toaster Driver - featured" -Toaster.SVCDESC = "Sample WDF Toaster Service" -ClassName = "Toaster" -WudfRdDisplayName="Windows Driver Foundation - User-mode Driver Framework Reflector" - diff --git a/general/toaster/umdf2/func/featured/wdffeaturedum.vcxproj b/general/toaster/umdf2/func/featured/wdffeaturedum.vcxproj deleted file mode 100644 index 1af04c81..00000000 --- a/general/toaster/umdf2/func/featured/wdffeaturedum.vcxproj +++ /dev/null @@ -1,180 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - {99A6009E-6137-462F-89C4-6931045895B1} - $(MSBuildProjectName) - 2 - Debug - Win32 - {3E5FB5B1-CA59-4675-AAF8-93039F74CF02} - - - - Windows10 - False - Universal - UMDF - WindowsUserModeDriver10.0 - DynamicLibrary - - - Windows10 - True - Universal - UMDF - WindowsUserModeDriver10.0 - DynamicLibrary - - - Windows10 - False - Universal - UMDF - WindowsUserModeDriver10.0 - DynamicLibrary - - - Windows10 - True - Universal - UMDF - WindowsUserModeDriver10.0 - DynamicLibrary - - - - $(IntDir) - - - - - - - - - - - - - - - - $(InfArch) - true - .\$(IntDir)\wdffeaturedum.inf - - - - wdffeaturedum - - - wdffeaturedum - - - wdffeaturedum - - - wdffeaturedum - - - - %(AdditionalDependencies);$(SDK_LIB_PATH)\mincore.lib - - - %(AdditionalIncludeDirectories);..\..\inc;..\shared - - - %(AdditionalIncludeDirectories);..\..\inc;..\shared - - - - - %(AdditionalIncludeDirectories);..\..\inc;..\shared - - - - - %(AdditionalDependencies);$(SDK_LIB_PATH)\mincore.lib - - - %(AdditionalIncludeDirectories);..\..\inc;..\shared - - - %(AdditionalIncludeDirectories);..\..\inc;..\shared - - - - - %(AdditionalIncludeDirectories);..\..\inc;..\shared - - - - - %(AdditionalDependencies);$(SDK_LIB_PATH)\mincore.lib - - - %(AdditionalIncludeDirectories);..\..\inc;..\shared - - - %(AdditionalIncludeDirectories);..\..\inc;..\shared - - - - - %(AdditionalIncludeDirectories);..\..\inc;..\shared - - - - - %(AdditionalDependencies);$(SDK_LIB_PATH)\mincore.lib - - - %(AdditionalIncludeDirectories);..\..\inc;..\shared - - - %(AdditionalIncludeDirectories);..\..\inc;..\shared - - - - - %(AdditionalIncludeDirectories);..\..\inc;..\shared - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/general/toaster/umdf2/func/featured/wdffeaturedum.vcxproj.Filters b/general/toaster/umdf2/func/featured/wdffeaturedum.vcxproj.Filters deleted file mode 100644 index ad344822..00000000 --- a/general/toaster/umdf2/func/featured/wdffeaturedum.vcxproj.Filters +++ /dev/null @@ -1,42 +0,0 @@ - - - - - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {180B07F2-6C79-44F0-9765-749A2975BA1F} - - - h;hpp;hxx;hm;inl;inc;xsd - {025585BB-48DE-4F3B-A929-D58821892D58} - - - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {A90CE102-D7E8-46E0-B8D8-D1A57A6CDE82} - - - inf;inv;inx;mof;mc; - {20EB3DBD-A818-46EE-A8B4-6A507F202B60} - - - - - Driver Files - - - Driver Files - - - - - Source Files - - - Source Files - - - - - Resource Files - - - \ No newline at end of file diff --git a/general/toaster/umdf2/func/shared/toaster.h b/general/toaster/umdf2/func/shared/toaster.h deleted file mode 100644 index 006166e7..00000000 --- a/general/toaster/umdf2/func/shared/toaster.h +++ /dev/null @@ -1,118 +0,0 @@ -/*++ - -Copyright (c) 1990-2000 Microsoft Corporation All Rights Reserved - -Module Name: - - Toaster.h - -Abstract: - - Header file for the toaster driver modules. - -Environment: - - User mode - ---*/ - - -#if !defined(_TOASTER_H_) -#define _TOASTER_H_ - -#include -#include -#pragma warning( disable: 4201 ) // nonstandard extension used : nameless struct/union -#include -#include -#include -#include -#include -#include "..\inc\driver.h" -#include "..\inc\public.h" - -#define TOASTER_POOL_TAG (ULONG) 'saoT' - -// -// The device extension for the device object -// -typedef struct _FDO_DATA -{ - - WDFWMIINSTANCE WmiDeviceArrivalEvent; - - BOOLEAN WmiPowerDeviceEnableRegistered; - -} FDO_DATA, *PFDO_DATA; - -WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(FDO_DATA, ToasterFdoGetData) - - -// -// Connector Types -// - -#define TOASTER_WMI_STD_I8042 0 -#define TOASTER_WMI_STD_SERIAL 1 -#define TOASTER_WMI_STD_PARALEL 2 -#define TOASTER_WMI_STD_USB 3 - -DRIVER_INITIALIZE DriverEntry; - -EVT_WDF_DRIVER_DEVICE_ADD ToasterEvtDeviceAdd; - -EVT_WDF_DEVICE_CONTEXT_CLEANUP ToasterEvtDeviceContextCleanup; -EVT_WDF_DEVICE_D0_ENTRY ToasterEvtDeviceD0Entry; -EVT_WDF_DEVICE_D0_EXIT ToasterEvtDeviceD0Exit; -EVT_WDF_DEVICE_PREPARE_HARDWARE ToasterEvtDevicePrepareHardware; -EVT_WDF_DEVICE_RELEASE_HARDWARE ToasterEvtDeviceReleaseHardware; - -EVT_WDF_DEVICE_SELF_MANAGED_IO_INIT ToasterEvtDeviceSelfManagedIoInit; - -// -// Io events callbacks. -// -EVT_WDF_IO_QUEUE_IO_READ ToasterEvtIoRead; -EVT_WDF_IO_QUEUE_IO_WRITE ToasterEvtIoWrite; -EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL ToasterEvtIoDeviceControl; -EVT_WDF_DEVICE_FILE_CREATE ToasterEvtDeviceFileCreate; -EVT_WDF_FILE_CLOSE ToasterEvtFileClose; - -NTSTATUS -ToasterWmiRegistration( - _In_ WDFDEVICE Device - ); - -// -// Power events callbacks -// -EVT_WDF_DEVICE_ARM_WAKE_FROM_S0 ToasterEvtDeviceArmWakeFromS0; -EVT_WDF_DEVICE_ARM_WAKE_FROM_SX ToasterEvtDeviceArmWakeFromSx; -EVT_WDF_DEVICE_DISARM_WAKE_FROM_S0 ToasterEvtDeviceDisarmWakeFromS0; -EVT_WDF_DEVICE_DISARM_WAKE_FROM_SX ToasterEvtDeviceDisarmWakeFromSx; -EVT_WDF_DEVICE_WAKE_FROM_S0_TRIGGERED ToasterEvtDeviceWakeFromS0Triggered; -EVT_WDF_DEVICE_WAKE_FROM_SX_TRIGGERED ToasterEvtDeviceWakeFromSxTriggered; - -PCHAR -DbgDevicePowerString( - IN WDF_POWER_DEVICE_STATE Type - ); - -// -// WMI event callbacks -// -EVT_WDF_WMI_INSTANCE_QUERY_INSTANCE EvtWmiInstanceStdDeviceDataQueryInstance; -EVT_WDF_WMI_INSTANCE_QUERY_INSTANCE EvtWmiInstanceToasterControlQueryInstance; -EVT_WDF_WMI_INSTANCE_SET_INSTANCE EvtWmiInstanceStdDeviceDataSetInstance; -EVT_WDF_WMI_INSTANCE_SET_INSTANCE EvtWmiInstanceToasterControlSetInstance; -EVT_WDF_WMI_INSTANCE_SET_ITEM EvtWmiInstanceToasterControlSetItem; -EVT_WDF_WMI_INSTANCE_SET_ITEM EvtWmiInstanceStdDeviceDataSetItem; -EVT_WDF_WMI_INSTANCE_EXECUTE_METHOD EvtWmiInstanceToasterControlExecuteMethod; - -NTSTATUS -ToasterFireArrivalEvent( - _In_ WDFDEVICE Device - ); - -#endif // _TOASTER_H_ - diff --git a/general/toaster/umdf2/func/simple/toaster.c b/general/toaster/umdf2/func/simple/toaster.c deleted file mode 100644 index 6ed215db..00000000 --- a/general/toaster/umdf2/func/simple/toaster.c +++ /dev/null @@ -1,418 +0,0 @@ -/*++ - -Copyright (c) Microsoft Corporation. All rights reserved. - - THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY - KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR - PURPOSE. - -Module Name: - - Toaster.c - -Abstract: - - This is a simple form of function driver for toaster device. The driver - doesn't handle any PnP and Power events because the framework provides - default behavior for those events. This driver has enough support to - allow an user application (toast/notify.exe) to open the device - interface registered by the driver and send read, write or ioctl requests. - -Environment: - - Kernel mode - ---*/ - -#include "toaster.h" - -#ifdef ALLOC_PRAGMA -#pragma alloc_text (INIT, DriverEntry) -#pragma alloc_text (PAGE, ToasterEvtDeviceAdd) -#pragma alloc_text (PAGE, ToasterEvtIoRead) -#pragma alloc_text (PAGE, ToasterEvtIoWrite) -#pragma alloc_text (PAGE, ToasterEvtIoDeviceControl) -#endif - - -NTSTATUS -DriverEntry( - IN PDRIVER_OBJECT DriverObject, - IN PUNICODE_STRING RegistryPath - ) -/*++ - -Routine Description: - DriverEntry initializes the driver and is the first routine called by the - system after the driver is loaded. DriverEntry configures and creates a WDF driver - object. - . -Parameters Description: - - DriverObject - represents the instance of the function driver that is loaded - into memory. DriverObject is allocated by the system before the - driver is loaded, and it is released by the system after the system unloads - the function driver from memory. - - RegistryPath - represents the driver specific path in the Registry. - The function driver can use the path to store driver related data between - reboots. The path does not store hardware instance specific data. - -Return Value: - - STATUS_SUCCESS if successful, - STATUS_UNSUCCESSFUL otherwise. - ---*/ -{ - NTSTATUS status = STATUS_SUCCESS; - WDF_DRIVER_CONFIG config; - - KdPrint(("Toaster Function Driver Sample - Driver Framework Edition.\n")); - - // - // Initiialize driver config to control the attributes that - // are global to the driver. Note that framework by default - // provides a driver unload routine. If DriverEntry creates any resources - // that require clean-up in driver unload, - // you can manually override the default by supplying a pointer to the EvtDriverUnload - // callback in the config structure. In general xxx_CONFIG_INIT macros are provided to - // initialize most commonly used members. - // - - WDF_DRIVER_CONFIG_INIT( - &config, - ToasterEvtDeviceAdd - ); - - - // - // Create a framework driver object to represent our driver. - // - status = WdfDriverCreate( - DriverObject, - RegistryPath, - WDF_NO_OBJECT_ATTRIBUTES, // Driver Attributes - &config, // Driver Config Info - WDF_NO_HANDLE - ); - - if (!NT_SUCCESS(status)) { - KdPrint( ("WdfDriverCreate failed with status 0x%x\n", status)); - } - - return status; -} - - -NTSTATUS -ToasterEvtDeviceAdd( - IN WDFDRIVER Driver, - IN PWDFDEVICE_INIT DeviceInit - ) -/*++ -Routine Description: - - ToasterEvtDeviceAdd is called by the framework in response to AddDevice - call from the PnP manager. We create and initialize a WDF device object to - represent a new instance of toaster device. - -Arguments: - - Driver - Handle to a framework driver object created in DriverEntry - - DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure. - -Return Value: - - NTSTATUS - ---*/ -{ - NTSTATUS status = STATUS_SUCCESS; - PFDO_DATA fdoData; - WDF_IO_QUEUE_CONFIG queueConfig; - WDF_OBJECT_ATTRIBUTES fdoAttributes; - WDFDEVICE hDevice; - WDFQUEUE queue; - - UNREFERENCED_PARAMETER(Driver); - - PAGED_CODE(); - - KdPrint(("ToasterEvtDeviceAdd called\n")); - - // - // Initialize attributes and a context area for the device object. - // - // - WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&fdoAttributes, FDO_DATA); - - // - // Create a framework device object.This call will in turn create - // a WDM device object, attach to the lower stack, and set the - // appropriate flags and attributes. - // - status = WdfDeviceCreate(&DeviceInit, &fdoAttributes, &hDevice); - if (!NT_SUCCESS(status)) { - KdPrint( ("WdfDeviceCreate failed with status code 0x%x\n", status)); - return status; - } - - // - // Get the device context by using the accessor function specified in - // the WDF_DECLARE_CONTEXT_TYPE_WITH_NAME macro for FDO_DATA. - // - fdoData = ToasterFdoGetData(hDevice); - - // - // Tell the Framework that this device will need an interface - // - status = WdfDeviceCreateDeviceInterface( - hDevice, - (LPGUID) &GUID_DEVINTERFACE_TOASTER, - NULL // ReferenceString - ); - - if (!NT_SUCCESS (status)) { - KdPrint( ("WdfDeviceCreateDeviceInterface failed 0x%x\n", status)); - return status; - } - - // - // Register I/O callbacks to tell the framework that you are interested - // in handling IRP_MJ_READ, IRP_MJ_WRITE, and IRP_MJ_DEVICE_CONTROL requests. - // If a specific callback function is not specified for one ofthese, - // the request will be dispatched to the EvtIoDefault handler, if any. - // If there is no EvtIoDefault handler, the request will be failed with - // STATUS_INVALID_DEVICE_REQUEST. - // WdfIoQueueDispatchParallel means that we are capable of handling - // all the I/O requests simultaneously and we are responsible for protecting - // data that could be accessed by these callbacks simultaneously. - // A default queue gets all the requests that are not - // configured for forwarding using WdfDeviceConfigureRequestDispatching. - // - WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&queueConfig, WdfIoQueueDispatchParallel); - - queueConfig.EvtIoRead = ToasterEvtIoRead; - queueConfig.EvtIoWrite = ToasterEvtIoWrite; - queueConfig.EvtIoDeviceControl = ToasterEvtIoDeviceControl; - - // - // By default, Static Driver Verifier (SDV) displays a warning if it - // doesn't find the EvtIoStop callback on a power-managed queue. - // The 'assume' below causes SDV to suppress this warning. If the driver - // has not explicitly set PowerManaged to WdfFalse, the framework creates - // power-managed queues when the device is not a filter driver. Normally - // the EvtIoStop is required for power-managed queues, but for this driver - // it is not needed b/c the driver doesn't hold on to the requests or - // forward them to other drivers. This driver completes the requests - // directly in the queue's handlers. If the EvtIoStop callback is not - // implemented, the framework waits for all driver-owned requests to be - // done before moving in the Dx/sleep states or before removing the - // device, which is the correct behavior for this type of driver. - // If the requests were taking an indeterminate amount of time to complete, - // or if the driver forwarded the requests to a lower driver/another stack, - // the queue should have an EvtIoStop/EvtIoResume. - // - __analysis_assume(queueConfig.EvtIoStop != 0); - status = WdfIoQueueCreate( - hDevice, - &queueConfig, - WDF_NO_OBJECT_ATTRIBUTES, - &queue - ); - __analysis_assume(queueConfig.EvtIoStop == 0); - - if (!NT_SUCCESS (status)) { - - KdPrint( ("WdfIoQueueCreate failed 0x%x\n", status)); - return status; - } - - return status; -} - -VOID -ToasterEvtIoRead ( - WDFQUEUE Queue, - WDFREQUEST Request, - size_t Length - ) -/*++ - -Routine Description: - - Performs read from the toaster device. This event is called when the - framework receives IRP_MJ_READ requests. - -Arguments: - - Queue - Handle to the framework queue object that is associated with the - I/O request. - Request - Handle to a framework request object. - - Lenght - Length of the data buffer associated with the request. - By default, the queue does not dispatch - zero length read & write requests to the driver and instead to - complete such requests with status success. So we will never get - a zero length request. - -Return Value: - - None. - ---*/ -{ - NTSTATUS status; - ULONG_PTR bytesCopied =0; - WDFMEMORY memory; - - UNREFERENCED_PARAMETER(Queue); - UNREFERENCED_PARAMETER(Length); - - PAGED_CODE(); - - KdPrint(( "ToasterEvtIoRead: Request: 0x%p, Queue: 0x%p\n", - Request, Queue)); - - // - // Get the request memory and perform read operation here - // - status = WdfRequestRetrieveOutputMemory(Request, &memory); - if(NT_SUCCESS(status) ) { - // - // Copy data into the memory buffer using WdfMemoryCopyFromBuffer - // - } - - WdfRequestCompleteWithInformation(Request, status, bytesCopied); -} - -VOID -ToasterEvtIoWrite ( - WDFQUEUE Queue, - WDFREQUEST Request, - size_t Length - ) -/*++ - -Routine Description: - - Performs write to the toaster device. This event is called when the - framework receives IRP_MJ_WRITE requests. - -Arguments: - - Queue - Handle to the framework queue object that is associated with the - I/O request. - Request - Handle to a framework request object. - - Lenght - Length of the data buffer associated with the request. - The default property of the queue is to not dispatch - zero lenght read & write requests to the driver and - complete is with status success. So we will never get - a zero length request. - -Return Value: - - None ---*/ - -{ - NTSTATUS status; - ULONG_PTR bytesWritten =0; - WDFMEMORY memory; - - UNREFERENCED_PARAMETER(Queue); - UNREFERENCED_PARAMETER(Length); - - KdPrint(("ToasterEvtIoWrite. Request: 0x%p, Queue: 0x%p\n", - Request, Queue)); - - PAGED_CODE(); - - // - // Get the request buffer and perform write operation here - // - status = WdfRequestRetrieveInputMemory(Request, &memory); - if(NT_SUCCESS(status) ) { - // - // 1) Use WdfMemoryCopyToBuffer to copy data from the request - // to driver buffer. - // 2) Or get the buffer pointer from the request by calling - // WdfRequestRetrieveInputBuffer - // 3) Or you can get the buffer pointer from the memory handle - // by calling WdfMemoryGetBuffer. - // - bytesWritten = Length; - } - - WdfRequestCompleteWithInformation(Request, status, bytesWritten); - -} - - -VOID -ToasterEvtIoDeviceControl( - IN WDFQUEUE Queue, - IN WDFREQUEST Request, - IN size_t OutputBufferLength, - IN size_t InputBufferLength, - IN ULONG IoControlCode - ) -/*++ -Routine Description: - - This event is called when the framework receives IRP_MJ_DEVICE_CONTROL - requests from the system. - -Arguments: - - Queue - Handle to the framework queue object that is associated - with the I/O request. - Request - Handle to a framework request object. - - OutputBufferLength - length of the request's output buffer, - if an output buffer is available. - InputBufferLength - length of the request's input buffer, - if an input buffer is available. - - IoControlCode - the driver-defined or system-defined I/O control code - (IOCTL) that is associated with the request. - -Return Value: - - VOID - ---*/ -{ - NTSTATUS status= STATUS_SUCCESS; - - UNREFERENCED_PARAMETER(Queue); - UNREFERENCED_PARAMETER(OutputBufferLength); - UNREFERENCED_PARAMETER(InputBufferLength); - - KdPrint(("ToasterEvtIoDeviceControl called\n")); - - PAGED_CODE(); - - // - // Use WdfRequestRetrieveInputBuffer and WdfRequestRetrieveOutputBuffer - // to get the request buffers. - // - - switch (IoControlCode) { - - default: - status = STATUS_INVALID_DEVICE_REQUEST; - } - - // - // Complete the Request. - // - WdfRequestCompleteWithInformation(Request, status, (ULONG_PTR) 0); -} - - diff --git a/general/toaster/umdf2/func/simple/wdfsimpleum.inx b/general/toaster/umdf2/func/simple/wdfsimpleum.inx deleted file mode 100644 index 6edb9388..00000000 --- a/general/toaster/umdf2/func/simple/wdfsimpleum.inx +++ /dev/null @@ -1,97 +0,0 @@ -;/*++ -; -;Copyright (c) Microsoft Corporation. All rights reserved. -; -;Module Name: -; wdfsimpleum.INF -; -;Abstract: -; INF file for installing the UMDF2 Toaster Driver -; -;Installation Notes: -; Using Devcon: Type "devcon install wdfsimpleum.inf root\toaster" to install -; -;--*/ - -[Version] -Signature="$WINDOWS NT$" -Class=TOASTER -ClassGuid={B85B7C50-6A01-11d2-B841-00C04FAD5171} -Provider=%MSFT% -DriverVer=03/20/2003,5.00.3788 -CatalogFile=wudf.cat - -[DestinationDirs] -DefaultDestDir = 12 - -; ================= Class section ===================== - -[ClassInstall32] -Addreg=ToasterClassReg - -[ToasterClassReg] -HKR,,,0,%ClassName% -HKR,,Icon,,100 -HKR,,DeviceCharacteristics,0x10001,0x100 ;Use same security checks on relative opens -HKR,,Security,,"D:P(A;;GA;;;SY)(A;;GA;;;BA)" ;Allow generic all access to system and built-in Admin. - ;This one overrides the security set by the driver - -[SourceDisksNames] -1 = %DiskId1%,,,"" - -[SourceDisksFiles] -wdfsimpleum.dll = 1,, - -;***************************************** -; Toaster Install Section -;***************************************** - -[Manufacturer] -%StdMfg%=Standard,NT$ARCH$ - -; -; Hw Id is root\toaster -; -[Standard.NT$ARCH$] -%Toaster.DeviceDesc%=Toaster_Device, root\toaster - -;---------------- copy files - -[Toaster_Device.NT] -CopyFiles=UMDriverCopy - -[UMDriverCopy] -wdfsimpleum.dll,,,0x00004000 ; COPYFLG_IN_USE_RENAME - -[DestinationDirs] -UMDriverCopy=12,UMDF ; copy to drivers\umdf - -;-------------- Service installation -[Toaster_Device.NT.Services] -AddService=WUDFRd,0x000001fa,WUDFRD_ServiceInstall - -[WUDFRD_ServiceInstall] -DisplayName = %WudfRdDisplayName% -ServiceType = 1 -StartType = 3 -ErrorControl = 1 -ServiceBinary = %12%\WUDFRd.sys - -;-------------- WDF specific section ------------- -[Toaster_Device.NT.Wdf] -UmdfService=wdfsimpleum, Toaster_Install -UmdfServiceOrder=wdfsimpleum - -[Toaster_Install] -UmdfLibraryVersion=$UMDFVERSION$ -ServiceBinary=%12%\UMDF\wdfsimpleum.dll - -[Strings] -SPSVCINST_ASSOCSERVICE= 0x00000002 -MSFT = "Microsoft" -StdMfg = "(Standard system devices)" -DiskId1 = "WDF Sample Toaster Installation Disk #1" -Toaster.DeviceDesc = "Sample UMDF Toaster Driver - simple" -ClassName = "Toaster" -WudfRdDisplayName="Windows Driver Foundation - User-mode Driver Framework Reflector" - diff --git a/general/toaster/umdf2/func/simple/wdfsimpleum.vcxproj b/general/toaster/umdf2/func/simple/wdfsimpleum.vcxproj deleted file mode 100644 index 5420719a..00000000 --- a/general/toaster/umdf2/func/simple/wdfsimpleum.vcxproj +++ /dev/null @@ -1,180 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - {4867F54B-D8EF-45B0-984E-D571D987174A} - $(MSBuildProjectName) - 2 - false - true - Debug - Win32 - {04436AEB-A589-41DD-A088-A1503096D2D8} - - - - Windows10 - False - Universal - UMDF - WindowsUserModeDriver10.0 - DynamicLibrary - - - Windows10 - True - Universal - UMDF - WindowsUserModeDriver10.0 - DynamicLibrary - - - Windows10 - False - Universal - UMDF - WindowsUserModeDriver10.0 - DynamicLibrary - - - Windows10 - True - Universal - UMDF - WindowsUserModeDriver10.0 - DynamicLibrary - - - - $(IntDir) - - - - - - - - - - - - - - - - $(InfArch) - true - .\$(IntDir)\wdfsimpleum.inf - - - - wdfsimpleum - - - wdfsimpleum - - - wdfsimpleum - - - wdfsimpleum - - - - %(AdditionalDependencies);$(SDK_LIB_PATH)\mincore.lib - - - %(AdditionalIncludeDirectories);..\..\inc;..\shared - - - %(AdditionalIncludeDirectories);..\..\inc;..\shared - - - - - %(AdditionalIncludeDirectories);..\..\inc;..\shared - - - - - %(AdditionalDependencies);$(SDK_LIB_PATH)\mincore.lib - - - %(AdditionalIncludeDirectories);..\..\inc;..\shared - - - %(AdditionalIncludeDirectories);..\..\inc;..\shared - - - - - %(AdditionalIncludeDirectories);..\..\inc;..\shared - - - - - %(AdditionalDependencies);$(SDK_LIB_PATH)\mincore.lib - - - %(AdditionalIncludeDirectories);..\..\inc;..\shared - - - %(AdditionalIncludeDirectories);..\..\inc;..\shared - - - - - %(AdditionalIncludeDirectories);..\..\inc;..\shared - - - - - %(AdditionalDependencies);$(SDK_LIB_PATH)\mincore.lib - - - %(AdditionalIncludeDirectories);..\..\inc;..\shared - - - %(AdditionalIncludeDirectories);..\..\inc;..\shared - - - - - %(AdditionalIncludeDirectories);..\..\inc;..\shared - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/general/toaster/umdf2/func/simple/wdfsimpleum.vcxproj.Filters b/general/toaster/umdf2/func/simple/wdfsimpleum.vcxproj.Filters deleted file mode 100644 index 6054e358..00000000 --- a/general/toaster/umdf2/func/simple/wdfsimpleum.vcxproj.Filters +++ /dev/null @@ -1,34 +0,0 @@ - - - - - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {00F8EE65-92A7-4127-B44C-E8F26A2136D5} - - - h;hpp;hxx;hm;inl;inc;xsd - {77C5B494-74A7-4FE1-97B8-0B859BE75D43} - - - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {9769E294-A7B6-4585-9CA6-AFDEA3DCA9F4} - - - inf;inv;inx;mof;mc; - {18744B3D-F47A-476E-9BF7-FE6592698961} - - - - - Driver Files - - - Driver Files - - - - - Source Files - - - \ No newline at end of file diff --git a/general/toaster/umdf2/inc/driver.h b/general/toaster/umdf2/inc/driver.h deleted file mode 100644 index b1073363..00000000 --- a/general/toaster/umdf2/inc/driver.h +++ /dev/null @@ -1,69 +0,0 @@ -/*++ -Copyright (c) 1990-2000 Microsoft Corporation All Rights Reserved - -Module Name: - - driver.h - -Abstract: - - This module contains the common declarations for the - bus, function and filter drivers. - -Environment: - - kernel mode only - ---*/ - -//#include "public.h" - -// -// Define an Interface Guid to access the proprietary toaster interface. -// This guid is used to identify a specific interface in IRP_MN_QUERY_INTERFACE -// handler. -// - -DEFINE_GUID(GUID_TOASTER_INTERFACE_STANDARD, - 0xe0b27630, 0x5434, 0x11d3, 0xb8, 0x90, 0x0, 0xc0, 0x4f, 0xad, 0x51, 0x71); -// {E0B27630-5434-11d3-B890-00C04FAD5171} - - -// -// GUID definition are required to be outside of header inclusion pragma to avoid -// error during precompiled headers. -// - -#ifndef __DRIVER_H -#define __DRIVER_H - -// -// Define Interface reference/dereference routines for -// Interfaces exported by IRP_MN_QUERY_INTERFACE -// - -typedef VOID (*PINTERFACE_REFERENCE)(PVOID Context); -typedef VOID (*PINTERFACE_DEREFERENCE)(PVOID Context); - -typedef -BOOLEAN -(*PTOASTER_GET_CRISPINESS_LEVEL)( - IN PVOID Context, - OUT PUCHAR Level - ); - -typedef -BOOLEAN -(*PTOASTER_SET_CRISPINESS_LEVEL)( - IN PVOID Context, - OUT UCHAR Level - ); - -typedef -BOOLEAN -(*PTOASTER_IS_CHILD_PROTECTED)( - IN PVOID Context - ); - -#endif - diff --git a/general/toaster/umdf2/inc/public.h b/general/toaster/umdf2/inc/public.h deleted file mode 100644 index 0628f95f..00000000 --- a/general/toaster/umdf2/inc/public.h +++ /dev/null @@ -1,167 +0,0 @@ -/*++ -Copyright (c) 1990-2000 Microsoft Corporation All Rights Reserved - -Module Name: - - public.h - -Abstract: - - This module contains the common declarations shared by driver - and user applications. - -Environment: - - user and kernel - ---*/ - -// -// Define an Interface Guid for bus enumerator class. -// This GUID is used to register (IoRegisterDeviceInterface) -// an instance of an interface so that enumerator application -// can send an ioctl to the bus driver. -// - -DEFINE_GUID (GUID_DEVINTERFACE_BUSENUM_TOASTER, - 0xD35F7840, 0x6A0C, 0x11d2, 0xB8, 0x41, 0x00, 0xC0, 0x4F, 0xAD, 0x51, 0x71); -// {D35F7840-6A0C-11d2-B841-00C04FAD5171} - -// -// Define an Interface Guid for toaster device class. -// This GUID is used to register (IoRegisterDeviceInterface) -// an instance of an interface so that user application -// can control the toaster device. -// - -DEFINE_GUID (GUID_DEVINTERFACE_TOASTER, - 0x781EF630, 0x72B2, 0x11d2, 0xB8, 0x52, 0x00, 0xC0, 0x4F, 0xAD, 0x51, 0x71); -//{781EF630-72B2-11d2-B852-00C04FAD5171} - -// -// Define a Setup Class GUID for Toaster Class. This is same -// as the TOASTSER CLASS guid in the INF files. -// - -DEFINE_GUID (GUID_DEVCLASS_TOASTER, - 0xB85B7C50, 0x6A01, 0x11d2, 0xB8, 0x41, 0x00, 0xC0, 0x4F, 0xAD, 0x51, 0x71); -//{B85B7C50-6A01-11d2-B841-00C04FAD5171} - -// -// Define a WMI GUID to get busenum info. -// - -DEFINE_GUID (TOASTER_BUS_WMI_STD_DATA_GUID, - 0x0006A660, 0x8F12, 0x11d2, 0xB8, 0x54, 0x00, 0xC0, 0x4F, 0xAD, 0x51, 0x71); -//{0006A660-8F12-11d2-B854-00C04FAD5171} - -// -// Define a WMI GUID to get toaster device info. -// - -DEFINE_GUID (TOASTER_WMI_STD_DATA_GUID, - 0xBBA21300L, 0x6DD3, 0x11d2, 0xB8, 0x44, 0x00, 0xC0, 0x4F, 0xAD, 0x51, 0x71); - -// -// Define a WMI GUID to represent device arrival notification WMIEvent class. -// - -DEFINE_GUID (TOASTER_NOTIFY_DEVICE_ARRIVAL_EVENT, - 0x1cdaff1, 0xc901, 0x45b4, 0xb3, 0x59, 0xb5, 0x54, 0x27, 0x25, 0xe2, 0x9c); -// {01CDAFF1-C901-45b4-B359-B5542725E29C} - - -// -// GUID definition are required to be outside of header inclusion pragma to avoid -// error during precompiled headers. -// - -#ifndef __PUBLIC_H -#define __PUBLIC_H - -#define BUS_HARDWARE_IDS L"{B85B7C50-6A01-11d2-B841-00C04FAD5171}\\MsToaster\0" -#define BUS_HARDWARE_IDS_LENGTH sizeof (BUS_HARDWARE_IDS) - -#define BUSENUM_COMPATIBLE_IDS L"{B85B7C50-6A01-11d2-B841-00C04FAD5171}\\MsCompatibleToaster\0" -#define BUSENUM_COMPATIBLE_IDS_LENGTH sizeof(BUSENUM_COMPATIBLE_IDS) - - -#define FILE_DEVICE_BUSENUM FILE_DEVICE_BUS_EXTENDER - -#define BUSENUM_IOCTL(_index_) \ - CTL_CODE (FILE_DEVICE_BUSENUM, _index_, METHOD_BUFFERED, FILE_READ_DATA) - -#define IOCTL_BUSENUM_PLUGIN_HARDWARE BUSENUM_IOCTL (0x0) -#define IOCTL_BUSENUM_UNPLUG_HARDWARE BUSENUM_IOCTL (0x1) -#define IOCTL_BUSENUM_EJECT_HARDWARE BUSENUM_IOCTL (0x2) -#define IOCTL_TOASTER_DONT_DISPLAY_IN_UI_DEVICE BUSENUM_IOCTL (0x3) - -// -// Data structure used in PlugIn and UnPlug ioctls -// - -typedef struct _BUSENUM_PLUGIN_HARDWARE -{ - // - // sizeof (struct _BUSENUM_HARDWARE) - // - IN ULONG Size; - - // - // Unique serial number of the device to be enumerated. - // Enumeration will be failed if another device on the - // bus has the same serail number. - // - - IN ULONG SerialNo; - - // - // An array of (zero terminated wide character strings). The array itself - // also null terminated (ie, MULTI_SZ) - // - #pragma warning(disable:4200) // nonstandard extension used - - IN WCHAR HardwareIDs[]; - - #pragma warning(default:4200) - -} BUSENUM_PLUGIN_HARDWARE, *PBUSENUM_PLUGIN_HARDWARE; - -typedef struct _BUSENUM_UNPLUG_HARDWARE -{ - // - // sizeof (struct _REMOVE_HARDWARE) - // - - IN ULONG Size; - - // - // Serial number of the device to be plugged out - // - - ULONG SerialNo; - - ULONG Reserved[2]; - -} BUSENUM_UNPLUG_HARDWARE, *PBUSENUM_UNPLUG_HARDWARE; - -typedef struct _BUSENUM_EJECT_HARDWARE -{ - // - // sizeof (struct _EJECT_HARDWARE) - // - - IN ULONG Size; - - // - // Serial number of the device to be ejected - // - - ULONG SerialNo; - - ULONG Reserved[2]; - -} BUSENUM_EJECT_HARDWARE, *PBUSENUM_EJECT_HARDWARE; - -#endif - diff --git a/general/toaster/umdf2/umdf2toaster.sln b/general/toaster/umdf2/umdf2toaster.sln deleted file mode 100644 index 27a7c11c..00000000 --- a/general/toaster/umdf2/umdf2toaster.sln +++ /dev/null @@ -1,123 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2013 -VisualStudioVersion = 12.0 -MinimumVisualStudioVersion = 12.0 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Package", "Package", "{DE39E506-CDA6-472B-AA38-CFD787389792}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Notify", "Notify", "{6A99D8D7-8707-44E7-8952-C08DA9607026}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Exe", "Exe", "{812F37C3-6174-45B1-BAE8-8A1D22588B5A}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Toast", "Toast", "{C76A23DC-DCC1-457B-A57C-FC050E0E28E0}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Enum", "Enum", "{29F16893-9AB9-45AC-AF5B-4E933C2E6A95}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Simple", "Simple", "{5652F0ED-6624-49EC-9DB9-B5A3F7253FA3}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Func", "Func", "{2C164544-0A50-43A5-A42C-B7B25D777B4E}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Featured", "Featured", "{0213881B-B2CC-453E-BBCA-95EE52FEA9C1}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Generic", "Generic", "{F2D765A7-8801-482C-924A-0B647DEAE5D5}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Filter", "Filter", "{870F719A-95BC-485D-9787-2634A3C2652F}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "package", "Package\package.VcxProj", "{52EEA7C4-68B9-4AE9-B3EC-881A49E9E1E5}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "notify", "exe\notify\notify.vcxproj", "{FEBBDE46-4BD4-462D-87BD-8FDC8C1ECB76}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "toast", "exe\toast\toast.vcxproj", "{9BF4F988-D8B7-4E73-BC77-6658D413212F}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Enum", "exe\enum\Enum.vcxproj", "{6E1593D4-08A1-45E4-A77F-AF34AC6F0D69}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wdfsimpleum", "func\simple\wdfsimpleum.vcxproj", "{4867F54B-D8EF-45B0-984E-D571D987174A}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wdffeaturedum", "func\featured\wdffeaturedum.vcxproj", "{99A6009E-6137-462F-89C4-6931045895B1}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "filterum", "filter\generic\filterum.vcxproj", "{A60F76D2-C512-4DA6-8C80-263F1B506267}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Release|Win32 = Release|Win32 - Debug|x64 = Debug|x64 - Release|x64 = Release|x64 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {52EEA7C4-68B9-4AE9-B3EC-881A49E9E1E5}.Debug|Win32.ActiveCfg = Debug|Win32 - {52EEA7C4-68B9-4AE9-B3EC-881A49E9E1E5}.Debug|Win32.Build.0 = Debug|Win32 - {52EEA7C4-68B9-4AE9-B3EC-881A49E9E1E5}.Release|Win32.ActiveCfg = Release|Win32 - {52EEA7C4-68B9-4AE9-B3EC-881A49E9E1E5}.Release|Win32.Build.0 = Release|Win32 - {52EEA7C4-68B9-4AE9-B3EC-881A49E9E1E5}.Debug|x64.ActiveCfg = Debug|x64 - {52EEA7C4-68B9-4AE9-B3EC-881A49E9E1E5}.Debug|x64.Build.0 = Debug|x64 - {52EEA7C4-68B9-4AE9-B3EC-881A49E9E1E5}.Release|x64.ActiveCfg = Release|x64 - {52EEA7C4-68B9-4AE9-B3EC-881A49E9E1E5}.Release|x64.Build.0 = Release|x64 - {FEBBDE46-4BD4-462D-87BD-8FDC8C1ECB76}.Debug|Win32.ActiveCfg = Debug|Win32 - {FEBBDE46-4BD4-462D-87BD-8FDC8C1ECB76}.Debug|Win32.Build.0 = Debug|Win32 - {FEBBDE46-4BD4-462D-87BD-8FDC8C1ECB76}.Release|Win32.ActiveCfg = Release|Win32 - {FEBBDE46-4BD4-462D-87BD-8FDC8C1ECB76}.Release|Win32.Build.0 = Release|Win32 - {FEBBDE46-4BD4-462D-87BD-8FDC8C1ECB76}.Debug|x64.ActiveCfg = Debug|x64 - {FEBBDE46-4BD4-462D-87BD-8FDC8C1ECB76}.Debug|x64.Build.0 = Debug|x64 - {FEBBDE46-4BD4-462D-87BD-8FDC8C1ECB76}.Release|x64.ActiveCfg = Release|x64 - {FEBBDE46-4BD4-462D-87BD-8FDC8C1ECB76}.Release|x64.Build.0 = Release|x64 - {9BF4F988-D8B7-4E73-BC77-6658D413212F}.Debug|Win32.ActiveCfg = Debug|Win32 - {9BF4F988-D8B7-4E73-BC77-6658D413212F}.Debug|Win32.Build.0 = Debug|Win32 - {9BF4F988-D8B7-4E73-BC77-6658D413212F}.Release|Win32.ActiveCfg = Release|Win32 - {9BF4F988-D8B7-4E73-BC77-6658D413212F}.Release|Win32.Build.0 = Release|Win32 - {9BF4F988-D8B7-4E73-BC77-6658D413212F}.Debug|x64.ActiveCfg = Debug|x64 - {9BF4F988-D8B7-4E73-BC77-6658D413212F}.Debug|x64.Build.0 = Debug|x64 - {9BF4F988-D8B7-4E73-BC77-6658D413212F}.Release|x64.ActiveCfg = Release|x64 - {9BF4F988-D8B7-4E73-BC77-6658D413212F}.Release|x64.Build.0 = Release|x64 - {6E1593D4-08A1-45E4-A77F-AF34AC6F0D69}.Debug|Win32.ActiveCfg = Debug|Win32 - {6E1593D4-08A1-45E4-A77F-AF34AC6F0D69}.Debug|Win32.Build.0 = Debug|Win32 - {6E1593D4-08A1-45E4-A77F-AF34AC6F0D69}.Release|Win32.ActiveCfg = Release|Win32 - {6E1593D4-08A1-45E4-A77F-AF34AC6F0D69}.Release|Win32.Build.0 = Release|Win32 - {6E1593D4-08A1-45E4-A77F-AF34AC6F0D69}.Debug|x64.ActiveCfg = Debug|x64 - {6E1593D4-08A1-45E4-A77F-AF34AC6F0D69}.Debug|x64.Build.0 = Debug|x64 - {6E1593D4-08A1-45E4-A77F-AF34AC6F0D69}.Release|x64.ActiveCfg = Release|x64 - {6E1593D4-08A1-45E4-A77F-AF34AC6F0D69}.Release|x64.Build.0 = Release|x64 - {4867F54B-D8EF-45B0-984E-D571D987174A}.Debug|Win32.ActiveCfg = Debug|Win32 - {4867F54B-D8EF-45B0-984E-D571D987174A}.Debug|Win32.Build.0 = Debug|Win32 - {4867F54B-D8EF-45B0-984E-D571D987174A}.Release|Win32.ActiveCfg = Release|Win32 - {4867F54B-D8EF-45B0-984E-D571D987174A}.Release|Win32.Build.0 = Release|Win32 - {4867F54B-D8EF-45B0-984E-D571D987174A}.Debug|x64.ActiveCfg = Debug|x64 - {4867F54B-D8EF-45B0-984E-D571D987174A}.Debug|x64.Build.0 = Debug|x64 - {4867F54B-D8EF-45B0-984E-D571D987174A}.Release|x64.ActiveCfg = Release|x64 - {4867F54B-D8EF-45B0-984E-D571D987174A}.Release|x64.Build.0 = Release|x64 - {99A6009E-6137-462F-89C4-6931045895B1}.Debug|Win32.ActiveCfg = Debug|Win32 - {99A6009E-6137-462F-89C4-6931045895B1}.Debug|Win32.Build.0 = Debug|Win32 - {99A6009E-6137-462F-89C4-6931045895B1}.Release|Win32.ActiveCfg = Release|Win32 - {99A6009E-6137-462F-89C4-6931045895B1}.Release|Win32.Build.0 = Release|Win32 - {99A6009E-6137-462F-89C4-6931045895B1}.Debug|x64.ActiveCfg = Debug|x64 - {99A6009E-6137-462F-89C4-6931045895B1}.Debug|x64.Build.0 = Debug|x64 - {99A6009E-6137-462F-89C4-6931045895B1}.Release|x64.ActiveCfg = Release|x64 - {99A6009E-6137-462F-89C4-6931045895B1}.Release|x64.Build.0 = Release|x64 - {A60F76D2-C512-4DA6-8C80-263F1B506267}.Debug|Win32.ActiveCfg = Debug|Win32 - {A60F76D2-C512-4DA6-8C80-263F1B506267}.Debug|Win32.Build.0 = Debug|Win32 - {A60F76D2-C512-4DA6-8C80-263F1B506267}.Release|Win32.ActiveCfg = Release|Win32 - {A60F76D2-C512-4DA6-8C80-263F1B506267}.Release|Win32.Build.0 = Release|Win32 - {A60F76D2-C512-4DA6-8C80-263F1B506267}.Debug|x64.ActiveCfg = Debug|x64 - {A60F76D2-C512-4DA6-8C80-263F1B506267}.Debug|x64.Build.0 = Debug|x64 - {A60F76D2-C512-4DA6-8C80-263F1B506267}.Release|x64.ActiveCfg = Release|x64 - {A60F76D2-C512-4DA6-8C80-263F1B506267}.Release|x64.Build.0 = Release|x64 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {52EEA7C4-68B9-4AE9-B3EC-881A49E9E1E5} = {DE39E506-CDA6-472B-AA38-CFD787389792} - {FEBBDE46-4BD4-462D-87BD-8FDC8C1ECB76} = {6A99D8D7-8707-44E7-8952-C08DA9607026} - {9BF4F988-D8B7-4E73-BC77-6658D413212F} = {C76A23DC-DCC1-457B-A57C-FC050E0E28E0} - {6E1593D4-08A1-45E4-A77F-AF34AC6F0D69} = {29F16893-9AB9-45AC-AF5B-4E933C2E6A95} - {4867F54B-D8EF-45B0-984E-D571D987174A} = {5652F0ED-6624-49EC-9DB9-B5A3F7253FA3} - {99A6009E-6137-462F-89C4-6931045895B1} = {0213881B-B2CC-453E-BBCA-95EE52FEA9C1} - {A60F76D2-C512-4DA6-8C80-263F1B506267} = {F2D765A7-8801-482C-924A-0B647DEAE5D5} - {6A99D8D7-8707-44E7-8952-C08DA9607026} = {812F37C3-6174-45B1-BAE8-8A1D22588B5A} - {C76A23DC-DCC1-457B-A57C-FC050E0E28E0} = {812F37C3-6174-45B1-BAE8-8A1D22588B5A} - {29F16893-9AB9-45AC-AF5B-4E933C2E6A95} = {812F37C3-6174-45B1-BAE8-8A1D22588B5A} - {5652F0ED-6624-49EC-9DB9-B5A3F7253FA3} = {2C164544-0A50-43A5-A42C-B7B25D777B4E} - {0213881B-B2CC-453E-BBCA-95EE52FEA9C1} = {2C164544-0A50-43A5-A42C-B7B25D777B4E} - {F2D765A7-8801-482C-924A-0B647DEAE5D5} = {870F719A-95BC-485D-9787-2634A3C2652F} - EndGlobalSection -EndGlobal diff --git a/general/tracing/SystemTraceControl/SystemTraceControl.sln b/general/tracing/SystemTraceControl/SystemTraceControl.sln index 4e74108b..c67a9a92 100644 --- a/general/tracing/SystemTraceControl/SystemTraceControl.sln +++ b/general/tracing/SystemTraceControl/SystemTraceControl.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SystemTraceControl", "SystemTraceControl.vcxproj", "{BBB08463-9C86-4690-B95B-106B49DD46E2}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SystemTraceControl", "SystemTraceControl.vcxproj", "{968DA402-7888-42A5-B2C3-676B80134771}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +13,14 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {BBB08463-9C86-4690-B95B-106B49DD46E2}.Debug|Win32.ActiveCfg = Debug|Win32 - {BBB08463-9C86-4690-B95B-106B49DD46E2}.Debug|Win32.Build.0 = Debug|Win32 - {BBB08463-9C86-4690-B95B-106B49DD46E2}.Release|Win32.ActiveCfg = Release|Win32 - {BBB08463-9C86-4690-B95B-106B49DD46E2}.Release|Win32.Build.0 = Release|Win32 - {BBB08463-9C86-4690-B95B-106B49DD46E2}.Debug|x64.ActiveCfg = Debug|x64 - {BBB08463-9C86-4690-B95B-106B49DD46E2}.Debug|x64.Build.0 = Debug|x64 - {BBB08463-9C86-4690-B95B-106B49DD46E2}.Release|x64.ActiveCfg = Release|x64 - {BBB08463-9C86-4690-B95B-106B49DD46E2}.Release|x64.Build.0 = Release|x64 + {968DA402-7888-42A5-B2C3-676B80134771}.Debug|Win32.ActiveCfg = Debug|Win32 + {968DA402-7888-42A5-B2C3-676B80134771}.Debug|Win32.Build.0 = Debug|Win32 + {968DA402-7888-42A5-B2C3-676B80134771}.Release|Win32.ActiveCfg = Release|Win32 + {968DA402-7888-42A5-B2C3-676B80134771}.Release|Win32.Build.0 = Release|Win32 + {968DA402-7888-42A5-B2C3-676B80134771}.Debug|x64.ActiveCfg = Debug|x64 + {968DA402-7888-42A5-B2C3-676B80134771}.Debug|x64.Build.0 = Debug|x64 + {968DA402-7888-42A5-B2C3-676B80134771}.Release|x64.ActiveCfg = Release|x64 + {968DA402-7888-42A5-B2C3-676B80134771}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/general/tracing/SystemTraceControl/SystemTraceControl.vcxproj b/general/tracing/SystemTraceControl/SystemTraceControl.vcxproj index 556e6d7d..a40899b5 100644 --- a/general/tracing/SystemTraceControl/SystemTraceControl.vcxproj +++ b/general/tracing/SystemTraceControl/SystemTraceControl.vcxproj @@ -19,11 +19,11 @@ - {BBB08463-9C86-4690-B95B-106B49DD46E2} + {968DA402-7888-42A5-B2C3-676B80134771} $(MSBuildProjectName) Debug Win32 - {E8A8798D-133D-48CA-B07A-E8D8A7C82C30} + {E2000ABD-F961-4FA7-A959-005FC6E3451F} diff --git a/general/tracing/SystemTraceControl/SystemTraceControl.vcxproj.Filters b/general/tracing/SystemTraceControl/SystemTraceControl.vcxproj.Filters index bc043bf7..1d664bf1 100644 --- a/general/tracing/SystemTraceControl/SystemTraceControl.vcxproj.Filters +++ b/general/tracing/SystemTraceControl/SystemTraceControl.vcxproj.Filters @@ -3,15 +3,15 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {C2A52F8F-D414-40D4-998E-62C57FFF543E} + {4EF85DAA-B6CF-4318-A2C6-C468645C29C1} h;hpp;hxx;hm;inl;inc;xsd - {CF32093A-DFB7-4C18-B086-1F1DB68AA8F4} + {23309F83-06E8-4B91-ACAA-F7132B6276A2} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {C370B48B-D85C-4319-911D-CC6D213BB287} + {EA06C1A4-65B4-4551-9760-BEDD786ACB50} diff --git a/general/tracing/evntdrv/Eventdrv/Eventdrv.vcxproj b/general/tracing/evntdrv/Eventdrv/Eventdrv.vcxproj index 38a37c6d..122b9938 100644 --- a/general/tracing/evntdrv/Eventdrv/Eventdrv.vcxproj +++ b/general/tracing/evntdrv/Eventdrv/Eventdrv.vcxproj @@ -19,11 +19,11 @@ - {71F967BF-4410-49F0-A9D9-A0968791E7C3} + {0AA897A5-DD5B-4C2F-826C-46C4C8261641} $(MSBuildProjectName) Debug Win32 - {D1927512-3AD6-432A-B43A-993734933EA0} + {77776F12-8749-4CD8-BCB8-45AFB9EF64A4} diff --git a/general/tracing/evntdrv/Eventdrv/Eventdrv.vcxproj.Filters b/general/tracing/evntdrv/Eventdrv/Eventdrv.vcxproj.Filters index b3a19f20..5b94af02 100644 --- a/general/tracing/evntdrv/Eventdrv/Eventdrv.vcxproj.Filters +++ b/general/tracing/evntdrv/Eventdrv/Eventdrv.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {FF39F92A-78D6-4DC4-8C57-61B8235F689E} + {653669AD-2AB5-4E15-A1E3-F56E6B5D988D} h;hpp;hxx;hm;inl;inc;xsd - {7D82ACC1-5CB5-4731-9F63-C6ECF120023F} + {EFAB409C-D315-4FC3-91AB-3AD0C028C1E7} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {C4F65E57-AD43-415D-A828-20341B0A35CA} + {65A4753A-3174-490A-8A34-C3F655C95643} inf;inv;inx;mof;mc; - {42E3A915-3C68-4861-986D-5BECD364D878} + {B7FEA61C-954A-4DA6-B0DB-65F77FD5396E} diff --git a/general/tracing/evntdrv/eventdrv.sln b/general/tracing/evntdrv/eventdrv.sln index f7556ef7..c6e89bde 100644 --- a/general/tracing/evntdrv/eventdrv.sln +++ b/general/tracing/evntdrv/eventdrv.sln @@ -3,13 +3,13 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Eventdrv", "Eventdrv", "{622DAC05-C30E-4BEE-B268-690B1B0DA989}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Eventdrv", "Eventdrv", "{17F2C037-F5B1-4C73-A09B-EA70DCF80BC5}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Evntctrl", "Evntctrl", "{90152226-E1D1-482C-9AB8-701B24BA34A1}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Evntctrl", "Evntctrl", "{1BDAAB5F-D67B-419D-857C-2A921360552B}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Eventdrv", "Eventdrv\Eventdrv.vcxproj", "{71F967BF-4410-49F0-A9D9-A0968791E7C3}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Eventdrv", "Eventdrv\Eventdrv.vcxproj", "{0AA897A5-DD5B-4C2F-826C-46C4C8261641}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "evntctrl", "evntctrl\evntctrl.vcxproj", "{09705E95-23AF-44BE-AD49-703F2A469DB0}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "evntctrl", "evntctrl\evntctrl.vcxproj", "{6D8C5584-FF3C-4C12-BE99-64A3A63CFA2D}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -19,28 +19,28 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {71F967BF-4410-49F0-A9D9-A0968791E7C3}.Debug|Win32.ActiveCfg = Debug|Win32 - {71F967BF-4410-49F0-A9D9-A0968791E7C3}.Debug|Win32.Build.0 = Debug|Win32 - {71F967BF-4410-49F0-A9D9-A0968791E7C3}.Release|Win32.ActiveCfg = Release|Win32 - {71F967BF-4410-49F0-A9D9-A0968791E7C3}.Release|Win32.Build.0 = Release|Win32 - {71F967BF-4410-49F0-A9D9-A0968791E7C3}.Debug|x64.ActiveCfg = Debug|x64 - {71F967BF-4410-49F0-A9D9-A0968791E7C3}.Debug|x64.Build.0 = Debug|x64 - {71F967BF-4410-49F0-A9D9-A0968791E7C3}.Release|x64.ActiveCfg = Release|x64 - {71F967BF-4410-49F0-A9D9-A0968791E7C3}.Release|x64.Build.0 = Release|x64 - {09705E95-23AF-44BE-AD49-703F2A469DB0}.Debug|Win32.ActiveCfg = Debug|Win32 - {09705E95-23AF-44BE-AD49-703F2A469DB0}.Debug|Win32.Build.0 = Debug|Win32 - {09705E95-23AF-44BE-AD49-703F2A469DB0}.Release|Win32.ActiveCfg = Release|Win32 - {09705E95-23AF-44BE-AD49-703F2A469DB0}.Release|Win32.Build.0 = Release|Win32 - {09705E95-23AF-44BE-AD49-703F2A469DB0}.Debug|x64.ActiveCfg = Debug|x64 - {09705E95-23AF-44BE-AD49-703F2A469DB0}.Debug|x64.Build.0 = Debug|x64 - {09705E95-23AF-44BE-AD49-703F2A469DB0}.Release|x64.ActiveCfg = Release|x64 - {09705E95-23AF-44BE-AD49-703F2A469DB0}.Release|x64.Build.0 = Release|x64 + {0AA897A5-DD5B-4C2F-826C-46C4C8261641}.Debug|Win32.ActiveCfg = Debug|Win32 + {0AA897A5-DD5B-4C2F-826C-46C4C8261641}.Debug|Win32.Build.0 = Debug|Win32 + {0AA897A5-DD5B-4C2F-826C-46C4C8261641}.Release|Win32.ActiveCfg = Release|Win32 + {0AA897A5-DD5B-4C2F-826C-46C4C8261641}.Release|Win32.Build.0 = Release|Win32 + {0AA897A5-DD5B-4C2F-826C-46C4C8261641}.Debug|x64.ActiveCfg = Debug|x64 + {0AA897A5-DD5B-4C2F-826C-46C4C8261641}.Debug|x64.Build.0 = Debug|x64 + {0AA897A5-DD5B-4C2F-826C-46C4C8261641}.Release|x64.ActiveCfg = Release|x64 + {0AA897A5-DD5B-4C2F-826C-46C4C8261641}.Release|x64.Build.0 = Release|x64 + {6D8C5584-FF3C-4C12-BE99-64A3A63CFA2D}.Debug|Win32.ActiveCfg = Debug|Win32 + {6D8C5584-FF3C-4C12-BE99-64A3A63CFA2D}.Debug|Win32.Build.0 = Debug|Win32 + {6D8C5584-FF3C-4C12-BE99-64A3A63CFA2D}.Release|Win32.ActiveCfg = Release|Win32 + {6D8C5584-FF3C-4C12-BE99-64A3A63CFA2D}.Release|Win32.Build.0 = Release|Win32 + {6D8C5584-FF3C-4C12-BE99-64A3A63CFA2D}.Debug|x64.ActiveCfg = Debug|x64 + {6D8C5584-FF3C-4C12-BE99-64A3A63CFA2D}.Debug|x64.Build.0 = Debug|x64 + {6D8C5584-FF3C-4C12-BE99-64A3A63CFA2D}.Release|x64.ActiveCfg = Release|x64 + {6D8C5584-FF3C-4C12-BE99-64A3A63CFA2D}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {71F967BF-4410-49F0-A9D9-A0968791E7C3} = {622DAC05-C30E-4BEE-B268-690B1B0DA989} - {09705E95-23AF-44BE-AD49-703F2A469DB0} = {90152226-E1D1-482C-9AB8-701B24BA34A1} + {0AA897A5-DD5B-4C2F-826C-46C4C8261641} = {17F2C037-F5B1-4C73-A09B-EA70DCF80BC5} + {6D8C5584-FF3C-4C12-BE99-64A3A63CFA2D} = {1BDAAB5F-D67B-419D-857C-2A921360552B} EndGlobalSection EndGlobal diff --git a/general/tracing/evntdrv/evntctrl/evntctrl.vcxproj b/general/tracing/evntdrv/evntctrl/evntctrl.vcxproj index 91610949..7d1f8cc6 100644 --- a/general/tracing/evntdrv/evntctrl/evntctrl.vcxproj +++ b/general/tracing/evntdrv/evntctrl/evntctrl.vcxproj @@ -19,11 +19,11 @@ - {09705E95-23AF-44BE-AD49-703F2A469DB0} + {6D8C5584-FF3C-4C12-BE99-64A3A63CFA2D} $(MSBuildProjectName) Debug Win32 - {4CB0AEF6-22DB-46DE-B86C-BA8FA83720FF} + {9B65A1F6-8697-49A7-B65C-CCFC5E769D1C} diff --git a/general/tracing/evntdrv/evntctrl/evntctrl.vcxproj.Filters b/general/tracing/evntdrv/evntctrl/evntctrl.vcxproj.Filters index fc9905ff..055f3f38 100644 --- a/general/tracing/evntdrv/evntctrl/evntctrl.vcxproj.Filters +++ b/general/tracing/evntdrv/evntctrl/evntctrl.vcxproj.Filters @@ -3,15 +3,15 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {CBA4CFF0-1A7A-4894-AC68-18D38BD5EABB} + {732FEB8C-759C-4315-8FE6-91C32E227CB8} h;hpp;hxx;hm;inl;inc;xsd - {6EB53DDD-D4F4-4C46-9218-63E8B1F46F74} + {1EB4D098-5821-4C5A-9534-1C28B7B0D2A4} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {479AEB6E-676D-4829-891B-3C82EADD4F94} + {0D82C9BE-D601-4B17-BE82-6F426FC0EACF} diff --git a/general/tracing/evntdrv/evntdrv.htm b/general/tracing/evntdrv/evntdrv.htm new file mode 100644 index 00000000..0d89619d --- /dev/null +++ b/general/tracing/evntdrv/evntdrv.htm @@ -0,0 +1,189 @@ + + + + + +Eventdrv + + + + + + + +

+ +
+ +
+ +

 

+ +

Eventdrv

+ +

Summary

+ + + +

Eventdrv is a sample kernel mode trace +provider/driver. The driver does not control any hardware; it simply generates +trace events. It is designed to demonstrate the use of ETW tracing in a driver.

+ +

Eventdrv registers as a provider by calling +the EtwRegister API. If successful, it logs a StartEvent event with the +device’s name, the length of the name, and the status code. Then, when it +receives a DeviceIOControl call, it logs a SampleEventA event. Finally, when +the driver gets unloaded, it logs an UnloadEvent event with a pointer to the +device object. Note that Windows Pre-Processor (WPP) Tracing tools such +as TraceView.exe cannot be used to start/stop and view traces.

+ +

  

+ +

Using the Sample

+ + + +

 To test the Eventdrv event tracing provider, use the following +procedure:

+ +

1. Build the Eventdrv sample +driver (in evntdrv\Eventdrv) by using the -cZg switch.

+ +

2.   +Install the manifest located in the evntdrv\Eventdrv folder by using the +following command:

+ +

      +wevtutil im evntdrv.xml
+
+Installing the manifest will create registry keys which allows tools to be able +to find the resource and message file(s) which contains event provider +information. Search MSDN for further details on the wevtutil tool.

+ +

3. Build the evntctrl executable +file (in evntdrv\evntctrl) by using the -cZg switch. Evntctrl sends IOCTLs to +Eventdrv, which then generates trace messages when it receives the IOCTLs.

+ +

4. Make a folder in the system directory called +ETWDriverSample. For example, C:\ETWDriverSample. Copy Eventdrv.sys +and evntctrl.exe to this folder. Also, copy Tracelog.exe from the tools\tracing +folder in the Driver Kit to this folder. This directory must be created because +the path to the resource file specified in the manifest evntdrv.xml points to +the %systemroot%\ETWDriverSample folder. If this folder is not created and the +Evntdrv.sys binary is not copied, decoding tools will not be able to find the +event information to decode the trace file.

+ +

5. Use Tracelog to start a trace +session that is called “TestEventdrv”. The following command starts the trace +session and creates a trace log file, Eventdrv.etl, in the local directory.
+
+Tracelog -start TestEventdrv -guid #b5a0bda9-50fe-4d0e-a83d-bae3f58c94d6 +-f Eventdrv.etl

+ +

6. To generate trace messages, run +Evntctrl.exe. This executable file is built in step 3. Each time you type a +character other than Q or q, Evntctrl sends an IOCTL to the driver that signals +it to generate trace messages. To stop Evntctrl, type Q or q.

+ + + +

7. To stop the trace session, use +the following Tracelog command:
+
+tracelog -stop TestEventdrv

+ +

8. To display the trace messages +in the Tracedrv.etl file, use Tracerpt. Type the following
+command:
+
+tracerpt Eventdrv.etl

+ +

      +This creates two files: summary.txt and dumpfile.xml. Dumpfile.xml will contain +the event information in an XML format. For additional options, do tracerpt /?.

+ +

9.   To uninstall the manifest, use the following command:

+ +

      +wevtutil um evntdrv.xml

+ + + +

Limitations

+ + + +

Eventdrv is designed for Windows Vista and +later versions of Windows.
+This sample driver should not be used in a production environment.

+ +

 

+ +

File List

+ + + +

Eventdrv
+
Drvioctl.h
+Evntdrv.c
+Evntdrv.xml
+Makefile
+Makefile.inc
+Sources

+ +

Evntctrl
+Install.c
+
Install.h
+
Makefile
+
Sources
+
Tracectl.c

+ +

 

+ +

Location

+ +

The files that comprise Eventdrv are included +in the Windows Driver Kit in the \src\general\tracing\evntdrv folder.

+ +

 

+ +
+ +
+ +
+ + + + + diff --git a/general/tracing/tracedriver/tracectl/tracectl.vcxproj b/general/tracing/tracedriver/tracectl/tracectl.vcxproj index e1e21430..36d8f30e 100644 --- a/general/tracing/tracedriver/tracectl/tracectl.vcxproj +++ b/general/tracing/tracedriver/tracectl/tracectl.vcxproj @@ -19,11 +19,11 @@
- {72739B3A-9B9B-41EE-9B0E-E73482470A03} + {3A8F1F69-AD42-492B-9F57-5F95EFCD75C6} $(MSBuildProjectName) Debug Win32 - {707AFE5D-65EB-4AED-967A-114E753D1037} + {3DEA2D5B-55CB-46FF-BA56-6FC217FF19AD} diff --git a/general/tracing/tracedriver/tracectl/tracectl.vcxproj.Filters b/general/tracing/tracedriver/tracectl/tracectl.vcxproj.Filters index 49a76abb..1482e22e 100644 --- a/general/tracing/tracedriver/tracectl/tracectl.vcxproj.Filters +++ b/general/tracing/tracedriver/tracectl/tracectl.vcxproj.Filters @@ -3,15 +3,15 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {162117FB-9571-483E-8BDC-60E6A31AD53D} + {F36F2396-6719-4C9E-AF20-5AD2738A351E} h;hpp;hxx;hm;inl;inc;xsd - {ECB2DAEF-8542-46F3-84A4-AB8FC5EDC817} + {27EB4DB8-FEAE-4B53-A49E-FB8F17DD47A0} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {CD34668D-32E2-4A6E-8DC5-7CCC09E3FC35} + {39E92D32-6DE6-4B95-A5B0-D7DCB33A2256} diff --git a/general/tracing/tracedriver/tracedrv.htm b/general/tracing/tracedriver/tracedrv.htm new file mode 100644 index 00000000..0d3dc032 --- /dev/null +++ b/general/tracing/tracedriver/tracedrv.htm @@ -0,0 +1,1052 @@ + + + + + + + + +TraceDrv + + + + + + + + + +
+ +

Tracedrv +

+ +

SUMMARY

+ +

Tracedrv is a sample driver +instrumented for software tracing. The driver does not control any hardware; it +simply generates trace messages. It is designed to show how to use WPP software +tracing macros in a driver.

+ +

 

+ +

Tracedrv initializes tracing (by +using WPP_INIT_TRACING) and, when it receives a DeviceIOControl +call, it starts a thread that logs 100 trace messages. The WPP software tracing +directives, calls, and macros in the code are accompanied by comments that explain +their purpose.

+ +

 

+ +

While examining Tracedrv, read the +"WPP Software Tracing" section of the Windows Driver Development Kit +(DDK) documentation (in Driver Development Tools, Tools for Software Tracing, +WPP Software Tracing). This section includes a reference section that describes +the directives, macros, and calls required for WPP software tracing. It also +includes "Sample WPP Software Tracing Code," a section that uses the Tracedrv sample to demonstrate the use of the WPP software +tracing elements.

+ +

 

+ +

USING THE SAMPLE

+ +

To test the Tracedrv event tracing +provider, use the following procedure. The tools used in this procedure are +included in the DDK and located in the \tools\tracing subdirectory. For more +information about the tracing tools, see the "Tools for Software +Tracing" section of the WDK documentation.

+ +
    +
  1. Build + the Tracedrv sample driver and the Tracectl executable file.
  2. +
      +
    1. Click tracedrv.sln to open the sample.
    2. +
    3. Right click project "tracectl", + select Properties, goto Linker -> Manifest + File, make sure "Generate + Manifest" is "No".
    4. +
    5. You can press "F7" or choose Build->Build + Solution.
    6. +
    +
  3. Copy + the Tracectl.exe file that was created in step 1 from the Tracectl directory (\src\general\tracing\tracedrv\tracectl\platform) + to the Tracedrv directory (\src\general\tracing\tracedrv\tracedrv\platform).
  4. +
  5. Use Tracepdb + to create a trace message format (TMF) file and a trace message control + (TMC) file from the Tracedrv.pdb file. Tracepdb + is located in the \bin\platform subdirectory of the WDK. The PDB + file that is used in this command is created by the Build utility in step + 1. From the \tools\tracing\platform subdirectory, type the + following command:
  6. +
+ +

tracepdb -f <path>\tracedrv.pdb

+ +
    +
  1. Create a control GUID + file for Tracedrv by opening a text file, adding + the following content, and saving the file as Tracedrv.ctl. +
  2. +
+ +

      +d58c126f-b309-11d1-969e-0000f875a5bc

+ +
    +
  1. Use Tracelog + to start a trace session that is called "TestTracedrv". + Tracelog is located in the \tools\tracing\platform + subdirectory of the DDK. The Tracedrv.ctl + file that is used in this command was created in step 4. The following + command starts a trace session and creates a trace log file, tracedrv.etl, in the local directory.
  2. +
+ +

      tracelog -start TestTracedrv +-guid tracedrv.ctl -f tracedrv.etl -flag 1

+ +

Note: Without the -flag parameter, Tracedrv will not generate any trace messages.

+ +
    +
  1. To + generate trace messages, run Tracectl.exe. This executable file is + built in step 2. Each time you type a character, other than Q or q, + Tracectl sends an IOCTL to the driver that + signals it to generate trace messages. To stop Tracectl, + type Q or q.
  2. +
  3. To stop the trace + session, use the following Tracelog command.
  4. +
+ +

      tracelog -stop TestTracedrv

+ +
    +
  1. To display the trace + messages in the Tracedrv.etl file, use Tracefmt. Tracefmt is + located in the \tools\tracing subdirectory of the DDK. The TMF file used + in this command was created by Tracepdb in step + 3. Type the following command:
  2. +
+ +

      tracefmt tracedrv.etl -p +<Path to TMF file> -o Tracedrv.out

+ +

The resulting Tracedrv.out file is a +human-readable text file of the Tracedrv trace +messages. To interpret the trace messages, in the Tracedrv.c +file, search for the DoTraceMessage macros.

+ +

 

+ +

LIMITATIONS

+ +

This sample driver should not be used in a production +environment.

+ +

 

+ +

Tracedrv is designed for +Windows XP and later versions of Windows. It does not demonstrate how to +add WPP software tracing to a Windows 2000 driver. (For information about +adding WPP software tracing to a Windows 2000 driver, see the Tracing FAQ +topic in the Windows WDK documentation.)

+ +

 

+ +

Also, because it is not a Plug and Play driver, Tracedrv does not demonstrate tracing in a Plug and Play +environment.

+ +

 

+ +

Tracedrv demonstrates the basic +elements required for software tracing. It does not demonstrate more advanced +tracing techniques, such as writing customized tracing calls (variations of DoTraceMessage), or the use of WMI calls for +software tracing.

+ +

 

+ +

FILE LIST

+ +

drvioctl.h

+ +

makefile

+ +

sources

+ +

tracedrv.c

+ +

tracedrv.ctl

+ +

tracedrv.rc

+ +

 

+ +

LOCATION

+ +

The files that comprise Tracedrv +are included in the Windows DDK in the \src\general\tracing\tracedrv directory.

+ +

 

+ +

FEEDBACK

+ +

We welcome +your comments, problem reports, and wish-list requests. Please submit them by +visiting the Windows +DDK Web site.

+ +

Top +of page

+ + + + + +
+

 

+
+ +

© Microsoft +Corporation 2005 +

+ +
+ + + + diff --git a/general/tracing/tracedriver/tracedrv.sln b/general/tracing/tracedriver/tracedrv.sln index b75b8638..6ad93c59 100644 --- a/general/tracing/tracedriver/tracedrv.sln +++ b/general/tracing/tracedriver/tracedrv.sln @@ -3,13 +3,13 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tracectl", "Tracectl", "{F3C08B55-33D7-458F-BE79-6878512FF1B1}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tracectl", "Tracectl", "{6924D03F-364D-445C-975D-882FB14B0058}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tracedrv", "Tracedrv", "{93C02447-AFF7-40E8-AED1-849588063150}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tracedrv", "Tracedrv", "{C8CBD4D8-1015-4418-87FD-AC97AFF374CA}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tracectl", "tracectl\tracectl.vcxproj", "{72739B3A-9B9B-41EE-9B0E-E73482470A03}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tracectl", "tracectl\tracectl.vcxproj", "{3A8F1F69-AD42-492B-9F57-5F95EFCD75C6}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tracedrv", "tracedrv\tracedrv.vcxproj", "{959FDB65-EF62-4ED3-8856-326B5AD4BB41}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tracedrv", "tracedrv\tracedrv.vcxproj", "{19455661-BB6E-4AB3-A48C-33ABBB7BAF8B}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -19,28 +19,28 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {72739B3A-9B9B-41EE-9B0E-E73482470A03}.Debug|Win32.ActiveCfg = Debug|Win32 - {72739B3A-9B9B-41EE-9B0E-E73482470A03}.Debug|Win32.Build.0 = Debug|Win32 - {72739B3A-9B9B-41EE-9B0E-E73482470A03}.Release|Win32.ActiveCfg = Release|Win32 - {72739B3A-9B9B-41EE-9B0E-E73482470A03}.Release|Win32.Build.0 = Release|Win32 - {72739B3A-9B9B-41EE-9B0E-E73482470A03}.Debug|x64.ActiveCfg = Debug|x64 - {72739B3A-9B9B-41EE-9B0E-E73482470A03}.Debug|x64.Build.0 = Debug|x64 - {72739B3A-9B9B-41EE-9B0E-E73482470A03}.Release|x64.ActiveCfg = Release|x64 - {72739B3A-9B9B-41EE-9B0E-E73482470A03}.Release|x64.Build.0 = Release|x64 - {959FDB65-EF62-4ED3-8856-326B5AD4BB41}.Debug|Win32.ActiveCfg = Debug|Win32 - {959FDB65-EF62-4ED3-8856-326B5AD4BB41}.Debug|Win32.Build.0 = Debug|Win32 - {959FDB65-EF62-4ED3-8856-326B5AD4BB41}.Release|Win32.ActiveCfg = Release|Win32 - {959FDB65-EF62-4ED3-8856-326B5AD4BB41}.Release|Win32.Build.0 = Release|Win32 - {959FDB65-EF62-4ED3-8856-326B5AD4BB41}.Debug|x64.ActiveCfg = Debug|x64 - {959FDB65-EF62-4ED3-8856-326B5AD4BB41}.Debug|x64.Build.0 = Debug|x64 - {959FDB65-EF62-4ED3-8856-326B5AD4BB41}.Release|x64.ActiveCfg = Release|x64 - {959FDB65-EF62-4ED3-8856-326B5AD4BB41}.Release|x64.Build.0 = Release|x64 + {3A8F1F69-AD42-492B-9F57-5F95EFCD75C6}.Debug|Win32.ActiveCfg = Debug|Win32 + {3A8F1F69-AD42-492B-9F57-5F95EFCD75C6}.Debug|Win32.Build.0 = Debug|Win32 + {3A8F1F69-AD42-492B-9F57-5F95EFCD75C6}.Release|Win32.ActiveCfg = Release|Win32 + {3A8F1F69-AD42-492B-9F57-5F95EFCD75C6}.Release|Win32.Build.0 = Release|Win32 + {3A8F1F69-AD42-492B-9F57-5F95EFCD75C6}.Debug|x64.ActiveCfg = Debug|x64 + {3A8F1F69-AD42-492B-9F57-5F95EFCD75C6}.Debug|x64.Build.0 = Debug|x64 + {3A8F1F69-AD42-492B-9F57-5F95EFCD75C6}.Release|x64.ActiveCfg = Release|x64 + {3A8F1F69-AD42-492B-9F57-5F95EFCD75C6}.Release|x64.Build.0 = Release|x64 + {19455661-BB6E-4AB3-A48C-33ABBB7BAF8B}.Debug|Win32.ActiveCfg = Debug|Win32 + {19455661-BB6E-4AB3-A48C-33ABBB7BAF8B}.Debug|Win32.Build.0 = Debug|Win32 + {19455661-BB6E-4AB3-A48C-33ABBB7BAF8B}.Release|Win32.ActiveCfg = Release|Win32 + {19455661-BB6E-4AB3-A48C-33ABBB7BAF8B}.Release|Win32.Build.0 = Release|Win32 + {19455661-BB6E-4AB3-A48C-33ABBB7BAF8B}.Debug|x64.ActiveCfg = Debug|x64 + {19455661-BB6E-4AB3-A48C-33ABBB7BAF8B}.Debug|x64.Build.0 = Debug|x64 + {19455661-BB6E-4AB3-A48C-33ABBB7BAF8B}.Release|x64.ActiveCfg = Release|x64 + {19455661-BB6E-4AB3-A48C-33ABBB7BAF8B}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {72739B3A-9B9B-41EE-9B0E-E73482470A03} = {F3C08B55-33D7-458F-BE79-6878512FF1B1} - {959FDB65-EF62-4ED3-8856-326B5AD4BB41} = {93C02447-AFF7-40E8-AED1-849588063150} + {3A8F1F69-AD42-492B-9F57-5F95EFCD75C6} = {6924D03F-364D-445C-975D-882FB14B0058} + {19455661-BB6E-4AB3-A48C-33ABBB7BAF8B} = {C8CBD4D8-1015-4418-87FD-AC97AFF374CA} EndGlobalSection EndGlobal diff --git a/general/tracing/tracedriver/tracedrv/tracedrv.vcxproj b/general/tracing/tracedriver/tracedrv/tracedrv.vcxproj index febcbdd7..31e6316f 100644 --- a/general/tracing/tracedriver/tracedrv/tracedrv.vcxproj +++ b/general/tracing/tracedriver/tracedrv/tracedrv.vcxproj @@ -19,11 +19,11 @@
- {959FDB65-EF62-4ED3-8856-326B5AD4BB41} + {19455661-BB6E-4AB3-A48C-33ABBB7BAF8B} $(MSBuildProjectName) Debug Win32 - {01308CF4-AB44-4626-BACF-D0555BC457DF} + {46E71AFA-97EB-4402-8982-491F04EE159C} diff --git a/general/tracing/tracedriver/tracedrv/tracedrv.vcxproj.Filters b/general/tracing/tracedriver/tracedrv/tracedrv.vcxproj.Filters index 029e408d..41133cad 100644 --- a/general/tracing/tracedriver/tracedrv/tracedrv.vcxproj.Filters +++ b/general/tracing/tracedriver/tracedrv/tracedrv.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {91F6D41E-6246-46E8-99D5-002ACC23AA49} + {8E3F54BF-DC75-4CA8-BC24-30E385BF6DE2} h;hpp;hxx;hm;inl;inc;xsd - {DF6424D7-7A22-42ED-B11F-508DD7CA41CD} + {3627B81B-D94D-4485-A492-73C31C368899} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {A42F3913-01F8-47A1-B888-182B29B1B137} + {51DDE1C7-D8F3-45E4-A8C3-B9FBEF4E0364} inf;inv;inx;mof;mc; - {EC7A4F43-C45A-4AAA-97BC-DFDF6C41C75C} + {AA4D7E47-8D1B-407A-BA84-A2D3F956CEE3} diff --git a/general/umdfSkeleton/UMDFSkeleton.vcxproj b/general/umdfSkeleton/UMDFSkeleton.vcxproj index 947c3517..f0462cf3 100644 --- a/general/umdfSkeleton/UMDFSkeleton.vcxproj +++ b/general/umdfSkeleton/UMDFSkeleton.vcxproj @@ -19,7 +19,7 @@ - {A0B8804E-85A9-4432-A812-E9F6947C647A} + {70388898-AB89-4971-A750-E49A07A4180B} $(MSBuildProjectName) 1 1 @@ -27,7 +27,7 @@ 9 Debug Win32 - {A084ACA0-8591-462C-A3F8-EB936C200BCA} + {AF73135B-9C65-43D8-8AA0-B878E28778DD} diff --git a/general/umdfSkeleton/UMDFSkeleton.vcxproj.Filters b/general/umdfSkeleton/UMDFSkeleton.vcxproj.Filters index da7d8ca7..90efaa53 100644 --- a/general/umdfSkeleton/UMDFSkeleton.vcxproj.Filters +++ b/general/umdfSkeleton/UMDFSkeleton.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {16B2A720-AEC4-4627-959C-8A289CB6F699} + {4071D9FA-8523-40C2-AD37-B96CB8438837} h;hpp;hxx;hm;inl;inc;xsd - {F54667DA-A0EB-4C54-92C9-9D2E3B44E169} + {FA619144-425B-4A1D-BE9D-C67C3DF67348} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {949A3C23-B62C-4219-A44F-CF5DBE78DD73} + {A3F17163-2904-4021-9EF6-73D05E31169D} inf;inv;inx;mof;mc; - {DDA0FB16-FA5D-4FB7-8EE6-DB37C36326C6} + {0EE7AE28-07A8-4B93-8708-F261564A77B5} diff --git a/general/umdfSkeleton/UMDFSkeleton_OSR.inx b/general/umdfSkeleton/UMDFSkeleton_OSR.inx index 4da9c3f9..af5b6e2d 100644 --- a/general/umdfSkeleton/UMDFSkeleton_OSR.inx +++ b/general/umdfSkeleton/UMDFSkeleton_OSR.inx @@ -51,8 +51,9 @@ KmdfService = WINUSB, WinUsb_Install UmdfService = UMDFSkeleton, UMDFSkeleton_Install UmdfServiceOrder = UMDFSkeleton +; Needed for Win7 support [WinUsb_Install] -KmdfLibraryVersion = $KMDFVERSION$ +KmdfLibraryVersion = 1.9 [UMDFSkeleton_Install] UmdfLibraryVersion=$UMDFVERSION$ diff --git a/general/umdfSkeleton/umdfSkeleton.sln b/general/umdfSkeleton/umdfSkeleton.sln index 2deba81c..cba8f90b 100644 --- a/general/umdfSkeleton/umdfSkeleton.sln +++ b/general/umdfSkeleton/umdfSkeleton.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UMDFSkeleton", "UMDFSkeleton.vcxproj", "{A0B8804E-85A9-4432-A812-E9F6947C647A}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UMDFSkeleton", "UMDFSkeleton.vcxproj", "{70388898-AB89-4971-A750-E49A07A4180B}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +13,14 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {A0B8804E-85A9-4432-A812-E9F6947C647A}.Debug|Win32.ActiveCfg = Debug|Win32 - {A0B8804E-85A9-4432-A812-E9F6947C647A}.Debug|Win32.Build.0 = Debug|Win32 - {A0B8804E-85A9-4432-A812-E9F6947C647A}.Release|Win32.ActiveCfg = Release|Win32 - {A0B8804E-85A9-4432-A812-E9F6947C647A}.Release|Win32.Build.0 = Release|Win32 - {A0B8804E-85A9-4432-A812-E9F6947C647A}.Debug|x64.ActiveCfg = Debug|x64 - {A0B8804E-85A9-4432-A812-E9F6947C647A}.Debug|x64.Build.0 = Debug|x64 - {A0B8804E-85A9-4432-A812-E9F6947C647A}.Release|x64.ActiveCfg = Release|x64 - {A0B8804E-85A9-4432-A812-E9F6947C647A}.Release|x64.Build.0 = Release|x64 + {70388898-AB89-4971-A750-E49A07A4180B}.Debug|Win32.ActiveCfg = Debug|Win32 + {70388898-AB89-4971-A750-E49A07A4180B}.Debug|Win32.Build.0 = Debug|Win32 + {70388898-AB89-4971-A750-E49A07A4180B}.Release|Win32.ActiveCfg = Release|Win32 + {70388898-AB89-4971-A750-E49A07A4180B}.Release|Win32.Build.0 = Release|Win32 + {70388898-AB89-4971-A750-E49A07A4180B}.Debug|x64.ActiveCfg = Debug|x64 + {70388898-AB89-4971-A750-E49A07A4180B}.Debug|x64.Build.0 = Debug|x64 + {70388898-AB89-4971-A750-E49A07A4180B}.Release|x64.ActiveCfg = Release|x64 + {70388898-AB89-4971-A750-E49A07A4180B}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/gpio/samples/sim.sln b/gpio/samples/sim.sln index edbafcc1..bfd63b86 100644 --- a/gpio/samples/sim.sln +++ b/gpio/samples/sim.sln @@ -3,21 +3,21 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Simdevice", "Simdevice", "{B836C8C4-99F3-4B16-8B3D-558EFC65F9D3}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Simdevice", "Simdevice", "{08989298-000B-48DE-B970-0BE88F9A5537}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Simdeviceumdf", "Simdeviceumdf", "{5302F4A4-2BE9-43C9-BF4E-4ED0D4A131A6}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Simdeviceumdf", "Simdeviceumdf", "{99AB1B58-560E-47F1-AC02-F709DE1F03FF}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Simgpio", "Simgpio", "{3544A23D-F159-4D5F-B41D-A045D7BB4220}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Simgpio", "Simgpio", "{B1F4E416-8293-4557-A064-A0EBAB34B7B3}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Simgpio_i2c", "Simgpio_i2c", "{E0A658B7-1A02-4468-AB84-54444838B9BD}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Simgpio_i2c", "Simgpio_i2c", "{EC78C5C6-E325-44DC-9548-095850571F96}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "simdevice", "simdevice\simdevice.vcxproj", "{57BFED37-06F0-435D-A4CA-610B56B8987F}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "simdevice", "simdevice\simdevice.vcxproj", "{1683AFEC-30BD-4F42-B05C-070C4502CCC3}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SimdeviceUMDF", "simdeviceumdf\SimdeviceUMDF.vcxproj", "{D768CF1C-AE06-4C12-B11D-21C5D70082F7}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SimdeviceUMDF", "simdeviceumdf\SimdeviceUMDF.vcxproj", "{D16242B2-F3C4-48C0-98C2-D35778C4B71F}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "simgpio", "simgpio\simgpio.vcxproj", "{BCCD1049-70D2-4C07-BE8C-E9B609BD1714}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "simgpio", "simgpio\simgpio.vcxproj", "{AEF88128-15A0-4F64-ABAD-504B75C24C6B}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "simgpio_i2c", "simgpio_i2c\simgpio_i2c.vcxproj", "{FBC7D66C-8D89-4ED5-B378-A4EBB8DED3B2}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "simgpio_i2c", "simgpio_i2c\simgpio_i2c.vcxproj", "{8D155F90-F6A1-4D96-A07F-31844C0587C5}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -27,46 +27,46 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {57BFED37-06F0-435D-A4CA-610B56B8987F}.Debug|Win32.ActiveCfg = Debug|Win32 - {57BFED37-06F0-435D-A4CA-610B56B8987F}.Debug|Win32.Build.0 = Debug|Win32 - {57BFED37-06F0-435D-A4CA-610B56B8987F}.Release|Win32.ActiveCfg = Release|Win32 - {57BFED37-06F0-435D-A4CA-610B56B8987F}.Release|Win32.Build.0 = Release|Win32 - {57BFED37-06F0-435D-A4CA-610B56B8987F}.Debug|x64.ActiveCfg = Debug|x64 - {57BFED37-06F0-435D-A4CA-610B56B8987F}.Debug|x64.Build.0 = Debug|x64 - {57BFED37-06F0-435D-A4CA-610B56B8987F}.Release|x64.ActiveCfg = Release|x64 - {57BFED37-06F0-435D-A4CA-610B56B8987F}.Release|x64.Build.0 = Release|x64 - {D768CF1C-AE06-4C12-B11D-21C5D70082F7}.Debug|Win32.ActiveCfg = Debug|Win32 - {D768CF1C-AE06-4C12-B11D-21C5D70082F7}.Debug|Win32.Build.0 = Debug|Win32 - {D768CF1C-AE06-4C12-B11D-21C5D70082F7}.Release|Win32.ActiveCfg = Release|Win32 - {D768CF1C-AE06-4C12-B11D-21C5D70082F7}.Release|Win32.Build.0 = Release|Win32 - {D768CF1C-AE06-4C12-B11D-21C5D70082F7}.Debug|x64.ActiveCfg = Debug|x64 - {D768CF1C-AE06-4C12-B11D-21C5D70082F7}.Debug|x64.Build.0 = Debug|x64 - {D768CF1C-AE06-4C12-B11D-21C5D70082F7}.Release|x64.ActiveCfg = Release|x64 - {D768CF1C-AE06-4C12-B11D-21C5D70082F7}.Release|x64.Build.0 = Release|x64 - {BCCD1049-70D2-4C07-BE8C-E9B609BD1714}.Debug|Win32.ActiveCfg = Debug|Win32 - {BCCD1049-70D2-4C07-BE8C-E9B609BD1714}.Debug|Win32.Build.0 = Debug|Win32 - {BCCD1049-70D2-4C07-BE8C-E9B609BD1714}.Release|Win32.ActiveCfg = Release|Win32 - {BCCD1049-70D2-4C07-BE8C-E9B609BD1714}.Release|Win32.Build.0 = Release|Win32 - {BCCD1049-70D2-4C07-BE8C-E9B609BD1714}.Debug|x64.ActiveCfg = Debug|x64 - {BCCD1049-70D2-4C07-BE8C-E9B609BD1714}.Debug|x64.Build.0 = Debug|x64 - {BCCD1049-70D2-4C07-BE8C-E9B609BD1714}.Release|x64.ActiveCfg = Release|x64 - {BCCD1049-70D2-4C07-BE8C-E9B609BD1714}.Release|x64.Build.0 = Release|x64 - {FBC7D66C-8D89-4ED5-B378-A4EBB8DED3B2}.Debug|Win32.ActiveCfg = Debug|Win32 - {FBC7D66C-8D89-4ED5-B378-A4EBB8DED3B2}.Debug|Win32.Build.0 = Debug|Win32 - {FBC7D66C-8D89-4ED5-B378-A4EBB8DED3B2}.Release|Win32.ActiveCfg = Release|Win32 - {FBC7D66C-8D89-4ED5-B378-A4EBB8DED3B2}.Release|Win32.Build.0 = Release|Win32 - {FBC7D66C-8D89-4ED5-B378-A4EBB8DED3B2}.Debug|x64.ActiveCfg = Debug|x64 - {FBC7D66C-8D89-4ED5-B378-A4EBB8DED3B2}.Debug|x64.Build.0 = Debug|x64 - {FBC7D66C-8D89-4ED5-B378-A4EBB8DED3B2}.Release|x64.ActiveCfg = Release|x64 - {FBC7D66C-8D89-4ED5-B378-A4EBB8DED3B2}.Release|x64.Build.0 = Release|x64 + {1683AFEC-30BD-4F42-B05C-070C4502CCC3}.Debug|Win32.ActiveCfg = Debug|Win32 + {1683AFEC-30BD-4F42-B05C-070C4502CCC3}.Debug|Win32.Build.0 = Debug|Win32 + {1683AFEC-30BD-4F42-B05C-070C4502CCC3}.Release|Win32.ActiveCfg = Release|Win32 + {1683AFEC-30BD-4F42-B05C-070C4502CCC3}.Release|Win32.Build.0 = Release|Win32 + {1683AFEC-30BD-4F42-B05C-070C4502CCC3}.Debug|x64.ActiveCfg = Debug|x64 + {1683AFEC-30BD-4F42-B05C-070C4502CCC3}.Debug|x64.Build.0 = Debug|x64 + {1683AFEC-30BD-4F42-B05C-070C4502CCC3}.Release|x64.ActiveCfg = Release|x64 + {1683AFEC-30BD-4F42-B05C-070C4502CCC3}.Release|x64.Build.0 = Release|x64 + {D16242B2-F3C4-48C0-98C2-D35778C4B71F}.Debug|Win32.ActiveCfg = Debug|Win32 + {D16242B2-F3C4-48C0-98C2-D35778C4B71F}.Debug|Win32.Build.0 = Debug|Win32 + {D16242B2-F3C4-48C0-98C2-D35778C4B71F}.Release|Win32.ActiveCfg = Release|Win32 + {D16242B2-F3C4-48C0-98C2-D35778C4B71F}.Release|Win32.Build.0 = Release|Win32 + {D16242B2-F3C4-48C0-98C2-D35778C4B71F}.Debug|x64.ActiveCfg = Debug|x64 + {D16242B2-F3C4-48C0-98C2-D35778C4B71F}.Debug|x64.Build.0 = Debug|x64 + {D16242B2-F3C4-48C0-98C2-D35778C4B71F}.Release|x64.ActiveCfg = Release|x64 + {D16242B2-F3C4-48C0-98C2-D35778C4B71F}.Release|x64.Build.0 = Release|x64 + {AEF88128-15A0-4F64-ABAD-504B75C24C6B}.Debug|Win32.ActiveCfg = Debug|Win32 + {AEF88128-15A0-4F64-ABAD-504B75C24C6B}.Debug|Win32.Build.0 = Debug|Win32 + {AEF88128-15A0-4F64-ABAD-504B75C24C6B}.Release|Win32.ActiveCfg = Release|Win32 + {AEF88128-15A0-4F64-ABAD-504B75C24C6B}.Release|Win32.Build.0 = Release|Win32 + {AEF88128-15A0-4F64-ABAD-504B75C24C6B}.Debug|x64.ActiveCfg = Debug|x64 + {AEF88128-15A0-4F64-ABAD-504B75C24C6B}.Debug|x64.Build.0 = Debug|x64 + {AEF88128-15A0-4F64-ABAD-504B75C24C6B}.Release|x64.ActiveCfg = Release|x64 + {AEF88128-15A0-4F64-ABAD-504B75C24C6B}.Release|x64.Build.0 = Release|x64 + {8D155F90-F6A1-4D96-A07F-31844C0587C5}.Debug|Win32.ActiveCfg = Debug|Win32 + {8D155F90-F6A1-4D96-A07F-31844C0587C5}.Debug|Win32.Build.0 = Debug|Win32 + {8D155F90-F6A1-4D96-A07F-31844C0587C5}.Release|Win32.ActiveCfg = Release|Win32 + {8D155F90-F6A1-4D96-A07F-31844C0587C5}.Release|Win32.Build.0 = Release|Win32 + {8D155F90-F6A1-4D96-A07F-31844C0587C5}.Debug|x64.ActiveCfg = Debug|x64 + {8D155F90-F6A1-4D96-A07F-31844C0587C5}.Debug|x64.Build.0 = Debug|x64 + {8D155F90-F6A1-4D96-A07F-31844C0587C5}.Release|x64.ActiveCfg = Release|x64 + {8D155F90-F6A1-4D96-A07F-31844C0587C5}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {57BFED37-06F0-435D-A4CA-610B56B8987F} = {B836C8C4-99F3-4B16-8B3D-558EFC65F9D3} - {D768CF1C-AE06-4C12-B11D-21C5D70082F7} = {5302F4A4-2BE9-43C9-BF4E-4ED0D4A131A6} - {BCCD1049-70D2-4C07-BE8C-E9B609BD1714} = {3544A23D-F159-4D5F-B41D-A045D7BB4220} - {FBC7D66C-8D89-4ED5-B378-A4EBB8DED3B2} = {E0A658B7-1A02-4468-AB84-54444838B9BD} + {1683AFEC-30BD-4F42-B05C-070C4502CCC3} = {08989298-000B-48DE-B970-0BE88F9A5537} + {D16242B2-F3C4-48C0-98C2-D35778C4B71F} = {99AB1B58-560E-47F1-AC02-F709DE1F03FF} + {AEF88128-15A0-4F64-ABAD-504B75C24C6B} = {B1F4E416-8293-4557-A064-A0EBAB34B7B3} + {8D155F90-F6A1-4D96-A07F-31844C0587C5} = {EC78C5C6-E325-44DC-9548-095850571F96} EndGlobalSection EndGlobal diff --git a/gpio/samples/simdevice/simdevice.vcxproj b/gpio/samples/simdevice/simdevice.vcxproj index 6d685fcf..3df57b24 100644 --- a/gpio/samples/simdevice/simdevice.vcxproj +++ b/gpio/samples/simdevice/simdevice.vcxproj @@ -19,12 +19,12 @@ - {57BFED37-06F0-435D-A4CA-610B56B8987F} + {1683AFEC-30BD-4F42-B05C-070C4502CCC3} $(MSBuildProjectName) 1 Debug Win32 - {7E5C1E9A-1990-437C-B2AB-608C84382F8B} + {59D8C9BB-479F-4995-BDB1-3493C6F6EE6C} diff --git a/gpio/samples/simdevice/simdevice.vcxproj.Filters b/gpio/samples/simdevice/simdevice.vcxproj.Filters index 2cc912e8..c031c4fe 100644 --- a/gpio/samples/simdevice/simdevice.vcxproj.Filters +++ b/gpio/samples/simdevice/simdevice.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {C0D3EEB7-2138-4947-92CF-E7B13BB61AA2} + {A4E7927D-2349-4071-BB6A-5A88985C9C5C} h;hpp;hxx;hm;inl;inc;xsd - {70E36F5B-DD23-4371-98D3-59AB4042B0F1} + {77C0EAF1-5ED7-4F36-95C8-F195123751D7} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {DCCD5E1C-EB33-41FC-81B3-52934D7E2A5A} + {FA74BC3C-6CFA-48DF-8233-655E0197C9A5} inf;inv;inx;mof;mc; - {6B2886D3-87CA-46FD-B2A0-C624C0F69F92} + {ABBAD374-35FA-4C9E-A4F6-EBBBA3F54511} diff --git a/gpio/samples/simdeviceumdf/SimdeviceUMDF.vcxproj b/gpio/samples/simdeviceumdf/SimdeviceUMDF.vcxproj index 05a8bfe6..d3e72c0f 100644 --- a/gpio/samples/simdeviceumdf/SimdeviceUMDF.vcxproj +++ b/gpio/samples/simdeviceumdf/SimdeviceUMDF.vcxproj @@ -19,7 +19,7 @@ - {D768CF1C-AE06-4C12-B11D-21C5D70082F7} + {D16242B2-F3C4-48C0-98C2-D35778C4B71F} $(MSBuildProjectName) 1 11 @@ -27,7 +27,7 @@ 11 Debug Win32 - {DF2D116B-B9CA-4AE1-BAD4-416349DA768D} + {64EE202C-C6D4-4A8C-98DC-0EAF28554A0F} diff --git a/gpio/samples/simdeviceumdf/SimdeviceUMDF.vcxproj.Filters b/gpio/samples/simdeviceumdf/SimdeviceUMDF.vcxproj.Filters index db8bda4d..f7033700 100644 --- a/gpio/samples/simdeviceumdf/SimdeviceUMDF.vcxproj.Filters +++ b/gpio/samples/simdeviceumdf/SimdeviceUMDF.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {7B1D3759-D374-48F4-8ADD-07752C95369D} + {896830D3-E2B8-4FCA-88F7-B19463DEF0C2} h;hpp;hxx;hm;inl;inc;xsd - {A065C827-3D09-4244-997C-14744BF574C4} + {13303711-BD89-4979-916B-9E5BB4E8817A} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {9EB984ED-A895-4F5D-97FD-C72ACA844DAD} + {04571589-1E01-4E0D-B8DA-A91738B670ED} inf;inv;inx;mof;mc; - {3940722F-AA7D-4F6A-8A19-3CD74FCBD352} + {4C152BF3-A4DC-42D4-BFE3-E8B703BBE867} diff --git a/gpio/samples/simgpio/simgpio.vcxproj b/gpio/samples/simgpio/simgpio.vcxproj index f9e47196..47e3f461 100644 --- a/gpio/samples/simgpio/simgpio.vcxproj +++ b/gpio/samples/simgpio/simgpio.vcxproj @@ -19,12 +19,12 @@ - {BCCD1049-70D2-4C07-BE8C-E9B609BD1714} + {AEF88128-15A0-4F64-ABAD-504B75C24C6B} $(MSBuildProjectName) 1 Debug Win32 - {1C686E11-FC59-4029-AFA6-6083113CBA26} + {D6E40FD6-4479-4E69-AC17-CC75141D18E7} diff --git a/gpio/samples/simgpio/simgpio.vcxproj.Filters b/gpio/samples/simgpio/simgpio.vcxproj.Filters index 21ab66e9..4e09f093 100644 --- a/gpio/samples/simgpio/simgpio.vcxproj.Filters +++ b/gpio/samples/simgpio/simgpio.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {BFF3D918-3BBB-4AF1-B1A2-C2A4FD8E82E8} + {65A688B8-1C22-40C7-B809-921DFABC7438} h;hpp;hxx;hm;inl;inc;xsd - {3BC12FA6-2491-4DA4-86C0-8F10AA4DB124} + {AF50110C-16B2-4D79-BA2E-7F9F66038B4D} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {004102F6-6CB6-4E30-A1D8-B663D4B8CE08} + {DFE00DCD-7A69-497A-8757-78398D64C66F} inf;inv;inx;mof;mc; - {38B34A48-263B-481A-81DE-81BF490980CD} + {56A85DDD-FDD8-451F-B882-8D792758B4DC} diff --git a/gpio/samples/simgpio_i2c/simgpio_i2c.vcxproj b/gpio/samples/simgpio_i2c/simgpio_i2c.vcxproj index 1e2e182e..e012d4e9 100644 --- a/gpio/samples/simgpio_i2c/simgpio_i2c.vcxproj +++ b/gpio/samples/simgpio_i2c/simgpio_i2c.vcxproj @@ -19,12 +19,12 @@ - {FBC7D66C-8D89-4ED5-B378-A4EBB8DED3B2} + {8D155F90-F6A1-4D96-A07F-31844C0587C5} $(MSBuildProjectName) 1 Debug Win32 - {ABDC1F8D-20A4-4A63-9D67-7B8374C9057D} + {84D9693D-232E-4A2A-AB11-F8477CEC5836} diff --git a/gpio/samples/simgpio_i2c/simgpio_i2c.vcxproj.Filters b/gpio/samples/simgpio_i2c/simgpio_i2c.vcxproj.Filters index e5d09d4d..30f81d7a 100644 --- a/gpio/samples/simgpio_i2c/simgpio_i2c.vcxproj.Filters +++ b/gpio/samples/simgpio_i2c/simgpio_i2c.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {522EE08F-03EE-45E0-875A-A47E2E9F025C} + {8F86BB64-A9E3-4E97-B7A8-47D504663D4A} h;hpp;hxx;hm;inl;inc;xsd - {22B4A1F1-B05A-4383-A9D2-BDBF45C56975} + {FC609C6E-4259-4CA8-BAA6-C8020B667EB0} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {E394D95C-DF2A-4F28-9A22-A3C121FC5394} + {308B7634-8106-4651-A527-67C836627552} inf;inv;inx;mof;mc; - {5D13D9B5-61BC-45B1-AF0D-4EDE9C7D2F80} + {1BDB4EDB-22EC-48BE-BFD3-47646B9F8771} diff --git a/hid/hclient/ReadMe.md b/hid/hclient/ReadMe.md new file mode 100644 index 00000000..f0d2b154 --- /dev/null +++ b/hid/hclient/ReadMe.md @@ -0,0 +1,22 @@ +HClient sample application +========================== + +The *HClient* sample demonstrates how to write a user-mode client application that communicates with HID devices. (These are devices that conform to the HID device class specification.) + +You will find this sample useful if you need to develop an application that communicates with, or extracts information from, a HID device. This sample illustrates a method for detecting a connected HID, opening that device for communication, and extracting or formatting the data into, or from, device reports. + +**Note**   + +To build this sample, you can use Microsoft Visual Studio 2013 (Express, Professional, or Ultimate) and Windows Driver Kit (WDK) 8.1 Update. You can get Visual Studio 2013 and WDK 8.1 Update [here](http://go.microsoft.com/fwlink/p/?LInkID=239721). + +You can also build this sample with Visual Studio 2013 (Professional or Ultimate) and [Windows Driver Kit (WDK) 8.1](http://go.microsoft.com/fwlink/p/?LInkID=391348). + +For Windows Driver Kit (WDK) 8 samples, download the [WDK 8 samples pack](%20http://go.microsoft.com/fwlink/?LinkId=317090). The samples in the WDK 8 samples pack will build only with Microsoft Visual Studio Professional 2012 (Professional or Ultimate) and WDK 8. + +Related topics +-------------- + +[Human Input Devices Design Guide](http://msdn.microsoft.com/en-us/library/windows/hardware/ff539952) + +[Human Input Devices Reference](http://msdn.microsoft.com/en-us/library/windows/hardware/ff539956) + diff --git a/hid/hclient/buffers.c b/hid/hclient/buffers.c new file mode 100644 index 00000000..75099235 --- /dev/null +++ b/hid/hclient/buffers.c @@ -0,0 +1,424 @@ +/*++ + +Copyright (c) Microsoft 1998, All Rights Reserved + +Module Name: + + buffers.c + +Abstract: + + This module contains the code for handling the display of HID report + buffers for the extended calls dialog box. + +Environment: + + User mode + +Revision History: + + May-98 : Created + +--*/ + +#include +#include +#include +#include "hidsdi.h" +#include "hidpi.h" +#include "buffers.h" +#include "strings.h" +#include +#include +#include + +#pragma warning(disable:4057) // indirection to slightly different base types +#pragma warning(disable:28146) // Warning is meant for kernel mode drivers + +#define CURRENT_REPORT(pDisp) (pDisp -> ReportBuffers + pDisp -> iCurrSelectionIndex) + +BOOLEAN +BufferDisplay_Init( + IN HWND hCB, + IN HWND hEB, + IN INT nBuffers, + IN INT iBufferSize, + IN HIDP_REPORT_TYPE RType, + _Outptr_result_maybenull_ PBUFFER_DISPLAY *ppBufferDisplay +) +/*++ +Routine Description: + This routine initializes the buffer display mechanism for a given report type + + The display mechanism maintains a list of list of nBuffers, where is each + is buffer is of iBufferSize and hCB and hEB are handles to the combo box and + edit box for displaying the buffer. + + The variable ppBufferDisplay is allocated block which is passed into other + buffer routines and contains information about the buffer for the other + routines. + + This function will return FALSE if there was a problem allocating memory +--*/ +{ +#pragma warning(push) +#pragma warning(disable:28197) // BufferDisplay_Destroy frees memory + PBUFFER_DISPLAY pNewDisplay; + UINT reportBuffersSize = 0; + CHAR *pszBufferHeader; + CHAR szBufferName[24]; + UINT iIndex; + UINT iCBIndex; + + pNewDisplay = (PBUFFER_DISPLAY) malloc(sizeof(BUFFER_DISPLAY)); + + *ppBufferDisplay = NULL; + + if (NULL == pNewDisplay) + { + return (FALSE); + } + + if(S_OK != ULongMult(sizeof(REPORT_BUFFER), nBuffers, &reportBuffersSize)) + { + free(pNewDisplay); + return (FALSE); + } + + pNewDisplay->ReportBuffers = (PREPORT_BUFFER) malloc(reportBuffersSize); + + if (NULL == pNewDisplay -> ReportBuffers) + { + free(pNewDisplay); + return (FALSE); + } + + memset(pNewDisplay -> ReportBuffers, 0x00, reportBuffersSize); + + pNewDisplay -> hBufferComboBox = hCB; + pNewDisplay -> hBufferEditBox = hEB; + pNewDisplay -> nReportBuffers = nBuffers; + pNewDisplay -> iBufferSize = iBufferSize; + pNewDisplay -> ReportType = RType; + + switch (pNewDisplay -> ReportType) + { + case HidP_Input: + pszBufferHeader = "Input"; + break; + + case HidP_Output: + pszBufferHeader = "Output"; + break; + + case HidP_Feature: + pszBufferHeader = "Feature"; + break; + + default: + pszBufferHeader = "Other"; + break; + } + + for (iIndex = 0; iIndex < pNewDisplay -> nReportBuffers; iIndex++) + { + if(FAILED(StringCbPrintf(szBufferName, sizeof(szBufferName), + "%s Buffer #%d", pszBufferHeader, iIndex))) + { + BufferDisplay_Destroy(pNewDisplay); + return (FALSE); + } + + iCBIndex = (INT) SendMessage(pNewDisplay -> hBufferComboBox, + CB_ADDSTRING, + 0, + (LPARAM) szBufferName); + + if (CB_ERR == iCBIndex || CB_ERRSPACE == iCBIndex) + { + BufferDisplay_Destroy(pNewDisplay); + return (FALSE); + } + + iCBIndex = (INT) SendMessage(pNewDisplay -> hBufferComboBox, + CB_SETITEMDATA, + iCBIndex, + iIndex); + + if (CB_ERR == iCBIndex || CB_ERRSPACE == iCBIndex) + { + BufferDisplay_Destroy(pNewDisplay); + return (FALSE); + } + } + + SendMessage(pNewDisplay -> hBufferComboBox, CB_SETCURSEL, 0, 0); + + BufferDisplay_ChangeSelection(pNewDisplay); + + *ppBufferDisplay = pNewDisplay; + return (TRUE); +#pragma warning(pop) // 28197 +} + +VOID +BufferDisplay_Destroy( + IN PBUFFER_DISPLAY pBufferDisplay +) +/*++ +Routine Description: + This routine cleans up the buffer display variable that was allocated by + the initialize routine +--*/ +{ + UINT iIndex; + + for (iIndex = 0; iIndex < pBufferDisplay -> nReportBuffers; iIndex++) + { + if (NULL != pBufferDisplay -> ReportBuffers[iIndex].pBuffer) + { + free(pBufferDisplay -> ReportBuffers[iIndex].pBuffer); + } + } + + free(pBufferDisplay -> ReportBuffers); + free(pBufferDisplay); + return; +} + +VOID +BufferDisplay_ChangeSelection( + IN PBUFFER_DISPLAY pBufferDisplay +) +/*++ +Routine Description: + This routine has the selection of a buffer to display via the combo box +--*/ +{ + INT iNewIndex; + + iNewIndex = (INT) SendMessage(pBufferDisplay -> hBufferComboBox, + CB_GETCURSEL, + 0, + 0); + + if (CB_ERR == iNewIndex) + { + return; + } + + iNewIndex = (INT) SendMessage(pBufferDisplay -> hBufferComboBox, + CB_GETITEMDATA, + iNewIndex, + 0); + + if (CB_ERR == iNewIndex) + { + return; + } + + pBufferDisplay -> iCurrSelectionIndex = iNewIndex; + + BufferDisplay_OutputBuffer(pBufferDisplay -> hBufferEditBox, + &(pBufferDisplay -> ReportBuffers[iNewIndex])); + + return; +} + +VOID +BufferDisplay_OutputBuffer( + HWND hEditBox, + PREPORT_BUFFER pReportBuffer +) +/*++ +Routine Description: + This routine outputs to hEditBox a byte representation of pReportBuffer +--*/ +{ + PCHAR BufferString; + + if (0 == pReportBuffer -> iBufferSize || NULL == pReportBuffer -> pBuffer) + { + SetWindowText(hEditBox, ""); + } + else + { + /* + // Create a buffer string the size of the buffer and display + // as bytes + */ + + Strings_CreateDataBufferString(pReportBuffer -> pBuffer, + pReportBuffer -> iBufferSize, + pReportBuffer -> iBufferSize, + 1, + &BufferString); + + if (NULL == BufferString) + { + SetWindowText(hEditBox, ""); + } + else + { + SetWindowText(hEditBox, BufferString); + free(BufferString); + } + } + return; +} + +BOOLEAN +BufferDisplay_UpdateBuffer( + _In_ PBUFFER_DISPLAY pBufferDisplay, + _In_reads_bytes_(ulNewBufferLength) PCHAR pNewBuffer, + _In_ ULONG ulNewBufferLength +) +/*++ +Routine Description: + This routine changes the data of the currently active report buffer for the + given buffer display structure. + + It returns FALSE if it needed to allocate a new buffer and the memory allocation + failed. +--*/ +{ + PREPORT_BUFFER pCurrentReport; + + if (pBufferDisplay->nReportBuffers <= pBufferDisplay->iCurrSelectionIndex) + { + return (FALSE); // error case + } + + pCurrentReport = CURRENT_REPORT(pBufferDisplay); + + if (NULL == pCurrentReport->pBuffer) + { + pCurrentReport->pBuffer = malloc(pBufferDisplay->iBufferSize); + if (NULL == pCurrentReport->pBuffer) + { + return (FALSE); + } + + pCurrentReport->iBufferSize = pBufferDisplay->iBufferSize; + } + + if(ulNewBufferLength < pCurrentReport->iBufferSize) + { + return (FALSE); + } + + memmove (pCurrentReport->pBuffer, pNewBuffer, pCurrentReport->iBufferSize); + + BufferDisplay_OutputBuffer(pBufferDisplay->hBufferEditBox, pCurrentReport); + + return (TRUE); +} + +INT +BufferDisplay_GetBufferSize( + IN PBUFFER_DISPLAY pBufferDisplay +) +/*++ +Routine Description: + This routine simply returns the size of the given buffer +--*/ +{ + return (pBufferDisplay -> iBufferSize); +} + +VOID +BufferDisplay_CopyCurrentBuffer( + _In_ PBUFFER_DISPLAY pBufferDisplay, + _Out_writes_bytes_(ulCopyBufferLength) PCHAR pCopyBuffer, + _In_ ULONG ulCopyBufferLength +) +/*++ +Routine Description: + This routine copies the currently active buffer for the given buffer display + into the buffer passed in by the caller. + + It is the caller's responsibility to allocate a buffer of the appropriate size + The appropriate size can be obtain by calling BufferDisplay_GetBufferSize +--*/ +{ + PREPORT_BUFFER pCurrentReport; + + pCurrentReport = CURRENT_REPORT(pBufferDisplay); + + if (NULL == pCurrentReport->pBuffer) + { + if(ulCopyBufferLength >= pBufferDisplay->iBufferSize) + { + memset(pCopyBuffer, 0x0, pBufferDisplay->iBufferSize); + } + } + else + { + if(ulCopyBufferLength >= pCurrentReport->iBufferSize) + { + memcpy(pCopyBuffer, pCurrentReport->pBuffer, pCurrentReport->iBufferSize); + } + } + return; +} + +INT +BufferDisplay_GetCurrentBufferNumber( + IN PBUFFER_DISPLAY pBufferDisplay +) +/*++ +Routine Description: + This routine returns the buffer number of the current buffer selection +--*/ +{ + return (pBufferDisplay -> iCurrSelectionIndex); +} + +UCHAR +BufferDisplay_GetCurrentReportID( + IN PBUFFER_DISPLAY pBufferDisplay +) +/*++ +Routine Description: + This routine returns the report ID of the current buffer selection +--*/ +{ + PREPORT_BUFFER pCurrentReport; + + pCurrentReport = CURRENT_REPORT(pBufferDisplay); + + return (pCurrentReport -> ucReportID); +} + +VOID +BufferDisplay_ClearBuffer( + IN PBUFFER_DISPLAY pBufferDisplay +) +/*++ +Routine Description: + This routine frees the current report buffer and set's it to NULL +--*/ +{ + PREPORT_BUFFER pCurrentReport; + + if (pBufferDisplay->nReportBuffers <= pBufferDisplay->iCurrSelectionIndex) + { + assert(FALSE); + return; + } + + pCurrentReport = CURRENT_REPORT(pBufferDisplay); + + if (NULL != pCurrentReport -> pBuffer) + { + free(pCurrentReport -> pBuffer); + + pCurrentReport -> iBufferSize = 0; + pCurrentReport -> ucReportID = 0; + pCurrentReport -> pBuffer = NULL; + } + + BufferDisplay_OutputBuffer(pBufferDisplay -> hBufferEditBox, + pCurrentReport); + return; +} diff --git a/hid/hclient/buffers.h b/hid/hclient/buffers.h new file mode 100644 index 00000000..ec790da9 --- /dev/null +++ b/hid/hclient/buffers.h @@ -0,0 +1,108 @@ +/*++ + +Copyright (c) Microsoft 1998, All Rights Reserved + +Module Name: + + buffers.h + +Abstract: + + This module declares the functions that and structures that are visible + to other modules. + +Environment: + + User mode + +Revision History: + + May-98 : Created + +--*/ + +#ifndef _BUFFERS_H_ +#define _BUFFERS_H_ + +typedef struct _REPORT_BUFFER +{ + _Field_size_(iBufferSize) + PUCHAR pBuffer; + UINT iBufferSize; + UCHAR ucReportID; + +} REPORT_BUFFER, *PREPORT_BUFFER; + +typedef struct _BUFFER_DISPLAY +{ + HWND hBufferComboBox; + HWND hBufferEditBox; + UINT iBufferSize; + UINT iCurrSelectionIndex; + UINT nReportBuffers; + _Field_size_(nReportBuffers) + PREPORT_BUFFER ReportBuffers; + HIDP_REPORT_TYPE ReportType; +} BUFFER_DISPLAY, *PBUFFER_DISPLAY; + +BOOLEAN +BufferDisplay_Init( + IN HWND hCB, + IN HWND hEB, + IN INT nBuffers, + IN INT iBufferSize, + IN HIDP_REPORT_TYPE RType, + _Outptr_result_maybenull_ PBUFFER_DISPLAY *ppBufferDisplay +); + +VOID +BufferDisplay_Destroy( + IN PBUFFER_DISPLAY pBufferDisplay +); + +VOID +BufferDisplay_ChangeSelection( + IN PBUFFER_DISPLAY pBufferDisplay +); + +BOOLEAN +BufferDisplay_UpdateBuffer( + _In_ PBUFFER_DISPLAY pBufferDisplay, + _In_reads_bytes_(ulNewBufferLength) PCHAR pNewBuffer, + _In_ ULONG ulNewBufferLength +); + +INT +BufferDisplay_GetBufferSize( + IN PBUFFER_DISPLAY pBufferDisplay +); + +VOID +BufferDisplay_CopyCurrentBuffer( + _In_ PBUFFER_DISPLAY pBufferDisplay, + _Out_writes_bytes_(ulCopyBufferLength) PCHAR pCopyBuffer, + _In_ ULONG ulCopyBufferLength +); + +INT +BufferDisplay_GetCurrentBufferNumber( + IN PBUFFER_DISPLAY pBufferDisplay +); + +UCHAR +BufferDisplay_GetCurrentReportID( + IN PBUFFER_DISPLAY pBufferDisplay +); + +VOID +BufferDisplay_OutputBuffer( + HWND hEditBox, + PREPORT_BUFFER pReportBuffer +); + +VOID +BufferDisplay_ClearBuffer( + IN PBUFFER_DISPLAY pBufferDisplay +); + +#endif diff --git a/hid/hclient/ecdisp.c b/hid/hclient/ecdisp.c new file mode 100644 index 00000000..5d25aa4c --- /dev/null +++ b/hid/hclient/ecdisp.c @@ -0,0 +1,4347 @@ +/*++ + +Copyright (c) Microsoft 1998, All Rights Reserved + +Module Name: + + ecdisp.c + +Abstract: + + This module contains the code to handle the extended calls dialog box + and the actions that can be performed in the dialog box. + +Environment: + + User mode + +Revision History: + + May-98 : Created + +--*/ + +/***************************************************************************** +/* Extended call display include files +/*****************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "hidusage.h" +#include "hidsdi.h" +#include "hid.h" +#include "hclient.h" +#include "resource.h" +#include "buffers.h" +#include "ecdisp.h" +#include "strings.h" + +/***************************************************************************** +/* Local macro definitions for the supported function calls +/*****************************************************************************/ + +#pragma warning(disable:4057) // indirection to slightly different base types +#pragma warning(disable:4201) +#pragma warning(disable:28146) // Warning is meant for kernel mode drivers +#pragma prefast(disable:38030, "Samples are not localized") + +#define HID_DEVCALLS 20 +#define HID_PPDCALLS 29 + +#define HID_NUMCALLS HID_DEVCALLS + HID_PPDCALLS + +#define HIDD_GET_HID_GUID 1 +#define HIDD_GET_FREE_PREPARSED_DATA 2 +#define HIDD_GET_CONFIGURATION 3 +#define HIDD_SET_CONFIGURATION 4 +#define HIDD_FLUSH_QUEUE 5 +#define HIDD_GET_ATTRIBUTES 6 +#define HIDD_SET_FEATURE 7 +#define HIDD_GET_FEATURE 8 +#define HIDD_GET_INPUT_REPORT 9 +#define HIDD_SET_OUTPUT_REPORT 10 +#define HIDD_GET_NUM_INPUT_BUFFERS 11 +#define HIDD_SET_NUM_INPUT_BUFFERS 12 +#define HIDD_GET_PHYSICAL_DESCRIPTOR 13 +#define HIDD_GET_MANUFACTURER_STRING 14 +#define HIDD_GET_PRODUCT_STRING 15 +#define HIDD_GET_INDEXED_STRING 16 +#define HIDD_GET_SERIAL_NUMBER_STRING 17 +#define HIDD_GET_MS_GENRE_DESCRIPTOR 18 +#define HID_READ_REPORT 19 +#define HID_WRITE_REPORT 20 +#define HIDP_GET_BUTTON_CAPS 21 +#define HIDP_GET_BUTTONS 22 +#define HIDP_GET_BUTTONS_EX 23 +#define HIDP_GET_CAPS 24 +#define HIDP_GET_DATA 25 +#define HIDP_GET_EXTENDED_ATTRIBUTES 26 +#define HIDP_GET_LINK_COLL_NODES 27 +#define HIDP_GET_SCALED_USAGE_VALUE 28 +#define HIDP_GET_SPECIFIC_BUTTON_CAPS 29 +#define HIDP_GET_SPECIFIC_VALUE_CAPS 30 +#define HIDP_GET_USAGES 31 +#define HIDP_GET_USAGES_EX 32 +#define HIDP_GET_USAGE_VALUE 33 +#define HIDP_GET_USAGE_VALUE_ARRAY 34 +#define HIDP_GET_VALUE_CAPS 35 +#define HIDP_INITIALIZE_REPORT_FOR_ID 36 +#define HIDP_MAX_DATA_LIST_LENGTH 37 +#define HIDP_MAX_USAGE_LIST_LENGTH 38 +#define HIDP_SET_BUTTONS 39 +#define HIDP_SET_DATA 40 +#define HIDP_SET_SCALED_USAGE_VALUE 41 +#define HIDP_SET_USAGES 42 +#define HIDP_SET_USAGE_VALUE 43 +#define HIDP_SET_USAGE_VALUE_ARRAY 44 +#define HIDP_TRANSLATE_USAGES 45 +#define HIDP_UNSET_BUTTONS 46 +#define HIDP_UNSET_USAGES 47 +#define HIDP_USAGE_LIST_DIFFERENCE 48 +#define HID_CLEAR_REPORT 49 + +/* +// These two definitions are not used by the display routines since +// the two functions were molded together into one for purpose of execution +*/ + +#define HIDD_GET_PREPARSED_DATA 50 +#define HIDD_FREE_PREPARSED_DATA 51 + + +#define IS_HIDD_FUNCTION(func) (((func) >= HIDD_GET_HID_GUID) && \ + ((func) <= HIDD_GET_MS_GENRE_DESCRIPTOR)) + + +#define IS_HIDP_FUNCTION(func) (((func) >= HIDP_GET_BUTTON_CAPS) && \ + ((func) <= HIDP_USAGE_LIST_DIFFERENCE)) + +#define IS_HID_FUNCTION(func) (((func) >= HID_READ_REPORT) && \ + ((func) <= HID_WRITE_REPORT)) + +#define IS_NOT_IMPLEMENTED(func) (((func) == HIDD_GET_CONFIGURATION) || \ + ((func) == HIDD_SET_CONFIGURATION) || \ + ((func) == HIDP_TRANSLATE_USAGES) || \ + (((func) == HIDP_INITIALIZE_REPORT_FOR_ID) && \ + (NULL == pfnHidP_InitializeReportForID)) || \ + (((func) == HIDP_GET_EXTENDED_ATTRIBUTES) && \ + (NULL == pfnHidP_GetExtendedAttributes))) + +/***************************************************************************** +/* Local macro definitions for buffer display sizes +/*****************************************************************************/ + +#define NUM_INPUT_BUFFERS 16 +#define NUM_OUTPUT_BUFFERS 16 +#define NUM_FEATURE_BUFFERS 16 + +/***************************************************************************** +/* Local macro definition for HidP_SetData dialog box +/*****************************************************************************/ + +#define SETDATA_LISTBOX_FORMAT "Index: %u, DataValue: %u" + +/***************************************************************************** +/* Local macro definition for display output to output windows +/*****************************************************************************/ + +#define TEMP_BUFFER_SIZE 1024 +#define OUTSTRING(win, str) SendMessage(win, LB_ADDSTRING, 0, (LPARAM) str) +#define OUTWSTRING(win, str) \ +{ \ + SIZE_T nBytes; \ +\ + errno_t result = wcstombs_s(&nBytes, szTempBuffer, TEMP_BUFFER_SIZE, str, TEMP_BUFFER_SIZE-1); \ + if (0 != result) { \ + OUTSTRING(win, "Cannot convert wide-character string"); \ + } \ + else { \ + szTempBuffer[nBytes] = '\0'; \ + OUTSTRING(win, szTempBuffer); \ + } \ +} + +#define DISPLAY_HIDD_STATUS(win, func, status, strret) \ +{ \ + strret = StringCbPrintf(szTempBuffer, \ + TEMP_BUFFER_SIZE, \ + "%s returned: %s", \ + func, \ + (status).IsHidError ? "FALSE" : "TRUE"); \ +\ + OUTSTRING(win, szTempBuffer); \ +\ + if ((status).IsHidError) { \ + strret = StringCbPrintf(szTempBuffer, \ + TEMP_BUFFER_SIZE, \ + "ErrorCode: %d", \ + GetLastError()); \ + }\ + OUTSTRING(win, szTempBuffer); \ +} + +#define DISPLAY_HIDP_STATUS(win, func, status, strret) \ +{ \ + int szTempBuffer_size = sizeof(szTempBuffer); \ + strret = StringCbPrintf(szTempBuffer, \ + szTempBuffer_size, \ + "%s returned: %s", \ + func, \ + ECDisp_GetHidAppStatusString(status.HidErrorCode)); \ +\ + if(SUCCEEDED(strret)) \ + { \ + OUTSTRING(win, szTempBuffer); \ + } \ + else \ + { \ + OUTSTRING(win, "ERROR: StringCbPrintf failed"); \ + } \ +} + +#define ECDISP_ERROR(win, msg) \ +{ \ + MessageBox(win, \ + msg, \ + HCLIENT_ERROR, \ + MB_ICONEXCLAMATION); \ +} + +#define GET_FUNCTION_NAME(index) ResolveFunctionName(index) + + +/***************************************************************************** +/* Local macro definition for retrieving data based on report type +/*****************************************************************************/ +#define SELECT_ON_REPORT_TYPE(rt, ival, oval, fval, res) \ +{ \ + switch ((rt)) { \ + case HidP_Input: \ + (res) = (ival); \ + break; \ +\ + case HidP_Output: \ + (res) = (oval); \ + break; \ +\ + case HidP_Feature: \ + (res) = (fval); \ + break; \ +\ + } \ +} + +/***************************************************************************** +/* Local macro definition for calculating size of a usage value array buffer +/*****************************************************************************/ +#define ROUND_TO_NEAREST_BYTE(val) (((val) % 8) ? ((val) / 8) + 1 : ((val) / 8)) + +/***************************************************************************** +/* Data types local to this module +/*****************************************************************************/ + +typedef struct _FUNCTION_NAMES +{ + UINT uiIndex; + char *szFunctionName; +} FUNCTION_NAMES; + +typedef struct _PARAMETER_STATE +{ + BOOL fInputReport; + BOOL fOutputReport; + BOOL fFeatureReport; + BOOL fReportID; + BOOL fUsagePage; + BOOL fUsage; + BOOL fLinkCollection; + BOOL fInputReportSelect; + BOOL fOutputReportSelect; + BOOL fFeatureReportSelect; +} PARAMETER_STATE; + +typedef enum { DLGBOX_INIT_FAILED = -1, DLGBOX_ERROR, DLGBOX_CANCEL, DLGBOX_OK } DLGBOX_STATUS; + +typedef struct _ECDISPLAY_PARAMS +{ + HIDP_REPORT_TYPE ReportType; + USAGE UsagePage; + USAGE Usage; + USHORT LinkCollection; + UCHAR ReportID; + _Field_size_(ListLength+1) + LPSTR szListString; + _Field_size_(ListLength2+1) + LPSTR szListString2; + _Field_size_(ListLength+1) + PUSAGE UsageList; + _Field_size_(ListLength2+1) + PUSAGE UsageList2; + ULONG ListLength; + ULONG ListLength2; + ULONG Index; + union { + PHIDP_DATA pDataList; + PULONG pValueList; + LONG ScaledValue; + ULONG Value; + }; +} ECDISPLAY_PARAMS, *PECDISPLAY_PARAMS; + +typedef struct _READ_PARAMS +{ + PHID_DEVICE device; + BOOLEAN stopThread; +} READ_PARAMS, *PREAD_PARAMS; + +/***************************************************************************** +/* Local data variables +/*****************************************************************************/ + +static CHAR szTempBuffer[TEMP_BUFFER_SIZE]; + +static PBUFFER_DISPLAY pInputDisplay; +static PBUFFER_DISPLAY pOutputDisplay; +static PBUFFER_DISPLAY pFeatureDisplay; + +static FUNCTION_NAMES DeviceCalls[HID_DEVCALLS] = { + { HIDD_GET_HID_GUID, "HidD_GetHidGuid" }, + { HIDD_GET_FREE_PREPARSED_DATA, "HidD_GetFreePreparsedData" }, + { HIDD_GET_CONFIGURATION, "HidD_GetConfiguration" }, + { HIDD_SET_CONFIGURATION, "HidD_SetConfiguration" }, + { HIDD_FLUSH_QUEUE, "HidD_FlushQueue" }, + { HIDD_GET_ATTRIBUTES, "HidD_GetAttributes" }, + { HIDD_SET_FEATURE, "HidD_SetFeature" }, + { HIDD_GET_FEATURE, "HidD_GetFeature" }, + { HIDD_GET_INPUT_REPORT, "HIDD_GetInputReport" }, + { HIDD_SET_OUTPUT_REPORT, "HidD_SetOutputReport" }, + { HIDD_GET_NUM_INPUT_BUFFERS, "HidD_GetNumInputBuffers" }, + { HIDD_SET_NUM_INPUT_BUFFERS, "HidD_SetNumInputBuffers" }, + { HIDD_GET_PHYSICAL_DESCRIPTOR, "HidD_GetPhysicalDescriptor" }, + { HIDD_GET_MANUFACTURER_STRING, "HidD_GetManufacturerString" }, + { HIDD_GET_PRODUCT_STRING, "HidD_GetProductString" }, + { HIDD_GET_INDEXED_STRING, "HidD_GetIndexedString" }, + { HIDD_GET_SERIAL_NUMBER_STRING, "HidD_GetSerialNumberString" }, + { HIDD_GET_MS_GENRE_DESCRIPTOR, "HidD_GetMsGenreDescriptor" }, + { HID_READ_REPORT, "Read Input Report" }, + { HID_WRITE_REPORT, "Write Report Buffer" } + +}; + +static FUNCTION_NAMES PpdCalls[HID_PPDCALLS] = { + { HIDP_GET_BUTTON_CAPS, "HidP_GetButtonCaps" }, + { HIDP_GET_BUTTONS, "HidP_GetButtons" }, + { HIDP_GET_BUTTONS_EX, "HidP_GetButtonsEx" }, + { HIDP_GET_CAPS, "HidP_GetCaps" }, + { HIDP_GET_DATA, "HidP_GetData" }, + { HIDP_GET_EXTENDED_ATTRIBUTES, "HidP_GetExtendedAttributes" }, + { HIDP_GET_LINK_COLL_NODES, "HidP_GetLinkCollectionNodes" }, + { HIDP_GET_SCALED_USAGE_VALUE, "HidP_GetScaledUsageValue" }, + { HIDP_GET_SPECIFIC_BUTTON_CAPS, "HidP_GetSpecificButtonCaps" }, + { HIDP_GET_SPECIFIC_VALUE_CAPS, "HidP_GetSpecificValueCaps" }, + { HIDP_GET_USAGES, "HidP_GetUsages" }, + { HIDP_GET_USAGES_EX, "HidP_GetUsagesEx" }, + { HIDP_GET_USAGE_VALUE, "HidP_GetUsageValue" }, + { HIDP_GET_USAGE_VALUE_ARRAY, "HidP_GetUsageValueArray" }, + { HIDP_GET_VALUE_CAPS, "HidP_GetValueCaps" }, + { HIDP_INITIALIZE_REPORT_FOR_ID, "HidP_InitializeReportForID" }, + { HIDP_MAX_DATA_LIST_LENGTH, "HidP_MaxDataListLength" }, + { HIDP_MAX_USAGE_LIST_LENGTH, "HidP_MaxUsageListLength" }, + { HIDP_SET_BUTTONS, "HidP_SetButtons" }, + { HIDP_SET_DATA, "HidP_SetData" }, + { HIDP_SET_SCALED_USAGE_VALUE, "HidP_SetScaledUsageValue" }, + { HIDP_SET_USAGES, "HidP_SetUsages" }, + { HIDP_SET_USAGE_VALUE, "HidP_SetUsageValue" }, + { HIDP_SET_USAGE_VALUE_ARRAY, "HidP_SetUsageValueArray" }, + { HIDP_TRANSLATE_USAGES, "HidP_TranslateUsagesToI8042ScanCodes" }, + { HIDP_UNSET_BUTTONS, "HidP_UnsetButtons" }, + { HIDP_UNSET_USAGES, "HidP_UnsetUsages" }, + { HIDP_USAGE_LIST_DIFFERENCE, "HidP_UsageListDifference" }, + { HID_CLEAR_REPORT, "Clear Report Buffer" } +}; + +static PARAMETER_STATE pState[HID_NUMCALLS] = { + { FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // HIDD_GET_HID_GUID + { FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // HIDD_GET_FREE_PREPARSED_DATA + { FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // HIDD_GET_CONFIGURATION + { FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // HIDD_SET_CONFIGURATION + { FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // HIDD_FLUSH_QUEUE + { FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // HIDD_GETATTRIBUTES + { FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE }, // HIDD_SET_FEATURE + { FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE }, // HIDD_GET_FEATURE + { FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE }, // HIDD_GET_INPUT_REPORT + { FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE }, // HIDD_SET_OUTPUT_REPORT + { FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // HIDD_GET_NUM_INPUT_BUFFERS + { FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // HIDD_SET_NUM_INPUT_BUFFERS + { FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // HIDD_GET_PHYSICAL_DESCRIPTOR + { FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // HIDD_GET_MANUFACTURER_STRING + { FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // HIDD_GET_PRODUCT_STRING + { FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // HIDD_GET_INDEXED_STRING + { FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // HIDD_GET_SERIAL_NUMBER_STRING + { FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // HIDD_GET_MS_GENRE_DESCRIPTOR + { FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE }, // HID_READ_REPORT + { FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE }, // HID_WRITE_BUFFER + { TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // HIDP_GET_BUTTON_CAPS + { TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, TRUE, TRUE }, // HIDP_GET_BUTTONS + { TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE }, // HIDP_GET_BUTTONS_EX + { FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // HIDP_GET_CAPS + { TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, TRUE }, // HIDP_GET_DATA + { TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, TRUE, TRUE }, // HIDP_GET_EXTENDED_ATTRIBUTES + { FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // HIDP_GET_LINK_COLL_NODES + { TRUE, TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE }, // HIDP_GET_SCALED_USAGE_VALUE + { TRUE, TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE }, // HIDP_GET_SPECIFIC_BUTTON_CAPS + { TRUE, TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE }, // HIDP_GET_SPECIFIC_VALUE_CAPS + { TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, TRUE, TRUE }, // HIDP_GET_USAGES + { TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE }, // HIDP_GET_USAGES_EX + { TRUE, TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE }, // HIDP_GET_USAGE_VALUE + { TRUE, TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE }, // HIDP_GET_USAGE_VALUE_ARRAY + { TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // HIDP_GET_VALUE_CAPS + { TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, TRUE, TRUE }, // HIDP_INITIALIZE_REPORT_FOR_ID + { TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // HIDP_MAX_DATA_LIST_LENGTH + { TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE }, // HIDP_MAX_USAGE_LIST_LENGTH + { TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, TRUE, TRUE }, // HIDP_SET_BUTTONS + { TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, TRUE }, // HIDP_SET_DATA + { TRUE, TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE }, // HIDP_SET_SCALED_USAGE_VALUE + { TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, TRUE, TRUE }, // HIDP_SET_USAGES + { TRUE, TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE }, // HIDP_SET_USAGE_VALUE + { TRUE, TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE }, // HIDP_SET_USAGE_VALUE_ARRAY + { FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // HIDP_TRANSLATE_USAGES + { TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, TRUE, TRUE }, // HIDP_UNSET_BUTTONS + { TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, TRUE, TRUE }, // HIDP_UNSET_USAGES + { FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // HIDP_USAGE_LIST_DIFFERENCE + { TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, TRUE } // HID_CLEAR_BUFFER + }; + + +/***************************************************************************** +/* Local function declarations +/*****************************************************************************/ + +VOID +vLoadExtCalls( + HWND hExtCalls +); + +VOID +vSetReportType( + HWND hDlg, + LONG lId +); + +VOID +vInitEditText( + HWND hText, + INT cbTextSize, + _In_ LPSTR pchText +); + +VOID vEnableParameters( + HWND hDlg, + LRESULT iCallSelection +); + +BOOL +fGetAndVerifyParameters( + HWND hDlg, + PECDISPLAY_PARAMS pParams +); + +BOOL +ECDisp_Execute( + IN INT FuncCall, + IN OUT PEXTCALL_PARAMS CallParams, + OUT PEXTCALL_STATUS CallStatus +); + +VOID +ECDisp_DisplayOutput( + IN HWND hOutputWindow, + IN INT FuncCall, + IN PEXTCALL_PARAMS Results +); + +VOID +vExecuteAndDisplayOutput( + HWND hOutputWindow, + PHID_DEVICE pDevice, + INT iFuncCall, + PECDISPLAY_PARAMS pParams +); + +CHAR *pchGetHidAppStatusString( + NTSTATUS StatusCode +); + +VOID +vInitECControls( + HWND hDlg, + USHORT InputReportByteLength, + PBUFFER_DISPLAY *ppInputDisplay, + USHORT OutputReportByteLength, + PBUFFER_DISPLAY *ppOutputDisplay, + USHORT FeatureReportByteLength, + PBUFFER_DISPLAY *ppFeatureDisplay +); + +VOID +BuildReportIDList( + IN PHIDP_BUTTON_CAPS phidButtonCaps, + IN USHORT nButtonCaps, + IN PHIDP_VALUE_CAPS phidValueCaps, + IN USHORT nValueCaps, + OUT UCHAR **ppReportIDList, + OUT INT *nReportIDs +); + +LRESULT CALLBACK +bSetUsagesDlgProc( + HWND hDlg, + UINT message, + WPARAM wParam, + LPARAM lParam +); + +LRESULT CALLBACK +bSetValueDlgProc( + HWND hDlg, + UINT message, + WPARAM wParam, + LPARAM lParam +); + +LRESULT CALLBACK +bSetInputBuffDlgProc( + HWND hDlg, + UINT message, + WPARAM wParam, + LPARAM lParam +); + +LRESULT CALLBACK +bSetDataDlgProc( + HWND hDlg, + UINT message, + WPARAM wParam, + LPARAM lParam +); + +LRESULT CALLBACK +bSetBufLenDlgProc( + HWND hDlg, + UINT message, + WPARAM wParam, + LPARAM lParam +); + +LRESULT CALLBACK +bSetInputBuffersDlgProc( + HWND hDlg, + UINT message, + WPARAM wParam, + LPARAM lParam +); + +LRESULT CALLBACK +bGetIndexedDlgProc( + HWND hDlg, + UINT message, + WPARAM wParam, + LPARAM lParam +); + +LRESULT CALLBACK +bGetUsageDiffDlgProc( + HWND hDlg, + UINT message, + WPARAM wParam, + LPARAM lParam +); + +BOOL +ConvertStringToUlongList( + _Inout_ LPSTR InString, + OUT PULONG *UlongList, + OUT PULONG nUlongs +); + +BOOL +ConvertStringToUsageList( + _In_ LPSTR InString, + OUT PUSAGE *UsageList, + OUT PULONG nUsages +); + +VOID +ECDisp_MakeGUIDString( + IN GUID guid, + _Out_writes_bytes_(uiBuffSize) CHAR szString[], + IN UINT uiBuffSize +); + +PCHAR +ECDisp_GetHidAppStatusString( + NTSTATUS StatusCode +); + +BOOL +ECDisp_ConvertUlongListToValueList( + IN PULONG UlongList, + IN ULONG nUlongs, + IN USHORT BitSize, + IN USHORT ReportCount, + _Outptr_result_bytebuffer_(*ValueListSize) PCHAR *ValueList, + OUT PULONG ValueListSize +); + +BOOL +SetDlgItemIntHex( + HWND hDlg, + INT nIDDlgItem, + UINT uValue, + INT nBytes +); + +PCHAR +ResolveFunctionName( + INT Index +); + + +DWORD WINAPI +ECDisp_ReadThreadProc( + LPVOID ThreadContext +); + +VOID +DisplayExtendedAttributes( + IN HWND OutputWindow, + IN PHIDP_UNKNOWN_TOKEN UnknownList, + IN ULONG UnknownListLength +); + +/***************************************************************************** +/* Global function definitions +/*****************************************************************************/ + +LRESULT CALLBACK +bExtCallDlgProc( + HWND hDlg, + UINT message, + WPARAM wParam, + LPARAM lParam +) +{ + static PHID_DEVICE pDevice; + static CHAR szTempBuff[1024]; + static CHAR szLabel[512]; + static CHAR szValue[512]; + static INT iLBCounter; + static UCHAR *pucInputReportIDs; + static UCHAR *pucOutputReportIDs; + static UCHAR *pucFeatureReportIDs; + static INT nInputReportIDs; + static INT nOutputReportIDs; + static INT nFeatureReportIDs; + static HANDLE ReadThread; + static READ_THREAD_CONTEXT readContext; + + INT iIndex; + ECDISPLAY_PARAMS params; + DWORD threadID; + + ZeroMemory(¶ms, sizeof(params)); + + switch(message) + { + case WM_INITDIALOG: + + /* + // Initializing the dialog box involves the following steps: + // 1) Determine from the parameter the pointer to the selected device + // 2) Initializing the controls in the dialog box to their initial values + // 3) Send a message that our list of routines has changed + */ + + pDevice = (PHID_DEVICE) lParam; + + vInitECControls(hDlg, + pDevice -> Caps.InputReportByteLength, + &pInputDisplay, + pDevice -> Caps.OutputReportByteLength, + &pOutputDisplay, + pDevice -> Caps.FeatureReportByteLength, + &pFeatureDisplay); + + ReadThread = NULL; + + PostMessage(hDlg, + WM_COMMAND, + IDC_EXTCALLS + (CBN_SELCHANGE << 16), + (LPARAM) GetDlgItem(hDlg,IDC_EXTCALLS)); + break; + + case WM_COMMAND: + switch(LOWORD(wParam)) + { + case IDC_EXTCALLS: + switch (HIWORD(wParam)) + { + case CBN_SELCHANGE: + iIndex = (INT) SendDlgItemMessage(hDlg, + IDC_EXTCALLS, + CB_GETCURSEL, + 0, + 0); + vEnableParameters(hDlg, + SendDlgItemMessage(hDlg, + IDC_EXTCALLS, + CB_GETITEMDATA, + iIndex, + 0)); + break; + } + break; + + case IDC_INPUT_SELECT: + if (CBN_SELCHANGE == HIWORD(wParam)) + { + BufferDisplay_ChangeSelection(pInputDisplay); + } + break; + + case IDC_OUTPUT_SELECT: + if (CBN_SELCHANGE == HIWORD(wParam)) + { + BufferDisplay_ChangeSelection(pOutputDisplay); + } + break; + + case IDC_FEATURE_SELECT: + if (CBN_SELCHANGE == HIWORD(wParam)) + { + BufferDisplay_ChangeSelection(pFeatureDisplay); + } + break; + + case IDC_EXECUTE: + /* + // Get the parameters and verify that they are all correct + // If there is an error, display an error message and + // don't continue any further. + */ + + if ( !fGetAndVerifyParameters(hDlg, ¶ms) ) + { + ECDISP_ERROR(hDlg, "Error: One or more parameters are invalid"); + } + + /* + // Else the parameters are valid and we can execute the call + */ + + else + { + iIndex = (INT) SendDlgItemMessage(hDlg, IDC_EXTCALLS, CB_GETCURSEL, 0, 0); + iIndex = (INT) SendDlgItemMessage(hDlg, IDC_EXTCALLS, CB_GETITEMDATA, iIndex, 0); + + /* + // Now that we know the function to execute we need to execute it + // and output the data + */ + + SendDlgItemMessage(hDlg, IDC_CALLOUTPUT, LB_RESETCONTENT, 0, 0); + vExecuteAndDisplayOutput(GetDlgItem(hDlg, IDC_CALLOUTPUT), pDevice, iIndex, ¶ms); + } + break; /* end IDC_EXECUTE case */ + + /* + // Start up a read thread that can read input reports while + // we operate on the other stuff + */ + + case IDC_READ_SYNCH: + case IDC_READ_ASYNCH: + + if (NULL == ReadThread) + { + readContext.HidDevice = pDevice; + readContext.TerminateThread = FALSE; + readContext.NumberOfReads = 1; + readContext.DisplayEvent = NULL; + readContext.DisplayWindow = hDlg; + + ReadThread = CreateThread( NULL, + 0, + (LOWORD(wParam) == IDC_READ_SYNCH) ? + SynchReadThreadProc : + AsynchReadThreadProc, + (LPVOID) &readContext, + 0, + &threadID); + + if (NULL == ReadThread) + { + MessageBox(hDlg, + "Unable to create read thread", + HCLIENT_ERROR, + MB_ICONEXCLAMATION); + } + else + { + EnableWindow(GetDlgItem(hDlg, IDC_READ_SYNCH), + (LOWORD(wParam) == IDC_READ_SYNCH)); + + EnableWindow(GetDlgItem(hDlg, IDC_READ_ASYNCH), + (LOWORD(wParam) == IDC_READ_ASYNCH)); + + SetWindowText(GetDlgItem(hDlg, LOWORD(wParam)), + "Stop Read Thread"); + + EnableWindow(GetDlgItem(hDlg, IDC_CANCEL), FALSE); + } + } + else + { + readContext.TerminateThread = TRUE; + + WaitForSingleObject(ReadThread, INFINITE); + + ReadThread = NULL; + + SetWindowText(GetDlgItem(hDlg, IDC_READ_SYNCH), + "Start Synchronous Read Thread"); + + SetWindowText(GetDlgItem(hDlg, IDC_READ_ASYNCH), + "Start Asynchronous Read Thread"); + + EnableWindow(GetDlgItem(hDlg, IDC_READ_SYNCH), TRUE); + EnableWindow(GetDlgItem(hDlg, IDC_READ_ASYNCH), TRUE); + EnableWindow(GetDlgItem(hDlg, IDC_CANCEL), TRUE); + } + break; + + case IDC_CANCEL: + BufferDisplay_Destroy(pInputDisplay); + BufferDisplay_Destroy(pOutputDisplay); + BufferDisplay_Destroy(pFeatureDisplay); + EndDialog(hDlg, 0); + break; + } + break; + + case WM_CLOSE: + PostMessage(hDlg, WM_COMMAND, IDC_CANCEL, 0); + break; + + } + return FALSE; +} + +VOID +vLoadExtCalls( + HWND hExtCalls +) +{ + INT iIndex; + UINT uiIndex; + + /* + // Load the physical device specific calls + */ + + for (uiIndex = 0; uiIndex < HID_DEVCALLS; uiIndex++) + { + iIndex = (INT) SendMessage(hExtCalls, + CB_ADDSTRING, + 0, + (LPARAM) DeviceCalls[uiIndex].szFunctionName); + + if (CB_ERR != iIndex && CB_ERRSPACE != iIndex) + { + SendMessage(hExtCalls, + CB_SETITEMDATA, + iIndex, + DeviceCalls[uiIndex].uiIndex); + } + } + + /* + // Load the other device calls no matter what + */ + + for (uiIndex = 0; uiIndex < HID_PPDCALLS; uiIndex++) + { + iIndex = (INT) SendMessage(hExtCalls, + CB_ADDSTRING, + 0, + (LPARAM) PpdCalls[uiIndex].szFunctionName); + + if (CB_ERR != iIndex && CB_ERRSPACE != iIndex) + { + SendMessage(hExtCalls, + CB_SETITEMDATA, + iIndex, + PpdCalls[uiIndex].uiIndex); + } + } + SendMessage(hExtCalls, CB_SETCURSEL, 0, 0); + + return; +} + +VOID vSetReportType( + HWND hDlg, + LONG lId +) +{ + CheckRadioButton(hDlg, IDC_INPUT, IDC_FEATURE, lId); + return; +} + +VOID +vInitEditText( + HWND hText, + INT cbTextSize, + _In_ LPSTR pchText +) +{ + SendMessage(hText, EM_SETLIMITTEXT, (WPARAM) cbTextSize, 0); + SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) pchText); + + return; +} + +VOID vEnableParameters( + HWND hDlg, + LRESULT iCallSelection +) +{ + EnableWindow(GetDlgItem(hDlg, IDC_INPUT), pState[iCallSelection-1].fInputReport); + EnableWindow(GetDlgItem(hDlg, IDC_OUTPUT), pState[iCallSelection-1].fOutputReport); + EnableWindow(GetDlgItem(hDlg, IDC_FEATURE), pState[iCallSelection-1].fFeatureReport); + EnableWindow(GetDlgItem(hDlg, IDC_REPORTID), pState[iCallSelection-1].fReportID); + EnableWindow(GetDlgItem(hDlg, IDC_USAGEPAGE), pState[iCallSelection-1].fUsagePage); + EnableWindow(GetDlgItem(hDlg, IDC_USAGE), pState[iCallSelection-1].fUsage); + EnableWindow(GetDlgItem(hDlg, IDC_LINKCOLL), pState[iCallSelection-1].fLinkCollection); + EnableWindow(GetDlgItem(hDlg, IDC_INPUT_SELECT), pState[iCallSelection-1].fInputReportSelect); + EnableWindow(GetDlgItem(hDlg, IDC_OUTPUT_SELECT), pState[iCallSelection-1].fOutputReportSelect); + EnableWindow(GetDlgItem(hDlg, IDC_FEATURE_SELECT), pState[iCallSelection-1].fFeatureReportSelect); + + return; +} + +BOOL +fGetAndVerifyParameters( + HWND hDlg, + PECDISPLAY_PARAMS pParams +) +{ + /* + // Declare a text buffer of size 7 since the parameter limit is at most 6 + // characters in the edit box. + */ + + CHAR WindowText[7]; + BOOL fStatus = TRUE; + PCHAR nptr; + + if (IsDlgButtonChecked(hDlg, IDC_INPUT)) + { + pParams -> ReportType = HidP_Input; + } + else if (IsDlgButtonChecked(hDlg, IDC_OUTPUT)) + { + pParams -> ReportType = HidP_Output; + } + else + { + pParams -> ReportType = HidP_Feature; + } + + /* + // Get and verify the usage page window text; + */ + + GetWindowText(GetDlgItem(hDlg, IDC_USAGEPAGE), WindowText, 7); + + pParams -> UsagePage = (USAGE) strtol(WindowText, &nptr, 16); + + if (*nptr != '\0') + { + fStatus = FALSE; + pParams -> UsagePage = 0; + } + + /* + // Get and verify the usage window text + */ + + GetWindowText(GetDlgItem(hDlg, IDC_USAGE), WindowText, 7); + + pParams -> Usage = (USAGE) strtol(WindowText, &nptr, 16); + + if (*nptr != '\0') + { + fStatus = FALSE; + pParams -> Usage = 0; + } + + /* + // Get and verify the link collection window text + */ + + GetWindowText(GetDlgItem(hDlg, IDC_LINKCOLL), WindowText, 7); + + pParams -> LinkCollection = (USAGE) strtol(WindowText, &nptr, 16); + + if (*nptr != '\0') + { + fStatus = FALSE; + pParams -> LinkCollection = 0; + } + + GetWindowText(GetDlgItem(hDlg, IDC_REPORTID), WindowText, 7); + + pParams -> ReportID = (UCHAR) strtol(WindowText, &nptr, 10); + + if (*nptr != '\0') + { + fStatus = FALSE; + pParams -> ReportID = 0; + } + + return (fStatus); +} + +VOID +vInitECControls( + HWND hDlg, + USHORT InputReportByteLength, + PBUFFER_DISPLAY *ppInputDisplay, + USHORT OutputReportByteLength, + PBUFFER_DISPLAY *ppOutputDisplay, + USHORT FeatureReportByteLength, + PBUFFER_DISPLAY *ppFeatureDisplay +) +{ + BOOLEAN fInitStatus; + + /* + // Begin by initializing the combo box with the calls that can be executed + */ + + vLoadExtCalls(GetDlgItem(hDlg, IDC_EXTCALLS)); + + /* + // Set the radio buttons initially to the input report type + */ + + vSetReportType(hDlg, IDC_INPUT); + + /* + // Initialize the edit controls text + */ + + vInitEditText(GetDlgItem(hDlg, IDC_USAGEPAGE), 6, "0x0000"); + vInitEditText(GetDlgItem(hDlg, IDC_USAGE), 6, "0x0000"); + vInitEditText(GetDlgItem(hDlg, IDC_LINKCOLL), 2, "0"); + vInitEditText(GetDlgItem(hDlg, IDC_REPORTID), 3, "0"); + + /* + // Initialize the report buffer boxes + */ + + fInitStatus = BufferDisplay_Init(GetDlgItem(hDlg, IDC_INPUT_SELECT), + GetDlgItem(hDlg, IDC_INPUT_BUFFER), + NUM_INPUT_BUFFERS, + InputReportByteLength, + HidP_Input, + ppInputDisplay); + + if (!fInitStatus) + { + ECDISP_ERROR(hDlg, "Error initializing input buffer display"); + } + + fInitStatus = BufferDisplay_Init(GetDlgItem(hDlg, IDC_OUTPUT_SELECT), + GetDlgItem(hDlg, IDC_OUTPUT_BUFFER), + NUM_OUTPUT_BUFFERS, + OutputReportByteLength, + HidP_Output, + ppOutputDisplay); + + if (!fInitStatus) + { + ECDISP_ERROR(hDlg, "Error initializing output buffer display"); + } + + fInitStatus = BufferDisplay_Init(GetDlgItem(hDlg, IDC_FEATURE_SELECT), + GetDlgItem(hDlg, IDC_FEATURE_BUFFER), + NUM_FEATURE_BUFFERS, + FeatureReportByteLength, + HidP_Feature, + ppFeatureDisplay); + + if (!fInitStatus) + { + ECDISP_ERROR(hDlg, "Error initializing feature buffer display"); + } + + /* + // Reset the output box content + */ + + SendMessage(GetDlgItem(hDlg, IDC_CALLOUTPUT), LB_RESETCONTENT, 0, 0); + return; +} + +BOOL +ECDisp_Execute( + IN INT FuncCall, + IN OUT PEXTCALL_PARAMS CallParams, + OUT PEXTCALL_STATUS CallStatus +) +/*++ +RoutineDescription: + This routine is a complex routine for executing all of the functions. The + routine was originally developed with consideration for future use that + never materialized. + + It makes use of the calls in extcalls.c which basically execute the given + function and does some verification on the buffers that are passed down to + HID.DLL. + + The input parameters are specify the function call to execute, the + call parameters structures and the call status structure. + + If any further buffers are needed for the specific calls, they will be + allocated here. + + The CallStatus parameters is a structure set by the ExtCalls_ routines + + Future versions of the HClient sample may remove this routine and/or the + ExtCalls_ routines to simply the code. +--*/ +{ + BOOL ExecuteStatus; + HIDP_VALUE_CAPS ValueCaps; + USHORT ValueCapsLength; + PULONG ValueList; + + NTSTATUS status; + DWORD numBytes; + ULONG size; + + /* + // Initially assume everything will go correctly and will set otherwise + // depending on the function call. + */ + + CallStatus -> IsHidError = FALSE; + + switch (FuncCall) + { + case HID_READ_REPORT: + CallStatus -> IsHidError = !ReadFile(CallParams -> DeviceHandle, + CallParams -> ReportBuffer, + CallParams -> ReportLength, + &numBytes, + NULL); + return (TRUE); + break; + + case HID_WRITE_REPORT: + CallStatus -> IsHidError = !WriteFile(CallParams -> DeviceHandle, + CallParams -> ReportBuffer, + CallParams -> ReportLength, + &numBytes, + NULL); + return (TRUE); + break; + + case HIDD_FLUSH_QUEUE: + CallStatus -> IsHidError = !HidD_FlushQueue(CallParams -> DeviceHandle); + return (TRUE); + break; + + case HIDD_GET_HID_GUID: + CallParams -> List = malloc(sizeof(GUID)); + + if (NULL != CallParams -> List) + { + HidD_GetHidGuid((GUID *) CallParams -> List); + } + return (NULL != CallParams -> List); + break; + + case HIDD_GET_PREPARSED_DATA: + CallStatus -> IsHidError = !HidD_GetPreparsedData(CallParams -> DeviceHandle, + CallParams -> ppPd); + return (TRUE); + + case HIDD_FREE_PREPARSED_DATA: + CallStatus -> IsHidError = !HidD_FreePreparsedData(CallParams -> Ppd); + return (TRUE); + + case HIDD_GET_ATTRIBUTES: + CallParams -> List = malloc(sizeof(HIDD_ATTRIBUTES)); + + if (NULL != CallParams -> List) + { + CallStatus -> IsHidError = !HidD_GetAttributes(CallParams -> DeviceHandle, + CallParams -> List); + } + return (NULL != CallParams -> List); + + case HIDD_GET_FEATURE: + *(CallParams -> ReportBuffer) = CallParams -> ReportID; + + CallStatus -> IsHidError = !HidD_GetFeature(CallParams -> DeviceHandle, + CallParams -> ReportBuffer, + CallParams -> ReportLength); + return (TRUE); + + case HIDD_SET_FEATURE: + CallStatus -> IsHidError = !HidD_SetFeature(CallParams -> DeviceHandle, + CallParams -> ReportBuffer, + CallParams -> ReportLength); + return (TRUE); + + case HIDD_GET_INPUT_REPORT: + *(CallParams -> ReportBuffer) = CallParams -> ReportID; + + CallStatus -> IsHidError = !HidD_GetInputReport(CallParams -> DeviceHandle, + CallParams -> ReportBuffer, + CallParams -> ReportLength); + return (TRUE); + + case HIDD_SET_OUTPUT_REPORT: + CallStatus -> IsHidError = !HidD_SetOutputReport(CallParams -> DeviceHandle, + CallParams -> ReportBuffer, + CallParams -> ReportLength); + return (TRUE); + + case HIDD_GET_NUM_INPUT_BUFFERS: + CallStatus -> IsHidError = !HidD_GetNumInputBuffers(CallParams -> DeviceHandle, + &CallParams -> Value); + return (TRUE); + + case HIDD_SET_NUM_INPUT_BUFFERS: + CallStatus -> IsHidError = !HidD_SetNumInputBuffers(CallParams -> DeviceHandle, + CallParams -> Value); + + return (TRUE); + + case HIDD_GET_PHYSICAL_DESCRIPTOR: + CallParams -> List = (PCHAR) malloc (CallParams -> ListLength); + + if (NULL != CallParams -> List ) + { + CallStatus -> IsHidError = !HidD_GetPhysicalDescriptor(CallParams -> DeviceHandle, + CallParams -> List, + CallParams -> ListLength); + } + return (NULL != CallParams -> List); + + case HIDD_GET_MANUFACTURER_STRING: + + CallParams -> List = (PWCHAR) malloc (CallParams -> ListLength); + + if (NULL != CallParams -> List ) + { + CallStatus -> IsHidError = !HidD_GetManufacturerString(CallParams -> DeviceHandle, + CallParams -> List, + CallParams -> ListLength); + } + return (NULL != CallParams -> List); + + case HIDD_GET_PRODUCT_STRING: + CallParams -> List = (PWCHAR) malloc (CallParams -> ListLength); + + if (NULL != CallParams -> List ) + { + CallStatus -> IsHidError = !HidD_GetProductString(CallParams -> DeviceHandle, + CallParams -> List, + CallParams -> ListLength); + } + return (NULL != CallParams -> List); + + case HIDP_GET_EXTENDED_ATTRIBUTES: + CallParams -> List = (PWCHAR) malloc (CallParams -> ListLength); + if (NULL != CallParams -> List ) + { + status = pfnHidP_GetExtendedAttributes(CallParams -> ReportType, + (USHORT) CallParams -> Index, + CallParams -> Ppd, + CallParams -> List, + &CallParams -> ListLength); + + CallStatus -> IsHidError = (HIDP_STATUS_SUCCESS != status); + CallStatus -> HidErrorCode = status; + } + return (NULL != CallParams -> List); + + case HIDD_GET_INDEXED_STRING: + CallParams -> List = (PWCHAR) malloc (CallParams -> ListLength); + + if (NULL != CallParams -> List ) + { + CallStatus -> IsHidError = !HidD_GetIndexedString(CallParams -> DeviceHandle, + CallParams -> Index, + CallParams -> List, + CallParams -> ListLength); + } + return (NULL != CallParams -> List); + + case HIDD_GET_SERIAL_NUMBER_STRING: + CallParams -> List = (PWCHAR) malloc (CallParams -> ListLength); + + if (NULL != CallParams -> List ) + { + CallStatus -> IsHidError = !HidD_GetSerialNumberString(CallParams -> DeviceHandle, + CallParams -> List, + CallParams -> ListLength); + } + return (NULL != CallParams -> List); + + case HIDD_GET_MS_GENRE_DESCRIPTOR: + CallParams -> List = (PCHAR) malloc (CallParams -> ListLength); + + if (NULL != CallParams -> List ) + { + CallStatus -> IsHidError = !HidD_GetMsGenreDescriptor(CallParams -> DeviceHandle, + CallParams -> List, + CallParams -> ListLength); + } + return (NULL != CallParams -> List); + + case HIDP_GET_BUTTON_CAPS: + size = CallParams -> ListLength * sizeof(HIDP_BUTTON_CAPS); + + CallParams -> List = malloc(size); + + if (NULL != CallParams -> List) + { + status = HidP_GetButtonCaps(CallParams -> ReportType, + CallParams -> List, + (PUSHORT) &CallParams -> ListLength, + CallParams -> Ppd); + + CallStatus -> IsHidError = (HIDP_STATUS_SUCCESS != status); + CallStatus -> HidErrorCode = status; + } + return (NULL != CallParams -> List); + + case HIDP_GET_BUTTONS: + + CallParams -> ListLength = HidP_MaxUsageListLength(CallParams -> ReportType, + CallParams -> UsagePage, + CallParams -> Ppd); + + CallParams -> List = malloc(CallParams -> ListLength * sizeof(USAGE)); + + if (NULL != CallParams -> List) + { + status = HidP_GetButtons(CallParams -> ReportType, + CallParams -> UsagePage, + CallParams -> LinkCollection, + CallParams -> List, + &CallParams -> ListLength, + CallParams -> Ppd, + CallParams -> ReportBuffer, + CallParams -> ReportLength); + + CallStatus -> IsHidError = (HIDP_STATUS_SUCCESS != status); + CallStatus -> HidErrorCode = status; + } + return (NULL != CallParams -> List); + + case HIDP_GET_BUTTONS_EX: + + CallParams -> ListLength = HidP_MaxUsageListLength(CallParams -> ReportType, + CallParams -> UsagePage, + CallParams -> Ppd); + + CallParams -> List = malloc(CallParams -> ListLength * sizeof(USAGE_AND_PAGE)); + + if (NULL != CallParams -> List) + { + status = HidP_GetButtonsEx(CallParams -> ReportType, + CallParams -> LinkCollection, + CallParams -> List, + &CallParams -> ListLength, + CallParams -> Ppd, + CallParams -> ReportBuffer, + CallParams -> ReportLength); + + CallStatus -> IsHidError = (HIDP_STATUS_SUCCESS != status); + CallStatus -> HidErrorCode = status; + } + return (NULL != CallParams -> List); + + + case HIDP_GET_CAPS: + + CallParams -> ListLength = sizeof(HIDP_CAPS); + + CallParams -> List = malloc(sizeof(HIDP_CAPS)); + + if (NULL != CallParams -> List) + { + status = HidP_GetCaps(CallParams -> Ppd, CallParams -> List); + + CallStatus -> IsHidError = (HIDP_STATUS_SUCCESS != status); + CallStatus -> HidErrorCode = status; + } + return (NULL != CallParams -> List); + + case HIDP_GET_DATA: + + CallParams -> ListLength = HidP_MaxDataListLength(CallParams -> ReportType, + CallParams -> Ppd); + + CallParams -> List = malloc(CallParams -> ListLength * sizeof(HIDP_DATA)); + + if (NULL != CallParams -> List) + { + status = HidP_GetData(CallParams -> ReportType, + CallParams -> List, + &CallParams -> ListLength, + CallParams -> Ppd, + CallParams -> ReportBuffer, + CallParams -> ReportLength); + + CallStatus -> IsHidError = (HIDP_STATUS_SUCCESS != status); + CallStatus -> HidErrorCode = status; + } + return (NULL != CallParams -> List); + + case HIDP_GET_LINK_COLL_NODES: + CallParams -> List = malloc(CallParams -> ListLength * sizeof(HIDP_LINK_COLLECTION_NODE)); + + if (NULL != CallParams -> List) + { + status = HidP_GetLinkCollectionNodes(CallParams -> List, + &CallParams -> ListLength, + CallParams -> Ppd); + + CallStatus -> IsHidError = (HIDP_STATUS_SUCCESS != status); + CallStatus -> HidErrorCode = status; + } + return (NULL != CallParams -> List); + + case HIDP_GET_SCALED_USAGE_VALUE: + + status = HidP_GetScaledUsageValue(CallParams -> ReportType, + CallParams -> UsagePage, + CallParams -> LinkCollection, + CallParams -> Usage, + &CallParams -> ScaledValue, + CallParams -> Ppd, + CallParams -> ReportBuffer, + CallParams -> ReportLength); + + CallStatus -> IsHidError = (HIDP_STATUS_SUCCESS != status); + CallStatus -> HidErrorCode = status; + + return (TRUE); + + case HIDP_GET_SPECIFIC_BUTTON_CAPS: + + CallParams -> List = malloc(CallParams -> ListLength * sizeof(HIDP_BUTTON_CAPS)); + + if (NULL != CallParams -> List) + { + status = HidP_GetSpecificButtonCaps(CallParams -> ReportType, + CallParams -> UsagePage, + CallParams -> LinkCollection, + CallParams -> Usage, + CallParams -> List, + (PUSHORT) &CallParams -> ListLength, + CallParams -> Ppd); + + CallStatus -> IsHidError = (HIDP_STATUS_SUCCESS != status); + CallStatus -> HidErrorCode = status; + } + return (NULL != CallParams -> List); + + case HIDP_GET_SPECIFIC_VALUE_CAPS: + + CallParams -> List = malloc(CallParams -> ListLength * sizeof(HIDP_VALUE_CAPS)); + + if (NULL != CallParams -> List) + { + status = HidP_GetSpecificValueCaps(CallParams -> ReportType, + CallParams -> UsagePage, + CallParams -> LinkCollection, + CallParams -> Usage, + CallParams -> List, + (PUSHORT) &CallParams -> ListLength, + CallParams -> Ppd); + + CallStatus -> IsHidError = (HIDP_STATUS_SUCCESS != status); + CallStatus -> HidErrorCode = status; + } + return (NULL != CallParams -> List); + + case HIDP_GET_USAGES: + CallParams -> ListLength = HidP_MaxUsageListLength(CallParams -> ReportType, + CallParams -> UsagePage, + CallParams -> Ppd); + + CallParams -> List = malloc(CallParams -> ListLength * sizeof(USAGE)); + + if (NULL != CallParams -> List) + { + status = HidP_GetUsages(CallParams -> ReportType, + CallParams -> UsagePage, + CallParams -> LinkCollection, + CallParams -> List, + &CallParams -> ListLength, + CallParams -> Ppd, + CallParams -> ReportBuffer, + CallParams -> ReportLength); + + CallStatus -> IsHidError = (HIDP_STATUS_SUCCESS != status); + CallStatus -> HidErrorCode = status; + } + return (NULL != CallParams -> List); + + case HIDP_GET_USAGES_EX: + CallParams -> ListLength = HidP_MaxUsageListLength(CallParams -> ReportType, + CallParams -> UsagePage, + CallParams -> Ppd); + + CallParams -> List = malloc(CallParams -> ListLength * sizeof(USAGE_AND_PAGE)); + + if (NULL != CallParams -> List) + { + status = HidP_GetUsagesEx(CallParams -> ReportType, + CallParams -> LinkCollection, + CallParams -> List, + &CallParams -> ListLength, + CallParams -> Ppd, + CallParams -> ReportBuffer, + CallParams -> ReportLength); + + CallStatus -> IsHidError = (HIDP_STATUS_SUCCESS != status); + CallStatus -> HidErrorCode = status; + } + return (NULL != CallParams -> List); + + case HIDP_GET_USAGE_VALUE: + status = HidP_GetUsageValue(CallParams -> ReportType, + CallParams -> UsagePage, + CallParams -> LinkCollection, + CallParams -> Usage, + &CallParams -> Value, + CallParams -> Ppd, + CallParams -> ReportBuffer, + CallParams -> ReportLength); + + CallStatus -> IsHidError = (HIDP_STATUS_SUCCESS != status); + CallStatus -> HidErrorCode = status; + + return (TRUE); + + case HIDP_GET_USAGE_VALUE_ARRAY: + + ValueCapsLength = 1; + status = HidP_GetSpecificValueCaps(CallParams -> ReportType, + CallParams -> UsagePage, + CallParams -> LinkCollection, + CallParams -> Usage, + &ValueCaps, + &ValueCapsLength, + CallParams -> Ppd); + + if (HIDP_STATUS_SUCCESS != status) + { + return (FALSE); + } + + CallParams -> BitSize = ValueCaps.BitSize; + CallParams -> ReportCount = ValueCaps.ReportCount; + CallParams -> ListLength + = ROUND_TO_NEAREST_BYTE(CallParams -> BitSize * CallParams -> ReportCount); + + CallParams -> List = malloc(CallParams -> ListLength); + + if (NULL != CallParams -> List) + { + status = HidP_GetUsageValueArray(CallParams -> ReportType, + CallParams -> UsagePage, + CallParams -> LinkCollection, + CallParams -> Usage, + CallParams -> List, + (USHORT) CallParams -> ListLength, + CallParams -> Ppd, + CallParams -> ReportBuffer, + CallParams -> ReportLength); + + CallStatus -> IsHidError = (HIDP_STATUS_SUCCESS != status); + CallStatus -> HidErrorCode = status; + } + return (NULL != CallParams -> List); + + case HIDP_GET_VALUE_CAPS: + CallParams -> List = malloc(CallParams -> ListLength * sizeof(HIDP_VALUE_CAPS)); + if (NULL != CallParams -> List) + { + status = HidP_GetValueCaps(CallParams -> ReportType, + CallParams -> List, + (PUSHORT) &CallParams -> ListLength, + CallParams -> Ppd); + + CallStatus -> IsHidError = (HIDP_STATUS_SUCCESS != status); + CallStatus -> HidErrorCode = status; + } + + + case HIDP_INITIALIZE_REPORT_FOR_ID: + + status = pfnHidP_InitializeReportForID(CallParams -> ReportType, + CallParams -> ReportID, + CallParams -> Ppd, + CallParams -> ReportBuffer, + CallParams -> ReportLength); + + CallStatus -> IsHidError = (HIDP_STATUS_SUCCESS != status); + CallStatus -> HidErrorCode = status; + + return (TRUE); + + case HIDP_MAX_USAGE_LIST_LENGTH: + + CallParams -> Value = HidP_MaxUsageListLength(CallParams -> ReportType, + CallParams -> UsagePage, + CallParams -> Ppd); + + CallStatus -> IsHidError = FALSE; + CallStatus -> HidErrorCode = HIDP_STATUS_SUCCESS; + + return (TRUE); + + case HIDP_MAX_DATA_LIST_LENGTH: + + CallParams -> Value = HidP_MaxDataListLength(CallParams -> ReportType, + CallParams -> Ppd); + + CallStatus -> IsHidError = FALSE; + CallStatus -> HidErrorCode = HIDP_STATUS_SUCCESS; + + return (TRUE); + + case HIDP_SET_BUTTONS: + + status = HidP_SetButtons(CallParams -> ReportType, + CallParams -> UsagePage, + CallParams -> LinkCollection, + CallParams -> List, + &CallParams -> ListLength, + CallParams -> Ppd, + CallParams -> ReportBuffer, + CallParams -> ReportLength); + + CallStatus -> IsHidError = (HIDP_STATUS_SUCCESS != status); + CallStatus -> HidErrorCode = status; + + return (TRUE); + + case HIDP_SET_DATA: + + status = HidP_SetData(CallParams -> ReportType, + CallParams -> List, + &CallParams -> ListLength, + CallParams -> Ppd, + CallParams -> ReportBuffer, + CallParams -> ReportLength); + + CallStatus -> IsHidError = (HIDP_STATUS_SUCCESS != status); + CallStatus -> HidErrorCode = status; + + return (TRUE); + + case HIDP_SET_SCALED_USAGE_VALUE: + status = HidP_SetUsageValue(CallParams -> ReportType, + CallParams -> UsagePage, + CallParams -> LinkCollection, + CallParams -> Usage, + CallParams -> ScaledValue, + CallParams -> Ppd, + CallParams -> ReportBuffer, + CallParams -> ReportLength); + + CallStatus -> IsHidError = (HIDP_STATUS_SUCCESS != status); + CallStatus -> HidErrorCode = status; + + return (TRUE); + + case HIDP_SET_USAGES: + status = HidP_SetUsages(CallParams -> ReportType, + CallParams -> UsagePage, + CallParams -> LinkCollection, + CallParams -> List, + &CallParams -> ListLength, + CallParams -> Ppd, + CallParams -> ReportBuffer, + CallParams -> ReportLength); + + CallStatus -> IsHidError = (HIDP_STATUS_SUCCESS != status); + CallStatus -> HidErrorCode = status; + + return (TRUE); + + case HIDP_SET_USAGE_VALUE: + status = HidP_SetUsageValue(CallParams -> ReportType, + CallParams -> UsagePage, + CallParams -> LinkCollection, + CallParams -> Usage, + CallParams -> Value, + CallParams -> Ppd, + CallParams -> ReportBuffer, + CallParams -> ReportLength); + + CallStatus -> IsHidError = (HIDP_STATUS_SUCCESS != status); + CallStatus -> HidErrorCode = status; + + return (TRUE); + + case HIDP_SET_USAGE_VALUE_ARRAY: + + ValueCapsLength = 1; + status = HidP_GetSpecificValueCaps(CallParams -> ReportType, + CallParams -> UsagePage, + CallParams -> LinkCollection, + CallParams -> Usage, + &ValueCaps, + &ValueCapsLength, + CallParams -> Ppd); + + if (HIDP_STATUS_SUCCESS != status) + { + return (FALSE); + } + + CallParams -> BitSize = ValueCaps.BitSize; + CallParams -> ReportCount = ValueCaps.ReportCount; + + ValueList = CallParams -> List; + ExecuteStatus = ECDisp_ConvertUlongListToValueList(ValueList, + CallParams -> ListLength, + CallParams -> BitSize, + CallParams -> ReportCount, + (PCHAR *) &CallParams -> List, + &CallParams -> ListLength); + + if (!ExecuteStatus) + { + return (FALSE); + } + + status = HidP_SetUsageValueArray(CallParams -> ReportType, + CallParams -> UsagePage, + CallParams -> LinkCollection, + CallParams -> Usage, + CallParams -> List, + (USHORT) CallParams -> ListLength, + CallParams -> Ppd, + CallParams -> ReportBuffer, + CallParams -> ReportLength); + + CallStatus -> IsHidError = (HIDP_STATUS_SUCCESS != status); + CallStatus -> HidErrorCode = status; + + return (TRUE); + + case HIDP_UNSET_BUTTONS: + status = HidP_UnsetButtons(CallParams -> ReportType, + CallParams -> UsagePage, + CallParams -> LinkCollection, + CallParams -> List, + &CallParams -> ListLength, + CallParams -> Ppd, + CallParams -> ReportBuffer, + CallParams -> ReportLength); + + CallStatus -> IsHidError = (HIDP_STATUS_SUCCESS != status); + CallStatus -> HidErrorCode = status; + + return (TRUE); + + case HIDP_UNSET_USAGES: + status = HidP_UnsetUsages(CallParams -> ReportType, + CallParams -> UsagePage, + CallParams -> LinkCollection, + CallParams -> List, + &CallParams -> ListLength, + CallParams -> Ppd, + CallParams -> ReportBuffer, + CallParams -> ReportLength); + + CallStatus -> IsHidError = (HIDP_STATUS_SUCCESS != status); + CallStatus -> HidErrorCode = status; + + return (TRUE); + + case HIDP_USAGE_LIST_DIFFERENCE: + CallParams -> MakeList = (PUSAGE) malloc (sizeof(USAGE) * CallParams -> ListLength); + + if (NULL == CallParams -> MakeList) + { + return (FALSE); + } + + CallParams -> BreakList = (PUSAGE) malloc (sizeof(USAGE) * CallParams -> ListLength); + if (NULL == CallParams -> BreakList) + { + free(CallParams -> MakeList); + + return (FALSE); + } + + status = HidP_UsageListDifference(CallParams -> List, + CallParams -> List2, + CallParams -> BreakList, + CallParams -> MakeList, + CallParams -> ListLength); + + CallStatus -> IsHidError = (HIDP_STATUS_SUCCESS != status); + CallStatus -> HidErrorCode = status; + + return (TRUE); + } + return (FALSE); +} + +VOID +ECDisp_DisplayOutput( + IN HWND hOutputWindow, + IN INT FuncCall, + IN PEXTCALL_PARAMS Results +) +/*++ +RoutineDescription: + This routine is responsible for displaying the output from calls to HID.DLL + functions. It must extract and interpret the appropriate data from the + PEXTCALL_PARAMS structure. +--*/ +{ + PHIDP_LINK_COLLECTION_NODE NodeList; + PHIDP_BUTTON_CAPS ButtonCaps; + PHIDP_VALUE_CAPS ValueCaps; + PHIDP_DATA DataList; + PHIDP_EXTENDED_ATTRIBUTES ExtAttrib; + PUSAGE_AND_PAGE UsageAndPageList; + PUSAGE UsageList; + PCHAR UsageValueArray; + ULONG UsageValueArraySize; + PBUFFER_DISPLAY pDisplay = NULL; + PCHAR PhysDescString; + PCHAR GenreDescString; + SIZE_T StringLength; + UINT RemainingBuffer=0; + + ULONG Index; + + + switch (FuncCall) { + case HIDD_GET_HID_GUID: + + StringCbCopy(szTempBuffer, TEMP_BUFFER_SIZE, "HID Guid: "); + StringLength = strlen(szTempBuffer); + if (StringLength < TEMP_BUFFER_SIZE) + { + RemainingBuffer = (UINT)(TEMP_BUFFER_SIZE - StringLength); + } + ECDisp_MakeGUIDString(*((LPGUID) Results -> List), + &szTempBuffer[StringLength], + RemainingBuffer); + + OUTSTRING(hOutputWindow, szTempBuffer); + break; + + case HIDD_GET_ATTRIBUTES: + vDisplayDeviceAttributes((PHIDD_ATTRIBUTES) Results -> List, + hOutputWindow); + break; + + case HIDD_GET_NUM_INPUT_BUFFERS: + StringCbPrintf(szTempBuffer, TEMP_BUFFER_SIZE, + "Number input buffers: %u", Results -> Value); + + OUTSTRING(hOutputWindow, szTempBuffer); + break; + + case HIDD_GET_MS_GENRE_DESCRIPTOR: + OUTSTRING(hOutputWindow, "MS Genre Descriptor"); + OUTSTRING(hOutputWindow, "==================="); + + /* + // To display a physical descriptor, the procedure currently just + // creates a string data buffer by bytes and displays that + // in the results box. It will display in rows of 16 bytes apiece. + */ + + Index = 0; + while (Index < Results -> ListLength) + { + Strings_CreateDataBufferString(((PCHAR) Results -> List) + Index, + Results -> ListLength - Index, + 16, + 1, + &GenreDescString); + + if (NULL != GenreDescString) + { + OUTSTRING(hOutputWindow, GenreDescString); + free(GenreDescString); + } + else + { + OUTSTRING(hOutputWindow, "Error trying to display ms genre descriptor"); + } + Index += 16; + } + break; + + case HIDD_GET_PHYSICAL_DESCRIPTOR: + OUTSTRING(hOutputWindow, "Physical Descriptor"); + OUTSTRING(hOutputWindow, "==================="); + + /* + // To display a physical descriptor, the procedure currently just + // creates a string data buffer by bytes and displays that + // in the results box. It will display in rows of 16 bytes apiece. + */ + + Index = 0; + while (Index < Results -> ListLength) + { + Strings_CreateDataBufferString(((PCHAR) Results -> List) + Index, + Results -> ListLength - Index, + 16, + 1, + &PhysDescString); + + if (NULL != PhysDescString) + { + OUTSTRING(hOutputWindow, PhysDescString); + free(PhysDescString); + } + else + { + OUTSTRING(hOutputWindow, "Error trying to display physical descriptor"); + } + Index += 16; + } + break; + + /* + // For the string descriptor call routines, the returned string is stored + // in the Results -> List parameter. It should be noted that the + // strings returned by these calls are wide-char strings and that these + // string are terminated with a NULL character if there was space withing + // the buffer to add such a character. If the buffer was only big enough + // to hold the characters of the string, there will be no null terminator + // and the output string display mechanism may fail to properly display this + // type of string. Fixing of this display mechanism is a future (low priority) + // workitem. + */ + + case HIDD_GET_PRODUCT_STRING: + OUTSTRING(hOutputWindow, "Product String"); + OUTSTRING(hOutputWindow, "=============="); + #pragma prefast(suppress: 26014, "Potential overflow check") + OUTWSTRING(hOutputWindow, Results -> List); + break; + + case HIDD_GET_MANUFACTURER_STRING: + OUTSTRING(hOutputWindow, "Manufacturer String"); + OUTSTRING(hOutputWindow, "==================="); + OUTWSTRING(hOutputWindow, Results -> List); + break; + + case HIDD_GET_INDEXED_STRING: + StringCbPrintf(szTempBuffer, TEMP_BUFFER_SIZE, + "Indexed String #%u:", Results -> Index); + + OUTSTRING(hOutputWindow, szTempBuffer); + OUTSTRING(hOutputWindow, "==================="); + OUTWSTRING(hOutputWindow, Results -> List); + break; + + case HIDD_GET_SERIAL_NUMBER_STRING: + OUTSTRING(hOutputWindow, "Serial Number String"); + OUTSTRING(hOutputWindow, "====================="); + OUTWSTRING(hOutputWindow, Results -> List); + break; + + case HIDP_GET_BUTTON_CAPS: + case HIDP_GET_SPECIFIC_BUTTON_CAPS: + + ButtonCaps = (PHIDP_BUTTON_CAPS) (Results -> List); + for (Index = 0; Index < Results -> ListLength; Index++, ButtonCaps++) + { + OUTSTRING(hOutputWindow, "=========================="); + vDisplayButtonAttributes(ButtonCaps, hOutputWindow); + } + break; + + /* + // HidP_GetButtons and HidP_GetUsages are in reality the same call. + // HidP_GetButtons actually a macro which gets redefined into + // HidP_GetUsages with the same parameter order. That is why their + // display mechanisms are identical. This call returns in the + // List parameter a list of Usages. The display mechanism converts + // these usages into a string of numbers. + */ + + case HIDP_GET_BUTTONS: + case HIDP_GET_USAGES: + + OUTSTRING(hOutputWindow, "Usages Returned"); + OUTSTRING(hOutputWindow, "==============="); + + UsageList = (PUSAGE) Results -> List; + for (Index = 0; Index < Results -> ListLength; Index++) + { + vCreateUsageString(UsageList + Index, szTempBuffer, TEMP_BUFFER_SIZE); + + OUTSTRING(hOutputWindow, szTempBuffer); + } + break; + + /* + // Like get their siblings, the normal get functions, these routines are + // currently one in the same. The difference between these routines + // and their siblings is the return of a usage page along with each + // usage. Therefore, both values must be displayed at the same time. + */ + + case HIDP_GET_BUTTONS_EX: + case HIDP_GET_USAGES_EX: + + OUTSTRING(hOutputWindow, "Usages Returned"); + OUTSTRING(hOutputWindow, "==============="); + + UsageAndPageList = (PUSAGE_AND_PAGE) Results -> List; + for (Index = 0; Index < Results -> ListLength; Index++) + { + vCreateUsageAndPageString(UsageAndPageList + Index, + szTempBuffer, + TEMP_BUFFER_SIZE); + + OUTSTRING(hOutputWindow, szTempBuffer); + } + break; + + case HIDP_GET_CAPS: + vDisplayDeviceCaps((PHIDP_CAPS) Results -> List, hOutputWindow); + break; + + case HIDP_GET_DATA: + OUTSTRING(hOutputWindow, "Data Indices"); + OUTSTRING(hOutputWindow, "============"); + + DataList = (PHIDP_DATA) Results -> List; + for (Index = 0; Index < Results -> ListLength; Index++) + { + vDisplayDataAttributes(DataList+Index, + FALSE, + hOutputWindow); + } + break; + + case HIDP_GET_EXTENDED_ATTRIBUTES: + OUTSTRING(hOutputWindow, "Extended Attributes"); + OUTSTRING(hOutputWindow, "==================="); + + ExtAttrib = (PHIDP_EXTENDED_ATTRIBUTES) Results -> List; + + DisplayExtendedAttributes(hOutputWindow, + ExtAttrib -> GlobalUnknowns, + ExtAttrib -> NumGlobalUnknowns); + break; + + case HIDP_GET_LINK_COLL_NODES: + + OUTSTRING(hOutputWindow, "Link Collection Nodes"); + OUTSTRING(hOutputWindow, "====================="); + + NodeList = (PHIDP_LINK_COLLECTION_NODE) Results -> List; + for (Index = 0; Index < Results -> ListLength; Index++) + { + OUTSTRING(hOutputWindow, "==========================="); + vDisplayLinkCollectionNode(NodeList+Index, + Index, + hOutputWindow); + } + break; + + case HIDP_GET_SCALED_USAGE_VALUE: + + StringCbPrintf(szTempBuffer, TEMP_BUFFER_SIZE, + "Scaled usage value: %ld", Results -> ScaledValue); + OUTSTRING(hOutputWindow, szTempBuffer); + + break; + + case HIDP_GET_USAGE_VALUE: + StringCbPrintf(szTempBuffer, TEMP_BUFFER_SIZE, + "Usage value: %lu", Results -> Value); + OUTSTRING(hOutputWindow, szTempBuffer); + break; + + /* + // To display a usage value array, we must extract each of the values + // in the array based on the ReportSize. The ReportSize is not necessarily + // an even byte size so we must use the special extraction routine to get + // each of the values in the array. + */ + + case HIDP_GET_USAGE_VALUE_ARRAY: + + UsageValueArray = (PCHAR) Results -> List; + UsageValueArraySize = Results->ListLength; + + for (Index = 0; Index < Results -> ReportCount; Index++) + { + vCreateUsageValueStringFromArray(UsageValueArray, + UsageValueArraySize, + Results -> BitSize, + (USHORT) Index, + szTempBuffer, + TEMP_BUFFER_SIZE); + + OUTSTRING(hOutputWindow, szTempBuffer); + } + break; + + case HIDP_GET_VALUE_CAPS: + case HIDP_GET_SPECIFIC_VALUE_CAPS: + + ValueCaps = (PHIDP_VALUE_CAPS) Results -> List; + + for (Index = 0; Index < (INT) Results -> ListLength; Index++) + { + OUTSTRING(hOutputWindow, "=========================="); + vDisplayValueAttributes(ValueCaps + Index, + hOutputWindow); + } + break; + + case HIDP_MAX_DATA_LIST_LENGTH: + StringCbPrintf(szTempBuffer, TEMP_BUFFER_SIZE, + "MaxDataListLength: %u", Results -> Value); + OUTSTRING(hOutputWindow, szTempBuffer); + break; + + case HIDP_MAX_USAGE_LIST_LENGTH: + StringCbPrintf(szTempBuffer, TEMP_BUFFER_SIZE, + "MaxUsageListLength: %u", Results -> Value); + OUTSTRING(hOutputWindow, szTempBuffer); + break; + + /* + // For HidP_UsageListDifference, we need to display both of the make and + // break lists generated by the function. Therefore, we end up creating + // two different usage list strings. + */ + + case HIDP_USAGE_LIST_DIFFERENCE: + + OUTSTRING(hOutputWindow, "Make List"); + OUTSTRING(hOutputWindow, "========="); + + UsageList = (PUSAGE) Results -> MakeList; + Index = 0; + + while (0 != *(UsageList+Index) && Index < Results -> ListLength) + { + vCreateUsageString(UsageList + Index, + szTempBuffer, + TEMP_BUFFER_SIZE); + + OUTSTRING(hOutputWindow, szTempBuffer); + Index++; + } + + OUTSTRING(hOutputWindow, "Break List"); + OUTSTRING(hOutputWindow, "=========="); + + UsageList = (PUSAGE) Results -> BreakList; + Index = 0; + + while (0 != *(UsageList+Index) && Index < Results -> ListLength) + { + vCreateUsageString(UsageList + Index, + szTempBuffer, + TEMP_BUFFER_SIZE); + + OUTSTRING(hOutputWindow, szTempBuffer); + Index++; + } + break; + + /* + // These functions simply update the buffer that is specified as the + // input parameter. We must select the correct display buffer mechanism + // based on the ReportType for the call and then update the given report + // in that display mechanism. + */ + + case HID_READ_REPORT: + case HIDD_GET_FEATURE: + case HIDD_GET_INPUT_REPORT: + case HIDP_INITIALIZE_REPORT_FOR_ID: + case HIDP_SET_BUTTONS: + case HIDP_SET_DATA: + case HIDP_SET_SCALED_USAGE_VALUE: + case HIDP_SET_USAGES: + case HIDP_SET_USAGE_VALUE: + case HIDP_SET_USAGE_VALUE_ARRAY: + case HIDP_UNSET_BUTTONS: + case HIDP_UNSET_USAGES: + SELECT_ON_REPORT_TYPE(Results -> ReportType, + pInputDisplay, + pOutputDisplay, + pFeatureDisplay, + pDisplay); + + if(NULL == pDisplay) + { + return; // error case + } + + BufferDisplay_UpdateBuffer(pDisplay, + Results->ReportBuffer, + Results->ReportLength); + break; + } + return; +} + +VOID +vExecuteAndDisplayOutput( + HWND hOutputWindow, + PHID_DEVICE pDevice, + INT iFuncCall, + PECDISPLAY_PARAMS params +) +/*++ +RoutineDescription: + This routine is a long function that is responsible for retrieving all the + paramter for a given function call, setting up the CallParameters structure + and then call the execute routine to get the necessary results and status of + the operation. It is then responsible for displaying the appropriate status + and results if the function did not fail + + This routine is a fairly long, complex routine to do a simple task. It may + be broken down in future versions to simplify some of the complexity. +--*/ +{ + EXTCALL_PARAMS CallParameters; + EXTCALL_STATUS CallStatus; + + DLGBOX_STATUS iDlgStatus; + BOOL ExecuteStatus; + PBUFFER_DISPLAY pBufferDisplay = NULL; + PCHAR pCopyBuffer = NULL; + UINT ulCopyBufferLength = 0; + PCHAR endp; + UINT DlgBoxNumber = 0; + BOOL List2Alloc; + BOOL MakeListAlloc; + BOOL BreakListAlloc; + ULONG newListLength = 0; + + HID_DEVICE readDevice = {0}; + HID_DEVICE writeDevice = {0}; + BOOL status = TRUE; + HRESULT stringReturn; + UINT tmpLen = 0; + + // Check for overrun condition + if(params->ListLength2 >= 2*params->ListLength + 2) + { + OUTSTRING(hOutputWindow, "Error in input parameters"); + return; + } + + RtlZeroMemory(&CallStatus, sizeof(CallStatus)); + + if(params->szListString2) + { + ZeroMemory(params->szListString2, params->ListLength2+1); + } + + if(params->UsageList) + { + ZeroMemory(params->UsageList, params->ListLength2+1); + } + + /* + // ExecuteAndDisplayOutput needless to say, consists of two parts: + // Executing and Displaying output. The first section involves the + // execution phase where all parameters are filled in if necessary + // and ECDisp_Execute is called + */ + + if (IS_NOT_IMPLEMENTED(iFuncCall)) + { + OUTSTRING(hOutputWindow, "Function not yet implemented"); + return; + } + + /* + // Check first to see if this is a HID_CLEAR_REPORT command. If it is + // all we need to do is get the report buffer that is checked and + // then call the clear buffer command + */ + + if (HID_CLEAR_REPORT == iFuncCall) + { + SELECT_ON_REPORT_TYPE(params -> ReportType, + pInputDisplay, + pOutputDisplay, + pFeatureDisplay, + pBufferDisplay); + + BufferDisplay_ClearBuffer(pBufferDisplay); + return; + } + + /* + // Need to perform the following steps in order to get the parameters for + // our call and then execute the call: + // 1) Get any additional parameters not supplied by the above dialog + // procedure. This occurs for such functions as: + // HIDP_SET_BUTTONS + // HIDP_SET_DATA + // HIDP_SET_USAGES + // HIDP_SET_USAGE_VALUE + // HIDP_SET_SCALED_USAGE_VALUE + // HIDP_SET_USAGE_VALUE_ARRAY + // HIDP_UNSET_BUTTONS + // HIDP_UNSET_USAGES + // For these functions, a separate dialog box must be called + // + // 2) Fill in the common parameters from the passed in params struct + // + */ + + /* + // Step 1: We're storing the values retrieved by these additional dialog + // box in the params struct since we may actually be passed in + // these values in the future instead of getting them here. Hence, + // we won't break any of the code that follows the switch statement + */ + + switch (iFuncCall) + { + case HIDP_SET_BUTTONS: + case HIDP_SET_USAGES: + case HIDP_UNSET_BUTTONS: + case HIDP_UNSET_USAGES: + + switch (iFuncCall) + { + case HIDP_SET_BUTTONS: + DlgBoxNumber = IDD_SET_BUTTONS; + break; + + case HIDP_SET_USAGES: + DlgBoxNumber = IDD_SET_USAGES; + break; + + case HIDP_UNSET_BUTTONS: + DlgBoxNumber = IDD_UNSET_BUTTONS; + break; + + case HIDP_UNSET_USAGES: + DlgBoxNumber = IDD_UNSET_USAGES; + break; + } + + iDlgStatus = (DLGBOX_STATUS) DialogBoxParam(NULL, + MAKEINTRESOURCE(DlgBoxNumber), + GetParent(hOutputWindow), + bSetUsagesDlgProc, + (LPARAM) params); + /* + // If the above call returns 1, then the dialog box routine + // successfully acquired a string from the user and put the + // pointer to it in params -> szListString. + // Now we need to convert the string to a usage list + */ + + if (DLGBOX_OK != iDlgStatus) + return; + + if (!ConvertStringToUsageList(params -> szListString, + ¶ms -> UsageList, + &newListLength)) + { + ECDISP_ERROR(GetParent(hOutputWindow), + "Error getting usage list"); + + free(params -> szListString); + return; + } + + if(params->ListLength >= newListLength) + { + params->ListLength = newListLength; + } + else + { + OUTSTRING(hOutputWindow, "Error in ListLength"); + free(params -> szListString); + return; + } + free(params -> szListString); + + break; + + case HIDP_GET_EXTENDED_ATTRIBUTES: + iDlgStatus = (DLGBOX_STATUS) DialogBoxParam(NULL, + MAKEINTRESOURCE(IDD_GET_EXT_ATTRIB), + GetParent(hOutputWindow), + bGetIndexedDlgProc, + (LPARAM) params); + + if (DLGBOX_OK != iDlgStatus) + return; + + params -> Index = strtoul(params -> szListString, &endp, 10); + + if ('\0' != *endp) + { + ECDISP_ERROR(GetParent(hOutputWindow), + "Invalid index value"); + + free(params -> szListString); + free(params -> szListString2); + return; + } + + free(params -> szListString); + +#pragma prefast(suppress:__WARNING_INVALID_PARAM_VALUE_1 , "szListString2 cannot be zero") + tmpLen = strtoul(params -> szListString2, &endp, 10); + + if ('\0' != *endp || tmpLen > params->ListLength) + { + ECDISP_ERROR(GetParent(hOutputWindow), + "Invalid buffer size"); + + free(params -> szListString2); + return; + } + params -> ListLength = tmpLen; + free(params -> szListString2); + break; + + case HIDD_GET_INDEXED_STRING: + iDlgStatus = (DLGBOX_STATUS) DialogBoxParam(NULL, + MAKEINTRESOURCE(IDD_GET_INDEX_STRING), + GetParent(hOutputWindow), + bGetIndexedDlgProc, + (LPARAM) params); + + if (DLGBOX_OK != iDlgStatus) + return; + + if (NULL == params->szListString || NULL == params->szListString2) + { + OUTSTRING(hOutputWindow, "Error in szListString"); + return; + } + + params -> Index = strtoul(params -> szListString, &endp, 10); + + if ('\0' != *endp) + { + ECDISP_ERROR(GetParent(hOutputWindow), + "Invalid index value"); + + free(params -> szListString); + free(params -> szListString2); + return; + } + + free(params -> szListString); + tmpLen = strtoul(params -> szListString2, &endp, 10); + + if ('\0' != *endp || tmpLen > params->ListLength) + { + ECDISP_ERROR(GetParent(hOutputWindow), + "Invalid buffer size"); + free(params -> szListString2); + return; + } + params -> ListLength = tmpLen; + free(params -> szListString2); + break; + + case HIDD_GET_MS_GENRE_DESCRIPTOR: + case HIDD_GET_PHYSICAL_DESCRIPTOR: + case HIDD_GET_MANUFACTURER_STRING: + case HIDD_GET_PRODUCT_STRING: + case HIDD_GET_SERIAL_NUMBER_STRING: + iDlgStatus = (DLGBOX_STATUS) DialogBoxParam(NULL, + MAKEINTRESOURCE(IDD_SET_BUFFER_LENGTH), + GetParent(hOutputWindow), + bSetBufLenDlgProc, + (LPARAM) params); + + if (DLGBOX_OK != iDlgStatus) + return; + + tmpLen = strtoul(params -> szListString, &endp, 10); + + + if (tmpLen > params->ListLength || '\0' != *endp) + { + free(params -> szListString); + params->ListLength = 0; + ECDISP_ERROR(GetParent(hOutputWindow), + "Invalid buffer length"); + return; + } + params -> ListLength = tmpLen; + free(params -> szListString); + break; + + case HIDD_SET_NUM_INPUT_BUFFERS: + iDlgStatus = (DLGBOX_STATUS) DialogBoxParam(NULL, + MAKEINTRESOURCE(IDD_SET_INPUT_BUFFERS), + GetParent(hOutputWindow), + bSetInputBuffDlgProc, + (LPARAM) params); + /* + // If the above call returns 1, then the dialog box routine + // successfully acquired a string from the user and put the + // pointer to it in params -> szListString. + // Now we need to convert the string to a usage list + */ + + if (DLGBOX_OK != iDlgStatus) + return; + + params -> Value = strtoul(params -> szListString, &endp, 10); + + if ('\0' != *endp) + { + ECDISP_ERROR(GetParent(hOutputWindow), + "Invalid value specified"); + + free(params -> szListString); + return; + } + free(params -> szListString); + break; + + case HIDP_SET_DATA: + iDlgStatus = (DLGBOX_STATUS) DialogBoxParam(NULL, + MAKEINTRESOURCE(IDD_SET_DATA), + GetParent(hOutputWindow), + bSetDataDlgProc, + (LPARAM) params); + + if (DLGBOX_OK != iDlgStatus) + return; + + break; + + case HIDP_SET_SCALED_USAGE_VALUE: + iDlgStatus = (DLGBOX_STATUS) DialogBoxParam(NULL, + MAKEINTRESOURCE(IDD_SET_SCALED_VALUE), + GetParent(hOutputWindow), + bSetValueDlgProc, + (LPARAM) params); + /* + // If the above call returns DLGBOX_OK, then the dialog box routine + // successfully acquired a string from the user and put the + // pointer to it in params -> szListString. + // Now we need to convert the string to a usage list + */ + + if (DLGBOX_OK != iDlgStatus) + return; + + params -> ScaledValue = strtol(params -> szListString, &endp, 10); + + if ('\0' != *endp) + { + ECDISP_ERROR(GetParent(hOutputWindow), + "Invalid scaled usage value"); + + free(params -> szListString); + return; + } + + free(params -> szListString); + break; + + case HIDP_SET_USAGE_VALUE: + iDlgStatus = (DLGBOX_STATUS) DialogBoxParam(NULL, + MAKEINTRESOURCE(IDD_SET_USAGE_VALUE), + GetParent(hOutputWindow), + bSetValueDlgProc, + (LPARAM) params); + /* + // If the above call returns 1, then the dialog box routine + // successfully acquired a string from the user and put the + // pointer to it in params -> szListString. + // Now we need to convert the string to a usage list + */ + + if (DLGBOX_OK != iDlgStatus) + return; + + params -> Value = strtoul(params -> szListString, &endp, 10); + + if ('\0' != *endp) + { + ECDISP_ERROR(GetParent(hOutputWindow), + "Invalid usage value"); + + free(params -> szListString); + return; + } + free(params -> szListString); + break; + + + case HIDP_SET_USAGE_VALUE_ARRAY: + iDlgStatus = (DLGBOX_STATUS) DialogBoxParam(NULL, + MAKEINTRESOURCE(IDD_SET_USAGE_VALUE_ARRAY), + GetParent(hOutputWindow), + bSetValueDlgProc, + (LPARAM) params); + + /* + // If the above call returns 1, then the dialog box routine + // successfully acquired a string from the user and put the + // pointer to it in params -> szListString. + // Now we need to convert the string to a usage list + */ + + if (DLGBOX_OK != iDlgStatus) + return; + + ExecuteStatus = ConvertStringToUlongList(params -> szListString, + ¶ms -> pValueList, + ¶ms -> ListLength); + free(params -> szListString); + params->szListString = NULL; + params->ListLength = 0; + + if (!ExecuteStatus) + { + ECDISP_ERROR(GetParent(hOutputWindow), + "Error getting list of values"); + return; + } + break; + + case HIDP_USAGE_LIST_DIFFERENCE: + iDlgStatus = (DLGBOX_STATUS) DialogBoxParam(NULL, + MAKEINTRESOURCE(IDD_USAGE_LIST_DIFFERENCE), + GetParent(hOutputWindow), + bGetUsageDiffDlgProc, + (LPARAM) params); + + if (DLGBOX_OK != iDlgStatus) + { + return; + } + + ExecuteStatus = Strings_StringToUnsignedList(params -> szListString, + sizeof(USAGE), + 16, + (PCHAR *) ¶ms -> UsageList, + ¶ms -> ListLength); + + if (!ExecuteStatus) + { + ECDISP_ERROR(GetParent(hOutputWindow), + "Error getting list of values"); + + free(params -> szListString); + params->szListString = NULL; + free(params -> szListString2); + params->szListString2 = NULL; + free(params -> UsageList); + params->UsageList = NULL; + free(params -> UsageList2); + params->UsageList2 = NULL; + + params->ListLength = 0; + params->ListLength2 = 0; + + return; + } + +#pragma warning(push) +#pragma warning(disable:26045) + +#pragma prefast(suppress:__WARNING_INVALID_PARAM_VALUE_1 , "szListString2 cannot be zero") + ExecuteStatus = Strings_StringToUnsignedList(params -> szListString2, + sizeof(USAGE), + 16, + (PCHAR *) ¶ms -> UsageList2, + ¶ms -> ListLength2); + + if (!ExecuteStatus) + { + ECDISP_ERROR(GetParent(hOutputWindow), + "Error getting list of values"); + + free(params -> szListString); + params->szListString = NULL; + free(params -> szListString2); + params->szListString2 = NULL; + free(params -> UsageList); + params->UsageList = NULL; + free(params -> UsageList2); + params->UsageList2 = NULL; + + params->ListLength = 0; + params->ListLength2 = 0; + + return; + } + + free(params -> szListString); + params->szListString = NULL; + + + free(params -> szListString2); + params->szListString2 = NULL; + + params->ListLength = 0; + params->ListLength2 = 0; + + break; + } + + /* + // Step 2: Extract the common parameters. It's probably easier + // to simply fill in the spots in call parameters whether they are used + // or not instead of filling in only those that are relevant to a given + // function. The details of some function relevant parameters are + // handled after this. + */ + + CallParameters.DeviceHandle = pDevice -> HidDevice; + CallParameters.ReportType = params -> ReportType; + CallParameters.Ppd = pDevice -> Ppd; + CallParameters.UsagePage = params -> UsagePage; + CallParameters.Usage = params -> Usage; + CallParameters.LinkCollection = params -> LinkCollection; + CallParameters.ReportID = params -> ReportID; + CallParameters.List = NULL; + CallParameters.List2 = NULL; + CallParameters.MakeList = NULL; + CallParameters.BreakList = NULL; + CallParameters.ListLength = 0; + + List2Alloc = FALSE; + MakeListAlloc = FALSE; + BreakListAlloc = FALSE; + + /* + // Step 3: Now we'll deal with those functions that require a report buffer of some kind + // which means we'll copy the current buffer of the selected reported + // type + */ + + switch (iFuncCall) + { + case HID_READ_REPORT: + + status = OpenHidDevice(pDevice -> DevicePath, + TRUE, + FALSE, + FALSE, + FALSE, + &readDevice); + + if (!status) + { + OUTSTRING(hOutputWindow, "Unable to open device for reading"); + } + + CallParameters.DeviceHandle = readDevice.HidDevice; + CallParameters.ReportType = HidP_Input; + CallParameters.ReportBuffer = readDevice.InputReportBuffer; + CallParameters.ReportLength = readDevice.Caps.InputReportByteLength; + break; + + case HID_WRITE_REPORT: + + status = OpenHidDevice(pDevice -> DevicePath, + TRUE, + FALSE, + FALSE, + FALSE, + &writeDevice); + + if (!status) + { + OUTSTRING(hOutputWindow, "Unable to open device for writing"); + } + +#pragma warning(push) +#pragma warning(disable:22116) + BufferDisplay_CopyCurrentBuffer(pOutputDisplay, + writeDevice.OutputReportBuffer, + writeDevice.Caps.OutputReportByteLength); +#pragma warning(pop) + + CallParameters.DeviceHandle = writeDevice.HidDevice; + CallParameters.ReportType = HidP_Output; + CallParameters.ReportBuffer = writeDevice.OutputReportBuffer; + CallParameters.ReportLength = writeDevice.Caps.OutputReportByteLength; + break; + + case HIDD_GET_INPUT_REPORT: + CallParameters.ReportType = HidP_Input; + CallParameters.ReportBuffer = pDevice -> InputReportBuffer; + CallParameters.ReportLength = pDevice -> Caps.InputReportByteLength; + break; + + case HIDD_GET_FEATURE: + CallParameters.ReportType = HidP_Feature; + CallParameters.ReportBuffer = pDevice -> FeatureReportBuffer; + CallParameters.ReportLength = pDevice -> Caps.FeatureReportByteLength; + break; + + case HIDD_GET_INDEXED_STRING: + case HIDP_GET_EXTENDED_ATTRIBUTES: + CallParameters.Index = params -> Index; + CallParameters.ListLength = params -> ListLength; + break; + + case HIDD_SET_OUTPUT_REPORT: + CallParameters.ReportType = HidP_Output; + BufferDisplay_CopyCurrentBuffer(pOutputDisplay, + pDevice->OutputReportBuffer, + pDevice->Caps.OutputReportByteLength); + CallParameters.ReportLength = BufferDisplay_GetBufferSize(pOutputDisplay); + CallParameters.ReportBuffer = pDevice -> OutputReportBuffer; + break; + + case HIDD_SET_FEATURE: + CallParameters.ReportType = HidP_Feature; + BufferDisplay_CopyCurrentBuffer(pFeatureDisplay, + pDevice->FeatureReportBuffer, + pDevice->Caps.FeatureReportByteLength); + CallParameters.ReportLength = BufferDisplay_GetBufferSize(pFeatureDisplay); + CallParameters.ReportBuffer = pDevice -> FeatureReportBuffer; + break; + + case HIDP_GET_BUTTONS: + case HIDP_GET_BUTTONS_EX: + case HIDP_GET_DATA: + case HIDP_GET_SCALED_USAGE_VALUE: + case HIDP_GET_USAGES: + case HIDP_GET_USAGES_EX: + case HIDP_GET_USAGE_VALUE: + case HIDP_GET_USAGE_VALUE_ARRAY: + case HIDP_INITIALIZE_REPORT_FOR_ID: + case HIDP_SET_BUTTONS: + case HIDP_SET_DATA: + case HIDP_SET_SCALED_USAGE_VALUE: + case HIDP_SET_USAGES: + case HIDP_SET_USAGE_VALUE: + case HIDP_SET_USAGE_VALUE_ARRAY: + case HIDP_UNSET_BUTTONS: + case HIDP_UNSET_USAGES: + + switch (CallParameters.ReportType) + { + case HidP_Input: + pBufferDisplay = pInputDisplay; + pCopyBuffer = pDevice -> InputReportBuffer; + ulCopyBufferLength = pDevice->Caps.InputReportByteLength; + break; + + case HidP_Output: + pBufferDisplay = pOutputDisplay; + pCopyBuffer = pDevice -> OutputReportBuffer; + ulCopyBufferLength = pDevice->Caps.OutputReportByteLength; + break; + + case HidP_Feature: + pBufferDisplay = pFeatureDisplay; + pCopyBuffer = pDevice -> FeatureReportBuffer; + ulCopyBufferLength = pDevice->Caps.FeatureReportByteLength; + break; + + } + + if(NULL == pBufferDisplay) + { + return; // error case + } + BufferDisplay_CopyCurrentBuffer(pBufferDisplay, + pCopyBuffer, + ulCopyBufferLength); + + CallParameters.ReportLength = BufferDisplay_GetBufferSize(pBufferDisplay); + CallParameters.ReportBuffer = pCopyBuffer; + break; + + default: + CallParameters.ReportLength = 0; + CallParameters.ReportBuffer = NULL; + } + + /* + // Now, we need to deal with those functions which have a List that is + // used for either retrieving or gathering data. There are two different + // cases. The first involves the user inputting a buffer and the system + // performing some action on the buffer, such as SetButtons. We'll also + // the other functions that require one of the union fields to be set. + // + */ + + /* + // The second case is where data is retrieved for the device. In this case, + // all we do is specify either the number of elements need for the buffer, + // the execute routine will worry about allocating the correct amount of + // space for those elements. Remember, however, that if the Execute routine + // allocates space, we need to free it up. + */ + + /* + // Then there's the third case UsageListDifference which truly changes + // everything. We've got to determine the size of the resulting lists + // is the MaxSize of the other two lists. Plus, we need to insure that + // our buffers are 00 terminated if they are less than the max size, ie + // there not the same size as the larger buffer. This may require + // reallocation of the block. + */ + + switch (iFuncCall) + { + /* + // First Case functions + */ + + case HIDP_SET_DATA: + CallParameters.List = (PVOID) params -> pDataList; + CallParameters.ListLength = params -> ListLength; + break; + + case HIDP_SET_BUTTONS: + case HIDP_UNSET_BUTTONS: + case HIDP_SET_USAGES: + case HIDP_UNSET_USAGES: + CallParameters.List = (PVOID) params -> UsageList; + CallParameters.ListLength = params -> ListLength; + break; + + case HIDP_SET_USAGE_VALUE_ARRAY: + CallParameters.List = (PVOID) params -> pValueList; + CallParameters.ListLength = params -> ListLength; + break; + + /* + // Second Case functions + */ + + case HIDP_GET_BUTTON_CAPS: + case HIDP_GET_SPECIFIC_BUTTON_CAPS: + SELECT_ON_REPORT_TYPE(CallParameters.ReportType, + pDevice -> Caps.NumberInputButtonCaps, + pDevice -> Caps.NumberOutputButtonCaps, + pDevice -> Caps.NumberFeatureButtonCaps, + CallParameters.ListLength); + break; + + case HIDP_GET_LINK_COLL_NODES: + CallParameters.ListLength = pDevice -> Caps.NumberLinkCollectionNodes; + break; + + case HIDD_GET_MS_GENRE_DESCRIPTOR: + case HIDD_GET_PHYSICAL_DESCRIPTOR: + case HIDD_GET_MANUFACTURER_STRING: + case HIDD_GET_PRODUCT_STRING: + case HIDD_GET_SERIAL_NUMBER_STRING: + CallParameters.ListLength = params -> ListLength; + break; + + case HIDP_GET_VALUE_CAPS: + case HIDP_GET_SPECIFIC_VALUE_CAPS: + SELECT_ON_REPORT_TYPE(CallParameters.ReportType, + pDevice -> Caps.NumberInputValueCaps, + pDevice -> Caps.NumberOutputValueCaps, + pDevice -> Caps.NumberFeatureValueCaps, + CallParameters.ListLength); + + case HIDD_GET_FREE_PREPARSED_DATA: + CallParameters.ppPd = &CallParameters.Ppd; + break; + + case HIDP_SET_SCALED_USAGE_VALUE: + CallParameters.ScaledValue = params -> ScaledValue; + break; + + case HIDP_SET_USAGE_VALUE: + case HIDD_SET_NUM_INPUT_BUFFERS: + CallParameters.Value = params -> Value; + break; + + /* + // That third case + */ + + case HIDP_USAGE_LIST_DIFFERENCE: + CallParameters.ListLength = max(params -> ListLength, + params -> ListLength2); + + CallParameters.List = params -> UsageList; + CallParameters.List2 = params -> UsageList2; + + if (CallParameters.ListLength > params -> ListLength) + { + CallParameters.List = (PUSAGE) realloc(params -> UsageList, + (params -> ListLength+1) * sizeof(USAGE)); + + if (NULL == CallParameters.List) + { + ECDISP_ERROR(GetParent(hOutputWindow), + "Error allocating memory"); + + free(params -> UsageList); + free(params -> UsageList2); + + return; + } + + *(((PUSAGE) CallParameters.List) + CallParameters.ListLength - 1) = 0; + } + else if (CallParameters.ListLength > params -> ListLength2) + { + CallParameters.List2 = (PUSAGE) realloc(params -> UsageList2, + (params -> ListLength+1) * sizeof(USAGE)); + + if (NULL == CallParameters.List2) + { + ECDISP_ERROR(GetParent(hOutputWindow), + "Error allocating memory"); + + free(params -> UsageList); + free(params -> UsageList2); + return; + } + + *(((PUSAGE) CallParameters.List2) + CallParameters.ListLength - 1) = 0; + } + List2Alloc = TRUE; + MakeListAlloc = TRUE; + BreakListAlloc = TRUE; + break; + } + + /* + // Params are now set up and ready to go, let's execute + */ + + if (HIDD_GET_FREE_PREPARSED_DATA == iFuncCall) + { + ExecuteStatus = ECDisp_Execute(HIDD_GET_PREPARSED_DATA, + &CallParameters, + &CallStatus); + + if (!ExecuteStatus) + { + OUTSTRING(hOutputWindow, "Unknown error: Couldn't execute function"); + return; + } + + DISPLAY_HIDD_STATUS(hOutputWindow, + "HidD_GetPreparsedData", + CallStatus, + stringReturn); + + if (!CallStatus.IsHidError) + { + ExecuteStatus = ECDisp_Execute(HIDD_FREE_PREPARSED_DATA, + &CallParameters, + &CallStatus); + + OUTSTRING(hOutputWindow, "======================="); + + if (!ExecuteStatus) + { + OUTSTRING(hOutputWindow, "Unknown error: Couldn't execute function"); + return; + } + + DISPLAY_HIDD_STATUS(hOutputWindow, + "HidD_FreePreparsedData", + CallStatus, + stringReturn); + } + } + else + { + if ((HID_READ_REPORT == iFuncCall || HID_WRITE_REPORT == iFuncCall) && + (!status)) + { + // + // Indicate there was an error so we don't display anything further + // + + CallStatus.IsHidError = TRUE; + } + else + { + ExecuteStatus = ECDisp_Execute(iFuncCall, + &CallParameters, + &CallStatus); + + if (!ExecuteStatus) + { + OUTSTRING(hOutputWindow, "Unknown error: Couldn't execute function"); + return; + } + + if (IS_HIDD_FUNCTION(iFuncCall) || IS_HID_FUNCTION(iFuncCall)) + { + DISPLAY_HIDD_STATUS(hOutputWindow, + GET_FUNCTION_NAME(iFuncCall), + CallStatus, + stringReturn); + + } + else + { + DISPLAY_HIDP_STATUS(hOutputWindow, + GET_FUNCTION_NAME(iFuncCall), + CallStatus, + stringReturn); + } + } + } + + + /* + // Display the other results only if there wasn't a HID error + */ + + if (!CallStatus.IsHidError || (HIDP_STATUS_NULL == CallStatus.HidErrorCode)) + { + OUTSTRING(hOutputWindow, "======================="); + + /* + // Now that general status information has been displayed, we need to + // display the info for the parts that are dependent on the function being + // called + */ + + ECDisp_DisplayOutput(hOutputWindow, + iFuncCall, + &CallParameters); + } + + if (CallParameters.List != NULL) + { + free(CallParameters.List); + } + + if (List2Alloc && CallParameters.List2 != NULL) + { + free(CallParameters.List2); + } + + if (MakeListAlloc && CallParameters.MakeList != NULL) + { + free(CallParameters.MakeList); + } + + if (BreakListAlloc && CallParameters.BreakList != NULL) + { + free(CallParameters.BreakList); + } + + return; +} +#pragma warning(pop) + +VOID +BuildReportIDList( + IN PHIDP_BUTTON_CAPS phidButtonCaps, + IN USHORT nButtonCaps, + IN PHIDP_VALUE_CAPS phidValueCaps, + IN USHORT nValueCaps, + OUT PUCHAR *ppReportIDList, + OUT INT *nReportIDs +) +/*++ +RoutineDescription: + This routine builds a list of report IDs that are listed in the passed in set + of ButtonCaps and ValueCaps structure. It allocates a buffer to store all + the ReportIDs, if it can. Otherwise the buffer is returned as NULL. + + Currently, this routine has no purpose in the HClient program. It was written + for some purpose which never materialized but was left in because it might be + useful in the future. +--*/ +{ + INT nAllocatedIDs; + INT nFoundIDs; + INT nWalkCount; + USHORT usIndex; + BOOL fIDFound; + UCHAR *pucBuffer; + UCHAR *pucNewBuffer; + UCHAR *pucWalk; + UCHAR ucReportID; + PHIDP_BUTTON_CAPS pButtonWalk; + + UNREFERENCED_PARAMETER(phidValueCaps); + + /* + // Initialize the output parameters in case there is some sort of failure + */ + + *nReportIDs = 0; + *ppReportIDList = NULL; + + if (0 == nButtonCaps && 0 == nValueCaps) + return; + + /* + // Initialize the beginning array size to 2 report IDs and alloc space + // for those IDs. If we need to add more report IDs we allocate more + // space + */ + + nAllocatedIDs = 2; + nFoundIDs = 0; + pButtonWalk = phidButtonCaps; + + pucBuffer = (UCHAR *) malloc(sizeof(UCHAR) * nAllocatedIDs); + if (NULL == pucBuffer) + return; + + /* + // Beginning with the button caps and then going to the value caps do the + // following + // + // 1) Take the report ID and search the array of report IDs looking for + // an existing report ID and add to the array if not there. + // + // 2) Add the report ID to the array in sorted order that way we sort the + // array at any time. + // + // 3) Must also realloc the array if we run out of array space + */ + + for (usIndex = 0; usIndex < nButtonCaps; usIndex++, pButtonWalk++) + { + ucReportID = pButtonWalk -> ReportID; + + pucWalk = pucBuffer; + nWalkCount = 0; + fIDFound = FALSE; + + while (!fIDFound && nWalkCount < nFoundIDs) + { + if (*pucWalk == ucReportID) + { + fIDFound = TRUE; + } + else if (ucReportID > *pucWalk) + { + pucWalk++; + nWalkCount++; + } + } + + if (!fIDFound) + { + if (nFoundIDs == nAllocatedIDs) + { + nAllocatedIDs *= 2; + + pucNewBuffer = (UCHAR *) realloc(pucBuffer, sizeof(UCHAR) * nAllocatedIDs); + + if (NULL == pucNewBuffer) + { + free(pucBuffer); + pucBuffer = NULL; + return; + } + else + { + pucBuffer = pucNewBuffer; + } + + pucWalk = pucBuffer + nWalkCount; + } + + /* + // At this point, pucWalk points to the smallest ReportID in the + // buffer that is greater than the ReportID we want to insert. + // We need to bump all reportIDs beginning at pucWalk up one + // spot and insert the new ReportID at pucWalk + */ + + memmove (pucWalk+1, pucWalk, (nFoundIDs - nWalkCount) * sizeof(UCHAR)); + *pucWalk = ucReportID; + nFoundIDs++; + } + } + + *ppReportIDList = pucBuffer; + *nReportIDs = nFoundIDs; + + return; +} + +LRESULT CALLBACK +bSetUsagesDlgProc( + HWND hDlg, + UINT message, + WPARAM wParam, + LPARAM lParam +) +{ + static PECDISPLAY_PARAMS pParams; + INT StringLength; + DLGBOX_STATUS RetValue; + + switch (message) + { + case WM_INITDIALOG: + + pParams = (PECDISPLAY_PARAMS) lParam; + + SetDlgItemIntHex(hDlg, + IDC_USAGE_PAGE, + pParams -> UsagePage, + 2); + break; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDOK: + StringLength = GetWindowTextLength(GetDlgItem(hDlg, IDC_USAGE_LIST)); + + if (StringLength > 0) + { + pParams -> szListString = (PCHAR) malloc(StringLength+1); + if (NULL == pParams -> szListString) + { + ECDISP_ERROR(hDlg, "Error allocating memory"); + RetValue = DLGBOX_ERROR; + } + else + { + GetWindowText(GetDlgItem(hDlg, IDC_USAGE_LIST), + pParams -> szListString, + StringLength+1); + + RetValue = DLGBOX_OK; + } + } + else + { + pParams -> szListString = NULL; + RetValue = DLGBOX_CANCEL; + } + + EndDialog(hDlg, RetValue); + break; + + case IDCANCEL: + EndDialog(hDlg, DLGBOX_CANCEL); + break; + } + break; + } + return (FALSE); +} + +LRESULT CALLBACK +bSetValueDlgProc( + HWND hDlg, + UINT message, + WPARAM wParam, + LPARAM lParam +) +{ + static PECDISPLAY_PARAMS pParams; + INT StringLength; + DLGBOX_STATUS RetValue; + + switch (message) + { + case WM_INITDIALOG: + + pParams = (PECDISPLAY_PARAMS) lParam; + + SetDlgItemIntHex(hDlg, + IDC_USAGE_PAGE, + pParams -> UsagePage, + sizeof(USAGE)); + + SetDlgItemIntHex(hDlg, + IDC_USAGE, + pParams -> Usage, + sizeof(USAGE)); + break; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDOK: + StringLength = GetWindowTextLength(GetDlgItem(hDlg, IDC_VALUE)); + + if (StringLength > 0) + { + pParams -> szListString = (PCHAR) malloc(StringLength+1); + if (NULL == pParams -> szListString) + { + ECDISP_ERROR(hDlg, "Error allocating memory"); + + RetValue = DLGBOX_ERROR; + } + else + { + GetWindowText(GetDlgItem(hDlg, IDC_VALUE), + pParams -> szListString, + StringLength+1); + + RetValue = DLGBOX_OK; + } + } + else + { + pParams -> szListString = NULL; + RetValue = DLGBOX_CANCEL; + } + + EndDialog(hDlg, RetValue); + break; + + case IDCANCEL: + EndDialog(hDlg, DLGBOX_CANCEL); + break; + } + break; + } + return (FALSE); +} + +LRESULT CALLBACK +bSetInputBuffDlgProc( + HWND hDlg, + UINT message, + WPARAM wParam, + LPARAM lParam +) +{ + static PECDISPLAY_PARAMS pParams; + INT StringLength; + DLGBOX_STATUS RetValue; + + switch (message) + { + case WM_INITDIALOG: + pParams = (PECDISPLAY_PARAMS) lParam; + break; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDOK: + StringLength = GetWindowTextLength(GetDlgItem(hDlg, IDC_INPUT_BUFFERS)); + + if (StringLength > 0) + { + pParams -> szListString = (PCHAR) malloc(StringLength+1); + + if (NULL == pParams -> szListString) + { + ECDISP_ERROR(hDlg, "Error allocating memory"); + + RetValue = DLGBOX_ERROR; + } + else + { + GetWindowText(GetDlgItem(hDlg, IDC_INPUT_BUFFERS), + pParams -> szListString, + StringLength+1); + + RetValue = DLGBOX_OK; + } + } + else + { + pParams -> szListString = NULL; + RetValue = DLGBOX_CANCEL; + } + + EndDialog(hDlg, RetValue); + break; + + case IDCANCEL: + EndDialog(hDlg, DLGBOX_CANCEL); + break; + } + break; + } + return (FALSE); +} + +LRESULT CALLBACK +bSetDataDlgProc( + HWND hDlg, + UINT message, + WPARAM wParam, + LPARAM lParam +) +{ + static CHAR DataString[TEMP_BUFFER_SIZE] = {0}; + static PECDISPLAY_PARAMS pParams; + UINT IndexValue; + ULONG Value; + BOOL lpTranslated; + DLGBOX_STATUS RetValue; + PCHAR endp; + INT ListBoxStatus; + PHIDP_DATA DataList; + PHIDP_DATA CurrData; + ULONG DataListLength; + ULONG Index; + + ZeroMemory(DataString, sizeof(DataString)); + + // Give PREFast a hint as it does not fully understand the annotations + // on memset() yet + _Analysis_assume_nullterminated_(DataString); + + switch (message) + { + case WM_INITDIALOG: + + pParams = (PECDISPLAY_PARAMS) lParam; + SendMessage(GetDlgItem(hDlg, IDC_VALUE), + EM_SETLIMITTEXT, + (WPARAM) 1024, + 0); + break; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDC_ADD_DATA: + IndexValue = GetDlgItemInt(hDlg, + IDC_INDEX, + &lpTranslated, + FALSE); + if (!lpTranslated) + { + ECDISP_ERROR(hDlg, + "Invalid index value: must be unsigned integer"); + break; + } + + if (0 == GetWindowText(GetDlgItem(hDlg, IDC_VALUE), + DataString, 1023)) + { + ECDISP_ERROR(hDlg, "Invalid data value"); + break; + } + + #pragma prefast(suppress: 28750, "Banned API check.") + CharUpperBuff(DataString, lstrlen(DataString)); + + if (0 == lstrcmp(DataString, "TRUE")) + { + Value = 1; + } + else if (0 == lstrcmp(DataString, "FALSE")) + { + Value = 0; + } + else + { + Value = strtoul(DataString, &endp, 10); + if ( (0 == Value) || (*endp != '\0') ) + { + ECDISP_ERROR(hDlg, "Invalid data value"); + break; + } + } + StringCbPrintf(DataString, + TEMP_BUFFER_SIZE, + SETDATA_LISTBOX_FORMAT, + IndexValue, + Value); + + ListBoxStatus = (INT) SendMessage(GetDlgItem(hDlg, IDC_DATA_LIST), + LB_ADDSTRING, + 0, + (LPARAM) DataString); + + if (CB_ERR == ListBoxStatus || CB_ERRSPACE == ListBoxStatus) + { + ECDISP_ERROR(hDlg, "Error adding string to data list"); + break; + } + break; + + case IDC_REMOVE_DATA: + SendMessage(GetDlgItem(hDlg, IDC_DATA_LIST), + LB_DELETESTRING, + SendMessage(GetDlgItem(hDlg, IDC_DATA_LIST), + LB_GETCURSEL, + 0, 0), + 0); + break; + + case IDOK: + DataListLength = (ULONG) SendMessage(GetDlgItem(hDlg, IDC_DATA_LIST), + LB_GETCOUNT, + 0, 0); + + if (0 != DataListLength) + { + DataList = malloc(DataListLength * sizeof(HIDP_DATA)); + if (NULL == DataList) + { + ECDISP_ERROR(hDlg, "Error allocating memory"); + + DataListLength = 0; + break; + } + + for (Index = 0, CurrData = DataList; Index < DataListLength; Index++, CurrData++) + { + if ( SendMessage(GetDlgItem(hDlg, IDC_DATA_LIST), + LB_GETTEXTLEN, + Index, + 0) < ARRAYSIZE( DataString ) ) + { + SendMessage(GetDlgItem(hDlg, IDC_DATA_LIST), + LB_GETTEXT, + Index, + (LPARAM) DataString); + } + + if (2 != sscanf_s(DataString, + SETDATA_LISTBOX_FORMAT, + &IndexValue, + &Value)) + { + ECDISP_ERROR(hDlg, + "Invalid DataString: expected 2 values"); + + CurrData -> DataIndex = (USHORT) IndexValue; + CurrData -> RawValue = Value; + + } + else + { + + CurrData -> DataIndex = (USHORT) IndexValue; + CurrData -> RawValue = Value; + } + } + RetValue = DLGBOX_OK; + } + else + { + DataList = NULL; + RetValue = DLGBOX_CANCEL; + } + + pParams -> pDataList = DataList; + pParams -> ListLength = DataListLength; + EndDialog(hDlg, RetValue); + break; + + case IDCANCEL: + EndDialog(hDlg, DLGBOX_CANCEL); + break; + } + break; + } + return (FALSE); +} + +LRESULT CALLBACK +bSetBufLenDlgProc( + HWND hDlg, + UINT message, + WPARAM wParam, + LPARAM lParam +) +{ + static PECDISPLAY_PARAMS pParams; + INT StringLength; + DLGBOX_STATUS RetValue; + + switch (message) + { + case WM_INITDIALOG: + + pParams = (PECDISPLAY_PARAMS) lParam; + break; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDOK: + StringLength = GetWindowTextLength(GetDlgItem(hDlg, IDC_BUFFER_LENGTH)); + + if (StringLength > 0) + { + pParams -> szListString = (PCHAR) malloc(StringLength+1); + if (NULL == pParams -> szListString) + { + ECDISP_ERROR(hDlg, "Error allocating memory"); + + RetValue = DLGBOX_ERROR; + + } + else + { + GetWindowText(GetDlgItem(hDlg, IDC_BUFFER_LENGTH), + pParams -> szListString, + StringLength+1); + + RetValue = DLGBOX_OK; + } + } + else + { + pParams -> szListString = NULL; + RetValue = DLGBOX_CANCEL; + } + + EndDialog(hDlg, RetValue); + break; + + case IDCANCEL: + EndDialog(hDlg, DLGBOX_CANCEL); + break; + } + break; + } + return (FALSE); +} + +LRESULT CALLBACK +bSetInputBuffersDlgProc( + HWND hDlg, + UINT message, + WPARAM wParam, + LPARAM lParam +) +{ + static PECDISPLAY_PARAMS pParams; + INT StringLength; + DLGBOX_STATUS RetValue; + + switch (message) + { + case WM_INITDIALOG: + + pParams = (PECDISPLAY_PARAMS) lParam; + break; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDOK: + StringLength = GetWindowTextLength(GetDlgItem(hDlg, IDC_INPUT_BUFFERS)); + + if (StringLength > 0) + { + pParams -> szListString = (PCHAR) malloc(StringLength+1); + + if (NULL == pParams -> szListString) + { + ECDISP_ERROR(hDlg, "Error allocating memory"); + RetValue = DLGBOX_ERROR; + } + else + { + GetWindowText(GetDlgItem(hDlg, IDC_INPUT_BUFFERS), + pParams -> szListString, + StringLength+1 + ); + RetValue = DLGBOX_OK; + } + } + else + { + pParams -> szListString = NULL; + RetValue = DLGBOX_CANCEL; + } + + EndDialog(hDlg, RetValue); + break; + + case IDCANCEL: + EndDialog(hDlg, DLGBOX_CANCEL); + break; + } + break; + } + return (FALSE); +} + +LRESULT CALLBACK +bGetIndexedDlgProc( + HWND hDlg, + UINT message, + WPARAM wParam, + LPARAM lParam +) +{ + static PECDISPLAY_PARAMS pParams; + INT StringLength; + INT StringLength2; + DLGBOX_STATUS RetValue; + + switch (message) + { + case WM_INITDIALOG: + + pParams = (PECDISPLAY_PARAMS) lParam; + break; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDOK: + StringLength = GetWindowTextLength(GetDlgItem(hDlg, IDC_INDEX)); + StringLength2 = GetWindowTextLength(GetDlgItem(hDlg, IDC_BUFFER_LENGTH)); + + if (StringLength <= 0 || StringLength2 <= 0) + { + pParams -> szListString = NULL; + pParams -> szListString2 = NULL; + EndDialog(hDlg, DLGBOX_CANCEL); + } + + pParams -> szListString = (PCHAR) malloc(StringLength+1); + pParams -> szListString2 = (PCHAR) malloc(StringLength2+1); + + if (NULL == pParams -> szListString || NULL == pParams -> szListString2) + { + ECDISP_ERROR(hDlg, "Error allocating memory"); + + if (NULL != pParams -> szListString) + free(pParams -> szListString); + + if (NULL != pParams -> szListString2) + free(pParams -> szListString2); + + RetValue = DLGBOX_ERROR; + } + else + { + GetWindowText(GetDlgItem(hDlg, IDC_INDEX), + pParams -> szListString, + StringLength+1); + + GetWindowText(GetDlgItem(hDlg, IDC_BUFFER_LENGTH), + pParams -> szListString2, + StringLength2+1); + + RetValue = DLGBOX_OK; + } + EndDialog(hDlg, RetValue); + break; + + case IDCANCEL: + EndDialog(hDlg, DLGBOX_CANCEL); + break; + } + break; + } + return (FALSE); +} + +LRESULT CALLBACK +bGetUsageDiffDlgProc( + HWND hDlg, + UINT message, + WPARAM wParam, + LPARAM lParam +) +{ + static PECDISPLAY_PARAMS pParams; + INT StringLength; + INT StringLength2; + DLGBOX_STATUS RetValue; + + switch (message) + { + case WM_INITDIALOG: + + pParams = (PECDISPLAY_PARAMS) lParam; + break; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDOK: + StringLength = GetWindowTextLength(GetDlgItem(hDlg, IDC_USAGE_LIST1)); + StringLength2 = GetWindowTextLength(GetDlgItem(hDlg, IDC_USAGE_LIST2)); + + if (StringLength <= 0) + { + pParams -> szListString = NULL; + } + else + { + pParams -> szListString = (PCHAR) malloc(StringLength+1); + if (NULL == pParams -> szListString) + { + ECDISP_ERROR(hDlg, + "Error allocating memory"); + + EndDialog(hDlg, DLGBOX_ERROR); + break; + } + } + + if (StringLength2 <= 0) + { + pParams -> szListString2 = NULL; + } + else + { + pParams -> szListString2 = (PCHAR) malloc(StringLength2+1); + if (NULL == pParams -> szListString2) + { + ECDISP_ERROR(hDlg, + "Error allocating memory"); + EndDialog(hDlg, DLGBOX_ERROR); + if (NULL != pParams -> szListString) + { + free(pParams -> szListString); + } + break; + } + } + + if ( !(pParams->szListString) ) + { + if(NULL == pParams->szListString) + { + return(FALSE); // error case + } + + GetWindowText(GetDlgItem(hDlg, IDC_USAGE_LIST1), + pParams -> szListString, + StringLength+1); + } + + if (pParams->szListString2 != NULL) + { + GetWindowText(GetDlgItem(hDlg, IDC_USAGE_LIST2), + pParams -> szListString2, + StringLength2+1); + } + + RetValue = DLGBOX_OK; + + EndDialog(hDlg, RetValue); + break; + + case IDCANCEL: + EndDialog(hDlg, DLGBOX_CANCEL); + break; + } + break; + } + return (FALSE); +} + +BOOL +ConvertStringToUsageList( + _In_ LPSTR InString, + OUT PUSAGE *UsageList, + OUT PULONG nUsages +) +/*++ +RoutineDescription: + This routine converts a string of values into a string of usages which are + currently 2 byte values. We use base 16 to specify that the usages should + be expressed as hexidecimal numbers. +--*/ +{ + return (Strings_StringToUnsignedList(InString, + sizeof(ULONG), + 16, + (PCHAR *) UsageList, + nUsages)); +} + +BOOL +ConvertStringToUlongList( + _Inout_ LPSTR InString, + OUT PULONG *UlongList, + OUT PULONG nUlongs +) +/*++ +RoutineDescription + This routine converts a string of values into a string of ulongs which are + currently 2 byte values. It requires that the numbers in the string be in + base 10 +--*/ +{ + return (Strings_StringToUnsignedList(InString, + sizeof(ULONG), + 10, + (PCHAR *) UlongList, + nUlongs)); +} + +BOOL +SetDlgItemIntHex( + HWND hDlg, + INT nIDDlgItem, + UINT uValue, + INT nBytes +) +{ + char szTempBuff[] = "0x00000000"; + + assert (1 == nBytes || 2 == nBytes || 4 == nBytes); + + /* + // Determine the width necessary to store the value + */ + + StringCbPrintf(szTempBuff, + (sizeof(szTempBuff)), + "0x%*X", (nBytes*2), uValue); + + SetDlgItemText(hDlg, nIDDlgItem, szTempBuff); + + return (TRUE); +} + +VOID +ECDisp_MakeGUIDString( + IN GUID guid, + _Out_writes_bytes_(uiBuffSize) CHAR szString[], + IN UINT uiBuffSize +) +{ + CHAR szCharString[18]; + UINT i; + + for (i = 0; i < 8; i++) + { + StringCbPrintf(&(szCharString[i]), sizeof(szCharString) - i, + "%x", guid.Data4[i]); + } + + StringCbPrintf(szString, uiBuffSize, + "%x-%x%x-%s", guid.Data1, guid.Data2, guid.Data3, szCharString); + return; +} + +PCHAR +ECDisp_GetHidAppStatusString( + NTSTATUS StatusCode +) +{ + static CHAR hidString[128]; + + switch (StatusCode) + { + case HIDP_STATUS_SUCCESS: + return ("Success"); + + case HIDP_STATUS_NULL: + return ("Status NULL"); + + case HIDP_STATUS_INVALID_PREPARSED_DATA: + return ("Invalid Preparsed Data"); + + case HIDP_STATUS_INVALID_REPORT_TYPE: + return ("Invalid Report Type"); + + case HIDP_STATUS_INVALID_REPORT_LENGTH: + return ("Invalid Report Length"); + + case HIDP_STATUS_USAGE_NOT_FOUND: + return ("Usage not found"); + + case HIDP_STATUS_VALUE_OUT_OF_RANGE: + return ("Value out of range"); + + case HIDP_STATUS_BAD_LOG_PHY_VALUES: + return ("Bad logical physical values"); + + case HIDP_STATUS_BUFFER_TOO_SMALL: + return ("Buffer too small"); + + case HIDP_STATUS_INTERNAL_ERROR: + return ("Internal error"); + + case HIDP_STATUS_I8242_TRANS_UNKNOWN: + return ("I8242 Translation unknown"); + + case HIDP_STATUS_INCOMPATIBLE_REPORT_ID: + return ("Incompatible report ID"); + + case HIDP_STATUS_NOT_VALUE_ARRAY: + return ("Not value array"); + + case HIDP_STATUS_IS_VALUE_ARRAY: + return ("Is value array"); + + case HIDP_STATUS_DATA_INDEX_NOT_FOUND: + return ("Data index not found"); + + case HIDP_STATUS_DATA_INDEX_OUT_OF_RANGE: + return ("Data index out of range"); + + case HIDP_STATUS_BUTTON_NOT_PRESSED: + return ("Button not pressed"); + + case HIDP_STATUS_REPORT_DOES_NOT_EXIST: + return ("Report does not exist"); + + case HIDP_STATUS_NOT_IMPLEMENTED: + return ("Not implemented"); + + default: + StringCbPrintf(hidString, sizeof(hidString), + "Unknown HID Status error: 0x%x", StatusCode); + return (hidString); + } +} + +BOOL +ECDisp_ConvertUlongListToValueList( + IN PULONG UlongList, + IN ULONG nUlongs, + IN USHORT BitSize, + IN USHORT ReportCount, + _Outptr_result_bytebuffer_(*ValueListSize) PCHAR *ValueList, + OUT PULONG ValueListSize +) +/*++ +RoutineDescription: + This routine takes a list of ULong values and formats a value list that is + used as input to HidP_SetUsageValueArray. Unfortunately, this HidP function + requires the caller to format the input buffer which means taking each of + the values in Ulong, truncating their values to meet bit size and then set + those bits at the appropriate spot in the buffer. That is the purpose of + this function + + The function will return TRUE if everything succeeded, FALSE otherwise. +--*/ +{ + + ULONG ulMask; + PCHAR List; + USHORT iByteIndex; + USHORT iByteOffset; + ULONG UlongIndex; + ULONG ListSize; + USHORT BitsToAdd; + USHORT nBits; + ULONG ulValue; + UCHAR LowByte; + + *ValueList = NULL; + *ValueListSize = 0; + + // + // Do some parameter validation...ReportCount should never be zero. + // + + if (0 == ReportCount) + { + *ValueList = "ERR"; + SetLastError(ERROR_INVALID_PARAMETER); + + return (FALSE); + } + + // + // Check the number of ulongs passed in is actually less than or equal + // to the report count and if not, use only the first ReportCount + // number of ULongs. + // + + if (nUlongs > ReportCount) + { + nUlongs = ReportCount; + } + + /* + // Allocate our buffer for the value list and return FALSE if it couldn't + // be done + */ + + ListSize = ROUND_TO_NEAREST_BYTE(BitSize * ReportCount); + List = (PCHAR) malloc(ListSize); + + if (NULL == List) + { + *ValueList = "ERR"; + SetLastError(ERROR_OUTOFMEMORY); + return (FALSE); + } + + /* + // Initialize the buffer to all zeroes + */ + + memset(List, 0x00, ListSize); + + /* + // Buffer has been allocated let's convert those values + */ + + /* + // Determine the mask that will be used to retrieve the cared about bits + // of our value + */ + + ulMask = (sizeof(ULONG)*8 == BitSize) ? ULONG_MAX : (1 << BitSize)-1; + + /* + // Initialize the iByteIndex and iByteOffset fields before entering the + // conversion loop. + */ + + iByteIndex = 0; + iByteOffset = 0; + + /* + // This is the main conversion loop. It performs the following steps on + // each Ulong in the ulong list + // 1) Sets BitsToAdd = BitSize + // 2) Gets the ulValue and the masks off the upper bits that we don't + // care about. + // 3) Determines how many bits can fit at the current byte index based + // on the current byte offset and the number of bits left to add + // 4) Retrieve those bits, shift them to the correct position and + // use bitwise or to get the correct values in the buffer + // 5) Increment the byte index and set our new byte offset + // 6) Shift our Ulong value right to get rid of least significant bits + // that have already been added + // 7) Repeat through step 3 until no more bits to add + */ + + for (UlongIndex = 0; UlongIndex < nUlongs; UlongIndex++) + { + BitsToAdd = BitSize; + + ulValue = *(UlongList + UlongIndex) & ulMask; + + while (BitsToAdd > 0) + { + nBits = (USHORT)min (8 - iByteOffset, BitsToAdd); + + LowByte = (UCHAR) (ulValue & 0xFF); + + LowByte = LowByte << iByteOffset; + + *(List+iByteIndex) |= LowByte; + + iByteIndex = (iByteOffset+nBits) >= 8 ? iByteIndex+1 : iByteIndex; + iByteOffset = (iByteOffset + nBits) % 8; + + BitsToAdd -= nBits; + + ulValue = ulValue >> nBits; + } + } + + *ValueList = List; + *ValueListSize = ListSize; + + if(NULL == *ValueList) + { + *ValueList = "ERR"; + return(FALSE); + } + + return (TRUE); +} + +PCHAR +ResolveFunctionName( + INT Index +) +{ + PCHAR FuncName; + + if (IS_HIDD_FUNCTION(Index) || IS_HID_FUNCTION(Index)) + { + FuncName = DeviceCalls[Index-1].szFunctionName; + } + else + { + if(Index > HID_DEVCALLS) + { + FuncName = PpdCalls[Index-HID_DEVCALLS-1].szFunctionName; + } + else + { + FuncName = 0; + } + } + + return (FuncName); +} + +VOID +DisplayExtendedAttributes( + IN HWND OutputWindow, + IN PHIDP_UNKNOWN_TOKEN UnknownList, + IN ULONG UnknownListLength +) +{ + PHIDP_UNKNOWN_TOKEN current; + ULONG index; + + StringCbPrintf(szTempBuffer, TEMP_BUFFER_SIZE, + "Number of attributes: %d", UnknownListLength); + OUTSTRING(OutputWindow, szTempBuffer); + + current = UnknownList; + for (index = 0; index < UnknownListLength; index++) + { + StringCbPrintf(szTempBuffer, + TEMP_BUFFER_SIZE, + "Token: %d BitField: 0x%X", + current -> Token, + current -> BitField); + + OUTSTRING(OutputWindow, szTempBuffer); + } + + return; +} diff --git a/hid/hclient/ecdisp.h b/hid/hclient/ecdisp.h new file mode 100644 index 00000000..ea0bd0f9 --- /dev/null +++ b/hid/hclient/ecdisp.h @@ -0,0 +1,88 @@ +/*++ + +Copyright (c) Microsoft 1998, All Rights Reserved + +Module Name: + + ecdisp.h + +Abstract: + + This module contains the public declarations for the extended calls dialog + box. + +Environment: + + User mode + +Revision History: + + May-98 : Created + +--*/ + +#ifndef _ECDISP_H_ +#define _ECDISP_H_ + +#if _MSC_VER >= 1200 +#pragma warning(push) +#endif +#pragma warning(disable:4201) // nameless struct/union + +typedef struct { + HANDLE DeviceHandle; + HIDP_REPORT_TYPE ReportType; + PHIDP_PREPARSED_DATA Ppd; + USAGE UsagePage; + USAGE Usage; + USHORT LinkCollection; + UCHAR ReportID; + PCHAR ReportBuffer; + ULONG ReportLength; + PVOID List; + ULONG ListLength; + ULONG Index; + union { + struct { + USHORT ReportCount; + USHORT BitSize; + }; + + struct { + PUSAGE List2; + PUSAGE MakeList; + PUSAGE BreakList; + }; + + PHIDP_PREPARSED_DATA *ppPd; + ULONG Value; + LONG ScaledValue; + }; +} EXTCALL_PARAMS, *PEXTCALL_PARAMS; + +typedef struct { + BOOL IsHidError; + NTSTATUS HidErrorCode; + +} EXTCALL_STATUS, *PEXTCALL_STATUS; + + +/***************************************************************************** +/* Global Extended Call display function declarations +/*****************************************************************************/ + +LRESULT CALLBACK +bExtCallDlgProc( + HWND hDlg, + UINT message, + WPARAM wParam, + LPARAM lParam +); + +#if _MSC_VER >= 1200 +#pragma warning(pop) +#else +#pragma warning(default:4201) +#endif + +#endif diff --git a/hid/hclient/hclient.c b/hid/hclient/hclient.c new file mode 100644 index 00000000..09114bf3 --- /dev/null +++ b/hid/hclient/hclient.c @@ -0,0 +1,3858 @@ +/*++ + +Copyright (c) Microsoft 1998, All Rights Reserved + +Module Name: + + hclient.c + +Abstract: + + This module contains the code for handling HClient's main dialog box and + for performing/calling the appropriate other routines. + +Environment: + + User mode + +Revision History: + + Nov-97 : Created + +--*/ + +#define __HCLIENT_C__ +#define LOG_FILE_NAME NULL + +//**************************************************************************** +// HClient include files +//**************************************************************************** + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "hidsdi.h" +#include "hid.h" +#include "resource.h" +#include "hclient.h" +#include "buffers.h" +#include "ecdisp.h" +#include "list.h" +#include + +#pragma warning(disable:4057) // indirection to slightly different base types +#pragma warning(disable:4127) // conditional expression in constant //while (1) +#pragma warning(disable:4702) // unreachable code //ExitThead +#pragma warning(disable:28146) // Warning is meant for kernel mode drivers +#pragma prefast(disable:17001, "By design, sample files are not internationalized.") +#pragma prefast(disable:38030, "By design, sample files are not internationalized.") + +//**************************************************************************** +// Local display macro definitions +//**************************************************************************** + +#define INPUT_BUTTON 1 +#define INPUT_VALUE 2 +#define OUTPUT_BUTTON 3 +#define OUTPUT_VALUE 4 +#define FEATURE_BUTTON 5 +#define FEATURE_VALUE 6 +#define HID_CAPS 7 +#define DEVICE_ATTRIBUTES 8 + +#define MAX_LB_ITEMS 200 + +#define MAX_WRITE_ELEMENTS 100 +#define MAX_OUTPUT_ELEMENTS 50 + +#define CONTROL_COUNT 9 +#define MAX_LABEL 128 +#define MAX_VALUE 128 +#define SMALL_BUFF 128 + +//**************************************************************************** +// Macro definition to get device block from the main dialog box procedure +//**************************************************************************** + +#define GET_CURRENT_DEVICE(hDlg, pDevice) \ +{ \ + pDevice = NULL; \ + iIndex = (INT) SendDlgItemMessage(hDlg, \ + IDC_DEVICES, \ + CB_GETCURSEL, \ + 0, \ + 0); \ + if (CB_ERR != iIndex) { \ + pDevice = (PHID_DEVICE) SendDlgItemMessage(hDlg, \ + IDC_DEVICES, \ + CB_GETITEMDATA, \ + iIndex, \ + 0); \ + } \ +} + +//**************************************************************************** +// Data types local to the HClient display routines +//**************************************************************************** + +typedef struct rWriteDataStruct_type +{ + + char szLabel[MAX_LABEL]; + char szValue[MAX_VALUE]; + +} rWriteDataStruct, *prWriteDataStruct; + +typedef struct rGetWriteDataParams_type +{ + prWriteDataStruct prItems; + int iCount; + +} rGetWriteDataParams, *prGetWriteDataParams; + +typedef struct _DEVICE_LIST_NODE +{ + LIST_NODE_HDR Hdr; + HDEVNOTIFY NotificationHandle; + HID_DEVICE HidDeviceInfo; + BOOL DeviceOpened; + +} DEVICE_LIST_NODE, *PDEVICE_LIST_NODE; + +//**************************************************************************** +// Global program variables +//**************************************************************************** + +// +// Pointers to the HID.DLL functions that were added into the Win98 OSR and +// Windows 2000 but we're not included in the original implementation of +// HID.DLL in Windows 98. By getting pointers to these functions instead of +// statically linking with them, we can avoid the link error that would +// occur when this runs on Windows 98. The typedefs to make this easier to +// declare are also included below. +// + +PGETEXTATTRIB __encoded_pointer pfnHidP_GetExtendedAttributes = NULL; + +PINITREPORT __encoded_pointer pfnHidP_InitializeReportForID = NULL; + + +//**************************************************************************** +// Global module variables +//**************************************************************************** +static HINSTANCE hGInstance; //global application instance handle + +static HANDLE HIDDLLModuleHandle = NULL; + +// +// Variables for handling the two different types of devices that can be loaded +// into the system. PhysicalDeviceList contains all the actual HID devices +// attached via the USB bus. +// + +static LIST PhysicalDeviceList; + +//**************************************************************************** +// Local data routine declarations +//**************************************************************************** + +VOID +vReadDataFromControls( + HWND hDlg, + prWriteDataStruct prData, + int iOffset, + int iCount +); + +INT_PTR CALLBACK +bGetDataDlgProc( + HWND hDlg, + UINT message, + WPARAM wParam, + LPARAM lParam +); + +INT_PTR CALLBACK +bMainDlgProc( + HWND hDlg, + UINT message, + WPARAM wParam, + LPARAM lParam +); + +INT_PTR CALLBACK +bFeatureDlgProc( + HWND hDlg, + UINT message, + WPARAM wParam, + LPARAM lParam +); + +INT_PTR CALLBACK +bReadDlgProc( + HWND hDlg, + UINT message, + WPARAM wParam, + LPARAM lParam +); + +VOID +vLoadItemTypes( + HWND hItemTypes +); + +BOOL +bGetData( + prWriteDataStruct, + int iCount, + HWND hParent, + _In_ LPSTR pszDialogName +); + +VOID +vLoadDevices( + HWND hDeviceCombo +); + +VOID +vFreeDeviceList( + PHID_DEVICE DeviceList, + ULONG nDevices +); + +VOID +vDisplayInputButtons( + PHID_DEVICE pDevice, + HWND hControl +); + +VOID +vDisplayInputValues( + PHID_DEVICE pDevice, + HWND hControl +); + +VOID +vDisplayOutputButtons( + PHID_DEVICE pDevice, + HWND hControl +); + +VOID +vDisplayOutputValues( + PHID_DEVICE pDevice, + HWND hControl +); + +VOID +vDisplayFeatureButtons( + PHID_DEVICE pDevice, + HWND hControl +); + +VOID +vDisplayFeatureValues( + PHID_DEVICE pDevice, + HWND hControl +); + +VOID +vWriteDataToControls( + HWND hDlg, + prWriteDataStruct prData, + int iOffset, + int iCount +); + +int +iPrepareDataFields( + PHID_DATA pData, + ULONG ulDataLength, + rWriteDataStruct rWriteData[], + int iMaxElements +); + +BOOL +bParseData( + PHID_DATA pData, + rWriteDataStruct rWriteData[], + INT iCount, + INT *piErrorLine +); + +BOOL +bSetButtonUsages( + PHID_DATA pCap, + _In_ LPSTR pszInputString +); + +VOID +BuildReportIDList( + IN PHIDP_BUTTON_CAPS phidButtonCaps, + IN USHORT nButtonCaps, + IN PHIDP_VALUE_CAPS phidValueCaps, + IN USHORT nValueCaps, + OUT UCHAR **ppReportIDList, + OUT INT *nReportIDs +); + +VOID +ReportToString( + PHID_DATA pData, + _Inout_updates_bytes_(iBuffSize) LPSTR szBuff, + UINT iBuffSize +); + +BOOL +RegisterHidDevice( + IN HWND WindowHandle, + IN PDEVICE_LIST_NODE DeviceNode +); + +VOID +DestroyDeviceListCallback( + IN PLIST_NODE_HDR ListNode +); + +//**************************************************************************** +// Function Definitions +//**************************************************************************** +void +DumpDeviceAttr( + _In_ PHIDD_ATTRIBUTES attr) +{ + printf("Vendor ID: 0x%x\n", attr->VendorID); + printf("Product ID: 0x%x\n", attr->ProductID); + printf("Version Number 0x%x\n", attr->VersionNumber); + printf("\n"); +} + +void +DumpButtonInfo( + _In_ PHIDP_BUTTON_CAPS pButton) +{ + ASSERT(pButton); + + printf("Report ID: 0x%x\n", pButton->ReportID); + printf("Usage Page: 0x%x\n", pButton->UsagePage); + printf("Alias: %s\n", pButton -> IsAlias ? "TRUE" : "FALSE"); + printf("Link Collection: %hu\n", pButton -> LinkCollection); + printf("Link Usage Page: 0x%x\n", pButton -> LinkUsagePage); + printf("Link Usage: 0x%x\n", pButton -> LinkUsage); + if (pButton->IsRange) + { + printf("Usage Min: 0x%x, Usage Max: 0x%x\n", + pButton->Range.UsageMin, + pButton->Range.UsageMax); + } + else + { + printf("Usage: 0x%x\n",pButton->NotRange.Usage); + } + + if (pButton->IsRange) + { + printf("Data Index Min: 0x%x, Data Index Max: 0x%x\n", + pButton->Range.DataIndexMin, + pButton->Range.DataIndexMax); + } + else + { + printf("DataIndex: 0x%x\n",pButton->NotRange.DataIndex); + } + + if (pButton->IsStringRange) + { + printf("String Min: 0x%x, String Max: 0x%x\n", + pButton->Range.StringMin, + pButton->Range.StringMax); + } + else + { + printf("String Index: 0x%x\n",pButton->NotRange.StringIndex); + } + + if (pButton->IsDesignatorRange) + { + printf("Designator Min: 0x%x, Designator Max: 0x%x\n", + pButton->Range.DesignatorMin, + pButton->Range.DesignatorMax); + } + else + { + printf("Designator Index: 0x%x\n", + pButton->NotRange.DesignatorIndex); + } + + printf("Absolute: %s\n",(pButton->IsAbsolute)?"Yes":"No"); + printf("\n"); +} + +void +DumpValueInfo( + _In_ PHIDP_VALUE_CAPS pValue) +{ + ASSERT(pValue); + + printf("Report ID 0x%x\n", pValue->ReportID); + printf("Usage Page: 0x%x\n", pValue->UsagePage); + printf("Bit size: 0x%x\n", pValue->BitSize); + printf("Report Count: 0x%x\n", pValue->ReportCount); + printf("Unit Exponent: 0x%x\n", pValue->UnitsExp); + printf("Has Null: 0x%x\n", pValue->HasNull); + printf("Alias: %s\n", pValue->IsAlias ? "TRUE" : "FALSE"); + + if (pValue->IsRange) + { + printf("Usage Min: 0x%x, Usage Max 0x%x\n", + pValue->Range.UsageMin, + pValue->Range.UsageMax); + } + else + { + printf("Usage: 0x%x\n", pValue -> NotRange.Usage); + } + + if (pValue->IsRange) + { + printf("Data Index Min: 0x%x, Data Index Max: 0x%x\n", + pValue->Range.DataIndexMin, + pValue->Range.DataIndexMax); + } + else + { + printf("DataIndex: 0x%x\n", pValue->NotRange.DataIndex); + } + + printf("Physical Minimum: %d, Physical Maximum: %d\n", + pValue->PhysicalMin, + pValue->PhysicalMax); + + printf("Logical Minimum: 0x%x, Logical Maximum: 0x%x\n", + pValue->LogicalMin, + pValue->LogicalMax); + + if (pValue->IsStringRange) + { + printf("String Min: 0x%x String Max 0x%x\n", + pValue->Range.StringMin, + pValue->Range.StringMax); + } + else + { + printf("String Index: 0x%x\n",pValue->NotRange.StringIndex); + } + + if (pValue->IsDesignatorRange) + { + printf("Designator Minimum: 0x%x, Max: 0x%x\n", + pValue->Range.DesignatorMin, + pValue->Range.DesignatorMax); + } + else + { + printf("Designator Index: 0x%x\n",pValue->NotRange.DesignatorIndex); + } + + printf("Absolute: %s\n", pValue->IsAbsolute? "Yes" : "No"); + printf("\n"); +} + +BOOL +CLM_AttachConsole() +{ + HANDLE stdOut = INVALID_HANDLE_VALUE; + int osfStdOut = -1; + FILE *cStdOut = NULL; + + if (AttachConsole(ATTACH_PARENT_PROCESS)) + { + stdOut = GetStdHandle(STD_OUTPUT_HANDLE); + if (INVALID_HANDLE_VALUE != stdOut) + { + osfStdOut = _open_osfhandle((intptr_t)stdOut, _O_TEXT); + if (-1 != osfStdOut) + { + cStdOut = _fdopen(osfStdOut, "w"); + } + } + } + + if (NULL == cStdOut) + { + MessageBox(NULL, "Failed attaching the console", NULL, MB_OK); + return FALSE; + } + else + { + *stdout = *cStdOut; + printf("\n"); + return TRUE; + } +} + +void +CLM_ShowDeviceInfo( + _In_ PHID_DEVICE pDevice) +{ + ULONG iIndex; + + // Device Attributes + printf("Device Attributes:\n"); + printf("------------------\n"); + DumpDeviceAttr(&pDevice->Attributes); + + // HID CAPS + printf("HID CAPS:\n"); + printf("---------\n"); + printf("Usage Page: 0x%x\n", pDevice->Caps.UsagePage); + printf("Input report byte length: %d\n", pDevice->Caps.InputReportByteLength); + printf("Output report byte length: %d\n", pDevice->Caps.OutputReportByteLength); + printf("Feature report byte length: %d\n", pDevice->Caps.FeatureReportByteLength); + printf("Number of collection nodes: %d\n", pDevice->Caps.NumberLinkCollectionNodes); + printf("\n"); + + // Input Buttons + if (0 == pDevice->Caps.NumberInputButtonCaps) + { + printf("No input buttons\n"); + printf("----------------\n"); + printf("\n"); + } + else { + for (iIndex = 0; iIndex < pDevice->Caps.NumberInputButtonCaps; iIndex ++) + { + PHIDP_BUTTON_CAPS pButton; + + printf("Input Button #%d:\n", iIndex+1); + printf("----------------\n"); + + pButton = &pDevice->InputButtonCaps[iIndex]; + DumpButtonInfo(pButton); + } + } + + // Output Buttons + if (0 == pDevice->Caps.NumberOutputButtonCaps) + { + printf("No output buttons\n"); + printf("-----------------\n"); + printf("\n"); + } + else + { + for (iIndex = 0; iIndex < pDevice->Caps.NumberOutputButtonCaps; iIndex ++) + { + PHIDP_BUTTON_CAPS pButton; + + printf("Output Button #%d:\n", iIndex+1); + printf("-----------------\n"); + + pButton = &pDevice->OutputButtonCaps[iIndex]; + DumpButtonInfo(pButton); + } + } + + // Feature Buttons + if (0 == pDevice->Caps.NumberFeatureButtonCaps) + { + printf("No feature buttons\n"); + printf("------------------\n"); + printf("\n"); + } + else + { + for (iIndex = 0; iIndex < pDevice->Caps.NumberFeatureButtonCaps; iIndex ++) + { + PHIDP_BUTTON_CAPS pButton; + + printf("Feature Button #%d:\n", iIndex+1); + printf("------------------\n"); + + pButton = &pDevice->FeatureButtonCaps[iIndex]; + DumpButtonInfo(pButton); + } + } + + // Input Values + if (0 == pDevice->Caps.NumberInputValueCaps) + { + printf("No input values\n"); + printf("---------------\n"); + printf("\n"); + } + else + { + for (iIndex = 0; iIndex < pDevice->Caps.NumberInputValueCaps; iIndex ++) + { + PHIDP_VALUE_CAPS pValue; + + printf("Input Value #%d:\n", iIndex+1); + printf("---------------\n"); + + pValue = &pDevice->InputValueCaps[iIndex]; + DumpValueInfo(pValue); + } + } + + // Output Values + if (0 == pDevice->Caps.NumberOutputValueCaps) + { + printf("No output values\n"); + printf("----------------\n"); + printf("\n"); + } + else + { + for (iIndex = 0; iIndex < pDevice->Caps.NumberOutputValueCaps; iIndex ++) + { + PHIDP_VALUE_CAPS pValue; + + printf("Output Value #%d:\n", iIndex+1); + printf("----------------\n"); + + pValue = &pDevice->OutputValueCaps[iIndex]; + DumpValueInfo(pValue); + } + } + + // Feature Values + if (0 == pDevice->Caps.NumberFeatureValueCaps) + { + printf("No feature values\n"); + printf("-----------------\n"); + printf("\n"); + } + else + { + for (iIndex = 0; iIndex < pDevice->Caps.NumberFeatureValueCaps; iIndex ++) + { + PHIDP_VALUE_CAPS pValue; + + printf("Feature Value #%d:\n", iIndex+1); + printf("-----------------\n"); + + pValue = &pDevice->FeatureValueCaps[iIndex]; + DumpValueInfo(pValue); + } + } +} + +void +CLM_PrintInputReport( + _In_ PHID_DEVICE pDevice + ) +{ + ULONG i; + CHAR szTempBuff[1024] = {0}; + + printf("-------------------------------\n"); + + printf("Raw Report Data: "); + for (i = 0; i < pDevice->Caps.InputReportByteLength; i++) { + printf("%02X ", (BYTE)pDevice->InputReportBuffer[i]); + } + printf("\n"); + + if (FALSE == UnpackReport (pDevice->InputReportBuffer, + pDevice->Caps.InputReportByteLength, + HidP_Input, + pDevice->InputData, + pDevice->InputDataLength, + pDevice->Ppd)) + { + printf("Failed parsing the report data\n"); + } + else { + printf("Parsed Data:\n"); + for (i = 0; i< pDevice->InputDataLength; i++) + { + ReportToString(&pDevice->InputData[i], szTempBuff, sizeof(szTempBuff)); + printf("HID_DATA[%d]: %s\n", i, szTempBuff); + } + } + + printf("-------------------------------\n"); +} + +void +CLM_SyncRead( + _In_ PHID_DEVICE pDevice, + _In_ BYTE reportID, + _In_ ULONG msecToSleep, + _In_ ULONG numReads) +{ + HID_DEVICE syncDevice; + ULONG numReadsDone = 0; + + RtlZeroMemory(&syncDevice, sizeof(syncDevice)); + + if (!OpenHidDevice(pDevice->DevicePath, + TRUE, + FALSE, + FALSE, + FALSE, + &syncDevice)) + { + printf("Failed opening the device for synchronous read.\n"); + goto Done; + } + + printf("Synchronous read started...\n"); + + while (INFINITE_READS == numReads || numReadsDone < numReads) + { + syncDevice.InputReportBuffer[0] = reportID; + + if (FALSE == HidD_GetInputReport(syncDevice.HidDevice, + syncDevice.InputReportBuffer, + syncDevice.Caps.InputReportByteLength )) + { + printf("HidD_GetInputReport() failed. Error: 0x%X\n", GetLastError()); + break; + } + + numReadsDone++; + + printf("Read #%d:\n",numReadsDone); + + CLM_PrintInputReport(&syncDevice); + + if (msecToSleep > 0) + { + Sleep(msecToSleep); + } + } + + printf("Synchronous read stopped.\n"); + +Done: + CloseHidDevice(&syncDevice); +} + +void +CLM_AsyncRead( + _In_ PHID_DEVICE pDevice, + _In_ ULONG numReads) +{ + HID_DEVICE asyncDevice; + READ_THREAD_CONTEXT readContext; + HANDLE readThread; + + if (!OpenHidDevice(pDevice->DevicePath, + TRUE, + FALSE, + FALSE, + FALSE, + &asyncDevice)) + { + printf("Failed opening the device for synchronous read.\n"); + return; + } + + readContext.HidDevice = &asyncDevice; + readContext.TerminateThread = FALSE; + readContext.NumberOfReads = numReads; + readContext.DisplayEvent = NULL; + readContext.DisplayWindow = NULL; + + readThread = CreateThread( NULL, + 0, + AsynchReadThreadProc, + &readContext, + CREATE_SUSPENDED, + NULL); + if (NULL == readThread) + { + printf("Failed creating the thread for asynchronous read. Error: 0x%x", + GetLastError()); + } + else { + printf("Asychronous read started.\n"); + ResumeThread(readThread); + WaitForSingleObject(readThread, INFINITE); + printf("Asychronous read stopped.\n"); + } + + if (readThread != NULL) + { + CloseHandle(readThread); + } + + CloseHidDevice(&asyncDevice); +} + +void +RunInCommandLineMode( + _In_reads_(nArgs) LPWSTR *szArgList, + _In_ int nArgs) +{ + DWORD nArgCmd = 0; + BOOL bPrintHelp = FALSE; + BOOL bConsoleAttached = FALSE; + PHID_DEVICE deviceList = NULL; + ULONG numDevices = 0; + ULONG nDevice = 0; + ULONG numReads = 0; + ULONG i; + ULONG reportID = 0; + ULONG msecToSleep = 0; + + if (nArgs < 2) + { + ASSERT(FALSE); + return; + } + + nArgCmd = wcstoul(szArgList[1], NULL, 10); + + bConsoleAttached = CLM_AttachConsole(); + + if (!bConsoleAttached) + { + goto Done; + } + + FindKnownHidDevices(&deviceList,&numDevices); + + switch (nArgCmd) + { + case 1: + for (i = 0; i < numDevices; i++) + { + if (INVALID_HANDLE_VALUE != deviceList[i].HidDevice) + { + printf("Device #%d: VID: 0x%04X PID: 0x%04X UsagePage: 0x%X Usage: 0x%X\n", + i, + deviceList[i].Attributes.VendorID, + deviceList[i].Attributes.ProductID, + deviceList[i].Caps.UsagePage, + deviceList[i].Caps.Usage); + } + else + { + printf("Device #%d: %s (error opening the device)\n", + i, + (NULL != deviceList[i].DevicePath) ? deviceList[i].DevicePath : ""); + } + } + break; + + case 2: + if (nArgs < 3) + { + bPrintHelp = TRUE; + break; + } + + // Get the device ID argument + nDevice = wcstoul(szArgList[2], NULL, 10); + + if (nDevice >= numDevices) + { + bPrintHelp = TRUE; + break; + } + + if (INVALID_HANDLE_VALUE == deviceList[nDevice].HidDevice) + { + printf("An error occurred while opening device #%d.\n", nDevice); + break; + } + + CLM_ShowDeviceInfo(&deviceList[nDevice]); + + break; + + case 3: + if (nArgs < 4) + { + bPrintHelp = TRUE; + break; + } + + // szArgList[2]: device_num + nDevice = wcstoul(szArgList[2], NULL, 10); + if (nDevice >= numDevices) + { + bPrintHelp = TRUE; + break; + } + + if (INVALID_HANDLE_VALUE == deviceList[nDevice].HidDevice) + { + printf("An error occurred while opening device #%d.\n", nDevice); + break; + } + + // szArgList[3]: report_ID + reportID = wcstoul(szArgList[3], NULL, 10); + if (reportID>255) { + bPrintHelp = TRUE; + break; + } + + // szArgList[4]: msec_to_sleep + if (nArgs >= 5) + { + msecToSleep = wcstoul(szArgList[4], NULL, 10); + } + + // szArgList[5]: num_reads + if (nArgs >= 6) + { + numReads = wcstoul(szArgList[5], NULL, 10); + if (0 == numReads) + { + numReads = 1; + } + } + else + { + numReads = INFINITE_READS; + } + + CLM_SyncRead(&deviceList[nDevice], (BYTE)reportID, msecToSleep, numReads); + + break; + + case 4: + if (nArgs < 3) + { + bPrintHelp = TRUE; + break; + } + + // szArgList[2]: device_num + nDevice = wcstoul(szArgList[2], NULL, 10); + if (nDevice >= numDevices) + { + bPrintHelp = TRUE; + break; + } + + if (INVALID_HANDLE_VALUE == deviceList[nDevice].HidDevice) + { + printf("An error occurred while opening device #%d.\n", nDevice); + break; + } + + // szArgList[3]: num_reads + if (nArgs >= 4) + { + numReads = wcstoul(szArgList[3], NULL, 10); + if (0 == numReads) + { + numReads = 1; + } + } + else + { + numReads = INFINITE_READS; + } + + CLM_AsyncRead(&deviceList[nDevice], numReads); + + break; + + default: + bPrintHelp = TRUE; + } + + if (bPrintHelp) + { + printf("Syntax: HCLIENT.EXE [arguments]\n" + "\n" + " action: 1 - List HID devices.\n" + "\n" + " 2 - Show device info.\n" + " arguments: device_num\n" + "\n" + " 3 - Do sync reads by calling HidD_GetInputReport.\n" + " arguments: device_num report_id [msec_to_sleep] [num_of_reads]\n" + "\n" + " 4 - Do async reads by calling ReadFile.\n" + " arguments: device_num [num_of_reads]\n"); + } + + printf("Press enter to exit.\n"); + +Done: + if (NULL != deviceList) + { + free(deviceList); + deviceList = NULL; + } + + if (bConsoleAttached) + { + FreeConsole(); + bConsoleAttached = FALSE; + } +} + + +/******************************* +*WinMain: Windows Entry point * +*******************************/ +int PASCAL +WinMain( + _In_ HINSTANCE hInstance, + _In_opt_ HINSTANCE hPrevInstance, + _In_ LPSTR lpCmdLine, + _In_ int nCmdShow +) +{ + LPWSTR *szArgList = NULL; + int nArgs; + + UNREFERENCED_PARAMETER(hPrevInstance); + UNREFERENCED_PARAMETER(lpCmdLine); + UNREFERENCED_PARAMETER(nCmdShow); + + // + // Save instance of the application for further reference + // + + hGInstance = hInstance; + + // + // Attempt to load HID.DLL...This should already be loaded due to the + // static linking of HID.DLL to this app on compilation. However, + // to insure that this application runs on Windows 98 gold, we cannot + // directly reference the new functions HidP_GetExtendedAttributes and + // HidP_InitializeReportForID so to use them, we'll get pointers to their + // functions instead. + // + + HIDDLLModuleHandle = LoadLibrary("HID.DLL"); + + if (NULL == HIDDLLModuleHandle) + { + // + // Something really bad happened here...Throw up and error dialog + // and bolt. + // + + MessageBox(NULL, + "Unable to open HID.DLL\n" + "This should never occur", + HCLIENT_ERROR, + MB_ICONSTOP); + + goto Done; + } + + // + // Get the function pointers, + // + + pfnHidP_GetExtendedAttributes = (PGETEXTATTRIB) GetProcAddress(HIDDLLModuleHandle, + "HidP_GetExtendedAttributes"); + + pfnHidP_InitializeReportForID = (PINITREPORT) GetProcAddress(HIDDLLModuleHandle, + "HidP_InitializeReportForID"); + + if (NULL == pfnHidP_GetExtendedAttributes || + NULL == pfnHidP_InitializeReportForID) + { + goto Done; + } + + szArgList = CommandLineToArgvW(GetCommandLineW(), &nArgs); + + if (NULL != szArgList && nArgs > 1) + { + // + // Command Line mode + // + + RunInCommandLineMode(szArgList, nArgs); + } + else + { + // + // Try to create the main dialog box. Cannot do much else if it fails + // so we'll throw up a message box and then exit the app + // + + if (-1 == DialogBox(hInstance, "MAIN_DIALOG", NULL, bMainDlgProc)) + { + MessageBox(NULL, + "Unable to create root dialog!", + "DialogBox failure", + MB_ICONSTOP); + } + } + +Done: + if (NULL != szArgList) + { + LocalFree(szArgList); + szArgList = NULL; + } + + if (NULL != HIDDLLModuleHandle) + { + FreeLibrary (HIDDLLModuleHandle); + } + + return (0); +} + +/************************************************* + * Main Dialog proc * + *************************************************/ + +// +// This the dialog box procedure for the main dialog display. +// + +INT_PTR CALLBACK +bMainDlgProc( + HWND hDlg, + UINT message, + WPARAM wParam, + LPARAM lParam +) +{ + static HWND hComboCtrl; + static rWriteDataStruct rWriteData[MAX_OUTPUT_ELEMENTS]; + static HDEVNOTIFY diNotifyHandle; + INT iIndex; + INT iCount; + CHAR szTempBuff[SMALL_BUFF]; + PHID_DEVICE pDevice; + PHIDP_BUTTON_CAPS pButtonCaps; + PHIDP_VALUE_CAPS pValueCaps; + INT iErrorLine; + INT iItemType; + PHID_DEVICE tempDeviceList = NULL; + ULONG numberDevices; + PDEVICE_LIST_NODE listNode; + DEV_BROADCAST_DEVICEINTERFACE broadcastInterface; + HID_DEVICE writeDevice; + BOOL status = FALSE; + PDEV_BROADCAST_HDR broadcastHdr; + + ZeroMemory(&writeDevice, sizeof(writeDevice)); + + switch (message) + { + case WM_INITDIALOG: + + // + // Initialize the device list. + // -- PhysicalDeviceList is for devices that are actually attached + // to the HID bus + // + + InitializeList(&PhysicalDeviceList); + + // + // Begin by finding all the Physical HID devices currently attached to + // the system. If that fails, exit the dialog box. + // + + if (!FindKnownHidDevices(&tempDeviceList, &numberDevices)) + { + EndDialog(hDlg, 0); + return FALSE; + } + + // + // For each device in the newly acquired list, create a device list + // node and add it the the list of physical device on the system + // + + pDevice = tempDeviceList; + for (iIndex = 0; (ULONG) iIndex < numberDevices; iIndex++, pDevice++) + { + listNode = malloc(sizeof(DEVICE_LIST_NODE)); + + if (NULL == listNode) { + + // + // When freeing up the device list, we need to kill those + // already in the Physical Device List and close + // that have not been added yet in the enumerated list + // + + DestroyListWithCallback(&PhysicalDeviceList, DestroyDeviceListCallback); + + CloseHidDevices(pDevice, numberDevices - iIndex); + + free(tempDeviceList); + + EndDialog(hDlg, 0); + return FALSE; + } + + listNode -> HidDeviceInfo = *pDevice; + listNode -> DeviceOpened = (INVALID_HANDLE_VALUE == pDevice->HidDevice) ? FALSE : TRUE; + + if (listNode -> DeviceOpened) + { + // + // Register this device node with the PnP system so the dialog + // window can recieve notification if this device is unplugged. + // + + if (!RegisterHidDevice(hDlg, listNode)) + { + StringCbPrintf(szTempBuff, + SMALL_BUFF, + "Failed registering device notifications for device #%d. Device changes won't be handled", + iIndex); + + MessageBox(hDlg, + szTempBuff, + HCLIENT_ERROR, + MB_ICONEXCLAMATION); + } + } + + InsertTail(&PhysicalDeviceList, listNode); + } + + // + // Free the temporary device list...It is no longer needed + // + + free(tempDeviceList); + + // + // Register for notification from the HidDevice class. Doing so + // allows the dialog box to receive device change notifications + // whenever a new HID device is added to the system + // + + broadcastInterface.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE); + broadcastInterface.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; + + HidD_GetHidGuid(&broadcastInterface.dbcc_classguid); + + diNotifyHandle = RegisterDeviceNotification(hDlg, + &broadcastInterface, + DEVICE_NOTIFY_WINDOW_HANDLE + ); + if (NULL == diNotifyHandle) + { + MessageBox(hDlg, + "Failed registering HID device class notifications. New devices won't be handled.", + HCLIENT_ERROR, + MB_ICONEXCLAMATION); + } + + // + // Update the device list box... + // + // + + vLoadDevices(GetDlgItem(hDlg, IDC_DEVICES)); + + // + // Load the types box + // + + vLoadItemTypes(GetDlgItem(hDlg, IDC_TYPE)); + + // + // Post a message that the device changed so the appropriate + // data for the first device in the system can be displayed + // + + PostMessage(hDlg, + WM_COMMAND, + IDC_DEVICES + (CBN_SELCHANGE<<16), + (LPARAM) GetDlgItem(hDlg, IDC_DEVICES)); + + break; // end WM_INITDIALOG case + + case WM_COMMAND: + + switch(LOWORD(wParam)) + { + // + // For a read, simply get the current device instance + // from the DEVICES combo box and call the read procedure + // with the HID_DEVICE block + // + + case IDC_READ: + GET_CURRENT_DEVICE(hDlg, pDevice); + + if (NULL != pDevice) + { + DialogBoxParam(hGInstance, + "READDATA", + hDlg, + bReadDlgProc, + (LPARAM) pDevice); + } + break; + + // + // For a write, the following steps are performed: + // 1) Get the current device data from the combo box + // 2) Prepare the data fields for display based on the data + // output data stored in the device data + // 3) Retrieve the data the from the user that is to be sent + // to the device + // 4) If all goes well and the data parses correctly, send the + // the new data values to the device + // + + case IDC_WRITE: + + GET_CURRENT_DEVICE(hDlg, pDevice); + + if (NULL != pDevice) + { + // + // In order to write to the device, need to get a + // writable handle to the device. In this case, the + // write will be a synchronous write. Begin by + // trying to open a second instance of this device with + // write access + // + + status = OpenHidDevice(pDevice -> DevicePath, + FALSE, + TRUE, + FALSE, + FALSE, + &writeDevice); + + if (!status) + { + MessageBox(hDlg, + "Couldn't open device for write access", + HCLIENT_ERROR, + MB_ICONEXCLAMATION); + } + else + { + iCount = iPrepareDataFields(writeDevice.OutputData, + writeDevice.OutputDataLength, + rWriteData, + MAX_OUTPUT_ELEMENTS); + + if (bGetData(rWriteData, iCount, hDlg, "WRITEDATA")) + { + + if (bParseData(writeDevice.OutputData, rWriteData, iCount, &iErrorLine)) + { + Write(&writeDevice); + } + else + { + if (FAILED(StringCbPrintf(szTempBuff, + SMALL_BUFF, + "Unable to parse line %x of output data", + iErrorLine))) + { + MessageBox(hDlg, + "StringCbPrintf failed", + HCLIENT_ERROR, + MB_ICONEXCLAMATION); + } + else + { + MessageBox(hDlg, + szTempBuff, + HCLIENT_ERROR, + MB_ICONEXCLAMATION); + } + } + } + CloseHidDevice(&writeDevice); + } + + } + break; //end case IDC_WRITE// + + // + // For processing features, get the current device data and call + // the Features dialog box, This dialog box will deal with + // sending and retrieving the features. + // + + case IDC_FEATURES: + GET_CURRENT_DEVICE(hDlg, pDevice); + + if (NULL != pDevice) + { + DialogBoxParam(hGInstance, + "FEATURES", + hDlg, + bFeatureDlgProc, + (LPARAM) pDevice); + } + break; + + // + // Likewise with extended calls dialog box. This procedure + // passes the address to the device data structure and lets + // the dialog box procedure manipulate the data however it + // wants to. + // + + case IDC_EXTCALLS: + GET_CURRENT_DEVICE(hDlg, pDevice); + + if (NULL != pDevice) + { + DialogBoxParam(hGInstance, + "EXTCALLS", + hDlg, + bExtCallDlgProc, + (LPARAM) pDevice); + } + break; + + // + // If there was a device change, issue an IDC_TYPE + // change to insure that the currently displayed types are + // updated to reflect the values of the device that has + // been selected + // + + case IDC_DEVICES: + switch (HIWORD(wParam)) + { + case CBN_SELCHANGE: + + GET_CURRENT_DEVICE(hDlg, pDevice); + + EnableWindow(GetDlgItem(hDlg, IDC_EXTCALLS), + (pDevice != NULL)); + + EnableWindow(GetDlgItem(hDlg, IDC_READ), + (pDevice != NULL) && + (pDevice -> Caps.InputReportByteLength)); + + EnableWindow(GetDlgItem(hDlg, IDC_WRITE), + (pDevice != NULL) && + (pDevice -> Caps.OutputReportByteLength)); + + EnableWindow(GetDlgItem(hDlg, IDC_FEATURES), + (pDevice != NULL) && + (pDevice -> Caps.FeatureReportByteLength)); + + PostMessage(hDlg, + WM_COMMAND, + IDC_TYPE + (CBN_SELCHANGE<<16), + (LPARAM) GetDlgItem(hDlg,IDC_TYPE)); + break; + + } + break; + + // + // On a type change, retrieve the currently active device + // from the IDC_DEVICES box and display the data that + // corresponds to the item just selected + // + + case IDC_TYPE: + switch (HIWORD(wParam)) + { + case CBN_SELCHANGE: + GET_CURRENT_DEVICE(hDlg, pDevice); + + SendDlgItemMessage(hDlg, + IDC_ITEMS, + LB_RESETCONTENT, + 0, + 0); + + SendDlgItemMessage(hDlg, + IDC_ATTRIBUTES, + LB_RESETCONTENT, + 0, + 0); + + if (NULL != pDevice) + { + iIndex = (INT) SendDlgItemMessage(hDlg, + IDC_TYPE, + CB_GETCURSEL, + 0, + 0); + + iItemType = (INT) SendDlgItemMessage(hDlg, + IDC_TYPE, + CB_GETITEMDATA, + iIndex, + 0); + + switch(iItemType) + { + case INPUT_BUTTON: + vDisplayInputButtons(pDevice,GetDlgItem(hDlg,IDC_ITEMS)); + break; + + case INPUT_VALUE: + vDisplayInputValues(pDevice,GetDlgItem(hDlg,IDC_ITEMS)); + break; + + case OUTPUT_BUTTON: + vDisplayOutputButtons(pDevice,GetDlgItem(hDlg,IDC_ITEMS)); + break; + + case OUTPUT_VALUE: + vDisplayOutputValues(pDevice,GetDlgItem(hDlg,IDC_ITEMS)); + break; + + case FEATURE_BUTTON: + vDisplayFeatureButtons(pDevice,GetDlgItem(hDlg,IDC_ITEMS)); + break; + + case FEATURE_VALUE: + vDisplayFeatureValues(pDevice,GetDlgItem(hDlg,IDC_ITEMS)); + break; + } + + PostMessage(hDlg, + WM_COMMAND, + IDC_ITEMS + (LBN_SELCHANGE << 16), + (LPARAM) GetDlgItem(hDlg,IDC_ITEMS)); + } + break; // case CBN_SELCHANGE + + } //end switch HIWORD wParam + break; //case IDC_TYPE control + + case IDC_ITEMS: + switch(HIWORD(wParam)) + { + case LBN_SELCHANGE: + + iItemType = 0; + + iIndex = (INT) SendDlgItemMessage(hDlg, + IDC_TYPE, + CB_GETCURSEL, + 0, + 0); + + if (-1 != iIndex) + { + iItemType = (INT) SendDlgItemMessage(hDlg, + IDC_TYPE, + CB_GETITEMDATA, + iIndex, + 0); + } + + iIndex = (INT) SendDlgItemMessage(hDlg, + IDC_ITEMS, + LB_GETCURSEL, + 0, + 0); + + switch (iItemType) + { + case INPUT_BUTTON: + case OUTPUT_BUTTON: + case FEATURE_BUTTON: + + pButtonCaps = NULL; + + if (-1 != iIndex) + { + pButtonCaps = (PHIDP_BUTTON_CAPS) SendDlgItemMessage(hDlg, + IDC_ITEMS, + LB_GETITEMDATA, + iIndex, + 0); + } + + SendDlgItemMessage(hDlg, IDC_ATTRIBUTES, LB_RESETCONTENT, 0, 0); + if (NULL != pButtonCaps) + { + vDisplayButtonAttributes(pButtonCaps, GetDlgItem(hDlg,IDC_ATTRIBUTES)); + } + break; + + case INPUT_VALUE: + case OUTPUT_VALUE: + case FEATURE_VALUE: + + pValueCaps = NULL; + + if (-1 != iIndex) + { + pValueCaps = (PHIDP_VALUE_CAPS) SendDlgItemMessage(hDlg, + IDC_ITEMS, + LB_GETITEMDATA, + iIndex, + 0); + } + + SendDlgItemMessage(hDlg, IDC_ATTRIBUTES, LB_RESETCONTENT, 0, 0); + + if (NULL != pValueCaps) + { + vDisplayValueAttributes(pValueCaps,GetDlgItem(hDlg,IDC_ATTRIBUTES)); + } + break; + + case HID_CAPS: + GET_CURRENT_DEVICE(hDlg, pDevice); + + if (NULL != pDevice) + { + vDisplayDeviceCaps(&(pDevice -> Caps),GetDlgItem(hDlg,IDC_ATTRIBUTES)); + } + break; + + case DEVICE_ATTRIBUTES: + GET_CURRENT_DEVICE(hDlg, pDevice); + + if (NULL != pDevice) + { + SendDlgItemMessage(hDlg, IDC_ATTRIBUTES, LB_RESETCONTENT, 0, 0); + + vDisplayDeviceAttributes(&(pDevice -> Attributes) ,GetDlgItem(hDlg,IDC_ATTRIBUTES)); + } + break; + + } //end switch iItemType// + break; //end case LBN_SELCHANGE in IDC_ITEMS// + + } //end switch HIWORD wParam// + break; //case IDC_ITEMS// + + case IDC_ABOUT: + + MessageBox(hDlg, + "Sample HID client Application. Microsoft Corp \nCopyright (C) 1997", + "About HClient", + MB_ICONINFORMATION); + break; + + case IDOK: + case IDCANCEL: + + // + // Destroy the physical device list for exit + // + + DestroyListWithCallback(&PhysicalDeviceList, DestroyDeviceListCallback); + + EndDialog(hDlg,0); + + break; + + } //end switch wParam// + break; + + // + // For a device change message, we are only concerned about the + // DBT_DEVICEREMOVECOMPLETE and DBT_DEVICEARRIVAL events. I have + // yet to determine how to process the device change message + // only for HID devices. Therefore, there are two problems + // with the below implementation. First of all, we must reload + // the device list any time a device is added to the system. + // Secondly, at least two DEVICEARRIVAL messages are received + // per HID. One corresponds to the physical device. The second + // change and any more correspond to each collection on the + // physical device so a system that has one HID device with + // two top level collections (a keyboard and a mouse) will receive + // three DEVICEARRIVAL/REMOVALs causing the program to reload it's + // device list more than once. + // + + // + // To handle dynamic changing of devices, we have already registered + // notification for both HID class changes and for notification + // for our open file objects. Since we are only concerned about + // arrival/removal of devices, we only need to process those wParam. + // lParam points to some sort of DEV_BROADCAST_HDR struct. For device + // arrival, we only deal with the message if that struct is a + // DEV_BROADCAST_DEVICEINTERFACE structure. For device removal, we're + // only concerned if the struct is a DEV_BROADCAST_HANDLE structure. + // + + case WM_DEVICECHANGE: + switch (wParam) + { + + case DBT_DEVICEARRIVAL: + + broadcastHdr = (PDEV_BROADCAST_HDR) lParam; + + if (DBT_DEVTYP_DEVICEINTERFACE == broadcastHdr -> dbch_devicetype) + { + PDEV_BROADCAST_DEVICEINTERFACE pbroadcastInterface; + PDEVICE_LIST_NODE currNode, nextNode; + BOOLEAN phyDevListChanged = FALSE; + + pbroadcastInterface = (PDEV_BROADCAST_DEVICEINTERFACE) lParam; + + // + // Search for a previous instance of this device + // in the device list...In some cases, multiple + // messages are received for the same device. We + // obviously only want one instance of the device + // showing up in the dialog box. + // + + currNode = (PDEVICE_LIST_NODE) GetListHead(&PhysicalDeviceList); + + // + // Check if the device is already in the list + // - If yes and the device is opened, ignore this notification. + // - If yes but the device is not opened, remove this node and + // then continne to process it as a new device. (We may have + // failed opening this device earlier, so it was not removed + // the list when the device was removed. Now it's connected + // again and we should keep only one instance in the list.) + // - If no, continue to process it as a new device. + // + + while (currNode != (PDEVICE_LIST_NODE)&PhysicalDeviceList) + { + // + // save the next node pointer first as we may remove + // the current node. + // + + nextNode = (PDEVICE_LIST_NODE) GetNextEntry(currNode); + + if ((NULL != currNode->HidDeviceInfo.DevicePath) && + (0 == strcmp(currNode -> HidDeviceInfo.DevicePath, + pbroadcastInterface -> dbcc_name))) + { + if (currNode -> DeviceOpened == FALSE) + { + // + // Remove the node from the list + // + + RemoveNode(currNode); + + // + // Let it free the memory of the device path string + // + + CloseHidDevice(&currNode -> HidDeviceInfo); + + // + // Free the memory of the node structure + // + + free(currNode); + + phyDevListChanged = TRUE; + } + else + { + return (TRUE); + } + } + + // + // Move to the next node + // + currNode = nextNode; + } + + // + // In this structure, we are given the name of the device + // to open. So all that needs to be done is open + // a new hid device with the string + // + + listNode = (PDEVICE_LIST_NODE) malloc(sizeof(DEVICE_LIST_NODE)); + + if (NULL == listNode) + { + MessageBox(hDlg, + "Error -- Couldn't allocate memory for new device list node", + HCLIENT_ERROR, + MB_ICONEXCLAMATION | MB_OK | MB_TASKMODAL); + } + else + { + + // + // Open the hid device for query access + // + + if (!OpenHidDevice (pbroadcastInterface -> dbcc_name, + FALSE, + FALSE, + FALSE, + FALSE, + &(listNode -> HidDeviceInfo))) + { + // + // Save the device path so it can be still listed. + // + + INT iDevicePathSize; + + iDevicePathSize = (INT)strlen(pbroadcastInterface -> dbcc_name) + 1; + + listNode -> HidDeviceInfo.DevicePath = malloc(iDevicePathSize); + + if (NULL == listNode -> HidDeviceInfo.DevicePath) + { + MessageBox(hDlg, + "Error -- Couldn't allocate memory for new device path", + HCLIENT_ERROR, + MB_ICONEXCLAMATION | MB_OK | MB_TASKMODAL); + + free(listNode); + + listNode = NULL; + } + else + { + StringCbCopy(listNode -> HidDeviceInfo.DevicePath, iDevicePathSize, pbroadcastInterface -> dbcc_name); + } + } + + if (NULL != listNode) + { + listNode -> DeviceOpened = (INVALID_HANDLE_VALUE == listNode -> HidDeviceInfo.HidDevice) ? FALSE : TRUE; + + if (listNode -> DeviceOpened) { + + if (!RegisterHidDevice(hDlg, listNode)) + { + MessageBox(hDlg, + "Error -- Couldn't register handle notification", + HCLIENT_ERROR, + MB_ICONEXCLAMATION | MB_OK | MB_TASKMODAL); + } + } + + InsertTail(&PhysicalDeviceList, listNode); + + phyDevListChanged = TRUE; + } + } + + if (phyDevListChanged) + { + vLoadDevices(GetDlgItem(hDlg,IDC_DEVICES)); + + PostMessage(hDlg, + WM_COMMAND, + IDC_DEVICES + (CBN_SELCHANGE << 16), + (LPARAM) GetDlgItem(hDlg,IDC_DEVICES)); + } + } + break; + + case DBT_DEVICEQUERYREMOVE: + + // + // If this message is received, the device is either + // being disabled or removed through device manager. + // To properly handle this request, we need to close + // the handle to the device. + // + + broadcastHdr = (PDEV_BROADCAST_HDR) lParam; + + if (DBT_DEVTYP_HANDLE == broadcastHdr -> dbch_devicetype) + { + PDEV_BROADCAST_HANDLE broadcastHandle; + PDEVICE_LIST_NODE currNode; + HDEVNOTIFY notificationHandle; + + broadcastHandle = (PDEV_BROADCAST_HANDLE) lParam; + + // + // Get the handle to the notification registration + // + + notificationHandle = broadcastHandle -> dbch_hdevnotify; + + // + // Search the physical device list for the handle that + // was removed... + // + + currNode = (PDEVICE_LIST_NODE) GetListHead(&PhysicalDeviceList); + + // + // Find out the device to close its handle + // + + while (currNode != (PDEVICE_LIST_NODE)&PhysicalDeviceList) + { + if (currNode ->NotificationHandle == notificationHandle) + { + if (currNode -> DeviceOpened) + { + CloseHidDevice(&(currNode -> HidDeviceInfo)); + + currNode -> DeviceOpened = FALSE; + } + + break; + } + + currNode = (PDEVICE_LIST_NODE) GetNextEntry(currNode); + } + + } + return (TRUE); + + case DBT_DEVICEREMOVEPENDING: + case DBT_DEVICEREMOVECOMPLETE: + + // + // Do the same steps for DBT_DEVICEREMOVEPENDING and + // DBT_DEVICEREMOVECOMPLETE. We do not receive the + // remove complete request for a device if it is + // disabled or removed via Device Manager. However, + // in that case will receive the remove pending. + // We remove the device from our currently displayed + // list of devices and unregister notification. + // + + broadcastHdr = (PDEV_BROADCAST_HDR) lParam; + + if (DBT_DEVTYP_HANDLE == broadcastHdr -> dbch_devicetype) + { + PDEV_BROADCAST_HANDLE broadcastHandle; + PDEVICE_LIST_NODE currNode; + HDEVNOTIFY notificationHandle; + + broadcastHandle = (PDEV_BROADCAST_HANDLE) lParam; + + // + // Get the handle for device notification + // + + notificationHandle = broadcastHandle -> dbch_hdevnotify; + + // + // Search the physical device list for the handle that + // was removed... + // + + currNode = (PDEVICE_LIST_NODE) GetListHead(&PhysicalDeviceList); + + while (currNode != (PDEVICE_LIST_NODE)&PhysicalDeviceList) + { + if(currNode ->NotificationHandle == notificationHandle) + { + // + // Node in PhysicalDeviceList has been found, do: + // 1) Unregister notification + // 2) Close the hid device + // 3) Remove the entry from the list + // 4) Free the memory for the entry + // + + PostMessage(hDlg, + WM_UNREGISTER_HANDLE, + 0, + (LPARAM) currNode -> NotificationHandle); + + // + // Close the device if still opened...This would + // occur on surprise removal. + // + + if (currNode -> DeviceOpened) + { + CloseHidDevice(&(currNode -> HidDeviceInfo)); + } + + RemoveNode(currNode); + + free(currNode); + + // + // Reload the device list + // + + vLoadDevices(GetDlgItem(hDlg,IDC_DEVICES)); + + PostMessage(hDlg, + WM_COMMAND, + IDC_DEVICES + (CBN_SELCHANGE << 16), + (LPARAM) GetDlgItem(hDlg,IDC_DEVICES)); + break; + } + + // + // The node has not been found yet. Move on to the next + // + + currNode = (PDEVICE_LIST_NODE) GetNextEntry(currNode); + } + + return TRUE; + } + break; + + default: + break; + } + break; + + // + // Application specific message used to defer the unregistering of a + // file object for device change notification. This separte message + // is sent when a WM_DEVICECHANGE (DBT_DEVICEREMOVECOMPLETE) has been + // received. The Unregistering of the notification must be deferred + // until after the WM_DEVICECHANGE message has been processed or the + // system will deadlock. The handle that is to be freed will be passed + // in as lParam for this message + // + + case WM_UNREGISTER_HANDLE: + UnregisterDeviceNotification ( (HDEVNOTIFY) lParam ); + break; + + } // end switch message + return FALSE; +} // end MainDlgProc + + +BOOL +bParseData( + PHID_DATA pData, + rWriteDataStruct rWriteData[], + int iCount, + int *piErrorLine +) +{ + INT iCap; + PHID_DATA pWalk; + BOOL noError = TRUE; + + pWalk = pData; + + for (iCap = 0; (iCap < iCount) && noError; iCap++) + { + // + // Check to see if our data is a value cap or not + // + + if (!pWalk->IsButtonData) + { + pWalk -> ValueData.Value = atol(rWriteData[iCap].szValue); + } + else + { + if (!bSetButtonUsages(pWalk, rWriteData[iCap].szValue) ) + { + *piErrorLine = iCap; + + noError = FALSE; + } + } + pWalk++; + } + return (noError); +} + +BOOL +bSetButtonUsages( + PHID_DATA pCap, + _In_ LPSTR pszInputString +) +{ + CHAR szTempString[SMALL_BUFF]; + CHAR pszDelimiter[] = " "; + CHAR *pszContext = NULL; + PCHAR pszToken; + INT iLoop; + PUSAGE pUsageWalk; + BOOL bNoError=TRUE; + + if(FAILED(StringCbCopy(szTempString, SMALL_BUFF, pszInputString) )) + { + return FALSE; + } + +#pragma warning(push) +#pragma prefast(disable:28193, "pszToken and pUsageWalk are examined") + + pszToken = strtok_s(szTempString, pszDelimiter, &pszContext); + + pUsageWalk = pCap -> ButtonData.Usages; + + memset(pUsageWalk, 0, pCap->ButtonData.MaxUsageLength * sizeof(USAGE)); + + for (iLoop = 0; ((ULONG) iLoop < pCap->ButtonData.MaxUsageLength) && (pszToken != NULL) && bNoError; iLoop++) + { + *pUsageWalk = (USAGE) atoi(pszToken); + + pszToken = strtok_s(NULL, pszDelimiter, &pszContext); + + pUsageWalk++; + } +#pragma warning(pop) + + return bNoError; +} //end function bSetButtonUsages// + + +INT +iPrepareDataFields( + PHID_DATA pData, + ULONG ulDataLength, + rWriteDataStruct rWriteData[], + int iMaxElements +) +{ + INT i; + PHID_DATA pWalk; + + pWalk = pData; + + for (i = 0; (i < iMaxElements) && ((unsigned) i < ulDataLength); i++) + { + if (!pWalk->IsButtonData) + { + StringCbPrintf(rWriteData[i].szLabel, + MAX_LABEL, + "ValueCap; ReportID: 0x%x, UsagePage=0x%x, Usage=0x%x", + pWalk->ReportID, + pWalk->UsagePage, + pWalk->ValueData.Usage); + } + else + { + StringCbPrintf(rWriteData[i].szLabel, + MAX_LABEL, + "Button; ReportID: 0x%x, UsagePage=0x%x, UsageMin: 0x%x, UsageMax: 0x%x", + pWalk->ReportID, + pWalk->UsagePage, + pWalk->ButtonData.UsageMin, + pWalk->ButtonData.UsageMax); + } + pWalk++; + } + return i; +} //end function iPrepareDataFields// + + +INT_PTR CALLBACK +bReadDlgProc( + HWND hDlg, + UINT message, + WPARAM wParam, + LPARAM lParam +) +{ + static INT iLbCounter; + static CHAR szTempBuff[1024]; + static READ_THREAD_CONTEXT readContext; + static HANDLE readThread; + static HID_DEVICE syncDevice; + static HID_DEVICE asyncDevice; + static BOOL doAsyncReads; + static BOOL doSyncReads; + + PHID_DEVICE pDevice; + DWORD threadID; + INT iIndex; + PHID_DATA pData; + UINT uLoop; + + + switch(message) + { + case WM_INITDIALOG: + + // + // Initialize the list box counter, the readThread, and the + // readContext.DisplayEvent. + // + + iLbCounter = 0; + readThread = NULL; + readContext.DisplayEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + + if (NULL == readContext.DisplayEvent) + { + EndDialog(hDlg, 0); + } + + // + // Get the opened device information for the device to perform + // reads upon + // + + pDevice = (PHID_DEVICE) lParam; + + // + // To do sync and async reads requires file handles with different + // attributes (ie. an async must be opened with the OVERLAPPED flag + // set). The device node that was passed in the context parameter + // was not opened for reading. Therefore, two more devices will + // be opened, one for async reads and one for sync reads. + // + + doSyncReads = OpenHidDevice(pDevice -> DevicePath, + TRUE, + FALSE, + FALSE, + FALSE, + &syncDevice); + + if (!doSyncReads) + { + MessageBox(hDlg, + "Unable to open device for synchronous reading", + HCLIENT_ERROR, + MB_ICONEXCLAMATION); + } + + // + // For asynchronous read, default to using the same information + // passed in as the lParam. This is because data related to + // Ppd and such cannot be retrieved using the standard HidD_ + // functions. However, it is necessary to parse future reports. + // + + doAsyncReads = OpenHidDevice(pDevice -> DevicePath, + TRUE, + FALSE, + TRUE, + FALSE, + &asyncDevice); + + if (!doAsyncReads) + { + MessageBox(hDlg, + "Unable to open device for asynchronous reading", + HCLIENT_ERROR, + MB_ICONEXCLAMATION); + } + + PostMessage(hDlg, WM_READ_DONE, 0, 0); + break; + + case WM_DISPLAY_READ_DATA: + + // + // LParam is the device that was read from + // + + pDevice = (PHID_DEVICE) lParam; + + // + // Display all the data stored in the Input data field for the device + // + + pData = pDevice -> InputData; + + SendDlgItemMessage(hDlg, + IDC_OUTPUT, + LB_ADDSTRING, + 0, + (LPARAM)"-------------------------------------------"); + + iLbCounter++; + + if (iLbCounter > MAX_LB_ITEMS) + { + SendDlgItemMessage(hDlg, + IDC_OUTPUT, + LB_DELETESTRING, + 0, + 0); + } + + for (uLoop = 0; uLoop < pDevice->InputDataLength; uLoop++) + { + ReportToString(pData, szTempBuff, sizeof(szTempBuff)); + + iIndex = (INT) SendDlgItemMessage(hDlg, + IDC_OUTPUT, + LB_ADDSTRING, + 0, + (LPARAM) szTempBuff); + + SendDlgItemMessage(hDlg, + IDC_OUTPUT, + LB_SETCURSEL, + iIndex, + 0); + + iLbCounter++; + + if (iLbCounter > MAX_LB_ITEMS) + { + SendDlgItemMessage(hDlg, + IDC_OUTPUT, + LB_DELETESTRING, + 0, + 0); + } + pData++; + } + SetEvent( readContext.DisplayEvent ); + break; + + case WM_READ_DONE: + EnableWindow(GetDlgItem(hDlg, IDOK), TRUE); + EnableWindow(GetDlgItem(hDlg, IDC_READ_SYNCH), doSyncReads); + EnableWindow(GetDlgItem(hDlg, IDC_READ_ASYNCH_ONCE), doAsyncReads); + EnableWindow(GetDlgItem(hDlg, IDC_READ_ASYNCH_CONT), doAsyncReads); + + SetWindowText(GetDlgItem(hDlg, IDC_READ_ASYNCH_ONCE), + "One Asynchronous Read"); + + SetWindowText(GetDlgItem(hDlg, IDC_READ_ASYNCH_CONT), + "Continuous Asynchronous Read"); + + readThread = NULL; + break; + + case WM_COMMAND: + switch(LOWORD(wParam)) + { + case IDC_READ_SYNCH: + + EnableWindow(GetDlgItem(hDlg, IDOK), FALSE); + EnableWindow(GetDlgItem(hDlg, IDC_READ_SYNCH), FALSE); + EnableWindow(GetDlgItem(hDlg, IDC_READ_ASYNCH_ONCE), FALSE); + EnableWindow(GetDlgItem(hDlg, IDC_READ_ASYNCH_CONT), FALSE); + + Read(&syncDevice); + + PostMessage(hDlg, WM_DISPLAY_READ_DATA, 0, (LPARAM) &syncDevice); + PostMessage(hDlg, WM_READ_DONE, 0, 0); + + break; + + case IDC_READ_ASYNCH_ONCE: + case IDC_READ_ASYNCH_CONT: + + // + // When these buttons are pushed there are two options: + // 1) Start a new asynch read thread (readThread == NULL) + // 2) Stop a previous asych read thread + // + + if (NULL == readThread) + { + // + // Start a new read thread + // + + readContext.HidDevice = &asyncDevice; + readContext.TerminateThread = FALSE; + readContext.NumberOfReads = (IDC_READ_ASYNCH_ONCE == LOWORD(wParam))?1:INFINITE_READS; + readContext.DisplayWindow = hDlg; + + readThread = CreateThread( NULL, + 0, + AsynchReadThreadProc, + &readContext, + 0, + &threadID); + + if (NULL == readThread) + { + MessageBox(hDlg, + "Unable to create read thread", + HCLIENT_ERROR, + MB_ICONEXCLAMATION); + } + else + { + EnableWindow(GetDlgItem(hDlg, IDOK), FALSE); + EnableWindow(GetDlgItem(hDlg, IDC_READ_SYNCH), FALSE); + EnableWindow(GetDlgItem(hDlg, IDC_READ_ASYNCH_ONCE), + IDC_READ_ASYNCH_ONCE == LOWORD(wParam)); + + EnableWindow(GetDlgItem(hDlg, IDC_READ_ASYNCH_CONT), + IDC_READ_ASYNCH_CONT == LOWORD(wParam)); + + SetWindowText(GetDlgItem(hDlg, LOWORD(wParam)), + "Stop Asynchronous Read"); + } + } + else + { + // + // Signal the terminate thread variable and + // wait for the read thread to complete. + // + + readContext.TerminateThread = TRUE; + WaitForSingleObject(readThread, INFINITE); + } + break; + + case IDCANCEL: + readContext.TerminateThread = TRUE; + WaitForSingleObject(readThread, INFINITE); + //Fall through!!! + + case IDOK: + CloseHidDevice(&asyncDevice); + EndDialog(hDlg,0); + break; + } + break; + } // end switch message + return FALSE; +} // end bReadDlgProc + +VOID +ReportToString( + PHID_DATA pData, + _Inout_updates_bytes_(iBuffSize) LPSTR szBuff, + UINT iBuffSize +) +{ + PCHAR pszWalk; + PUSAGE pUsage; + ULONG i; + UINT iRemainingBuffer; + UINT iStringLength; + UINT j; + + // + // For button data, all the usages in the usage list are to be displayed + // + + if (pData -> IsButtonData) + { + if(FAILED(StringCbPrintf (szBuff, + iBuffSize, + "Usage Page: 0x%x, Usages: ", + pData -> UsagePage))) + { + for(j=0; j ButtonData.Usages; + i < pData -> ButtonData.MaxUsageLength; + i++, pUsage++) + { + if (0 == *pUsage) + { + break; // A usage of zero is a non button. + } + if(FAILED(StringCbPrintf (pszWalk, iRemainingBuffer, " 0x%x", *pUsage))) + { + return; // error case + } + iRemainingBuffer -= (UINT)strlen(pszWalk); + pszWalk += strlen(pszWalk); + } + } + else + { + if(FAILED(StringCbPrintf (szBuff, + iBuffSize, + "Usage Page: 0x%x, Usage: 0x%x, Scaled: %d Value: %d", + pData->UsagePage, + pData->ValueData.Usage, + pData->ValueData.ScaledValue, + pData->ValueData.Value))) + { + return; // error case + } + } +} + +INT_PTR CALLBACK +bFeatureDlgProc( + HWND hDlg, + UINT message, + WPARAM wParam, + LPARAM lParam +) +{ + static PHID_DEVICE pDevice; + static INT iLbCounter; + static rWriteDataStruct rWriteData[MAX_WRITE_ELEMENTS]; + static CHAR szTempBuff[1024]; + INT iIndex; + INT iCount; + INT iErrorLine; + PHID_DATA pData; + UINT uLoop; + + switch(message) + { + case WM_INITDIALOG: + iLbCounter = 0; + pDevice = (PHID_DEVICE) lParam; + break; + + case WM_COMMAND: + switch(LOWORD(wParam)) + { + case IDC_READ: + + GetFeature(pDevice); + + pData = pDevice -> FeatureData; + + SendDlgItemMessage(hDlg, + IDC_OUTPUT, + LB_ADDSTRING, + 0, + (LPARAM)"------------ Read Features ---------------"); + + iLbCounter++; + + if (iLbCounter > MAX_LB_ITEMS) + { + SendDlgItemMessage(hDlg, + IDC_OUTPUT, + LB_DELETESTRING, + 0, + 0); + } + + for (uLoop = 0; uLoop < pDevice -> FeatureDataLength; uLoop++) + { + ReportToString(pData, szTempBuff, sizeof(szTempBuff)); + + iIndex = (INT) SendDlgItemMessage(hDlg, + IDC_OUTPUT, + LB_ADDSTRING, + 0, + (LPARAM) szTempBuff); + + SendDlgItemMessage(hDlg, + IDC_OUTPUT, + LB_SETCURSEL, + iIndex, + (LPARAM) 0); + + iLbCounter++; + if (iLbCounter > MAX_LB_ITEMS) + { + SendDlgItemMessage(hDlg, + IDC_OUTPUT, + LB_DELETESTRING, + 0, + 0); + } + pData++; + } + break; + + case IDC_WRITE: + iCount = iPrepareDataFields(pDevice -> FeatureData, + pDevice -> FeatureDataLength, + rWriteData, + MAX_OUTPUT_ELEMENTS); + + if (bGetData(rWriteData, iCount, hDlg, "WRITEFEATURE")) + { + if (!bParseData(pDevice -> FeatureData, rWriteData,iCount, &iErrorLine)) + { + StringCbPrintf(szTempBuff, + sizeof(szTempBuff), + "Unable to parse line %x of output data", + iErrorLine); + + MessageBox(hDlg, + szTempBuff, + HCLIENT_ERROR, + MB_ICONEXCLAMATION); + } + else + { + if ( SetFeature(pDevice) ) + { + SendDlgItemMessage(hDlg, + IDC_OUTPUT, + LB_ADDSTRING, + 0, + (LPARAM)"------------ Write Feature ---------------"); + } + else + { + SendDlgItemMessage(hDlg, + IDC_OUTPUT, + LB_ADDSTRING, + 0, + (LPARAM)"------------ Write Feature Error ---------------"); + } + } + } + break; + + + case IDOK: + case IDCANCEL: + EndDialog(hDlg,0); + break; + } + break; + } //end switch message// + return FALSE; +} //end bReadDlgProc// + +VOID +vDisplayDeviceCaps( + IN PHIDP_CAPS pCaps, + IN HWND hControl +) +{ + static CHAR szTempBuff[SMALL_BUFF]; + + SendMessage(hControl, LB_RESETCONTENT, 0, 0); + + StringCbPrintf(szTempBuff, SMALL_BUFF, "Usage Page: 0x%x", pCaps -> UsagePage); + SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff); + + StringCbPrintf(szTempBuff, SMALL_BUFF, "Usage: 0x%x",pCaps -> Usage); + SendMessage(hControl,LB_ADDSTRING, 0, (LPARAM) szTempBuff); + + StringCbPrintf(szTempBuff, SMALL_BUFF, "Input report byte length: %d",pCaps -> InputReportByteLength); + SendMessage(hControl,LB_ADDSTRING, 0, (LPARAM) szTempBuff); + + StringCbPrintf(szTempBuff, SMALL_BUFF, "Output report byte length: %d",pCaps -> OutputReportByteLength); + SendMessage(hControl,LB_ADDSTRING, 0, (LPARAM) szTempBuff); + + StringCbPrintf(szTempBuff, SMALL_BUFF, "Feature report byte length: %d",pCaps -> FeatureReportByteLength); + SendMessage(hControl,LB_ADDSTRING, 0, (LPARAM) szTempBuff); + + StringCbPrintf(szTempBuff, SMALL_BUFF, "Number of collection nodes %d: ", pCaps -> NumberLinkCollectionNodes); + SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff); + + return; +} + +VOID +vDisplayDeviceAttributes( + PHIDD_ATTRIBUTES pAttrib, + HWND hControl +) +{ + static CHAR szTempBuff[SMALL_BUFF]; + + StringCbPrintf(szTempBuff, SMALL_BUFF, "Vendor ID: 0x%x", pAttrib -> VendorID); + SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff); + + StringCbPrintf(szTempBuff, SMALL_BUFF, "Product ID: 0x%x", pAttrib -> ProductID); + SendMessage(hControl, LB_ADDSTRING, 0,(LPARAM) szTempBuff); + + StringCbPrintf(szTempBuff, SMALL_BUFF, "Version Number 0x%x", pAttrib -> VersionNumber); + SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff); + + return; +} + +VOID +vDisplayDataAttributes( + PHIDP_DATA pData, + BOOL IsButton, + HWND hControl +) +{ + static CHAR szTempBuff[SMALL_BUFF]; + + SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) "================"); + + StringCbPrintf(szTempBuff, SMALL_BUFF, "Index: 0x%x", pData -> DataIndex); + SendMessage(hControl,LB_ADDSTRING, 0, (LPARAM) szTempBuff); + + StringCbPrintf(szTempBuff, SMALL_BUFF, "IsButton: %s", IsButton ? "TRUE" : "FALSE"); + SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff); + + if (IsButton) + { + StringCbPrintf(szTempBuff, SMALL_BUFF, "Button pressed: %s", pData -> On ? "TRUE" : "FALSE"); + SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff); + } + else + { + StringCbPrintf(szTempBuff, SMALL_BUFF, "Data value: 0x%x", pData -> RawValue); + SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff); + } +} + +VOID +vDisplayButtonAttributes( + IN PHIDP_BUTTON_CAPS pButton, + IN HWND hControl +) +{ + static CHAR szTempBuff[SMALL_BUFF]; + + StringCbPrintf(szTempBuff, SMALL_BUFF, "Report ID: 0x%x", pButton->ReportID); + SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff); + + StringCbPrintf(szTempBuff, SMALL_BUFF, "Usage Page: 0x%x", pButton->UsagePage); + SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff); + + StringCbPrintf(szTempBuff, + SMALL_BUFF, + "Alias: %s", + pButton -> IsAlias ? "TRUE" : "FALSE"); + + SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff); + + StringCbPrintf(szTempBuff, + SMALL_BUFF, + "Link Collection: %hu", + pButton -> LinkCollection); + + SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff); + + StringCbPrintf(szTempBuff, + SMALL_BUFF, + "Link Usage Page: 0x%x", + pButton -> LinkUsagePage); + + SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff); + + StringCbPrintf(szTempBuff, + SMALL_BUFF, + "Link Usage: 0x%x", + pButton -> LinkUsage); + + SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff); + + if (pButton->IsRange) + { + StringCbPrintf(szTempBuff, + SMALL_BUFF, + "Usage Min: 0x%x, Usage Max: 0x%x", + pButton->Range.UsageMin, + pButton->Range.UsageMax); + } + else + { + StringCbPrintf(szTempBuff, SMALL_BUFF, "Usage: 0x%x",pButton->NotRange.Usage); + + } + SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff); + + if (pButton->IsRange) + { + StringCbPrintf(szTempBuff, + SMALL_BUFF, + "Data Index Min: 0x%x, Data Index Max: 0x%x", + pButton->Range.DataIndexMin, + pButton->Range.DataIndexMax); + + } + else + { + StringCbPrintf(szTempBuff, SMALL_BUFF, "DataIndex: 0x%x",pButton->NotRange.DataIndex); + } + + SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff); + + if (pButton->IsStringRange) + { + StringCbPrintf(szTempBuff, + SMALL_BUFF, + "String Min: 0x%x, String Max: 0x%x", + pButton->Range.StringMin, + pButton->Range.StringMax); + } + else + { + StringCbPrintf(szTempBuff, SMALL_BUFF, "String Index: 0x%x",pButton->NotRange.StringIndex); + } + SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff); + + if (pButton->IsDesignatorRange) + { + StringCbPrintf(szTempBuff, + SMALL_BUFF, + "Designator Min: 0x%x, Designator Max: 0x%x", + pButton->Range.DesignatorMin, + pButton->Range.DesignatorMax); + + } + else + { + StringCbPrintf(szTempBuff, + SMALL_BUFF, + "Designator Index: 0x%x", + pButton->NotRange.DesignatorIndex); + } + SendMessage(hControl, LB_ADDSTRING, 0,(LPARAM) szTempBuff); + + if (pButton->IsAbsolute) + { + SendMessage(hControl, LB_ADDSTRING,0, (LPARAM) "Absolute: Yes"); + } + else + { + SendMessage(hControl, LB_ADDSTRING,0, (LPARAM) "Absolute: No"); + } + return; +} + +VOID +vDisplayValueAttributes( + IN PHIDP_VALUE_CAPS pValue, + HWND hControl +) +{ + static CHAR szTempBuff[SMALL_BUFF]; + + StringCbPrintf(szTempBuff, SMALL_BUFF, "Report ID 0x%x", pValue->ReportID); + SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff); + + StringCbPrintf(szTempBuff, SMALL_BUFF, "Usage Page: 0x%x", pValue->UsagePage); + SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff); + + StringCbPrintf(szTempBuff, SMALL_BUFF, "Bit size: 0x%x", pValue->BitSize); + SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff); + + StringCbPrintf(szTempBuff, SMALL_BUFF, "Report Count: 0x%x", pValue->ReportCount); + SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff); + + StringCbPrintf(szTempBuff, SMALL_BUFF, "Unit Exponent: 0x%x", pValue->UnitsExp); + SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff); + + StringCbPrintf(szTempBuff, SMALL_BUFF, "Has Null: 0x%x", pValue->HasNull); + SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff); + + + if (pValue->IsAlias) + { + StringCbPrintf(szTempBuff, SMALL_BUFF, "Alias"); + } + else + { + StringCbPrintf(szTempBuff, SMALL_BUFF, "====="); + } + SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff); + + if (pValue->IsRange) + { + StringCbPrintf(szTempBuff, + SMALL_BUFF, + "Usage Min: 0x%x, Usage Max 0x%x", + pValue->Range.UsageMin, + pValue->Range.UsageMax); + } + else + { + StringCbPrintf(szTempBuff, SMALL_BUFF, "Usage: 0x%x", pValue -> NotRange.Usage); + } + SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff); + + if (pValue->IsRange) + { + StringCbPrintf(szTempBuff, + SMALL_BUFF, + "Data Index Min: 0x%x, Data Index Max: 0x%x", + pValue->Range.DataIndexMin, + pValue->Range.DataIndexMax); + } + else + { + StringCbPrintf(szTempBuff, SMALL_BUFF, "DataIndex: 0x%x", pValue->NotRange.DataIndex); + } + SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff); + + StringCbPrintf(szTempBuff, + SMALL_BUFF, + "Physical Minimum: %d, Physical Maximum: %d", + pValue->PhysicalMin, + pValue->PhysicalMax); + + SendMessage(hControl, LB_ADDSTRING, 0,(LPARAM) szTempBuff); + + StringCbPrintf(szTempBuff, + SMALL_BUFF, + "Logical Minimum: 0x%x, Logical Maximum: 0x%x", + pValue->LogicalMin, + pValue->LogicalMax); + + SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff); + + if (pValue->IsStringRange) + { + StringCbPrintf(szTempBuff, + SMALL_BUFF, + "String Min: 0x%x String Max 0x%x", + pValue->Range.StringMin, + pValue->Range.StringMax); + } + else + { + StringCbPrintf(szTempBuff, SMALL_BUFF, "String Index: 0x%x",pValue->NotRange.StringIndex); + } + SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff); + + if (pValue->IsDesignatorRange) + { + StringCbPrintf(szTempBuff, + SMALL_BUFF, + "Designator Minimum: 0x%x, Max: 0x%x", + pValue->Range.DesignatorMin, + pValue->Range.DesignatorMax); + } + else + { + StringCbPrintf(szTempBuff, SMALL_BUFF, "Designator Index: 0x%x",pValue->NotRange.DesignatorIndex); + } + SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff); + + if (pValue->IsAbsolute) + { + SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) "Absolute: Yes"); + } + else + { + SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) "Absolute: No"); + } + return; +} + +VOID +vDisplayInputButtons( + IN PHID_DEVICE pDevice, + IN HWND hControl +) +{ + INT iLoop; + PHIDP_BUTTON_CAPS pButtonCaps; + static CHAR szTempBuff[SMALL_BUFF]; + INT iIndex; + + SendMessage(hControl, LB_RESETCONTENT, 0, (LPARAM) 0); + + pButtonCaps = pDevice->InputButtonCaps; + for (iLoop = 0; iLoop < pDevice->Caps.NumberInputButtonCaps; iLoop++) + { + StringCbPrintf(szTempBuff, SMALL_BUFF, "Input button cap # %d", iLoop); + + iIndex = (INT) SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff); + + if (-1 != iIndex) + { + SendMessage(hControl, LB_SETITEMDATA, iIndex,(LPARAM) pButtonCaps); + } + + pButtonCaps++; + } + SendMessage(hControl, LB_SETCURSEL, 0, 0 ); +} + +VOID +vDisplayOutputButtons( + IN PHID_DEVICE pDevice, + IN HWND hControl +) +{ + INT iLoop; + static CHAR szTempBuff[SMALL_BUFF]; + INT iIndex; + PHIDP_BUTTON_CAPS pButtonCaps; + + SendMessage(hControl, LB_RESETCONTENT, 0, (LPARAM) 0); + + pButtonCaps = pDevice -> OutputButtonCaps; + + for (iLoop = 0; iLoop < pDevice->Caps.NumberOutputButtonCaps; iLoop++) + { + StringCbPrintf(szTempBuff, SMALL_BUFF, "Output button cap # %d", iLoop); + iIndex = (INT) SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff); + + if (-1 != iIndex) + { + SendMessage(hControl, LB_SETITEMDATA, iIndex, (LPARAM) pButtonCaps); + } + pButtonCaps++; + } + + SendMessage(hControl, LB_SETCURSEL, 0, 0); + return; +} + +VOID +vDisplayInputValues( + IN PHID_DEVICE pDevice, + IN HWND hControl +) +{ + INT iLoop; + static CHAR szTempBuff[SMALL_BUFF]; + INT iIndex; + PHIDP_VALUE_CAPS pValueCaps; + + SendMessage(hControl, LB_RESETCONTENT, 0, 0); + + pValueCaps = pDevice -> InputValueCaps; + + for (iLoop=0; iLoop < pDevice->Caps.NumberInputValueCaps; iLoop++) + { + StringCbPrintf(szTempBuff, SMALL_BUFF, "Input value cap # %d",iLoop); + iIndex = (INT) SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff); + + if (-1 != iIndex) + { + SendMessage(hControl, LB_SETITEMDATA, iIndex,(LPARAM) pValueCaps); + } + pValueCaps++; + } + + SendMessage(hControl, LB_SETCURSEL, 0, 0); + return; +} + +VOID +vDisplayOutputValues( + IN PHID_DEVICE pDevice, + IN HWND hControl) +{ + INT iLoop; + static CHAR szTempBuff[SMALL_BUFF]; + INT iIndex; + PHIDP_VALUE_CAPS pValueCaps; + + SendMessage(hControl, LB_RESETCONTENT, 0, 0); + pValueCaps = pDevice -> OutputValueCaps; + + for (iLoop = 0; iLoop < pDevice->Caps.NumberOutputValueCaps; iLoop++) + { + StringCbPrintf(szTempBuff, SMALL_BUFF, "Output value cap # %d", iLoop); + iIndex = (INT) SendMessage(hControl, + LB_ADDSTRING, + 0, + (LPARAM) szTempBuff); + + if (-1 != iIndex) + { + SendMessage(hControl, LB_SETITEMDATA, iIndex, (LPARAM) pValueCaps); + } + pValueCaps++; + } + + SendMessage(hControl, LB_SETCURSEL, 0, 0); + + return; +} + +VOID +vDisplayFeatureButtons( + IN PHID_DEVICE pDevice, + IN HWND hControl +) +{ + INT iLoop; + static CHAR szTempBuff[SMALL_BUFF]; + INT iIndex; + PHIDP_BUTTON_CAPS pButtonCaps; + + SendMessage(hControl, LB_RESETCONTENT, 0, 0); + + pButtonCaps = pDevice -> FeatureButtonCaps; + + for (iLoop = 0; iLoop < pDevice->Caps.NumberFeatureButtonCaps; iLoop++) + { + StringCbPrintf(szTempBuff, SMALL_BUFF, "Feature button cap # %d", iLoop); + iIndex = (INT) SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff); + + if (-1 != iIndex) + { + SendMessage(hControl, LB_SETITEMDATA, iIndex, (LPARAM) pButtonCaps); + } + pButtonCaps++; + } + SendMessage(hControl, LB_SETCURSEL, 0, 0); + return; +} + +VOID +vDisplayFeatureValues( + IN PHID_DEVICE pDevice, + IN HWND hControl +) +{ + INT iLoop; + static CHAR szTempBuff[SMALL_BUFF]; + INT iIndex; + PHIDP_VALUE_CAPS pValueCaps; + + SendMessage(hControl, LB_RESETCONTENT, 0, 0); + pValueCaps = pDevice ->FeatureValueCaps; + + for (iLoop = 0; iLoop < pDevice->Caps.NumberFeatureValueCaps; iLoop++) + { + StringCbPrintf(szTempBuff, SMALL_BUFF, "Feature value cap # %d", iLoop); + iIndex = (INT) SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff); + + if (-1 != iIndex) + { + SendMessage(hControl, LB_SETITEMDATA, iIndex, (LPARAM) pValueCaps); + } + + pValueCaps++; + } + SendMessage(hControl, LB_SETCURSEL, 0, 0); + return; +} + +VOID +vLoadItemTypes( + IN HWND hItemTypes +) +{ + INT iIndex; + + iIndex = (INT) SendMessage(hItemTypes, CB_ADDSTRING, 0, (LPARAM) "INPUT BUTTON"); + + if (-1 != iIndex) + { + SendMessage(hItemTypes, CB_SETITEMDATA, iIndex, INPUT_BUTTON); + + iIndex = (INT) SendMessage(hItemTypes, CB_ADDSTRING, 0 ,(LPARAM) "INPUT VALUE"); + if (-1 != iIndex) + { + SendMessage(hItemTypes, CB_SETITEMDATA, iIndex, INPUT_VALUE); + } + + iIndex = (INT) SendMessage(hItemTypes, CB_ADDSTRING, 0, (LPARAM) "OUTPUT BUTTON"); + if (-1 != iIndex) + { + SendMessage(hItemTypes,CB_SETITEMDATA,iIndex,OUTPUT_BUTTON); + } + + iIndex = (INT) SendMessage(hItemTypes, CB_ADDSTRING, 0, (LPARAM) "OUTPUT VALUE"); + if (-1 != iIndex) + { + SendMessage(hItemTypes, CB_SETITEMDATA, iIndex, OUTPUT_VALUE); + } + + iIndex = (INT) SendMessage(hItemTypes, CB_ADDSTRING, 0, (LPARAM) "FEATURE BUTTON"); + if (-1 != iIndex) + { + SendMessage(hItemTypes, CB_SETITEMDATA, iIndex, FEATURE_BUTTON); + } + + iIndex = (INT) SendMessage(hItemTypes, CB_ADDSTRING, 0, (LPARAM) "FEATURE VALUE"); + if (-1 != iIndex) + { + SendMessage(hItemTypes, CB_SETITEMDATA, iIndex, FEATURE_VALUE); + } + + iIndex = (INT) SendMessage(hItemTypes, CB_ADDSTRING, 0, (LPARAM) "HID CAPS"); + if (-1 != iIndex ) + { + SendMessage(hItemTypes, CB_SETITEMDATA, iIndex, HID_CAPS); + } + + iIndex = (INT) SendMessage(hItemTypes, CB_ADDSTRING, 0, (LPARAM) "DEVICE ATTRIBUTES"); + if (-1 != iIndex) + { + SendMessage(hItemTypes, CB_SETITEMDATA, iIndex, DEVICE_ATTRIBUTES); + } + + SendMessage(hItemTypes, CB_SETCURSEL, 0, 0); + } +} + +VOID vLoadDevices( + HWND hDeviceCombo +) +{ + PDEVICE_LIST_NODE currNode; + + static CHAR szTempBuff[SMALL_BUFF]; + INT i = 0; + INT iIndex; + + // + // Reset the content of the device list box. + // + + SendMessage(hDeviceCombo, CB_RESETCONTENT, 0, 0); + + + if (!IsListEmpty(&PhysicalDeviceList)) + { + currNode = (PDEVICE_LIST_NODE) GetListHead(&PhysicalDeviceList); + + do + { + if (INVALID_HANDLE_VALUE != currNode -> HidDeviceInfo.HidDevice) + { + StringCbPrintf(szTempBuff, + SMALL_BUFF, + "Device #%d: VID: 0x%04X PID: 0x%04X UsagePage: 0x%X Usage: 0x%X", + i++, + currNode -> HidDeviceInfo.Attributes.VendorID, + currNode -> HidDeviceInfo.Attributes.ProductID, + currNode -> HidDeviceInfo.Caps.UsagePage, + currNode -> HidDeviceInfo.Caps.Usage); + } + else + { + StringCbPrintf(szTempBuff, + SMALL_BUFF, + "*Device #%d: %s", + i++, + (NULL != currNode -> HidDeviceInfo.DevicePath) ? (currNode -> HidDeviceInfo.DevicePath) : ""); + } + + iIndex = (INT) SendMessage(hDeviceCombo, CB_ADDSTRING, 0, (LPARAM) szTempBuff); + + if (CB_ERR != iIndex && INVALID_HANDLE_VALUE != currNode -> HidDeviceInfo.HidDevice) + { + SendMessage(hDeviceCombo, CB_SETITEMDATA, iIndex, (LPARAM) &(currNode -> HidDeviceInfo)); + } + + currNode = (PDEVICE_LIST_NODE) GetNextEntry(currNode); + + } while ((PLIST) currNode != &PhysicalDeviceList); + + } + + + SendMessage(hDeviceCombo, CB_SETCURSEL, 0, 0); + + return; +} + +BOOL +bGetData( + prWriteDataStruct pItems, + INT iCount, + HWND hParent, + _In_ LPSTR pszDialogName +) +{ + rGetWriteDataParams rParams; + static rWriteDataStruct arTempItems[MAX_WRITE_ELEMENTS]; + INT iResult; + + + if (iCount > MAX_WRITE_ELEMENTS) + { + iCount = MAX_WRITE_ELEMENTS; + } + + memcpy( &(arTempItems[0]), pItems, sizeof(rWriteDataStruct)*iCount); + + rParams.iCount = iCount; + rParams.prItems = &(arTempItems[0]); + + iResult = (INT) DialogBoxParam(hGInstance, + pszDialogName, + hParent, + bGetDataDlgProc, + (LPARAM) &rParams); + if (iResult) + { + memcpy(pItems, arTempItems, sizeof(rWriteDataStruct)*iCount); + } + return iResult; +} + +INT_PTR CALLBACK +bGetDataDlgProc( + HWND hDlg, + UINT message, + WPARAM wParam, + LPARAM lParam +) +{ + static prWriteDataStruct prData; + static prGetWriteDataParams pParams; + static INT iDisplayCount; + static INT iScrollRange; + static INT iCurrentScrollPos=0; + static HWND hScrollBar; + INT iTemp; + SCROLLINFO rScrollInfo; + + switch(message) + { + case WM_INITDIALOG: + + pParams = (prGetWriteDataParams) lParam; + prData = pParams -> prItems; + hScrollBar = GetDlgItem(hDlg, IDC_SCROLLBAR); + + if (pParams -> iCount > CONTROL_COUNT) + { + iDisplayCount = CONTROL_COUNT; + iScrollRange = pParams -> iCount - CONTROL_COUNT; + rScrollInfo.fMask = SIF_RANGE | SIF_POS; + rScrollInfo.nPos = 0; + rScrollInfo.nMin = 0; + rScrollInfo.nMax = iScrollRange; + rScrollInfo.cbSize = sizeof(rScrollInfo); + rScrollInfo.nPage = CONTROL_COUNT; + SetScrollInfo(hScrollBar,SB_CTL,&rScrollInfo,TRUE); + } + else + { + iDisplayCount=pParams->iCount; + EnableWindow(hScrollBar,FALSE); + } + vWriteDataToControls(hDlg, prData, 0, pParams->iCount); + break; + + case WM_COMMAND: + switch(LOWORD(wParam)) + { + case IDOK: + case ID_SEND: + vReadDataFromControls(hDlg, prData, iCurrentScrollPos, iDisplayCount); + EndDialog(hDlg,1); + break; + + case IDCANCEL: + EndDialog(hDlg,0); + break; + } + break; + + case WM_VSCROLL: + vReadDataFromControls(hDlg, prData, iCurrentScrollPos, iDisplayCount); + + switch(LOWORD(wParam)) + { + case SB_LINEDOWN: + ++iCurrentScrollPos; + break; + + case SB_LINEUP: + --iCurrentScrollPos; + break; + + case SB_THUMBPOSITION: + iCurrentScrollPos = HIWORD(wParam); + + case SB_PAGEUP: + iCurrentScrollPos -= CONTROL_COUNT; + break; + + case SB_PAGEDOWN: + iCurrentScrollPos += CONTROL_COUNT; + break; + } + + if (iCurrentScrollPos < 0) + { + iCurrentScrollPos = 0; + } + + if (iCurrentScrollPos > iScrollRange) + { + iCurrentScrollPos = iScrollRange; + } + + SendMessage(hScrollBar, SBM_SETPOS, iCurrentScrollPos, TRUE); + iTemp = LOWORD(wParam); + + if ( (iTemp == SB_LINEDOWN) || (iTemp == SB_LINEUP) || (iTemp == SB_THUMBPOSITION)|| (iTemp == SB_PAGEUP) || (iTemp==SB_PAGEDOWN) ) + { + vWriteDataToControls(hDlg, prData, iCurrentScrollPos, iDisplayCount); + } + break; + } + return FALSE; +} //end function bGetDataDlgProc// + +VOID +vReadDataFromControls( + HWND hDlg, + prWriteDataStruct prData, + INT iOffset, + INT iCount +) +{ + INT iLoop; + INT iValueControlID = IDC_OUT_EDIT1; + prWriteDataStruct pDataWalk; + HWND hValueWnd; + + pDataWalk = prData + iOffset; + for (iLoop = 0; (iLoop < iCount) && (iLoop < CONTROL_COUNT); iLoop++) + { + hValueWnd = GetDlgItem(hDlg, iValueControlID); + + GetWindowText(hValueWnd, pDataWalk -> szValue, MAX_VALUE); + + iValueControlID++; + + pDataWalk++; + } + + return; +} + +VOID +vWriteDataToControls( + HWND hDlg, + prWriteDataStruct prData, + INT iOffset, + INT iCount +) +{ + INT iLoop; + INT iLabelControlID = IDC_OUT_LABEL1; + INT iValueControlID = IDC_OUT_EDIT1; + HWND hLabelWnd, hValueWnd; + prWriteDataStruct pDataWalk; + + pDataWalk = prData + iOffset; + + for (iLoop = 0; (iLoop < iCount) && (iLoop < CONTROL_COUNT); iLoop++) + { + hLabelWnd = GetDlgItem(hDlg, iLabelControlID); + hValueWnd = GetDlgItem(hDlg, iValueControlID); + + ShowWindow(hLabelWnd, SW_SHOW); + ShowWindow(hValueWnd, SW_SHOW); + + SetWindowText(hLabelWnd, pDataWalk -> szLabel); + SetWindowText(hValueWnd, pDataWalk -> szValue); + + iLabelControlID++; + iValueControlID++; + pDataWalk++; + } + + // + // Hide the controls + // + + for (; iLoop < CONTROL_COUNT; iLoop++) + { + hLabelWnd = GetDlgItem(hDlg,iLabelControlID); + hValueWnd = GetDlgItem(hDlg,iValueControlID); + + ShowWindow(hLabelWnd,SW_HIDE); + ShowWindow(hValueWnd,SW_HIDE); + + iLabelControlID++; + iValueControlID++; + } +} + +VOID +vCreateUsageString( + _In_ PUSAGE pUsageList, + _Out_writes_(uiStringSize) CHAR szString[], + _In_ UINT uiStringSize +) +{ + + StringCbPrintf(szString, + uiStringSize, + "Usage: %#04x", + *pUsageList); + + return; +} + +VOID +vCreateUsageAndPageString( + _In_ PUSAGE_AND_PAGE pUsageList, + _Out_writes_(uiStringSize) CHAR szString[], + _In_ UINT uiStringSize +) +{ + + StringCbPrintf(szString, + uiStringSize, + "Usage Page: %#04x Usage: %#04x", + pUsageList->UsagePage, + pUsageList->Usage); + + return; +} + +VOID +vDisplayLinkCollectionNode( + IN PHIDP_LINK_COLLECTION_NODE pLCNode, + IN ULONG ulLinkIndex, + IN HWND hControl +) +{ + static CHAR szTempBuff[SMALL_BUFF]; + + StringCbPrintf(szTempBuff, SMALL_BUFF, "Index: 0x%x", ulLinkIndex); + SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff); + + StringCbPrintf(szTempBuff, SMALL_BUFF, "Usage Page: 0x%x", pLCNode -> LinkUsagePage); + SendMessage(hControl, LB_ADDSTRING,0, (LPARAM)szTempBuff); + + StringCbPrintf(szTempBuff, SMALL_BUFF, "Usage: 0x%x", pLCNode -> LinkUsage); + SendMessage(hControl, LB_ADDSTRING,0, (LPARAM) szTempBuff); + + StringCbPrintf(szTempBuff, SMALL_BUFF, "Parent Index: 0x%x", pLCNode -> Parent); + SendMessage(hControl, LB_ADDSTRING,0, (LPARAM) szTempBuff); + + StringCbPrintf(szTempBuff, SMALL_BUFF, "Number of Children: 0x%x", pLCNode -> NumberOfChildren); + SendMessage(hControl, LB_ADDSTRING,0, (LPARAM) szTempBuff); + + StringCbPrintf(szTempBuff, SMALL_BUFF, "Next Sibling: 0x%x", pLCNode -> NextSibling); + SendMessage(hControl, LB_ADDSTRING,0, (LPARAM) szTempBuff); + + StringCbPrintf(szTempBuff, SMALL_BUFF, "First Child: 0x%x", pLCNode -> FirstChild); + SendMessage(hControl, LB_ADDSTRING,0, (LPARAM) szTempBuff); + + return; +} + +VOID +vCreateUsageValueStringFromArray( + _In_reads_(uiBufferSize)PCHAR pBuffer, + _In_ UINT uiBufferSize, + _In_ USHORT BitSize, + _In_ USHORT UsageIndex, + _Out_writes_(uiStringSize) CHAR szString[], + _In_ UINT uiStringSize +) +/*++ +Routine Description: + Given a report buffer, pBuffer, this routine extracts the given usage + at UsageIndex from the array and outputs to szString the string + representation of that value. The input parameter BitSize specifies + the number of bits representing that value in the array. This is + useful for extracting individual members of a UsageValueArray. +--*/ +{ + UINT iByteIndex; + USHORT iByteOffset; + UCHAR ucLeftoverBits; + ULONG ulMask; + ULONG ulValue; + + // + // Calculate the byte and byte offset into the buffer for the given + // index value + // + + iByteIndex = (UsageIndex * BitSize) >> 3; + iByteOffset = (UsageIndex * BitSize) & 7; + + // + // Make sure we don't go past our buffer + // + if(iByteIndex + (UINT)4 > uiBufferSize) + { + if(sizeof(szString) <= uiStringSize) + { + StringCbPrintf(szString, uiStringSize, "ERR"); + } + return; + } + + // + // Extract the 32-bit value beginning at ByteIndex. This value + // will contain some or all of the value we are attempting to retrieve + // + + ulValue = *(PULONG) (pBuffer + iByteIndex); + + // + // Shift that value to the right by our byte offset.. + // + + ulValue = ulValue >> iByteOffset; + + // + // At this point, ulValue contains the first 32-iByteOffset bits beginning + // the appropriate offset in the buffer. There are now two cases to + // look at: + // + // 1) BitSize > 32-iByteOffset -- In which case, we need to extract + // iByteOffset bits from the next + // byte in the array and OR them as + // the MSBs of ulValue + // + // 2) BitSize < 32-iByteOffset -- Need to get only the BitSize LSBs + // + // + + // + // Case #1 + // + + if (BitSize > sizeof(ULONG)*8 - iByteOffset) + { + // + // Get the next byte of the report following the four bytes we + // retrieved earlier for ulValue + // + if ( (iByteIndex+4) < uiBufferSize ) + { + ucLeftoverBits = *(pBuffer+iByteIndex+4); + } + else + { + StringCbPrintf(szString, uiStringSize, "ERR"); + return; // error case + } + + // + // Shift those bits to the left for anding to our previous value + // + + ulMask = ucLeftoverBits << (24 + (8 - iByteOffset)); + ulValue |= ulMask; + + } + else if (BitSize < sizeof(ULONG)*8 - iByteOffset) + { + // + // Need to mask the most significant bits that are part of another + // value(s), not the one we are currently working with. + // + + ulMask = (1 << BitSize) - 1; + ulValue &= ulMask; + } + + // + // We've now got the correct value, now output to the string + // + + StringCbPrintf(szString, uiStringSize, "Usage value: %lu", ulValue); + + return; +} + + +BOOL +RegisterHidDevice( + IN HWND WindowHandle, + IN PDEVICE_LIST_NODE DeviceNode +) +{ + DEV_BROADCAST_HANDLE broadcastHandle; + + broadcastHandle.dbch_size = sizeof(DEV_BROADCAST_HANDLE); + broadcastHandle.dbch_devicetype = DBT_DEVTYP_HANDLE; + broadcastHandle.dbch_handle = DeviceNode -> HidDeviceInfo.HidDevice; + + DeviceNode -> NotificationHandle = RegisterDeviceNotification( + WindowHandle, + &broadcastHandle, + DEVICE_NOTIFY_WINDOW_HANDLE); + + return (NULL != DeviceNode -> NotificationHandle); +} + +VOID +DestroyDeviceListCallback( + PLIST_NODE_HDR ListNode +) +{ + PDEVICE_LIST_NODE deviceNode; + + deviceNode = (PDEVICE_LIST_NODE) ListNode; + + // + // The callback function needs to do the following steps... + // 1) Close the HidDevice + // 2) Unregister device notification (if registered) + // 3) Free the allocated memory block + // + + CloseHidDevice(&(deviceNode -> HidDeviceInfo)); + + if (NULL != deviceNode -> NotificationHandle) + { + UnregisterDeviceNotification(deviceNode -> NotificationHandle); + } + + free (deviceNode); + + return; +} + +DWORD WINAPI +AsynchReadThreadProc( + PREAD_THREAD_CONTEXT Context +) +{ + HANDLE completionEvent; + BOOL readStatus; + DWORD waitStatus; + ULONG numReadsDone; + + // + // Create the completion event to send to the the OverlappedRead routine + // + + completionEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + + // + // If NULL returned, then we cannot proceed any farther so we just exit the + // the thread + // + + if (NULL == completionEvent) + { + goto AsyncRead_End; + } + + // + // Now we enter the main read loop, which does the following: + // 1) Calls ReadOverlapped() + // 2) Waits for read completion with a timeout just to check if + // the main thread wants us to terminate our the read request + // 3) If the read fails, we simply break out of the loop + // and exit the thread + // 4) If the read succeeds, we call UnpackReport to get the relevant + // info and then post a message to main thread to indicate that + // there is new data to display. + // 5) We then block on the display event until the main thread says + // it has properly displayed the new data + // 6) Look to repeat this loop if we are doing more than one read + // and the main thread has yet to want us to terminate + // + + numReadsDone = 0; + + do + { + // + // Call ReadOverlapped() and if the return status is TRUE, the ReadFile + // succeeded so we need to block on completionEvent, otherwise, we just + // exit + // + + readStatus = ReadOverlapped( Context -> HidDevice, completionEvent ); + + + if (!readStatus) + { + break; + } + + while (!Context -> TerminateThread) + { + // + // Wait for the completion event to be signaled or a timeout + // + + waitStatus = WaitForSingleObject (completionEvent, READ_THREAD_TIMEOUT ); + + // + // If completionEvent was signaled, then a read just completed + // so let's leave this loop and process the data + // + + if ( WAIT_OBJECT_0 == waitStatus) + { + break; + } + } + + // + // Check the TerminateThread again...If it is not set, then data has + // been read. In this case, we want to Unpack the report into our + // input info and then send a message to the main thread to display + // the new data. + // + + if (!Context -> TerminateThread) + { + numReadsDone++; + + UnpackReport(Context -> HidDevice -> InputReportBuffer, + Context -> HidDevice -> Caps.InputReportByteLength, + HidP_Input, + Context -> HidDevice -> InputData, + Context -> HidDevice -> InputDataLength, + Context -> HidDevice -> Ppd); + + if (NULL != Context -> DisplayEvent) + { + PostMessage(Context -> DisplayWindow, + WM_DISPLAY_READ_DATA, + 0, + (LPARAM) Context -> HidDevice); + + WaitForSingleObject( Context -> DisplayEvent, INFINITE ); + } + else if (NULL == Context -> DisplayWindow) + { + // Running in console mode + printf("Read #%d\n", numReadsDone); + CLM_PrintInputReport(Context -> HidDevice); + } + } + } while ( !Context -> TerminateThread && + (INFINITE_READS == Context -> NumberOfReads || + numReadsDone < Context -> NumberOfReads)); + + +AsyncRead_End: + + PostMessage( Context -> DisplayWindow, WM_READ_DONE, 0, 0); + ExitThread(0); + return (0); +} + +DWORD WINAPI +SynchReadThreadProc( + PREAD_THREAD_CONTEXT Context +) +{ + ULONG numReadsDone = 0; + do + { + Read(Context -> HidDevice); + + numReadsDone ++; + + UnpackReport(Context -> HidDevice -> InputReportBuffer, + Context -> HidDevice -> Caps.InputReportByteLength, + HidP_Input, + Context -> HidDevice -> InputData, + Context -> HidDevice -> InputDataLength, + Context -> HidDevice -> Ppd); + + if (NULL != Context -> DisplayEvent) + { + PostMessage(Context -> DisplayWindow, + WM_DISPLAY_READ_DATA, + 0, + (LPARAM) Context -> HidDevice); + + WaitForSingleObject( Context -> DisplayEvent, INFINITE ); + } + + if (INFINITE_READS != Context -> NumberOfReads && + numReadsDone == Context -> NumberOfReads) + { + break; + } + } while ( !Context -> TerminateThread); + + PostMessage( Context -> DisplayWindow, WM_READ_DONE, 0, 0); + ExitThread(0); + return (0); +} diff --git a/hid/hclient/hclient.h b/hid/hclient/hclient.h new file mode 100644 index 00000000..cd8087fc --- /dev/null +++ b/hid/hclient/hclient.h @@ -0,0 +1,153 @@ +/*++ + +Copyright (c) Microsoft 1998, All Rights Reserved + +Module Name: + + hclient.h + +Abstract: + + This module contains the public declarations and definitions that are + defined in hclient.c and available to other modules outside of it. + +Environment: + + User mode + +Revision History: + + Nov-97 : Created + +--*/ + +#ifndef __HCLIENT_H__ +#define __HCLIENT_H__ + +#define WM_UNREGISTER_HANDLE WM_USER+1 +#define WM_DISPLAY_READ_DATA WM_USER+2 +#define WM_READ_DONE WM_USER+3 + +#define READ_THREAD_TIMEOUT 1000 + +#define HCLIENT_ERROR "HClient Error" + +#define INFINITE_READS ((ULONG)-1) + +typedef struct _READ_THREAD_CONTEXT +{ + PHID_DEVICE HidDevice; + + HWND DisplayWindow; + HANDLE DisplayEvent; + + ULONG NumberOfReads; + BOOL TerminateThread; + +} READ_THREAD_CONTEXT, *PREAD_THREAD_CONTEXT; + + +typedef NTSTATUS __stdcall GETEXTATTRIB ( + HIDP_REPORT_TYPE, + USHORT, + PHIDP_PREPARSED_DATA, + PHIDP_EXTENDED_ATTRIBUTES, + PULONG); + +typedef GETEXTATTRIB *PGETEXTATTRIB; + +typedef NTSTATUS __stdcall INITREPORT ( + HIDP_REPORT_TYPE, + UCHAR, + PHIDP_PREPARSED_DATA, + PCHAR, + ULONG); + +typedef INITREPORT *PINITREPORT; + + +extern PGETEXTATTRIB pfnHidP_GetExtendedAttributes; + +extern PINITREPORT pfnHidP_InitializeReportForID; + +VOID +vDisplayDeviceAttributes( + IN PHIDD_ATTRIBUTES pAttrib, + IN HWND hControl +); + +VOID +vDisplayButtonAttributes( + IN PHIDP_BUTTON_CAPS pButton, + IN HWND hControl +); + +VOID +vDisplayDataAttributes( + PHIDP_DATA pData, + BOOL IsButton, + HWND hControl +); + +VOID +vCreateUsageAndPageString( + _In_ PUSAGE_AND_PAGE pUsageList, + _Out_writes_(uiStringSize) CHAR szString[], + _In_ UINT uiStringSize +); + +VOID +vCreateUsageString( + _In_ PUSAGE pUsageList, + _Out_writes_(uiStringSize) CHAR szString[], + _In_ UINT uiStringSize +); + +VOID +vDisplayDeviceCaps( + IN PHIDP_CAPS pCaps, + IN HWND hControl +); + +VOID +vDisplayValueAttributes( + IN PHIDP_VALUE_CAPS pValue, + IN HWND hControl +); + +VOID +vDisplayLinkCollectionNode( + IN PHIDP_LINK_COLLECTION_NODE pLCNode, + IN ULONG ulLinkIndex, + IN HWND hControl +); + +VOID +vCreateUsageValueStringFromArray( + _In_reads_(uiBufferSize)PCHAR pBuffer, + _In_ UINT uiBufferSize, + _In_ USHORT BitSize, + _In_ USHORT UsageIndex, + _Out_writes_(uiStringSize) CHAR szString[], + _In_ UINT uiStringSize +); + +VOID +vDisplayValueAttributes( + IN PHIDP_VALUE_CAPS pValue, + IN HWND hControl +); + +DWORD WINAPI +AsynchReadThreadProc( + PREAD_THREAD_CONTEXT Context +); + +DWORD WINAPI +SynchReadThreadProc( + PREAD_THREAD_CONTEXT Context +); + +#endif + + diff --git a/hid/hclient/hclient.htm b/hid/hclient/hclient.htm new file mode 100644 index 00000000..de1fa7b6 --- /dev/null +++ b/hid/hclient/hclient.htm @@ -0,0 +1,775 @@ + + + + + + + + +HCLIENT + + + + + + + + + + + + +
+ +

HCLIENT

+ +

SUMMARY

+ +

This document and +associated sample code describe how to write a user-mode client application to +communicate with devices that conform to the HID device class specification. +This article is useful to application writers who need to develop a user-mode +application that communicates with and extracts information from an +HID-compatible device. This sample illustrates the method for detecting HID +devices, opening those HID devices for communication, and extracting and +formatting the data into or from device reports.

+ +

The HID class consists +primarily of devices that are used by humans to control the operation of +computer systems. Typical HID devices include keyboards, mice, and joysticks. +Non-typical devices might include front-panel controls (knobs, switches, or +buttons) or controls found on devices such as telephones, VCR remote controls, +games, and simulation devices. The underlying common feature of all HID devices +is the need for guaranteed delivery of small amounts of non-periodic data.

+ +

The basic communication +mechanism for HID class devices is the HID report. Every HID device must supply +a report descriptor that details the format of the different reports that it +creates for its device. The HID class drivers and HID.DLL is provide +an interface for extracting the relevant data from these reports.

+ +

Although the HClient sample is a user-mode application, many of the +functions available in HID.DLL are available to kernel-mode HID clients as +well. The functions exported by HID.DLL have a prefix of either HidD_ or HidP_. All functions +with a HidP_ prefix are available to kernel-mode +clients. However, the mechanism for opening HID devices and obtaining the +necessary information such as preparsed data is +different in this context.

+ +

BUILDING THE SAMPLE

+ +

To build the HClient.exe +sample, follow these instructions.

+ +
    +
  1. Run the standard Windows NT®/Windows® 2000 DDK build + environment (checked or free)
  2. +
  3. Change to the .\src\wdm\hid\hclient + directory
  4. +
  5. Execute build
  6. +
  7. The built HClient.exe will be found in + .\lib\<i386|alpha>\<checked|free>
  8. +
+ +

The HClient +sources are dependent on the following system include files and libraries.

+ +
        HIDSDI.H       User-mode only definitions and declarations
        HIDPI.H        Definitions and declarations for user-mode and kernel-mode HID clients
        HIDUSAGE.H     Macro definitions for predefined usage table and usage values as 
                       defined in the HID Spec 1.0 and HID Usage Table Spec 1.0
        HID.LIB        Library file needed to resolve exported HID.DLL functions
+ +

Kernel-mode clients may +also need the following files:

+ +
        HIDPDDI.H      Declarations and definitions for features available through the HID ioctl interface
        HIDPARSE.LIB   Library file needed to resolve exported HIDPARSE.SYS functions
+ +

TOOLS

+ +

The only tools needed to +work with HClient are HID devices. In the Windows +NT/Windows 2000 system, file handles cannot be opened on mice and keyboards. +However, all other HID devices will be available and recognized by HClient for testing purposes.

+ +

RESOURCES

+ +

See the Universal Serial Bus Device Class Definition for +Human Interface Devices (HID) Version 1.0 and Universal Serial Bus HID Usage +Tables 1.0.

+ +

CODE TOUR

+ +

File Manifest

+ +
Files         Description
 
HCLIENT.HTM    The documentation for this sample (this file)
SOURCES        The generic file for building the code sample
BUFFERS.C      Code for displaying HID report buffers in the extended calls 
               dialog box.            
BUFFERS.H      Function and structure declaration visible to other modules
DEBUG.C        Contains the function definitions for debug memory allocation tracking      
DEBUG.H        Contains public macro definitions and function declarations for 
               the debugging routines to deal with asserts, traps, and memory allocations
ECDISP.C       Code to handle the extended calls dialog box
ECDISP.H       Contains public declarations for the extended calls dialog
               box
HCLIENT.C      Code for handling HClient's main dialog box 
HCLIENT.H      Contains public declarations and definitions for HCLIENT.C and
               visible to other modules
HCLIENT.RC     Visual C++ generated resource file for HClient
HID.H          Contains declarations and definitions for handling devices and
               data within HClient
LIST.H         Contains public macro definitions for manipulating doubly-linked lists
LOGPNP.C       Code for finding, loading and building logical HID device 
               structures 
LOGPNP.H       Contains public function declarations for LOGPNP.C
MAKEFILE       NT DDK build environment makefile     
PNP.C          Contains the code for finding, adding, removing, and
               identifying hid devices.
REPORT.C       Contains the code for reading/writing hid reports and
               translating those HID reports into useful information.
RESOURCE.H     Visual C++ generated resource definition file
STRINGS.C      Code for converting data buffers and integer values
               to and from string representation for display.
STRINGS.H      Contains public function definitions for STRINGS.C
+ +

Programming Tour

+ +

The core functionality +relevant to HID client applications is contained in the files REPORT.C and +PNP.C. The code in these files implements the basic features that most clients +will require. Most of the other source files contain code for handling the user +interface and calling the main tasks that are in the above two files. This +section covers those relevant topics.

+ +

The major topics covered +in this tour are:

+ +
    +
  • Detecting Installed HID devices
  • +
  • Opening HID Devices
  • +
  • Communicating with HID Devices
  • +
  • Building/Interpreting HID Reports
  • +
+ +

Detecting Installed +HID Devices

+ +

A necessary component of +a HID client application is the detection of installed HID devices. The +function FindKnownHidDevices() in PNP.C details how to do that work. The basic steps for +identifying attached HID devices are:

+ +
    +
  • Call HidD_GetHidGuid() – + Get the HID device class GUID
  • +
  • Call SetupDiGetClassDevs() + – Get a handle to a set of devices which implement the HID interface
  • +
  • Call SetupDiEnumDeviceInterfaces() – For each device in the returned set of devices, + obtain the interface information for all exposed HID interfaces.
  • +
  • Call SetupDiGetDeviceInterfaceDetail() – For each interface obtained in the previous call, + get the detailed information block for that interface. This detailed + information includes the string that can be passed to CreateFile() + to open a handle to the device
  • +
  • Call SetupDiDestroyDeviceInfoList() – Free up the device information set that was + obtained in the call to SetupDiGetClassDevs().
  • +
+ +

The remainder of the code +implemented in the function deals with creating a list of HID_DEVICE structures +which contain information for each HID device in the system. This sample client +accesses all HID devices in the system. A more specific implementation may only +be looking for a certain type of HID device such as a joystick/gamepad.

+ +

Opening HID Devices

+ +

After detecting a HID +device, HClient proceeds to open that device. When +opening the device, HClient creates a HID_DEVICE +structure to contain any information about the device that further routines +might use. HID_DEVICE is defined as follows in HID.H:

+ +
+ + + + + +
 typedef struct _HID_DEVICE {   
    HANDLE               HidDevice; // A file handle to the hid device.
    PHIDP_PREPARSED_DATA Ppd;       // The opaque parser info describing this device
    HIDP_CAPS            Caps;      // The Capabilities of this hid device.
    HIDD_ATTRIBUTES      Attributes;
 
    PCHAR                InputReportBuffer;
    PHID_DATA            InputData;       // array of hid data structures
    ULONG                InputDataLength; // Num elements in this array.
    PHIDP_BUTTON_CAPS    InputButtonCaps;
    PHIDP_VALUE_CAPS     InputValueCaps;
 
    PCHAR                OutputReportBuffer;
    PHID_DATA            OutputData;
    ULONG                OutputDataLength;
    PHIDP_BUTTON_CAPS    OutputButtonCaps;
    PHIDP_VALUE_CAPS     OutputValueCaps;
 
    PCHAR                FeatureReportBuffer;
    PHID_DATA            FeatureData;
    ULONG                FeatureDataLength;
    PHIDP_BUTTON_CAPS    FeatureButtonCaps;
    PHIDP_VALUE_CAPS     FeatureValueCaps;
 
} HID_DEVICE, *PHID_DEVICE;
+ +
+ +

In addition to storing +the basic HID structures as defined in HIDPI.H and HIDSDI.H, the HID_DEVICE +structure also maintains an array of HID_DATA structures for each report type. +These structures contain the most recent value used for each of the controls +defined in the HIDP_VALUE_CAPS list and HIDP_BUTTON_CAPS list for the given +report type. The fields within this structure are used by routines that +pack/unpack data reports. The usage of these fields is discussed further in the +section entitled Building/Interpreting HID Reports.

+ +

The function OpenHidDevice() +in PNP.C performs the necessary steps to fill a HID_DEVICE structure for a +device. In order to do so, it performs the following steps:

+ +
    +
  • Call CreateFile() – Open a handle to the specific HID device. In this + case, we request read/write access to the device, allow the device to be + shared, and synchronize access to the device handle (no OVERLAPPED flag).
  • +
  • Call HidD_GetPreparsedData() – Get the preparsed data + for the device. The preparsed data is a HID + parser specific block of data used for processing HID reports. The memory + for this structure is allocated by the HID.DLL function and must be freed + when no longer needed with HidD_FreePreparsedData().
  • +
  • Call HidD_GetAttributes() – Get the attributes of the device. The attributes + structure contains the vendor ID, product ID and version number of the + given HID device
  • +
  • Call HidD_GetCaps() – Get the capabilities of the device. The device + capabilities include the usage page and usage of the device, the required + buffer length for the different reports on the device, the number of link + collection nodes on the device and a count of the number of buttons and + values for each of the different report types.
  • +
  • Call FillDeviceInfo() – Fill in the rest of the HID_DEVICE structure. This + function allocates space for and retrieves the link collection nodes, the + value caps, and the button caps for the device.
  • +
+ +

A given client application +may not need to perform all of the above steps. For instance, if a client +application only operates with a specific HID device (ie. +vendor ID/product ID), it may forego any more processing after retrieving the +attributes if the device it is currently opening is not the one it’s interested +in.

+ +

A client application may +also work only for a given usage page/usage combination. For example, a monitor +control application would only need to open devices that match the monitor +usage page and usage combination.

+ +

Lastly, a HID client may +require only a subset of the detailed information currently stored in the +HID_DEVICE structure. This sample application performs a broad range of +functionality to provide a detailed sample.

+ +

Communicating with HID +Devices

+ +

As mentioned above, a HID +device’s basic method of communication is through reports. A HID device can +contain as many as 255 reports for each report type (Input, Output, and +Feature). In order to properly communicate with a device, a client application +must be able to create reports (when sending data) or extract data from reports +(when receiving data). See the section titled: Building/Interpreting HID +Reports for information on how to manipulate these report buffers.

+ +

A HID device reports +information to the host through Input reports or Feature Reports. Typically, +input reports contain the data generated by user interaction, such as a button +press. Feature reports, on the other hand, report the current state or settings +for a device. The methods for obtaining these two different reports are +implemented in the functions Read() and GetFeature() in REPORT.C.

+ +

In order to receive data, +HClient must use the file handle created in OpenHidDevice that has READ access and the buffer allocated +for the given report type. For input reports, Read() +calls the Win32 API ReadFile() and waits for the +device to return a report. For feature reports, GetFeature() sets the first +byte of the report buffer to the desired report ID and calls HidD_GetFeature() to obtain that feature report. After +receiving a report back from the underlying drivers, these routines call UnpackReport() +to fill in the corresponding HID_DATA structures.

+ +

Outputting data to a +device is a bit more complicated. Once again, there are two different types of +reports that can be sent to a device, Output and Feature. The corresponding +functions for outputting data are Write() and SetFeature() in REPORT.C.

+ +

The first step that both +of these functions perform is creating the desired report buffer. First, the +HID_DATA structure with the desired report ID value is found. Then, these +functions call PackReport() to set the data values within the allocated report buffer +for that report ID. Once the report buffer has been created, either WriteFile() +or HidD_SetFeature() is called to send the report +packet to the device.

+ +

It is important to +understand that all access to a HID device file handle is synchronized. +Therefore, all threads using that handle will block until all previous requests +to the device have completed. One possible client implementation would have one +thread continuously read input reports while another thread sends or receives +feature reports. Since the HidD_GetFeature() and HidD_SetFeature functions +are implemented as DeviceIoControl calls, they are +also synchronized with ReadFile and WriteFile(). There are two solutions to this scenario. One solutions uses overlapped I/O for asynchronous control. The +second is to open two handles for the device, one for the read thread and one +for the feature thread.

+ +

Building/Interpreting +HID Reports

+ +

The last important idea +when dealing with reports is extracting/setting data values from/in a given +report buffer. The section covers the details of the functions PackReport() +and UnpackReport() as implemented in REPORT.C.

+ +

As mentioned above, in +order to communicate with a HID device, the client application must be able to +either create the appropriate report to send to the device or extract the +relevant information from a report received from the device. When Hclient initially opened the HID device and created the +HID_DEVICE structure for that device, it also created an array of HID_DATA +structures for each of the report types. The format of this HID_DATA structure +is as follows:

+ +
+ + + + + +
 typedef struct _HID_DATA {
   BOOLEAN     IsButtonData;
   UCHAR       Reserved;
   USAGE       UsagePage;   // The usage page for which we are looking.
   ULONG       Status;      // The last status returned from the accessor function
                            // when updating this field.
   ULONG       ReportID;    // ReportID for this given data structure
   BOOLEAN     IsDataSet;   // Variable to track whether a given data structure
                            //  has already been added to a report structure
 
   union {
      struct {
         ULONG       UsageMin;       // Variables to track the usage minimum and max
         ULONG       UsageMax;       // If equal, then only a single usage
         ULONG       MaxUsageLength; // Usages buffer length.
         PUSAGE      Usages;         // list of usages (buttons ``down'' on the device.
 
      } ButtonData;
      struct {
         USAGE       Usage; // The usage describing this value;
         USHORT      Reserved;
 
         ULONG       Value;
         LONG        ScaledValue;
      } ValueData;
   };
} HID_DATA, *PHID_DATA;
+ +
+ +

When creating the HID +reports for sending to the device, the function PackReport() is used. PackReport takes as input a pointer to a HID_DATA structure +and the appropriate report buffer. The pointer should point to the first +HID_DATA structure in the array that contains the report ID for the report to +be created. With this information, PackReport() performs the following steps:

+ +
    +
  • Zeroes out the current report buffer
  • +
  • Searches the array of HID_DATA structures looking all + data values that match the report ID
  • +
  • For each data value structure found, it calls HidP_SetUsageValue to set the value currently stored + in the structure into the report.
  • +
  • For each button structure found, it calls HidP_SetUsages with the corresponding usage value to + set the button state in the report to "On".
  • +
+ +

After having looped +through the array of HID_DATA structures, the report buffer will have the +appropriate report ID set as the first byte in the buffer and is ready to be +sent to the device.

+ +

In a similar manner, UnpackReport() +extracts data from a given report. Like PackReport(), this function receives a report buffer returned by the +device and an array of HID_DATA structures that could possibly be filled in. +This routine performs the following steps:

+ +
    +
  • Extracts the report ID from the first byte of the + report buffer
  • +
  • Searches the array of HID_DATA structures looking for + all structures that match the report ID
  • +
  • For each data value structure found, it call HidP_GetUsageValue and HidP_GetScaledUsageValue to set the Value and ScaledValue fields.
  • +
  • For each button structure, UnpackReport() calls HidP_GetUsages() to retrieve all the "On" + buttons for that data structure.
  • +
+ +

Once finished, the array +of HID_DATA structures will contain the new settings based on the information +returned in the report buffer.

+ +

Top of page

+ + + + + +
+

 

+
+ +

© 2004 Microsoft +Corporation

+ +
+ + + + diff --git a/hid/hclient/hclient.mk b/hid/hclient/hclient.mk new file mode 100644 index 00000000..3bb9a830 --- /dev/null +++ b/hid/hclient/hclient.mk @@ -0,0 +1,39 @@ +ROOT=..\..\..\..\.. +SRCDIR=.. + +WANT_C1132=TRUE +WANT_WDMDDK=TRUE +IS_32 = TRUE +IS_SDK = TRUE +IS_PRIVATE = TRUE +WIN32 = TRUE +DEPENDNAME=..\depend.mk +WIN32_LEAN_AND_MEAN=0 + +L32EXE = HCLIENT.EXE +L32RES = HCLIENT.res +PROPBINS=$(L32EXE) HCLIENT.sym +TARGETS=$(L32EXE) HCLIENT.sym +L32OBJS = hclient.obj pnp.obj report.obj strings.obj logpnp.obj buffers.obj ecdisp.obj +L32FLAGS = /MAP /subsystem:windows /machine:I386 + +CFLAGS = /nologo /Oi /W3 /D "WIN32" /D "_WINDOWS" /YX /c $(CFLAGS) +L32LIBSNODEP = $(ROOT)\dev\tools\c932\lib\libcmt.lib \ + $(W32LIBID)\kernel32.lib \ + $(W32LIBID)\USER32.LIB \ + $(W32LIBID)\GDI32.LIB \ + $(W32LIBID)\WINSPOOL.LIB \ + $(W32LIBID)\COMDLG32.LIB \ + $(W32LIBID)\advapi32.lib \ + $(W32LIBID)\shell32.lib \ + $(W32LIBID)\uuid.lib \ + $(ROOT)\dev\tools\c932\lib\crtdll.lib \ + $(ROOT)\wdm\ddk\lib\i386\hid.lib \ + $(ROOT)\wdm\ddk\lib\i386\hidclass.lib \ + $(ROOT)\dev\lib\setupapi.lib + +!include $(ROOT)\dev\master.mk + +RCSRCS=hclient.rc + +INCLUDE=$(ROOT)\wdm\ddk\inc;$(ROOT)\dev\inc;$(ROOT)\dev\ntddk\inc;$(INCLUDE);$(ROOT)\dev\msdev\mfc\include; diff --git a/hid/hclient/hclient.rc b/hid/hclient/hclient.rc new file mode 100644 index 00000000..1b02b6e5 --- /dev/null +++ b/hid/hclient/hclient.rc @@ -0,0 +1,370 @@ +#include +#include + +#include + +#pragma prefast(disable:17001, "Samples are not localized") + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN +#define VER_FILEDESCRIPTION_STR "HID Sample Client" +#define VER_INTERNALNAME_STR "hclient\0" +#define VER_ORIGINALFILENAME_STR "HCLIENT.EXE" + +#include + +#include "resource.h" + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +MAIN_DIALOG DIALOG DISCARDABLE 0, 0, 384, 277 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Sample HID client app" +FONT 8, "MS Shell Dlg" +BEGIN + COMBOBOX IDC_DEVICES,4,18,373,99,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_TYPE,4,48,373,99,CBS_DROPDOWNLIST | CBS_SORT | + WS_VSCROLL | WS_TABSTOP + LISTBOX IDC_ITEMS,4,81,373,44,LBS_SORT | LBS_NOINTEGRALHEIGHT | + WS_VSCROLL | WS_HSCROLL | WS_TABSTOP + LISTBOX IDC_ATTRIBUTES,4,143,373,89,LBS_NOINTEGRALHEIGHT | + WS_VSCROLL | WS_HSCROLL | WS_TABSTOP + PUSHBUTTON "Extended Client Calls...",IDC_EXTCALLS,20,241,78,14 + PUSHBUTTON "Modify Features...",IDC_FEATURES,20,256,78,14 + PUSHBUTTON "Blocked Write Data...",IDC_WRITE,128,241,78,14 + PUSHBUTTON "Blocked Read Data...",IDC_READ,128,256,78,14 + DEFPUSHBUTTON "About...",IDC_ABOUT,236,241,50,14 + DEFPUSHBUTTON "Exit",IDOK,316,241,50,14 + PUSHBUTTON "Start Tests",IDC_START_TESTS,316,256,50,14,NOT + WS_VISIBLE + LTEXT "HID Device to Examine (* indicates errors while opening)",IDC_STATIC,6,6,255,9 + LTEXT "Item Type to examine",IDC_STATIC,5,36,357,11 + LTEXT "Items",IDC_STATIC,6,67,156,12 + LTEXT "Item attributes",IDC_STATIC,5,129,176,9 +END + +READDATA DIALOG DISCARDABLE 0, 0, 387, 173 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Dialog" +FONT 8, "MS Shell Dlg" +BEGIN + PUSHBUTTON "Continuous Asynchronous Read",IDC_READ_ASYNCH_CONT,50, + 146,106,14 + PUSHBUTTON "One Asynchronous Read",IDC_READ_ASYNCH_ONCE,164,146,84, + 14 + PUSHBUTTON "Synchronous Read",IDC_READ_SYNCH,256,146,66,14 + DEFPUSHBUTTON "OK",IDOK,330,146,50,14 + LISTBOX IDC_OUTPUT,7,6,373,126,LBS_NOINTEGRALHEIGHT | WS_VSCROLL +END + +WRITEDATA DIALOG DISCARDABLE 0, 0, 387, 196 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Write to device" +FONT 8, "MS Shell Dlg" +BEGIN + DEFPUSHBUTTON "Cancel",IDCANCEL,325,177,50,14 + PUSHBUTTON "Send to device",ID_SEND,255,177,59,14 + LTEXT "abcdefghijklmonopqrstuvwayz",IDC_OUT_LABEL1,9,17,241,11 + EDITTEXT IDC_OUT_EDIT1,255,16,105,12,ES_AUTOHSCROLL + GROUPBOX "Output Buttons && Values",box,5,0,375,176 + LTEXT "abcdefghijklmonopqrstuvwayz",IDC_OUT_LABEL2,10,34,241, + 11 + EDITTEXT IDC_OUT_EDIT2,255,33,105,12,ES_AUTOHSCROLL + LTEXT "abcdefghijklmonopqrstuvwayz",IDC_OUT_LABEL3,9,52,241,11 + EDITTEXT IDC_OUT_EDIT3,255,51,105,12,ES_AUTOHSCROLL + LTEXT "abcdefghijklmonopqrstuvwayz",IDC_OUT_LABEL4,9,68,241,11 + EDITTEXT IDC_OUT_EDIT4,255,67,105,12,ES_AUTOHSCROLL + LTEXT "abcdefghijklmonopqrstuvwayz",IDC_OUT_LABEL5,9,85,241,11 + EDITTEXT IDC_OUT_EDIT5,255,84,105,12,ES_AUTOHSCROLL + LTEXT "abcdefghijklmonopqrstuvwayz",IDC_OUT_LABEL6,10,101,241, + 11 + EDITTEXT IDC_OUT_EDIT6,256,100,105,12,ES_AUTOHSCROLL + LTEXT "abcdefghijklmonopqrstuvwayz",IDC_OUT_LABEL7,10,118,241, + 11 + EDITTEXT IDC_OUT_EDIT7,256,117,105,12,ES_AUTOHSCROLL + LTEXT "abcdefghijklmonopqrstuvwayz",IDC_OUT_LABEL8,10,135,241, + 11 + EDITTEXT IDC_OUT_EDIT8,256,134,105,12,ES_AUTOHSCROLL + LTEXT "abcdefghijklmonopqrstuvwayz",IDC_OUT_LABEL9,10,153,241, + 11 + EDITTEXT IDC_OUT_EDIT9,256,152,105,12,ES_AUTOHSCROLL + SCROLLBAR IDC_SCROLLBAR,363,5,12,167,SBS_VERT +END + +WRITEFEATURE DIALOG DISCARDABLE 0, 0, 412, 215 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Modify Features" +FONT 8, "MS Shell Dlg" +BEGIN + DEFPUSHBUTTON "Cancel",IDCANCEL,351,190,50,14 + PUSHBUTTON "Send to device",ID_SEND,281,190,59,14 + LTEXT "abcdefghijklmonopqrstuvwayz",IDC_OUT_LABEL1,17,26,192, + 11 + EDITTEXT IDC_OUT_EDIT1,211,24,169,15,ES_AUTOHSCROLL + GROUPBOX "Feature Buttons && Values",box,13,14,376,171 + LTEXT "abcdefghijklmonopqrstuvwayz",IDC_OUT_LABEL2,18,43,192, + 11 + EDITTEXT IDC_OUT_EDIT2,211,41,169,15,ES_AUTOHSCROLL + LTEXT "abcdefghijklmonopqrstuvwayz",IDC_OUT_LABEL3,17,61,194, + 11 + EDITTEXT IDC_OUT_EDIT3,211,59,169,15,ES_AUTOHSCROLL + LTEXT "abcdefghijklmonopqrstuvwayz",IDC_OUT_LABEL4,17,77,194, + 11 + EDITTEXT IDC_OUT_EDIT4,211,76,169,15,ES_AUTOHSCROLL + LTEXT "abcdefghijklmonopqrstuvwayz",IDC_OUT_LABEL5,17,94,194, + 11 + EDITTEXT IDC_OUT_EDIT5,211,93,169,15,ES_AUTOHSCROLL + LTEXT "abcdefghijklmonopqrstuvwayz",IDC_OUT_LABEL6,18,110,194, + 11 + EDITTEXT IDC_OUT_EDIT6,212,110,169,15,ES_AUTOHSCROLL + LTEXT "abcdefghijklmonopqrstuvwayz",IDC_OUT_LABEL7,18,127,194, + 11 + EDITTEXT IDC_OUT_EDIT7,212,127,169,15,ES_AUTOHSCROLL + LTEXT "abcdefghijklmonopqrstuvwayz",IDC_OUT_LABEL8,18,144,194, + 11 + EDITTEXT IDC_OUT_EDIT8,212,144,169,15,ES_AUTOHSCROLL + LTEXT "abcdefghijklmonopqrstuvwayz",IDC_OUT_LABEL9,18,162,194, + 11 + EDITTEXT IDC_OUT_EDIT9,212,162,169,15,ES_AUTOHSCROLL + SCROLLBAR IDC_SCROLLBAR,389,18,12,167,SBS_VERT +END + +FEATURES DIALOG DISCARDABLE 0, 0, 323, 173 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Feature Data" +FONT 8, "MS Shell Dlg" +BEGIN + DEFPUSHBUTTON "OK",IDOK,260,146,50,14 + LISTBOX IDC_OUTPUT,7,6,309,126,LBS_NOINTEGRALHEIGHT | WS_VSCROLL | + WS_TABSTOP + PUSHBUTTON "Read Features",IDC_READ,193,146,59,13 + PUSHBUTTON "Modify Features",IDC_WRITE,126,146,59,13 +END + +EXTCALLS DIALOG DISCARDABLE 0, 0, 355, 290 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Extended Client Calls" +FONT 8, "MS Shell Dlg" +BEGIN + COMBOBOX IDC_EXTCALLS,7,18,341,71,CBS_DROPDOWNLIST | CBS_SORT | + WS_VSCROLL | WS_TABSTOP + EDITTEXT IDC_REPORTID,53,54,31,12,WS_GROUP + EDITTEXT IDC_USAGEPAGE,137,54,31,12,WS_GROUP + EDITTEXT IDC_USAGE,211,54,31,12,WS_GROUP + EDITTEXT IDC_LINKCOLL,303,54,21,12,ES_NUMBER | WS_GROUP + CONTROL "Input Report",IDC_INPUT,"Button",BS_AUTORADIOBUTTON | + WS_GROUP | WS_TABSTOP,23,84,52,10 + CONTROL "Output Report",IDC_OUTPUT,"Button",BS_AUTORADIOBUTTON | + WS_TABSTOP,135,84,57,10 + CONTROL "Feature Report",IDC_FEATURE,"Button",BS_AUTORADIOBUTTON | + WS_TABSTOP,249,84,61,10 + COMBOBOX IDC_INPUT_SELECT,19,118,88,30,CBS_DROPDOWN | CBS_SORT | + WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_OUTPUT_SELECT,130,118,87,30,CBS_DROPDOWN | CBS_SORT | + WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_FEATURE_SELECT,240,118,84,30,CBS_DROPDOWN | CBS_SORT | + WS_VSCROLL | WS_TABSTOP + EDITTEXT IDC_INPUT_BUFFER,20,140,87,21,ES_MULTILINE | + ES_AUTOHSCROLL | ES_READONLY + EDITTEXT IDC_OUTPUT_BUFFER,130,140,86,21,ES_MULTILINE | + ES_AUTOHSCROLL | ES_READONLY + EDITTEXT IDC_FEATURE_BUFFER,239,140,84,21,ES_MULTILINE | + ES_AUTOHSCROLL | ES_READONLY + LISTBOX IDC_CALLOUTPUT,7,185,341,64,NOT LBS_NOTIFY | + LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_HSCROLL | + WS_TABSTOP + PUSHBUTTON "Start Synchronous Read Thread",IDC_READ_SYNCH,10,255, + 110,14 + PUSHBUTTON "Start Asynchronous Read Thread",IDC_READ_ASYNCH,10,270, + 110,14 + PUSHBUTTON "Set Params",IDC_SET_PARAMS,135,255,50,14 + PUSHBUTTON "Execute",IDC_EXECUTE,205,255,58,14 + PUSHBUTTON "Cancel",IDC_CANCEL,285,255,50,14 + LTEXT "DLL Call to Execute",IDC_STATIC,7,7,64,8 + GROUPBOX "Report Type",IDC_STATIC,17,74,308,24 + LTEXT "Call Output",IDC_STATIC,7,175,36,8 + LTEXT "Report ID:",IDC_STATIC,15,57,34,8 + LTEXT "Usage Page:",IDC_STATIC,95,57,42,8 + LTEXT "Usage:",IDC_STATIC,183,57,23,8 + RTEXT "Link Collection:",IDC_STATIC,249,57,53,8 + GROUPBOX "Parameters",IDC_STATIC,7,38,341,129 +END + +IDD_SET_BUTTONS DIALOGEX DISCARDABLE 0, 0, 185, 79 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Set Button Usages" +FONT 8, "MS Shell Dlg" +BEGIN + DEFPUSHBUTTON "OK",IDOK,128,57,50,14 + PUSHBUTTON "Cancel",IDCANCEL,65,57,50,14 + LTEXT "Usage Page:",IDC_STATIC,7,7,42,8 + LTEXT "",IDC_USAGE_PAGE,54,7,34,8 + LTEXT "Usages (hex):",IDC_STATIC,7,29,44,8 + EDITTEXT IDC_USAGE_LIST,54,26,124,13,ES_AUTOHSCROLL +END + +IDD_SET_SCALED_VALUE DIALOGEX DISCARDABLE 0, 0, 185, 82 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Set Scaled Usage Value" +FONT 8, "MS Shell Dlg" +BEGIN + DEFPUSHBUTTON "OK",IDOK,128,60,50,14 + PUSHBUTTON "Cancel",IDCANCEL,65,60,50,14 + LTEXT "Usage Page:",IDC_STATIC,7,7,42,8 + LTEXT "",IDC_USAGE_PAGE,54,7,34,8 + LTEXT "Value:",IDC_STATIC,27,37,21,8 + EDITTEXT IDC_VALUE,53,34,62,13,ES_AUTOHSCROLL + LTEXT "Usage:",IDC_STATIC,25,21,24,8 + LTEXT "",IDC_USAGE,54,21,34,8 +END + +IDD_SET_USAGE_VALUE DIALOGEX DISCARDABLE 0, 0, 185, 82 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Set Usage Value" +FONT 8, "MS Shell Dlg" +BEGIN + DEFPUSHBUTTON "OK",IDOK,128,60,50,14 + PUSHBUTTON "Cancel",IDCANCEL,65,60,50,14 + LTEXT "Usage Page:",IDC_STATIC,7,7,42,8 + LTEXT "",IDC_USAGE_PAGE,54,7,34,8 + LTEXT "Value:",IDC_STATIC,27,37,21,8 + EDITTEXT IDC_VALUE,53,34,62,13,ES_AUTOHSCROLL + LTEXT "Usage:",IDC_STATIC,25,21,24,8 + LTEXT "",IDC_USAGE,54,21,34,8 +END + +IDD_SET_USAGE_VALUE_ARRAY DIALOGEX DISCARDABLE 0, 0, 185, 82 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Set Usage Value Array" +FONT 8, "MS Shell Dlg" +BEGIN + DEFPUSHBUTTON "OK",IDOK,128,60,50,14 + PUSHBUTTON "Cancel",IDCANCEL,65,60,50,14 + LTEXT "Usage Page:",IDC_STATIC,7,7,42,8 + LTEXT "",IDC_USAGE_PAGE,54,7,34,8 + LTEXT "Value:",IDC_STATIC,27,37,21,8 + EDITTEXT IDC_VALUE,53,34,125,13,ES_AUTOHSCROLL + LTEXT "Usage:",IDC_STATIC,25,21,24,8 + LTEXT "",IDC_USAGE,54,21,34,8 +END + +IDD_USAGE_LIST_DIFFERENCE DIALOGEX DISCARDABLE 0, 0, 227, 95 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Usage List Difference" +FONT 8, "MS Shell Dlg" +BEGIN + DEFPUSHBUTTON "OK",IDOK,170,73,50,14 + PUSHBUTTON "Cancel",IDCANCEL,111,73,50,14 + LTEXT "Previous Usage List (hex):",IDC_STATIC,7,19,83,8 + EDITTEXT IDC_USAGE_LIST1,96,16,124,13,ES_AUTOHSCROLL + LTEXT "Current Usage List (hex):",IDC_STATIC,12,44,78,8 + EDITTEXT IDC_USAGE_LIST2,96,41,124,13,ES_AUTOHSCROLL +END + +IDD_UNSET_BUTTONS DIALOGEX DISCARDABLE 0, 0, 185, 79 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Unset Button Usages" +FONT 8, "MS Shell Dlg" +BEGIN + DEFPUSHBUTTON "OK",IDOK,128,57,50,14 + PUSHBUTTON "Cancel",IDCANCEL,65,57,50,14 + LTEXT "Usage Page:",IDC_STATIC,7,7,42,8 + LTEXT "",IDC_USAGE_PAGE,54,7,34,8 + LTEXT "Usages (hex):",IDC_STATIC,7,29,44,8 + EDITTEXT IDC_USAGE_LIST,54,26,124,13,ES_AUTOHSCROLL +END + +IDD_UNSET_USAGES DIALOGEX DISCARDABLE 0, 0, 185, 79 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "'Unset Usages" +FONT 8, "MS Shell Dlg" +BEGIN + DEFPUSHBUTTON "OK",IDOK,128,57,50,14 + PUSHBUTTON "Cancel",IDCANCEL,65,57,50,14 + LTEXT "Usage Page:",IDC_STATIC,7,7,42,8 + LTEXT "",IDC_USAGE_PAGE,54,7,34,8 + LTEXT "Usages (hex):",IDC_STATIC,7,29,44,8 + EDITTEXT IDC_USAGE_LIST,54,26,124,13,ES_AUTOHSCROLL +END + +IDD_SET_DATA DIALOGEX DISCARDABLE 0, 0, 188, 159 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Set Data" +FONT 8, "MS Shell Dlg" +BEGIN + DEFPUSHBUTTON "OK",IDOK,131,137,50,14 + PUSHBUTTON "Cancel",IDCANCEL,65,137,50,14 + LTEXT "Value:",-1,30,33,21,8 + EDITTEXT IDC_VALUE,55,32,28,13,ES_AUTOHSCROLL + LTEXT "Data Index:",-1,13,8,38,8 + EDITTEXT IDC_INDEX,55,6,28,14,ES_AUTOHSCROLL + PUSHBUTTON "Add Data",IDC_ADD_DATA,19,58,63,15 + PUSHBUTTON "Remove Data",IDC_REMOVE_DATA,101,58,63,15 + LISTBOX IDC_DATA_LIST,7,85,174,49,LBS_NOINTEGRALHEIGHT | + WS_VSCROLL | WS_HSCROLL | WS_TABSTOP +END + +IDD_SET_BUFFER_LENGTH DIALOGEX DISCARDABLE 0, 0, 170, 66 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Set Buffer Length" +FONT 8, "MS Shell Dlg" +BEGIN + DEFPUSHBUTTON "OK",IDOK,113,44,50,14 + PUSHBUTTON "Cancel",IDCANCEL,51,44,50,14 + LTEXT "Data Buffer Length (in bytes):",IDC_STATIC,8,20,93,8 + EDITTEXT IDC_BUFFER_LENGTH,109,18,54,13,ES_AUTOHSCROLL +END + +IDD_SET_INPUT_BUFFERS DIALOGEX DISCARDABLE 0, 0, 170, 79 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Set Number Input Buffers" +FONT 8, "MS Shell Dlg" +BEGIN + DEFPUSHBUTTON "OK",IDOK,98,57,50,14 + PUSHBUTTON "Cancel",IDCANCEL,35,57,50,14 + LTEXT "Number Of Input Buffers:",IDC_STATIC,8,20,79,8 + EDITTEXT IDC_INPUT_BUFFERS,91,17,54,13,ES_AUTOHSCROLL +END + +IDD_GET_INDEX_STRING DIALOGEX DISCARDABLE 0, 0, 170, 81 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Get Indexed String" +FONT 8, "MS Shell Dlg" +BEGIN + DEFPUSHBUTTON "OK",IDOK,113,59,50,14 + PUSHBUTTON "Cancel",IDCANCEL,51,59,50,14 + LTEXT "Data Buffer Length (in bytes):",IDC_STATIC,8,33,93,8 + EDITTEXT IDC_BUFFER_LENGTH,109,31,54,13,ES_AUTOHSCROLL + LTEXT "String Index:",IDC_STATIC,61,14,40,8 + EDITTEXT IDC_INDEX,109,13,39,12,ES_AUTOHSCROLL +END + +IDD_SET_USAGES DIALOGEX DISCARDABLE 0, 0, 185, 79 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Set Usages" +FONT 8, "MS Shell Dlg" +BEGIN + DEFPUSHBUTTON "OK",IDOK,128,57,50,14 + PUSHBUTTON "Cancel",IDCANCEL,65,57,50,14 + LTEXT "Usage Page:",IDC_STATIC,7,7,42,8 + LTEXT "",IDC_USAGE_PAGE,54,7,34,8 + LTEXT "Usages (hex):",IDC_STATIC,7,29,44,8 + EDITTEXT IDC_USAGE_LIST,54,26,124,13,ES_AUTOHSCROLL +END + +IDD_GET_EXT_ATTRIB DIALOGEX DISCARDABLE 0, 0, 170, 81 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Get Extended Attributes" +FONT 8, "MS Shell Dlg" +BEGIN + DEFPUSHBUTTON "OK",IDOK,113,59,50,14 + PUSHBUTTON "Cancel",IDCANCEL,51,59,50,14 + LTEXT "Data Buffer Length (in bytes):",IDC_STATIC,8,33,93,8 + EDITTEXT IDC_BUFFER_LENGTH,109,31,54,13,ES_AUTOHSCROLL + LTEXT "Data Index:",IDC_STATIC,61,14,38,8 + EDITTEXT IDC_INDEX,109,13,39,12,ES_AUTOHSCROLL +END diff --git a/hid/hclient/hclient.sln b/hid/hclient/hclient.sln new file mode 100644 index 00000000..69314509 --- /dev/null +++ b/hid/hclient/hclient.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0 +MinimumVisualStudioVersion = 12.0 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hclient", "hclient.vcxproj", "{AC9126E3-E293-428A-AEDB-6E3F0F7ACD21}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {AC9126E3-E293-428A-AEDB-6E3F0F7ACD21}.Debug|Win32.ActiveCfg = Debug|Win32 + {AC9126E3-E293-428A-AEDB-6E3F0F7ACD21}.Debug|Win32.Build.0 = Debug|Win32 + {AC9126E3-E293-428A-AEDB-6E3F0F7ACD21}.Release|Win32.ActiveCfg = Release|Win32 + {AC9126E3-E293-428A-AEDB-6E3F0F7ACD21}.Release|Win32.Build.0 = Release|Win32 + {AC9126E3-E293-428A-AEDB-6E3F0F7ACD21}.Debug|x64.ActiveCfg = Debug|x64 + {AC9126E3-E293-428A-AEDB-6E3F0F7ACD21}.Debug|x64.Build.0 = Debug|x64 + {AC9126E3-E293-428A-AEDB-6E3F0F7ACD21}.Release|x64.ActiveCfg = Release|x64 + {AC9126E3-E293-428A-AEDB-6E3F0F7ACD21}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/hid/hclient/hclient.vcxproj b/hid/hclient/hclient.vcxproj new file mode 100644 index 00000000..6ef71350 --- /dev/null +++ b/hid/hclient/hclient.vcxproj @@ -0,0 +1,185 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {AC9126E3-E293-428A-AEDB-6E3F0F7ACD21} + $(MSBuildProjectName) + Debug + Win32 + {A2706ED9-AB39-4810-94CD-F7BE251F6456} + + + + Windows10 + False + Desktop + + WindowsApplicationForDrivers10.0 + Application + + + Windows10 + True + Desktop + + WindowsApplicationForDrivers10.0 + Application + + + Windows10 + False + Desktop + + WindowsApplicationForDrivers10.0 + Application + + + Windows10 + True + Desktop + + WindowsApplicationForDrivers10.0 + Application + + + + $(IntDir) + + + + + + + + + + + + + + + + hclient + + + hclient + + + hclient + + + hclient + + + + true + Level4 + %(AdditionalIncludeDirectories) + + + + + %(AdditionalDependencies);hid.lib;setupapi.lib;comdlg32.lib;shell32.lib + + + %(AdditionalIncludeDirectories) + + + %(AdditionalIncludeDirectories) + + + + + true + Level4 + %(AdditionalIncludeDirectories) + + + + + %(AdditionalDependencies);hid.lib;setupapi.lib;comdlg32.lib;shell32.lib + + + %(AdditionalIncludeDirectories) + + + %(AdditionalIncludeDirectories) + + + + + true + Level4 + %(AdditionalIncludeDirectories) + + + + + %(AdditionalDependencies);hid.lib;setupapi.lib;comdlg32.lib;shell32.lib + + + %(AdditionalIncludeDirectories) + + + %(AdditionalIncludeDirectories) + + + + + true + Level4 + %(AdditionalIncludeDirectories) + + + + + %(AdditionalDependencies);hid.lib;setupapi.lib;comdlg32.lib;shell32.lib + + + %(AdditionalIncludeDirectories) + + + %(AdditionalIncludeDirectories) + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/hid/hclient/hclient.vcxproj.Filters b/hid/hclient/hclient.vcxproj.Filters new file mode 100644 index 00000000..929de5a4 --- /dev/null +++ b/hid/hclient/hclient.vcxproj.Filters @@ -0,0 +1,42 @@ + + + + + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* + {3CD69E69-D314-43C2-988D-6A3C580F61BE} + + + h;hpp;hxx;hm;inl;inc;xsd + {D93C41DB-1154-4AB9-8FAB-EF653138D12B} + + + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml + {BF7E346B-B570-4400-8C2B-765D723A7FBF} + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Resource Files + + + \ No newline at end of file diff --git a/hid/hclient/hid.h b/hid/hclient/hid.h new file mode 100644 index 00000000..af149ba7 --- /dev/null +++ b/hid/hclient/hid.h @@ -0,0 +1,206 @@ +/*++ + +Copyright (c) Microsoft 1998, All Rights Reserved + +Module Name: + + hid.h + +Abstract: + + This module contains the declarations and definitions for use with the + hid user mode client sample driver. + +Environment: + + Kernel & user mode + +--*/ + +#ifndef HID_H +#define HID_H + +#if _MSC_VER >= 1200 +#pragma warning(push) +#endif +#pragma warning(disable:4201) // nameless struct/union + +#include "hidsdi.h" +#include "setupapi.h" + + + +typedef struct _SP_FNCLASS_DEVICE_DATA { + DWORD cbSize; + GUID FunctionClassGuid; + TCHAR DevicePath [ANYSIZE_ARRAY]; +} SP_FNCLASS_DEVICE_DATA, *PSP_FNCLASS_DEVICE_DATA; + +BOOLEAN +SetupDiGetFunctionClassDeviceInfo ( + IN HDEVINFO DeviceInfoSet, + IN PSP_DEVINFO_DATA DeviceInfoData, + OUT PSP_FNCLASS_DEVICE_DATA FunctionClassDeviceData, + IN DWORD FunctionClassDeviceDataSize, + OUT PDWORD RequiredSize + ); + +#define ASSERT(x) + +// +// A structure to hold the steady state data received from the hid device. +// Each time a read packet is received we fill in this structure. +// Each time we wish to write to a hid device we fill in this structure. +// This structure is here only for convenience. Most real applications will +// have a more efficient way of moving the hid data to the read, write, and +// feature routines. +// +typedef struct _HID_DATA { + BOOLEAN IsButtonData; + UCHAR Reserved; + USAGE UsagePage; // The usage page for which we are looking. + ULONG Status; // The last status returned from the accessor function + // when updating this field. + ULONG ReportID; // ReportID for this given data structure + BOOLEAN IsDataSet; // Variable to track whether a given data structure + // has already been added to a report structure + + union { + struct { + ULONG UsageMin; // Variables to track the usage minimum and max + ULONG UsageMax; // If equal, then only a single usage + ULONG MaxUsageLength; // Usages buffer length. + PUSAGE Usages; // list of usages (buttons ``down'' on the device. + + } ButtonData; + struct { + USAGE Usage; // The usage describing this value; + USHORT Reserved; + + ULONG Value; + LONG ScaledValue; + } ValueData; + }; +} HID_DATA, *PHID_DATA; + +typedef struct _HID_DEVICE { + PCHAR DevicePath; + HANDLE HidDevice; // A file handle to the hid device. + BOOL OpenedForRead; + BOOL OpenedForWrite; + BOOL OpenedOverlapped; + BOOL OpenedExclusive; + + PHIDP_PREPARSED_DATA Ppd; // The opaque parser info describing this device + HIDP_CAPS Caps; // The Capabilities of this hid device. + HIDD_ATTRIBUTES Attributes; + + PCHAR InputReportBuffer; + _Field_size_(InputDataLength) + PHID_DATA InputData; // array of hid data structures + ULONG InputDataLength; // Num elements in this array. + PHIDP_BUTTON_CAPS InputButtonCaps; + PHIDP_VALUE_CAPS InputValueCaps; + + PCHAR OutputReportBuffer; + _Field_size_(OutputDataLength) + PHID_DATA OutputData; + ULONG OutputDataLength; + PHIDP_BUTTON_CAPS OutputButtonCaps; + PHIDP_VALUE_CAPS OutputValueCaps; + + PCHAR FeatureReportBuffer; + _Field_size_(FeatureDataLength) PHID_DATA FeatureData; + ULONG FeatureDataLength; + PHIDP_BUTTON_CAPS FeatureButtonCaps; + PHIDP_VALUE_CAPS FeatureValueCaps; +} HID_DEVICE, *PHID_DEVICE; + + +BOOLEAN +OpenHidDevice ( + _In_ LPSTR DevicePath, + _In_ BOOL HasReadAccess, + _In_ BOOL HasWriteAccess, + _In_ BOOL IsOverlapped, + _In_ BOOL IsExclusive, + _Out_ PHID_DEVICE HidDevice +); + +BOOLEAN +FindKnownHidDevices ( + OUT PHID_DEVICE * HidDevices, // A array of struct _HID_DEVICE + OUT PULONG NumberDevices // the length of this array. + ); + +BOOLEAN +FillDeviceInfo( + IN PHID_DEVICE HidDevice +); + +VOID +CloseHidDevices ( + OUT PHID_DEVICE HidDevices, // A array of struct _HID_DEVICE + OUT ULONG NumberDevices // the length of this array. + ); + +VOID +CloseHidDevice ( + IN PHID_DEVICE HidDevice + ); + + +BOOLEAN +Read ( + PHID_DEVICE HidDevice + ); + +BOOLEAN +ReadOverlapped ( + PHID_DEVICE HidDevice, + HANDLE CompletionEvent + ); + +BOOLEAN +Write ( + PHID_DEVICE HidDevice + ); + +BOOLEAN +UnpackReport ( + _In_reads_bytes_(ReportBufferLength)PCHAR ReportBuffer, + IN USHORT ReportBufferLength, + IN HIDP_REPORT_TYPE ReportType, + IN OUT PHID_DATA Data, + IN ULONG DataLength, + IN PHIDP_PREPARSED_DATA Ppd + ); + +BOOLEAN +PackReport ( + _Out_writes_bytes_(ReportBufferLength)PCHAR ReportBuffer, + IN USHORT ReportBufferLength, + IN HIDP_REPORT_TYPE ReportType, + IN PHID_DATA Data, + IN ULONG DataLength, + IN PHIDP_PREPARSED_DATA Ppd + ); + +BOOLEAN +SetFeature ( + PHID_DEVICE HidDevice + ); + +BOOLEAN +GetFeature ( + PHID_DEVICE HidDevice + ); + +#if _MSC_VER >= 1200 +#pragma warning(pop) +#else +#pragma warning(default:4201) +#endif + +#endif + diff --git a/hid/hclient/list.h b/hid/hclient/list.h new file mode 100644 index 00000000..71dd94d7 --- /dev/null +++ b/hid/hclient/list.h @@ -0,0 +1,282 @@ +/*++ + +Copyright (c) Microsoft 1998, All Rights Reserved + +Module Name: + + list.h + +Abstract: + + This module contains the code for manipulating list structures. + +Environment: + + User mode + +Revision History: + + Nov-97 : Created + +--*/ + + +#ifndef __LIST_H__ +#define __LIST_H__ + +#include + +typedef LIST_ENTRY LIST_NODE_HDR, *PLIST_NODE_HDR; +typedef LIST_NODE_HDR LIST, *PLIST; + +typedef VOID PLIST_CALLBACK(PLIST_NODE_HDR); + +VOID +InitializeList( + IN PLIST NewList +); + +VOID +InsertHead( + IN PLIST List, + IN PLIST_NODE_HDR ListNode +); + +VOID +InsertTail( + IN PLIST List, + IN PLIST_NODE_HDR ListNode +); + +VOID +RemoveNode( + IN PLIST_NODE_HDR ListNode +); + +PLIST_NODE_HDR +RemoveHead( + IN PLIST List +); + +PLIST_NODE_HDR +RemoveTail( + IN PLIST List +); + +BOOL +IsListEmpty( + IN PLIST List +); + +PLIST_NODE_HDR +GetListHead( + IN PLIST List +); + +PLIST_NODE_HDR +GetListTail( + IN PLIST List +); + +PLIST_NODE_HDR +GetNextEntry( + IN PLIST_NODE_HDR ListNode +); + +PLIST_NODE_HDR +GetPrevEntry( + IN PLIST_NODE_HDR ListNode +); + +VOID +DestroyListNoCallback( + IN PLIST List +); + +VOID +DestroyListWithCallback( + IN PLIST List, + IN PLIST_CALLBACK Callback +); + + +/***************************************************************************** +/* Macro definitions of list functions +/*****************************************************************************/ + + /* + // VOID + // InitializeList( + // IN PLIST NewList + // ); + */ + + #define InitializeList(nl) \ + { ((PLIST)(nl)) -> Flink = ((PLIST)(nl)) -> Blink = nl; } + + /* + // VOID + // InsertHead( + / IN PLIST List, + // IN PLIST_NODE_HDR ListNode + // ); + */ + + #define InsertHead(List, Node) { \ + PLIST_NODE_HDR _EX_Flink; \ + PLIST_NODE_HDR _EX_List; \ + \ + _EX_List = ((PLIST_NODE_HDR) (List)); \ + _EX_Flink = _EX_List -> Flink; \ + ((PLIST_NODE_HDR) (Node))->Blink = _EX_List; \ + ((PLIST_NODE_HDR) (Node))->Flink = _EX_Flink; \ + _EX_Flink->Blink = (((PLIST_NODE_HDR) (Node))); \ + _EX_List->Flink = ((PLIST_NODE_HDR) (Node)); \ + } + + + /* + // VOID + // InsertTail( + // IN PLIST List, + // IN PLIST_NODE_HDR ListNode + // ); + */ + + #define InsertTail(List, Node) { \ + PLIST_NODE_HDR _EX_Blink; \ + PLIST_NODE_HDR _EX_List; \ + \ + _EX_List = ((PLIST_NODE_HDR) (List)); \ + _EX_Blink = _EX_List->Blink; \ + ((PLIST_NODE_HDR) (Node))->Flink = _EX_List; \ + ((PLIST_NODE_HDR) (Node))->Blink = _EX_Blink; \ + _EX_Blink->Flink = (((PLIST_NODE_HDR) (Node))); \ + _EX_List->Blink = ((PLIST_NODE_HDR) (Node)); \ + } + + /* + // VOID + // RemoveNode( + // IN PLIST_NODE_HDR ListNode + // ); + */ + + #define RemoveNode(node) { \ + PLIST_NODE_HDR _EX_Blink; \ + PLIST_NODE_HDR _EX_Flink; \ + \ + _EX_Flink = ((PLIST_NODE_HDR) (node))->Flink; \ + _EX_Blink = ((PLIST_NODE_HDR) (node))->Blink; \ + _EX_Blink->Flink = _EX_Flink; \ + _EX_Flink->Blink = _EX_Blink; \ + } + + + /* + // PLIST_NODE_HDR + // RemoveHead( + // IN PLIST List + // ); + */ + + #define RemoveHead(List) \ + GetListHead((List)); \ + RemoveNode(((PLIST_NODE_HDR) (List))->Flink) + + /* + // PLIST_NODE_HDR + // RemoveTail( + // IN PLIST List + // ); + */ + + #define RemoveTail(List) \ + GetListTail((List)); \ + RemoveNode(((PLIST_NODE_HDR) (List))->Blink) + + /* + // BOOL + // IsListEmpty( + // IN PLIST List + // ); + */ + + #define IsListEmpty(List) \ + (((PLIST_NODE_HDR) (List))->Flink == ((PLIST_NODE_HDR) (List))) + + /* + // PLIST_NODE_HDR + // GetListHead( + // IN PLIST List + // ); + */ + + #define GetListHead(List) \ + (((PLIST_NODE_HDR) (List))->Flink) + + /* + // PLIST_NODE_HDR + // GetListTail( + // IN PLIST List + // ); + */ + + #define GetListTail(List) \ + (((PLIST_NODE_HDR) (List))->Blink) + + + /* + // PLIST_NODE_HDR + // GetNextEntry( + // IN PLIST_NODE_HDR ListNode + // ); + */ + + #define GetNextEntry(ListNode) \ + (((PLIST_NODE_HDR) (ListNode)) -> Flink); + + /* + // PLIST_NODE_HDR + // GetPrevEntry( + // IN PLIST_NODE_HDR ListNode + // ); + */ + + #define GetPrevEntry(ListNode) \ + (((PLIST_NODE_HDR) (ListNode)) -> Blink); + + /* + // VOID + // DestroyListNoCallback( + // IN PLIST List, + // IN PLIST_CALLBACK Callback + // ); + */ + + #define DestroyListNoCallback(list) \ + PLIST_NODE_HDR currNode; \ + \ + while (!IsListEmpty((list))) { \ + currNode = RemoveHead((list)); \ + } \ + } + + /* + // VOID + // DestroyListWithCallback( + // IN PLIST List, + // IN PLIST_CALLBACK Callback + // ); + */ + + #define DestroyListWithCallback(list, cb) { \ + PLIST_NODE_HDR currNode; \ + \ + while (!IsListEmpty((list))) { \ + currNode = RemoveHead((list)); \ + (cb)(currNode); \ + } \ + } + +#endif diff --git a/hid/hclient/pnp.c b/hid/hclient/pnp.c new file mode 100644 index 00000000..722f46a5 --- /dev/null +++ b/hid/hclient/pnp.c @@ -0,0 +1,993 @@ +/*++ + +Copyright (c) 1996 Microsoft Corporation + +Module Name: + + pnp.c + +Abstract: + + This module contains the code + for finding, adding, removing, and identifying hid devices. + +Environment: + + User mode + +--*/ + +#include +#include +#include +#include +#include "hidsdi.h" +#include "hid.h" +#include +#include + +#pragma warning(disable:28146) // Warning is meant for kernel mode drivers + +BOOLEAN +FindKnownHidDevices ( + OUT PHID_DEVICE * HidDevices, // A array of struct _HID_DEVICE + OUT PULONG NumberDevices // the length of this array. + ) +/*++ +Routine Description: + Do the required PnP things in order to find all the HID devices in + the system at this time. +--*/ +{ + HDEVINFO hardwareDeviceInfo = INVALID_HANDLE_VALUE; + SP_DEVICE_INTERFACE_DATA deviceInfoData; + ULONG i; + BOOLEAN done = FALSE; + PHID_DEVICE hidDeviceInst; + GUID hidGuid; + PSP_DEVICE_INTERFACE_DETAIL_DATA functionClassDeviceData = NULL; + ULONG predictedLength = 0; + ULONG requiredLength = 0; + PHID_DEVICE newHidDevices; + + + HidD_GetHidGuid (&hidGuid); + + *HidDevices = NULL; + *NumberDevices = 0; + + // + // Open a handle to the plug and play dev node. + // + hardwareDeviceInfo = SetupDiGetClassDevs ( &hidGuid, + NULL, // Define no enumerator (global) + NULL, // Define no + (DIGCF_PRESENT | // Only Devices present + DIGCF_DEVICEINTERFACE)); // Function class devices. + + if (INVALID_HANDLE_VALUE == hardwareDeviceInfo) + { + goto Done; + } + + // + // Take a wild guess to start + // + + *NumberDevices = 4; + done = FALSE; + deviceInfoData.cbSize = sizeof (SP_DEVICE_INTERFACE_DATA); + + i=0; + while (!done) + { + *NumberDevices *= 2; + + if (*HidDevices) + { + newHidDevices = + realloc (*HidDevices, (*NumberDevices * sizeof (HID_DEVICE))); + + if (NULL == newHidDevices) + { + free(*HidDevices); + } + + *HidDevices = newHidDevices; + } + else + { + *HidDevices = calloc (*NumberDevices, sizeof (HID_DEVICE)); + } + + if (NULL == *HidDevices) + { + goto Done; + } + + hidDeviceInst = *HidDevices + i; + + for (; i < *NumberDevices; i++, hidDeviceInst++) + { + // + // Initialize an empty HID_DEVICE + // + RtlZeroMemory(hidDeviceInst,sizeof(HID_DEVICE)); + + hidDeviceInst -> HidDevice = INVALID_HANDLE_VALUE; + + if (SetupDiEnumDeviceInterfaces (hardwareDeviceInfo, + 0, // No care about specific PDOs + &hidGuid, + i, + &deviceInfoData)) + { + // + // allocate a function class device data structure to receive the + // goods about this particular device. + // + + SetupDiGetDeviceInterfaceDetail ( + hardwareDeviceInfo, + &deviceInfoData, + NULL, // probing so no output buffer yet + 0, // probing so output buffer length of zero + &requiredLength, + NULL); // not interested in the specific dev-node + + + predictedLength = requiredLength; + + functionClassDeviceData = malloc (predictedLength); + if (functionClassDeviceData) + { + functionClassDeviceData->cbSize = sizeof (SP_DEVICE_INTERFACE_DETAIL_DATA); + ZeroMemory(functionClassDeviceData->DevicePath, sizeof(functionClassDeviceData->DevicePath)); + } + else + { + goto Done; + } + + // + // Retrieve the information from Plug and Play. + // + + if (SetupDiGetDeviceInterfaceDetail ( + hardwareDeviceInfo, + &deviceInfoData, + functionClassDeviceData, + predictedLength, + &requiredLength, + NULL)) + { + // + // Open device with just generic query abilities to begin with + // + + if (! OpenHidDevice (functionClassDeviceData -> DevicePath, + FALSE, // ReadAccess - none + FALSE, // WriteAccess - none + FALSE, // Overlapped - no + FALSE, // Exclusive - no + hidDeviceInst)) + { + // + // Save the device path so it can be still listed. + // + INT iDevicePathSize; + + iDevicePathSize = (INT)strlen(functionClassDeviceData -> DevicePath) + 1; + + hidDeviceInst -> DevicePath = malloc(iDevicePathSize); + + if (NULL != hidDeviceInst -> DevicePath) + { + StringCbCopy(hidDeviceInst -> DevicePath, iDevicePathSize, functionClassDeviceData -> DevicePath); + } + } + } + + free(functionClassDeviceData); + functionClassDeviceData = NULL; + } + else + { + if (ERROR_NO_MORE_ITEMS == GetLastError()) + { + done = TRUE; + break; + } + } + } + } + + *NumberDevices = i; + +Done: + if (FALSE == done) + { + if (NULL != *HidDevices) + { + free(*HidDevices); + *HidDevices = NULL; + } + } + + if (INVALID_HANDLE_VALUE != hardwareDeviceInfo) + { + SetupDiDestroyDeviceInfoList (hardwareDeviceInfo); + hardwareDeviceInfo = INVALID_HANDLE_VALUE; + } + + return done; +} + +BOOLEAN +OpenHidDevice ( + _In_ LPSTR DevicePath, + _In_ BOOL HasReadAccess, + _In_ BOOL HasWriteAccess, + _In_ BOOL IsOverlapped, + _In_ BOOL IsExclusive, + _Out_ PHID_DEVICE HidDevice +) +/*++ +RoutineDescription: + Given the HardwareDeviceInfo, representing a handle to the plug and + play information, and deviceInfoData, representing a specific hid device, + open that device and fill in all the relivant information in the given + HID_DEVICE structure. + + return if the open and initialization was successfull or not. + +--*/ +{ + DWORD accessFlags = 0; + DWORD sharingFlags = 0; + BOOLEAN bRet = FALSE; + INT iDevicePathSize; + + RtlZeroMemory(HidDevice,sizeof(HID_DEVICE)); + HidDevice -> HidDevice = INVALID_HANDLE_VALUE; + + if (NULL == DevicePath) + { + goto Done; + } + + iDevicePathSize = (INT)strlen(DevicePath) + 1; + + HidDevice -> DevicePath = malloc(iDevicePathSize); + + if (NULL == HidDevice -> DevicePath) + { + goto Done; + } + + StringCbCopy(HidDevice -> DevicePath, iDevicePathSize, DevicePath); + + if (HasReadAccess) + { + accessFlags |= GENERIC_READ; + } + + if (HasWriteAccess) + { + accessFlags |= GENERIC_WRITE; + } + + if (!IsExclusive) + { + sharingFlags = FILE_SHARE_READ | FILE_SHARE_WRITE; + } + + // + // The hid.dll api's do not pass the overlapped structure into deviceiocontrol + // so to use them we must have a non overlapped device. If the request is for + // an overlapped device we will close the device below and get a handle to an + // overlapped device + // + + HidDevice->HidDevice = CreateFile (DevicePath, + accessFlags, + sharingFlags, + NULL, // no SECURITY_ATTRIBUTES structure + OPEN_EXISTING, // No special create flags + 0, // Open device as non-overlapped so we can get data + NULL); // No template file + + if (INVALID_HANDLE_VALUE == HidDevice->HidDevice) + { + goto Done; + } + + HidDevice -> OpenedForRead = HasReadAccess; + HidDevice -> OpenedForWrite = HasWriteAccess; + HidDevice -> OpenedOverlapped = IsOverlapped; + HidDevice -> OpenedExclusive = IsExclusive; + + // + // If the device was not opened as overlapped, then fill in the rest of the + // HidDevice structure. However, if opened as overlapped, this handle cannot + // be used in the calls to the HidD_ exported functions since each of these + // functions does synchronous I/O. + // + + if (!HidD_GetPreparsedData (HidDevice->HidDevice, &HidDevice->Ppd)) + { + goto Done; + } + + if (!HidD_GetAttributes (HidDevice->HidDevice, &HidDevice->Attributes)) + { + goto Done; + } + + if (!HidP_GetCaps (HidDevice->Ppd, &HidDevice->Caps)) + { + goto Done; + } + + // + // At this point the client has a choice. It may chose to look at the + // Usage and Page of the top level collection found in the HIDP_CAPS + // structure. In this way it could just use the usages it knows about. + // If either HidP_GetUsages or HidP_GetUsageValue return an error then + // that particular usage does not exist in the report. + // This is most likely the preferred method as the application can only + // use usages of which it already knows. + // In this case the app need not even call GetButtonCaps or GetValueCaps. + // + // In this example, however, we will call FillDeviceInfo to look for all + // of the usages in the device. + // + + if (FALSE == FillDeviceInfo(HidDevice)) + { + goto Done; + } + + if (IsOverlapped) + { + CloseHandle(HidDevice->HidDevice); + HidDevice->HidDevice = INVALID_HANDLE_VALUE; + + HidDevice->HidDevice = CreateFile (DevicePath, + accessFlags, + sharingFlags, + NULL, // no SECURITY_ATTRIBUTES structure + OPEN_EXISTING, // No special create flags + FILE_FLAG_OVERLAPPED, // Now we open the device as overlapped + NULL); // No template file + + if (INVALID_HANDLE_VALUE == HidDevice->HidDevice) + { + goto Done; + } + } + + bRet = TRUE; + +Done: + if (!bRet) + { + CloseHidDevice(HidDevice); + } + + return (bRet); +} + +BOOLEAN +FillDeviceInfo( + IN PHID_DEVICE HidDevice +) +{ + ULONG numValues; + USHORT numCaps; + PHIDP_BUTTON_CAPS buttonCaps; + PHIDP_VALUE_CAPS valueCaps; + PHID_DATA data; + ULONG i; + USAGE usage; + UINT dataIdx; + ULONG newFeatureDataLength; + ULONG tmpSum; + BOOLEAN bRet = FALSE; + + // + // setup Input Data buffers. + // + + // + // Allocate memory to hold on input report + // + + HidDevice->InputReportBuffer = (PCHAR) + calloc (HidDevice->Caps.InputReportByteLength, sizeof (CHAR)); + + + // + // Allocate memory to hold the button and value capabilities. + // NumberXXCaps is in terms of array elements. + // + + HidDevice->InputButtonCaps = buttonCaps = (PHIDP_BUTTON_CAPS) + calloc (HidDevice->Caps.NumberInputButtonCaps, sizeof (HIDP_BUTTON_CAPS)); + + if (NULL == buttonCaps) + { + goto Done; + } + + HidDevice->InputValueCaps = valueCaps = (PHIDP_VALUE_CAPS) + calloc (HidDevice->Caps.NumberInputValueCaps, sizeof (HIDP_VALUE_CAPS)); + + if (NULL == valueCaps) + { + goto Done; + } + + // + // Have the HidP_X functions fill in the capability structure arrays. + // + + numCaps = HidDevice->Caps.NumberInputButtonCaps; + + if(numCaps > 0) + { + if(HIDP_STATUS_SUCCESS != (HidP_GetButtonCaps (HidP_Input, + buttonCaps, + &numCaps, + HidDevice->Ppd))) + { + goto Done; + } + } + + numCaps = HidDevice->Caps.NumberInputValueCaps; + + if(numCaps > 0) + { + if(HIDP_STATUS_SUCCESS != (HidP_GetValueCaps (HidP_Input, + valueCaps, + &numCaps, + HidDevice->Ppd))) + { + goto Done; + } + } + + + // + // Depending on the device, some value caps structures may represent more + // than one value. (A range). In the interest of being verbose, over + // efficient, we will expand these so that we have one and only one + // struct _HID_DATA for each value. + // + // To do this we need to count up the total number of values are listed + // in the value caps structure. For each element in the array we test + // for range if it is a range then UsageMax and UsageMin describe the + // usages for this range INCLUSIVE. + // + + numValues = 0; + for (i = 0; i < HidDevice->Caps.NumberInputValueCaps; i++, valueCaps++) + { + if (valueCaps->IsRange) + { + numValues += valueCaps->Range.UsageMax - valueCaps->Range.UsageMin + 1; + if(valueCaps->Range.UsageMin > valueCaps->Range.UsageMax) + { + goto Done; // overrun check + } + } + else + { + numValues++; + } + } + + valueCaps = HidDevice->InputValueCaps; + + // + // Allocate a buffer to hold the struct _HID_DATA structures. + // One element for each set of buttons, and one element for each value + // found. + // + + HidDevice->InputDataLength = HidDevice->Caps.NumberInputButtonCaps + + numValues; + + HidDevice->InputData = data = (PHID_DATA) + calloc (HidDevice->InputDataLength, sizeof (HID_DATA)); + + if (NULL == data) + { + goto Done; + } + + // + // Fill in the button data + // + dataIdx = 0; + for (i = 0; + i < HidDevice->Caps.NumberInputButtonCaps; + i++, data++, buttonCaps++, dataIdx++) + { + data->IsButtonData = TRUE; + data->Status = HIDP_STATUS_SUCCESS; + data->UsagePage = buttonCaps->UsagePage; + if (buttonCaps->IsRange) + { + data->ButtonData.UsageMin = buttonCaps -> Range.UsageMin; + data->ButtonData.UsageMax = buttonCaps -> Range.UsageMax; + } + else + { + data -> ButtonData.UsageMin = data -> ButtonData.UsageMax = buttonCaps -> NotRange.Usage; + } + + data->ButtonData.MaxUsageLength = HidP_MaxUsageListLength ( + HidP_Input, + buttonCaps->UsagePage, + HidDevice->Ppd); + data->ButtonData.Usages = (PUSAGE) + calloc (data->ButtonData.MaxUsageLength, sizeof (USAGE)); + + data->ReportID = buttonCaps -> ReportID; + } + + // + // Fill in the value data + // + + for (i = 0; i < HidDevice->Caps.NumberInputValueCaps ; i++, valueCaps++) + { + if (valueCaps->IsRange) + { + for (usage = valueCaps->Range.UsageMin; + usage <= valueCaps->Range.UsageMax; + usage++) + { + if(dataIdx >= (HidDevice->InputDataLength)) + { + goto Done; // error case + } + data->IsButtonData = FALSE; + data->Status = HIDP_STATUS_SUCCESS; + data->UsagePage = valueCaps->UsagePage; + data->ValueData.Usage = usage; + data->ReportID = valueCaps -> ReportID; + data++; + dataIdx++; + } + } + else + { + if(dataIdx >= (HidDevice->InputDataLength)) + { + goto Done; // error case + } + data->IsButtonData = FALSE; + data->Status = HIDP_STATUS_SUCCESS; + data->UsagePage = valueCaps->UsagePage; + data->ValueData.Usage = valueCaps->NotRange.Usage; + data->ReportID = valueCaps -> ReportID; + data++; + dataIdx++; + } + } + + // + // setup Output Data buffers. + // + + HidDevice->OutputReportBuffer = (PCHAR) + calloc (HidDevice->Caps.OutputReportByteLength, sizeof (CHAR)); + + HidDevice->OutputButtonCaps = buttonCaps = (PHIDP_BUTTON_CAPS) + calloc (HidDevice->Caps.NumberOutputButtonCaps, sizeof (HIDP_BUTTON_CAPS)); + + if (NULL == buttonCaps) + { + goto Done; + } + + HidDevice->OutputValueCaps = valueCaps = (PHIDP_VALUE_CAPS) + calloc (HidDevice->Caps.NumberOutputValueCaps, sizeof (HIDP_VALUE_CAPS)); + + if (NULL == valueCaps) + { + goto Done; + } + + numCaps = HidDevice->Caps.NumberOutputButtonCaps; + if(numCaps > 0) + { + if(HIDP_STATUS_SUCCESS != (HidP_GetButtonCaps (HidP_Output, + buttonCaps, + &numCaps, + HidDevice->Ppd))) + { + goto Done; + } + } + + numCaps = HidDevice->Caps.NumberOutputValueCaps; + if(numCaps > 0) + { + if(HIDP_STATUS_SUCCESS != (HidP_GetValueCaps (HidP_Output, + valueCaps, + &numCaps, + HidDevice->Ppd))) + { + goto Done; + } + } + + numValues = 0; + for (i = 0; i < HidDevice->Caps.NumberOutputValueCaps; i++, valueCaps++) + { + if (valueCaps->IsRange) + { + numValues += valueCaps->Range.UsageMax + - valueCaps->Range.UsageMin + 1; + } + else + { + numValues++; + } + } + valueCaps = HidDevice->OutputValueCaps; + + HidDevice->OutputDataLength = HidDevice->Caps.NumberOutputButtonCaps + + numValues; + + HidDevice->OutputData = data = (PHID_DATA) + calloc (HidDevice->OutputDataLength, sizeof (HID_DATA)); + + if (NULL == data) + { + goto Done; + } + + for (i = 0; + i < HidDevice->Caps.NumberOutputButtonCaps; + i++, data++, buttonCaps++) + { + if (i >= HidDevice->OutputDataLength) + { + goto Done; + } + + if(FAILED(ULongAdd((HidDevice->Caps).NumberOutputButtonCaps , + (valueCaps->Range).UsageMax, &tmpSum))) + { + goto Done; + } + + if((valueCaps->Range).UsageMin == tmpSum) + { + goto Done; + } + + data->IsButtonData = TRUE; + data->Status = HIDP_STATUS_SUCCESS; + data->UsagePage = buttonCaps->UsagePage; + + if (buttonCaps->IsRange) + { + data->ButtonData.UsageMin = buttonCaps -> Range.UsageMin; + data->ButtonData.UsageMax = buttonCaps -> Range.UsageMax; + } + else + { + data -> ButtonData.UsageMin = data -> ButtonData.UsageMax = buttonCaps -> NotRange.Usage; + } + + data->ButtonData.MaxUsageLength = HidP_MaxUsageListLength ( + HidP_Output, + buttonCaps->UsagePage, + HidDevice->Ppd); + + data->ButtonData.Usages = (PUSAGE) + calloc (data->ButtonData.MaxUsageLength, sizeof (USAGE)); + + data->ReportID = buttonCaps -> ReportID; + } + + for (i = 0; i < HidDevice->Caps.NumberOutputValueCaps ; i++, valueCaps++) + { + if (valueCaps->IsRange) + { + for (usage = valueCaps->Range.UsageMin; + usage <= valueCaps->Range.UsageMax; + usage++) + { + data->IsButtonData = FALSE; + data->Status = HIDP_STATUS_SUCCESS; + data->UsagePage = valueCaps->UsagePage; + data->ValueData.Usage = usage; + data->ReportID = valueCaps -> ReportID; + data++; + } + } + else + { + data->IsButtonData = FALSE; + data->Status = HIDP_STATUS_SUCCESS; + data->UsagePage = valueCaps->UsagePage; + data->ValueData.Usage = valueCaps->NotRange.Usage; + data->ReportID = valueCaps -> ReportID; + data++; + } + } + + // + // setup Feature Data buffers. + // + + HidDevice->FeatureReportBuffer = (PCHAR) + calloc (HidDevice->Caps.FeatureReportByteLength, sizeof (CHAR)); + + HidDevice->FeatureButtonCaps = buttonCaps = (PHIDP_BUTTON_CAPS) + calloc (HidDevice->Caps.NumberFeatureButtonCaps, sizeof (HIDP_BUTTON_CAPS)); + + if (NULL == buttonCaps) + { + goto Done; + } + + HidDevice->FeatureValueCaps = valueCaps = (PHIDP_VALUE_CAPS) + calloc (HidDevice->Caps.NumberFeatureValueCaps, sizeof (HIDP_VALUE_CAPS)); + + if (NULL == valueCaps) + { + goto Done; + } + + numCaps = HidDevice->Caps.NumberFeatureButtonCaps; + if(numCaps > 0) + { + if(HIDP_STATUS_SUCCESS != (HidP_GetButtonCaps (HidP_Feature, + buttonCaps, + &numCaps, + HidDevice->Ppd))) + { + goto Done; + } + } + + numCaps = HidDevice->Caps.NumberFeatureValueCaps; + if(numCaps > 0) + { + if(HIDP_STATUS_SUCCESS != (HidP_GetValueCaps (HidP_Feature, + valueCaps, + &numCaps, + HidDevice->Ppd))) + { + goto Done; + } + } + + numValues = 0; + for (i = 0; i < HidDevice->Caps.NumberFeatureValueCaps; i++, valueCaps++) + { + if (valueCaps->IsRange) + { + numValues += valueCaps->Range.UsageMax + - valueCaps->Range.UsageMin + 1; + } + else + { + numValues++; + } + } + valueCaps = HidDevice->FeatureValueCaps; + + if(FAILED(ULongAdd(HidDevice->Caps.NumberFeatureButtonCaps, + numValues, &newFeatureDataLength))) + { + goto Done; + } + + HidDevice->FeatureDataLength = newFeatureDataLength; + + HidDevice->FeatureData = data = (PHID_DATA) + calloc (HidDevice->FeatureDataLength, sizeof (HID_DATA)); + + if (NULL == data) + { + goto Done; + } + + dataIdx = 0; + for (i = 0; + i < HidDevice->Caps.NumberFeatureButtonCaps; + i++, data++, buttonCaps++, dataIdx++) + { + data->IsButtonData = TRUE; + data->Status = HIDP_STATUS_SUCCESS; + data->UsagePage = buttonCaps->UsagePage; + + if (buttonCaps->IsRange) + { + data->ButtonData.UsageMin = buttonCaps -> Range.UsageMin; + data->ButtonData.UsageMax = buttonCaps -> Range.UsageMax; + } + else + { + data -> ButtonData.UsageMin = data -> ButtonData.UsageMax = buttonCaps -> NotRange.Usage; + } + + data->ButtonData.MaxUsageLength = HidP_MaxUsageListLength ( + HidP_Feature, + buttonCaps->UsagePage, + HidDevice->Ppd); + data->ButtonData.Usages = (PUSAGE) + calloc (data->ButtonData.MaxUsageLength, sizeof (USAGE)); + + data->ReportID = buttonCaps -> ReportID; + } + + for (i = 0; i < HidDevice->Caps.NumberFeatureValueCaps ; i++, valueCaps++) + { + if (valueCaps->IsRange) + { + for (usage = valueCaps->Range.UsageMin; + usage <= valueCaps->Range.UsageMax; + usage++) + { + if(dataIdx >= (HidDevice->FeatureDataLength)) + { + goto Done; // error case + } + data->IsButtonData = FALSE; + data->Status = HIDP_STATUS_SUCCESS; + data->UsagePage = valueCaps->UsagePage; + data->ValueData.Usage = usage; + data->ReportID = valueCaps -> ReportID; + data++; + dataIdx++; + } + } + else + { + if(dataIdx >= (HidDevice->FeatureDataLength)) + { + goto Done; // error case + } + data->IsButtonData = FALSE; + data->Status = HIDP_STATUS_SUCCESS; + data->UsagePage = valueCaps->UsagePage; + data->ValueData.Usage = valueCaps->NotRange.Usage; + data->ReportID = valueCaps -> ReportID; + data++; + dataIdx++; + } + } + + bRet = TRUE; + +Done: + // + // We leave the resource clean-up to the caller. + // + return (bRet); +} + +VOID +CloseHidDevices( + IN PHID_DEVICE HidDevices, + IN ULONG NumberDevices +) +{ + ULONG Index; + + for (Index = 0; Index < NumberDevices; Index++) + { + CloseHidDevice(HidDevices+Index); + } + + return; +} + +VOID +CloseHidDevice ( + IN PHID_DEVICE HidDevice +) +{ + if (NULL != HidDevice -> DevicePath) + { + free(HidDevice -> DevicePath); + HidDevice -> DevicePath = NULL; + } + + if (INVALID_HANDLE_VALUE != HidDevice -> HidDevice) + { + CloseHandle(HidDevice -> HidDevice); + HidDevice -> HidDevice = INVALID_HANDLE_VALUE; + } + + if (NULL != HidDevice -> Ppd) + { + HidD_FreePreparsedData(HidDevice -> Ppd); + HidDevice -> Ppd = NULL; + } + + if (NULL != HidDevice -> InputReportBuffer) + { + free(HidDevice -> InputReportBuffer); + HidDevice -> InputReportBuffer = NULL; + } + + if (NULL != HidDevice -> InputData) + { + free(HidDevice -> InputData); + HidDevice -> InputData = NULL; + } + + if (NULL != HidDevice -> InputButtonCaps) + { + free(HidDevice -> InputButtonCaps); + HidDevice -> InputButtonCaps = NULL; + } + + if (NULL != HidDevice -> InputValueCaps) + { + free(HidDevice -> InputValueCaps); + HidDevice -> InputValueCaps = NULL; + } + + if (NULL != HidDevice -> OutputReportBuffer) + { + free(HidDevice -> OutputReportBuffer); + HidDevice -> OutputReportBuffer = NULL; + } + + if (NULL != HidDevice -> OutputData) + { + free(HidDevice -> OutputData); + HidDevice -> OutputData = NULL; + } + + if (NULL != HidDevice -> OutputButtonCaps) + { + free(HidDevice -> OutputButtonCaps); + HidDevice -> OutputButtonCaps = NULL; + } + + if (NULL != HidDevice -> OutputValueCaps) + { + free(HidDevice -> OutputValueCaps); + HidDevice -> OutputValueCaps = NULL; + } + + if (NULL != HidDevice -> FeatureReportBuffer) + { + free(HidDevice -> FeatureReportBuffer); + HidDevice -> FeatureReportBuffer = NULL; + } + + if (NULL != HidDevice -> FeatureData) + { + free(HidDevice -> FeatureData); + HidDevice -> FeatureData = NULL; + } + + if (NULL != HidDevice -> FeatureButtonCaps) + { + free(HidDevice -> FeatureButtonCaps); + HidDevice -> FeatureButtonCaps = NULL; + } + + if (NULL != HidDevice -> FeatureValueCaps) + { + free(HidDevice -> FeatureValueCaps); + HidDevice -> FeatureValueCaps = NULL; + } + + return; +} + diff --git a/hid/hclient/report.c b/hid/hclient/report.c new file mode 100644 index 00000000..6734092f --- /dev/null +++ b/hid/hclient/report.c @@ -0,0 +1,600 @@ +/*++ + +Copyright (c) 1996 Microsoft Corporation + +Module Name: + + report.c + +Abstract: + + This module contains the code for reading/writing hid reports and + translating those HID reports into useful information. + +Environment: + + User mode + +--*/ + +#include +#include +#include "hidsdi.h" +#include "hid.h" + + +BOOLEAN +Read ( + PHID_DEVICE HidDevice + ) +/*++ +RoutineDescription: + Given a struct _HID_DEVICE, obtain a read report and unpack the values + into the InputData array. +--*/ +{ + DWORD bytesRead; + BOOLEAN result = FALSE; + + if (!ReadFile (HidDevice->HidDevice, + HidDevice->InputReportBuffer, + HidDevice->Caps.InputReportByteLength, + &bytesRead, + NULL)) + { + goto Done; + } + + ASSERT (bytesRead == HidDevice->Caps.InputReportByteLength); + if (bytesRead != HidDevice->Caps.InputReportByteLength) + { + goto Done; + } + + result = UnpackReport (HidDevice->InputReportBuffer, + HidDevice->Caps.InputReportByteLength, + HidP_Input, + HidDevice->InputData, + HidDevice->InputDataLength, + HidDevice->Ppd); +Done: + return result; +} + +BOOLEAN +ReadOverlapped ( + PHID_DEVICE HidDevice, + HANDLE CompletionEvent + ) +/*++ +RoutineDescription: + Given a struct _HID_DEVICE, obtain a read report and unpack the values + into the InputData array. +--*/ +{ + static OVERLAPPED overlap; + DWORD bytesRead; + BOOL readStatus; + + /* + // Setup the overlap structure using the completion event passed in to + // to use for signalling the completion of the Read + */ + + memset(&overlap, 0, sizeof(OVERLAPPED)); + + overlap.hEvent = CompletionEvent; + + /* + // Execute the read call saving the return code to determine how to + // proceed (ie. the read completed synchronously or not). + */ + + readStatus = ReadFile ( HidDevice -> HidDevice, + HidDevice -> InputReportBuffer, + HidDevice -> Caps.InputReportByteLength, + &bytesRead, + &overlap); + + /* + // If the readStatus is FALSE, then one of two cases occurred. + // 1) ReadFile call succeeded but the Read is an overlapped one. Here, + // we should return TRUE to indicate that the Read succeeded. However, + // the calling thread should be blocked on the completion event + // which means it won't continue until the read actually completes + // + // 2) The ReadFile call failed for some unknown reason...In this case, + // the return code will be FALSE + */ + + if (!readStatus) + { + return (ERROR_IO_PENDING == GetLastError()); + } + + /* + // If readStatus is TRUE, then the ReadFile call completed synchronously, + // since the calling thread is probably going to wait on the completion + // event, signal the event so it knows it can continue. + */ + + else + { + SetEvent(CompletionEvent); + return (TRUE); + } +} + +BOOLEAN +Write ( + PHID_DEVICE HidDevice +) +/*++ +RoutineDescription: + Given a struct _HID_DEVICE, take the information in the HID_DATA array + pack it into multiple write reports and send each report to the HID device +--*/ +{ + DWORD bytesWritten; + PHID_DATA pData; + ULONG Index; + BOOLEAN Status; + BOOLEAN WriteStatus; + + /* + // Begin by looping through the HID_DEVICE's HID_DATA structure and setting + // the IsDataSet field to FALSE to indicate that each structure has + // not yet been set for this Write call. + */ + + pData = HidDevice -> OutputData; + + for (Index = 0; Index < HidDevice -> OutputDataLength; Index++, pData++) + { + pData -> IsDataSet = FALSE; + } + + /* + // In setting all the data in the reports, we need to pack a report buffer + // and call WriteFile for each report ID that is represented by the + // device structure. To do so, the IsDataSet field will be used to + // determine if a given report field has already been set. + */ + + Status = TRUE; + + pData = HidDevice -> OutputData; + for (Index = 0; Index < HidDevice -> OutputDataLength; Index++, pData++) + { + + if (!pData -> IsDataSet) + { + /* + // Package the report for this data structure. PackReport will + // set the IsDataSet fields of this structure and any other + // structures that it includes in the report with this structure + */ + + PackReport (HidDevice->OutputReportBuffer, + HidDevice->Caps.OutputReportByteLength, + HidP_Output, + pData, + HidDevice->OutputDataLength - Index, + HidDevice->Ppd); + + /* + // Now a report has been packaged up...Send it down to the device + */ + + WriteStatus = WriteFile (HidDevice->HidDevice, + HidDevice->OutputReportBuffer, + HidDevice->Caps.OutputReportByteLength, + &bytesWritten, + NULL) && (bytesWritten == HidDevice -> Caps.OutputReportByteLength); + + Status = Status && WriteStatus; + } + } + return (Status); +} + +BOOLEAN +SetFeature ( + PHID_DEVICE HidDevice +) +/*++ +RoutineDescription: +Given a struct _HID_DEVICE, take the information in the HID_DATA array +pack it into multiple reports and send it to the hid device via HidD_SetFeature() +--*/ +{ + PHID_DATA pData; + ULONG Index; + BOOLEAN Status; + BOOLEAN FeatureStatus; + /* + // Begin by looping through the HID_DEVICE's HID_DATA structure and setting + // the IsDataSet field to FALSE to indicate that each structure has + // not yet been set for this SetFeature() call. + */ + + pData = HidDevice -> FeatureData; + + for (Index = 0; Index < HidDevice -> FeatureDataLength; Index++, pData++) + { + pData -> IsDataSet = FALSE; + } + + /* + // In setting all the data in the reports, we need to pack a report buffer + // and call WriteFile for each report ID that is represented by the + // device structure. To do so, the IsDataSet field will be used to + // determine if a given report field has already been set. + */ + + Status = TRUE; + + pData = HidDevice -> FeatureData; + for (Index = 0; Index < HidDevice -> FeatureDataLength; Index++, pData++) + { + if (!pData -> IsDataSet) + { + /* + // Package the report for this data structure. PackReport will + // set the IsDataSet fields of this structure and any other + // structures that it includes in the report with this structure + */ + + PackReport (HidDevice->FeatureReportBuffer, + HidDevice->Caps.FeatureReportByteLength, + HidP_Feature, + pData, + HidDevice->FeatureDataLength - Index, + HidDevice->Ppd); + + /* + // Now a report has been packaged up...Send it down to the device + */ + + FeatureStatus =(HidD_SetFeature (HidDevice->HidDevice, + HidDevice->FeatureReportBuffer, + HidDevice->Caps.FeatureReportByteLength)); + + Status = FeatureStatus && Status; + } + } + return (Status); +} + +BOOLEAN +GetFeature ( + PHID_DEVICE HidDevice +) +/*++ +RoutineDescription: + Given a struct _HID_DEVICE, fill in the feature data structures with + all features on the device. May issue multiple HidD_GetFeature() calls to + deal with multiple report IDs. +--*/ +{ + ULONG Index; + PHID_DATA pData; + BOOLEAN FeatureStatus; + BOOLEAN Status; + + /* + // As with writing data, the IsDataSet value in all the structures should be + // set to FALSE to indicate that the value has yet to have been set + */ + + pData = HidDevice -> FeatureData; + + for (Index = 0; Index < HidDevice -> FeatureDataLength; Index++, pData++) + { + pData -> IsDataSet = FALSE; + } + + /* + // Next, each structure in the HID_DATA buffer is filled in with a value + // that is retrieved from one or more calls to HidD_GetFeature. The + // number of calls is equal to the number of reportIDs on the device + */ + + Status = TRUE; + pData = HidDevice -> FeatureData; + + for (Index = 0; Index < HidDevice -> FeatureDataLength; Index++, pData++) + { + /* + // If a value has yet to have been set for this structure, build a report + // buffer with its report ID as the first byte of the buffer and pass + // it in the HidD_GetFeature call. Specifying the report ID in the + // first specifies which report is actually retrieved from the device. + // The rest of the buffer should be zeroed before the call + */ + + if (!pData -> IsDataSet) + { + memset(HidDevice -> FeatureReportBuffer, 0x00, HidDevice->Caps.FeatureReportByteLength); + + HidDevice -> FeatureReportBuffer[0] = (UCHAR) pData -> ReportID; + + FeatureStatus = HidD_GetFeature (HidDevice->HidDevice, + HidDevice->FeatureReportBuffer, + HidDevice->Caps.FeatureReportByteLength); + + /* + // If the return value is TRUE, scan through the rest of the HID_DATA + // structures and fill whatever values we can from this report + */ + + + if (FeatureStatus) + { + FeatureStatus = UnpackReport ( HidDevice->FeatureReportBuffer, + HidDevice->Caps.FeatureReportByteLength, + HidP_Feature, + HidDevice->FeatureData, + HidDevice->FeatureDataLength, + HidDevice->Ppd); + } + + Status = Status && FeatureStatus; + } + } + + return (Status); +} + + +BOOLEAN +UnpackReport ( + _In_reads_bytes_(ReportBufferLength)PCHAR ReportBuffer, + IN USHORT ReportBufferLength, + IN HIDP_REPORT_TYPE ReportType, + IN OUT PHID_DATA Data, + IN ULONG DataLength, + IN PHIDP_PREPARSED_DATA Ppd +) +/*++ +Routine Description: + Given ReportBuffer representing a report from a HID device where the first + byte of the buffer is the report ID for the report, extract all the HID_DATA + in the Data list from the given report. +--*/ +{ + ULONG numUsages; // Number of usages returned from GetUsages. + ULONG i; + UCHAR reportID; + ULONG Index; + ULONG nextUsage; + BOOLEAN result = FALSE; + + reportID = ReportBuffer[0]; + + for (i = 0; i < DataLength; i++, Data++) + { + if (reportID == Data->ReportID) + { + if (Data->IsButtonData) + { + numUsages = Data->ButtonData.MaxUsageLength; + + Data->Status = HidP_GetUsages (ReportType, + Data->UsagePage, + 0, // All collections + Data->ButtonData.Usages, + &numUsages, + Ppd, + ReportBuffer, + ReportBufferLength); + + if (HIDP_STATUS_SUCCESS != Data->Status) + { + goto Done; + } + + // + // Get usages writes the list of usages into the buffer + // Data->ButtonData.Usages newUsage is set to the number of usages + // written into this array. + // A usage cannot not be defined as zero, so we'll mark a zero + // following the list of usages to indicate the end of the list of + // usages + // + // NOTE: One anomaly of the GetUsages function is the lack of ability + // to distinguish the data for one ButtonCaps from another + // if two different caps structures have the same UsagePage + // For instance: + // Caps1 has UsagePage 07 and UsageRange of 0x00 - 0x167 + // Caps2 has UsagePage 07 and UsageRange of 0xe0 - 0xe7 + // + // However, calling GetUsages for each of the data structs + // will return the same list of usages. It is the + // responsibility of the caller to set in the HID_DEVICE + // structure which usages actually are valid for the + // that structure. + // + + /* + // Search through the usage list and remove those that + // correspond to usages outside the define ranged for this + // data structure. + */ + + for (Index = 0, nextUsage = 0; Index < numUsages; Index++) + { + if (Data -> ButtonData.UsageMin <= Data -> ButtonData.Usages[Index] && + Data -> ButtonData.Usages[Index] <= Data -> ButtonData.UsageMax) + { + Data -> ButtonData.Usages[nextUsage++] = Data -> ButtonData.Usages[Index]; + + } + } + + if (nextUsage < Data -> ButtonData.MaxUsageLength) + { + Data->ButtonData.Usages[nextUsage] = 0; + } + } + else + { + Data->Status = HidP_GetUsageValue ( + ReportType, + Data->UsagePage, + 0, // All Collections. + Data->ValueData.Usage, + &Data->ValueData.Value, + Ppd, + ReportBuffer, + ReportBufferLength); + + if (HIDP_STATUS_SUCCESS != Data->Status) + { + goto Done; + } + + Data->Status = HidP_GetScaledUsageValue ( + ReportType, + Data->UsagePage, + 0, // All Collections. + Data->ValueData.Usage, + &Data->ValueData.ScaledValue, + Ppd, + ReportBuffer, + ReportBufferLength); + + if (HIDP_STATUS_SUCCESS != Data->Status && + HIDP_STATUS_NULL != Data->Status) + { + goto Done; + } + + } + Data -> IsDataSet = TRUE; + } + } + + result = TRUE; + +Done: + return (result); +} + + +BOOLEAN +PackReport ( + _Out_writes_bytes_(ReportBufferLength)PCHAR ReportBuffer, + IN USHORT ReportBufferLength, + IN HIDP_REPORT_TYPE ReportType, + IN PHID_DATA Data, + IN ULONG DataLength, + IN PHIDP_PREPARSED_DATA Ppd + ) +/*++ +Routine Description: + This routine takes in a list of HID_DATA structures (DATA) and builds + in ReportBuffer the given report for all data values in the list that + correspond to the report ID of the first item in the list. + + For every data structure in the list that has the same report ID as the first + item in the list will be set in the report. Every data item that is + set will also have it's IsDataSet field marked with TRUE. + + A return value of FALSE indicates an unexpected error occurred when setting + a given data value. The caller should expect that assume that no values + within the given data structure were set. + + A return value of TRUE indicates that all data values for the given report + ID were set without error. +--*/ +{ + ULONG numUsages; // Number of usages to set for a given report. + ULONG i; + ULONG CurrReportID; + BOOLEAN result = FALSE; + + /* + // All report buffers that are initially sent need to be zero'd out + */ + + memset (ReportBuffer, (UCHAR) 0, ReportBufferLength); + + /* + // Go through the data structures and set all the values that correspond to + // the CurrReportID which is obtained from the first data structure + // in the list + */ + + CurrReportID = Data -> ReportID; + + for (i = 0; i < DataLength; i++, Data++) + { + /* + // There are two different ways to determine if we set the current data + // structure: + // 1) Store the report ID were using and only attempt to set those + // data structures that correspond to the given report ID. This + // example shows this implementation. + // + // 2) Attempt to set all of the data structures and look for the + // returned status value of HIDP_STATUS_INVALID_REPORT_ID. This + // error code indicates that the given usage exists but has a + // different report ID than the report ID in the current report + // buffer + */ + + if (Data -> ReportID == CurrReportID) + { + if (Data->IsButtonData) + { + numUsages = Data->ButtonData.MaxUsageLength; + Data->Status = HidP_SetUsages (ReportType, + Data->UsagePage, + 0, // All collections + Data->ButtonData.Usages, + &numUsages, + Ppd, + ReportBuffer, + ReportBufferLength); + } + else + { + Data->Status = HidP_SetUsageValue (ReportType, + Data->UsagePage, + 0, // All Collections. + Data->ValueData.Usage, + Data->ValueData.Value, + Ppd, + ReportBuffer, + ReportBufferLength); + } + + if (HIDP_STATUS_SUCCESS != Data->Status) + { + goto Done; + } + } + } + + /* + // At this point, all data structures that have the same ReportID as the + // first one will have been set in the given report. Time to loop + // through the structure again and mark all of those data structures as + // having been set. + */ + + for (i = 0; i < DataLength; i++, Data++) + { + if (CurrReportID == Data -> ReportID) + { + Data -> IsDataSet = TRUE; + } + } + + result = TRUE; + +Done: + return result; +} + diff --git a/hid/hclient/resource.h b/hid/hclient/resource.h new file mode 100644 index 00000000..141e8c33 --- /dev/null +++ b/hid/hclient/resource.h @@ -0,0 +1,137 @@ +#define IDC_STATIC -1 + +#define IDD_SET_BUTTONS 108 +#define IDD_SET_SCALED_VALUE 109 +#define IDD_SET_USAGE_VALUE 110 +#define IDD_AUTOTEST_PARAMS 111 +#define IDD_SET_USAGE_VALUE_ARRAY 112 +#define IDD_USAGE_LIST_DIFFERENCE 113 +#define IDD_UNSET_BUTTONS 114 +#define IDD_UNSET_USAGES 115 +#define IDD_SET_DATA 116 +#define IDD_SET_BUFFER_LENGTH 117 +#define IDD_SET_INPUT_BUFFERS 118 +#define IDD_GET_INDEX_STRING 119 +#define IDD_SET_USAGES 120 +#define IDD_AUTOTEST_RESULTS 121 +#define IDD_AUTOTEST_NEW 122 +#define IDD_GET_EXT_ATTRIB 123 +#define IDC_DEVICES 1001 +#define IDC_TYPE 1002 +#define IDC_ITEMS 1003 +#define IDC_ATTRIBUTES 1004 +#define IDC_READ 1005 +#define IDC_ABOUT 1006 +#define IDC_WRITE 1007 +#define IDC_EXTCALLS 1008 +#define IDC_SEND 1100 +#define ID_SEND 1100 +#define IDC_OUTPUT 1101 +#define IDC_EDIT1 1102 +#define IDC_USAGEPAGE 1102 +#define IDC_USAGE_LIST 1102 +#define IDC_STRING_INDEX 1102 +#define IDC_LOGFILE 1102 +#define IDC_REPORTID 1103 +#define IDC_USAGE_LIST2 1103 +#define box 1111 +#define IDC_SCROLLBAR1 1121 +#define IDC_SCROLLBAR 1121 +#define IDC_INPUT 1122 +#define IDC_FEATURE 1124 +#define IDC_USAGE 1126 +#define IDC_LINKCOLL 1127 +#define IDC_CALLOUTPUT 1128 +#define IDC_EXECUTE 1129 +#define IDC_CANCEL 1130 +#define IDC_FEATURES 1131 +#define IDC_SET_PARAMS 1131 +#define IDC_REPORT_BUFFER 1132 +#define IDC_INPUT_BUFFER 1132 +#define IDC_BUFFER_TYPE 1133 +#define IDC_BUFFER_SIZE 1134 +#define IDC_INPUT_SELECT 1135 +#define IDC_FEATURE_BUFFER 1136 +#define IDC_USAGE_PAGE 1136 +#define IDC_FEATURE_SELECT 1137 +#define IDC_OUTPUT_BUFFER 1138 +#define IDC_VALUE 1138 +#define IDC_OUTPUT_SELECT 1139 +#define IDC_INDEX 1142 +#define IDC_ADD_DATA 1143 +#define IDC_REMOVE_DATA 1144 +#define IDC_DATA_LIST 1145 +#define IDC_INPUT_BUFFERS 1147 +#define IDC_BUFFER_LENGTH 1149 +#define IDC_USAGE_LIST1 1150 +#define IDC_START_TESTS 1151 +#define IDC_LOAD_LOGICAL_DEVICE 1152 +#define IDC_USELOG 1152 +#define IDC_INFINITE 1153 +#define IDC_PPD_ITS 1154 +#define IDC_STRESSLOG 1154 +#define IDC_RUN_PPD 1155 +#define IDC_RUN_CAPS 1156 +#define IDC_RUN_ATTRIB 1157 +#define IDC_RUN_STRINGS 1158 +#define IDC_RUN_GUID 1159 +#define IDC_ITERATIONS 1160 +#define IDC_CAPS_ITS 1161 +#define IDC_ATT_ITS 1162 +#define IDC_STR_ITS 1163 +#define IDC_GUID_ITS 1164 +#define IDC_TEST_ITS 1165 +#define IDC_RUN_BUFFERS 1165 +#define IDC_BUFFER_ITS 1166 +#define IDC_STOP_TESTS 1167 +#define IDC_RUN_GETFEATURE 1167 +#define IDC_GETFEA_ITS 1168 +#define IDC_GETFEAT_ITS 1168 +#define IDC_LOGFILENAME 1169 +#define IDC_RUN_SETFEATURE 1169 +#define IDC_SETFEA_ITS 1170 +#define IDC_TEST_RESULTS 1172 +#define IDC_DEVICE_LIST 1174 +#define IDC_END_TESTS 1175 +#define IDC_READ_SYNCH 1176 +#define IDC_READ_ASYNCH_ONCE 1177 +#define IDC_READ_ASYNCH 1177 +#define IDC_READ_ASYNCH_CONT 1178 +#define IDC_RUN_LIST 1178 +#define IDC_NRUN_LIST 1179 +#define IDC_REMOVE_TEST 1180 +#define IDC_ADD_TEST 1181 +#define IDC_DESELECT_RUN 1182 +#define IDC_SELECT_RUN 1183 +#define IDC_DESELECT_NRUN 1184 +#define IDC_SELECT_NRUN 1185 +#define IDC_SET_ITERATIONS 1186 +#define IDC_OUT_LABEL1 2000 +#define IDC_OUT_LABEL2 2001 +#define IDC_OUT_LABEL3 2002 +#define IDC_OUT_LABEL4 2003 +#define IDC_OUT_LABEL5 2004 +#define IDC_OUT_LABEL6 2005 +#define IDC_OUT_LABEL7 2006 +#define IDC_OUT_LABEL8 2007 +#define IDC_OUT_LABEL9 2008 +#define IDC_OUT_EDIT1 3000 +#define IDC_OUT_EDIT2 3001 +#define IDC_OUT_EDIT3 3002 +#define IDC_OUT_EDIT4 3003 +#define IDC_OUT_EDIT5 3004 +#define IDC_OUT_EDIT6 3005 +#define IDC_OUT_EDIT7 3006 +#define IDC_OUT_EDIT8 3007 +#define IDC_OUT_EDIT9 3008 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 122 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1188 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/hid/hclient/strings.c b/hid/hclient/strings.c new file mode 100644 index 00000000..58a4338e --- /dev/null +++ b/hid/hclient/strings.c @@ -0,0 +1,411 @@ +/*++ + +Copyright (c) Microsoft 1998, All Rights Reserved + +Module Name: + + strings.c + +Abstract: + + This module contains code for converting data buffers and integer values + to and from string representation for display. + +Environment: + + User mode + +Revision History: + + May-98 : Created + +--*/ + +#include +#include +#include +#include +#include +#include "strings.h" +#include + +#pragma warning(disable:4057) // indirection to slightly different base types +#pragma warning(disable:28146) // Warning is meant for kernel mode drivers + +#define ROUND_UP_ON_DIVIDE(d, n) (0 == ((d) % (n)) ? ((d)/(n)) : ((d)/(n))+1) + +VOID +Strings_CreateDataBufferString( + _In_reads_bytes_(DataBufferLength) PCHAR DataBuffer, + _In_ ULONG DataBufferLength, + _In_ ULONG NumBytesToDisplay, + _In_ ULONG DisplayBlockSize, + _Outptr_result_maybenull_ LPSTR *BufferString +) +/*++ +Routine Description: + This routine takes a DataBuffer of size DataBufferLength and creates a string + in BufferString that contains a string representation of the bytes stored in + data buffer. + + The parameter NumBytesToDisplay tells the routine the maximum number of bytes + from the buffer to display. For instance, a caller may only want to convert + the first four bytes of an eight byte buffer to a string + + The parameter DisplayBlockSize indicates how many bytes should be grouped + together in the display. Valid values are 1, 2, 4 and would indicate whether + the displayed bytes should be displayed as bytes, words, or dwords. + + The routine allocates a buffer big enough to store the data. Callers of this + routine are responsible for freeing this string buffer. +--*/ +{ + ULONG BufferStringLength; + ULONG MaxDisplayedBytes; + PUCHAR NextByte; + PUCHAR String = NULL; + PUCHAR CurrentBufferOffset; + PUCHAR CurrentBufferOffsetBase; + UINT nFullIterations; + INT LeftOverBytes; + UINT IterationIndex; + INT ByteOffset; + BOOLEAN Success = FALSE; + + Success = FALSE; + + /* + // Determine the maximum number of bytes that will be displayed in + // the string + */ + + MaxDisplayedBytes = (NumBytesToDisplay > DataBufferLength) ? DataBufferLength + : NumBytesToDisplay; + + *BufferString = NULL; + + if(NumBytesToDisplay > DataBufferLength) + { + goto Done; // error case + } + + /* + // Determine the size of the string we'll need: This is based on the + // maximum number of displayed bytes (MaxDisplayedBytes) and the + // DisplayBlockSize + */ + + BufferStringLength = 2*MaxDisplayedBytes + ROUND_UP_ON_DIVIDE(MaxDisplayedBytes, + DisplayBlockSize + ); + + /* + // Now we need to allocate string space + */ + + String = (PCHAR) malloc(BufferStringLength * sizeof(CHAR)); + + if (NULL != String) { + + /* + // Determine how many iterations through the conversion routine must be made. + */ + + nFullIterations = MaxDisplayedBytes / DisplayBlockSize; + + /* + // Initialize our variables which point to data in the buffer to convert + // and the byte in the string in which to put the converted data value. + // Next byte is set to String-1 because it is incremented on entry into the + // loop. + */ + + CurrentBufferOffset = DataBuffer; + CurrentBufferOffsetBase = CurrentBufferOffset; + + NextByte = String-1; + + /* + // Each iteration of the loop creates a block of DisplayBlockSize. Any + // partial iterations are performed afterwards if the number of bytes + // to display is not a multiple of the display block size + */ + IterationIndex = 0; + do + { + NextByte++; + + /* + // Output a block of data size. Notice the bytes are accessed in + // reverse order to display the the MSB of a block as the first + // value in the string + */ + + if(DisplayBlockSize > DataBufferLength) + { + goto Done; // error case + } + + for (ByteOffset = DisplayBlockSize-1; ByteOffset >= 0; ByteOffset--) + { + if(DataBufferLength == 1 && NumBytesToDisplay <= 1 && + ((2*DisplayBlockSize + (CurrentBufferOffset - CurrentBufferOffsetBase) - IterationIndex - 1) / 4 <= 0)) + { + goto Done; // overrun condition + } + if((PLONG)(CurrentBufferOffset + ByteOffset) - (PLONG)DataBuffer >= (LONG)DataBufferLength) + { + goto Done; + } + if(FAILED(StringCbPrintf(NextByte,(String + BufferStringLength - NextByte), + "%02X", *(CurrentBufferOffset+ByteOffset)))) + { + goto Done; // Error case + } + + NextByte += 2; + } + + /* + // Insert the space to separate blocks + */ + + *(NextByte) = ' '; + + CurrentBufferOffset += DisplayBlockSize; + + IterationIndex++; + }while(IterationIndex < nFullIterations); + + /* + // Resolve any other bytes that are left over + */ + + LeftOverBytes = (MaxDisplayedBytes % DisplayBlockSize); + + if (0 == LeftOverBytes) + { + *(NextByte) = '\0'; + } + + for (ByteOffset = LeftOverBytes-1, NextByte++; ByteOffset >= 0; ByteOffset--) + { + + if (ByteOffset < 0) + { + goto Done; + } + + if(ByteOffset + DataBuffer > CurrentBufferOffset+ByteOffset) + { + goto Done; + } + + StringCbPrintf(NextByte,(String + BufferStringLength - NextByte), + "%02X", *(CurrentBufferOffset+ByteOffset)); + + NextByte += 2; + } + + *BufferString = String; + Success = TRUE; + } + +Done: + if (FALSE == Success) + { + if (NULL != String) + { + free(String); + String = NULL; + } + } + + return; +} + +_When_(*nUnsigneds == 0, _At_(*UnsignedList, _Post_null_)) +_When_(*nUnsigneds > 0, _At_(*UnsignedList, _Post_notnull_)) +_Success_(return != FALSE) +BOOL +Strings_StringToUnsignedList( + _Inout_ LPSTR InString, + _In_ ULONG UnsignedSize, + _In_ ULONG Base, + _Outptr_result_bytebuffer_maybenull_(*nUnsigneds) PCHAR *UnsignedList, + _Out_ PULONG nUnsigneds +) +/*++ +Routine Description: + This routine takes an input string, InString, and creates a list of unsigned + values of all the values that are in the list. The caller can specify a + base, Base, for all the numbers in the list or specify 0 to let the function + determine the base depending on the format of the number in the string. + + The parameter UnsignedSize specifies the size of unsigneds to store in the list. + + The routine allocates a CHAR buffer to store the list of unsigned values. + + On exit, nUnsigneds will report the number of unsigned values stored in + UnsignedList. + + The function will return TRUE if it could convert all of the numbers in the + string into the unsigned list. It will return FALSE if there was a problem + with the string or if there was a problem allocating memory to store the + unsigned list. +--*/ +{ + CHAR tokDelims[] = "\t,; "; + PCHAR strToken; + PCHAR strContext = '\0'; + PCHAR endp; + BOOL fStatus = FALSE; + ULONG ulValue; + PCHAR pList = NULL; + PCHAR pNewList; + ULONG nAllocUnsigneds; + ULONG nActualUnsigneds = 0; + ULONG ulMaxValue; + + if(NULL == UnsignedList) + { + goto Done; + } + + /* + // Begin by initializing our unsigned list + // 1) Start with initial allocation for 2 unsigneds, this will + // be expanded if necessary + // 2) If initial allocation fails, return FALSE; + */ + + nAllocUnsigneds = 2; + nActualUnsigneds = 0; + + pList = (PCHAR) malloc(nAllocUnsigneds * sizeof(ULONG)); + + if (NULL == pList) + { + goto Done; + } + + /* + // Calculate the maximum value that can be represented with the value for + // iBufferSize; + */ + + ulMaxValue = (sizeof(ULONG) == UnsignedSize) ? ULONG_MAX + : (1 << (UnsignedSize*8)) - 1; + + /* + // Begin our processing of the token string. + // 1) Set fStatus to TRUE to get through loop the first time + // 2) Try to get the first token -- if we can't get the first token + // then we pass through loop + */ + + fStatus = TRUE; + + strToken = strtok_s(InString, tokDelims, &strContext); + + /* + // Loop until there are no more tokens or we detect an error (fStatus == FALSE) + */ + + while (NULL != strToken && fStatus) + { + /* + // Set fStatus initially to false. Only if nothing goes wrong in + // the loop will this get set to TRUE + */ + + fStatus = FALSE; + + /* + // Attempt to convert the token + */ + + ulValue = strtoul(strToken, &endp, Base); + + /* + // To be a valid value, *endp must point to the NULL character + */ + + if ((0 != ulValue) && '\0' == *endp) + { + /* + // Check to see that the ulValue found is less than or equal to + // the maximum allowed by UnsignedSize. + */ + + if (ulValue <= ulMaxValue) + { + /* + // If we're set to overrun our buffer, attempt to allocate + // more space. If we can't then release the old space + // and fail the loop. + */ + + if (nAllocUnsigneds == nActualUnsigneds) + { + ULONG newListSize = 0; + + if(FAILED(ULongMult(nAllocUnsigneds, 2, &nAllocUnsigneds)) || + FAILED(ULongMult(nAllocUnsigneds, UnsignedSize, &newListSize))) + { + break; + } + + pNewList = (PCHAR) realloc(pList, newListSize); + + if (NULL == pNewList) + { + break; + } + pList = pNewList; + } + + /* + // Add the token to the end of the list of unsigneds + */ + + memcpy(pList + (UnsignedSize * nActualUnsigneds), + &ulValue, + UnsignedSize); + + nActualUnsigneds++; + + /* + // Prepare to reenter the loop. Set fStatus = TRUE + // Try to get another token + */ + + fStatus = TRUE; + + strToken = strtok_s(NULL, tokDelims, &strContext); + } + } + } + +Done: + /* + // If the loop failed for some reason or we found no unsigneds + // release the list + */ + + if (!fStatus || 0 == nActualUnsigneds) + { + if (NULL != pList) + { + free(pList); + pList = NULL; + } + nActualUnsigneds = 0; + } + + *UnsignedList = pList; + *nUnsigneds = nActualUnsigneds; + + return (fStatus); +} + diff --git a/hid/hclient/strings.h b/hid/hclient/strings.h new file mode 100644 index 00000000..d999a53e --- /dev/null +++ b/hid/hclient/strings.h @@ -0,0 +1,49 @@ +/*++ + +Copyright (c) Microsoft 1998, All Rights Reserved + +Module Name: + + strings.h + +Abstract: + + This module contains the public function definitions for the routines + in strings.c that handle conversion of integer/data buffer to/from + string represenation + +Environment: + + User mode + +Revision History: + + May-98 : Created + +--*/ + +#ifndef __STRINGS_H__ +#define __STRINGS_H__ + +VOID +Strings_CreateDataBufferString( + _In_reads_bytes_(DataBufferLength) PCHAR DataBuffer, + _In_ ULONG DataBufferLength, + _In_ ULONG NumBytesToDisplay, + _In_ ULONG DisplayBlockSize, + _Outptr_result_maybenull_ LPSTR *BufferString +); + +_When_(*nUnsigneds == 0, _At_(*UnsignedList, _Post_null_)) +_When_(*nUnsigneds > 0, _At_(*UnsignedList, _Post_notnull_)) +_Success_(return != FALSE) +BOOL +Strings_StringToUnsignedList( + _Inout_ LPSTR InString, + _In_ ULONG UnsignedSize, + _In_ ULONG Base, + _Outptr_result_bytebuffer_maybenull_(*nUnsigneds) PCHAR *UnsignedList, + _Out_ PULONG nUnsigneds +); + +#endif diff --git a/hid/vhidmini2/ReadMe.md b/hid/vhidmini2/ReadMe.md new file mode 100644 index 00000000..567ff063 --- /dev/null +++ b/hid/vhidmini2/ReadMe.md @@ -0,0 +1,22 @@ +HID Minidriver Sample (UMDF V2) +====================================== + +The *HID minidriver* sample demonstrates how to write a HID minidriver using User-Mode Driver Framework (UMDF). + +The sample demonstrates how to communicate with an HID minidriver from an HID client using a custom-feature item in order to control certain features of the HID minidriver. This is needed since other conventional modes for communicating with a driver, like custom IOCTL or WMI, do not work with the HID minidriver. The sample also is useful in testing the correctness of a HID report descriptor without using a physical device. + +**Note** +Due to a known bug in the current Windows Driver Kit tools, when building this sample in Debug mode, the exe project may report some ApiValidator warnings. These can be safely ignored. + + +Related topics +-------------- + +[Creating UMDF-based HID Minidrivers](http://msdn.microsoft.com/en-us/library/windows/hardware/hh439579) + +[Human Input Devices Design Guide](http://msdn.microsoft.com/en-us/library/windows/hardware/ff539952) + +[Human Input Devices Reference](http://msdn.microsoft.com/en-us/library/windows/hardware/ff539956) + +[UMDF HID Minidriver IOCTLs](http://msdn.microsoft.com/en-us/library/windows/hardware/hh463977) + diff --git a/hid/vhidmini2/app/testvhid.c b/hid/vhidmini2/app/testvhid.c new file mode 100644 index 00000000..27c150b5 --- /dev/null +++ b/hid/vhidmini2/app/testvhid.c @@ -0,0 +1,792 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + testvhid.c + +Environment: + + user mode only + +Author: + +--*/ + +#include +#include +#include +#include +#include +#include "common.h" +#include + +// +// These are the default device attributes set in the driver +// which are used to identify the device. +// +#define HIDMINI_DEFAULT_PID 0xFEED +#define HIDMINI_DEFAULT_VID 0xDEED + +// +// These are the device attributes returned by the mini driver in response +// to IOCTL_HID_GET_DEVICE_ATTRIBUTES. +// +#define HIDMINI_TEST_PID 0xDEEF +#define HIDMINI_TEST_VID 0xFEED +#define HIDMINI_TEST_VERSION 0x0505 + +USAGE g_MyUsagePage = 0xFF00; +USAGE g_MyUsage = 0x01; + +#define USE_ALT_USAGE_PAGE "UseAltUsagePage" + +// +// Function prototypes +// +BOOLEAN +GetFeature( + HANDLE file + ); + +BOOLEAN +SetFeature( + HANDLE file + ); + +BOOLEAN +GetInputReport( + HANDLE file + ); + +BOOLEAN +SetOutputReport( + HANDLE file + ); + +BOOLEAN +CheckIfOurDevice( + HANDLE file + ); + +BOOLEAN +ReadInputData( + _In_ HANDLE file + ); + +BOOLEAN +WriteOutputData( + _In_ HANDLE file + ); + +BOOLEAN +GetIndexedString( + HANDLE File + ); + +BOOLEAN +GetStrings( + HANDLE File + ); + +BOOLEAN +FindMatchingDevice( + _In_ LPGUID Guid, + _Out_ HANDLE* Handle + ); + +// +// Implementation +// +INT __cdecl +main( + _In_ ULONG argc, + _In_reads_(argc) PCHAR argv[] + ) +{ + GUID hidguid; + HANDLE file = INVALID_HANDLE_VALUE; + BOOLEAN found = FALSE; + BOOLEAN bSuccess = FALSE; + + + UNREFERENCED_PARAMETER(argc); + UNREFERENCED_PARAMETER(argv); + + + srand( (unsigned)time( NULL ) ); + + HidD_GetHidGuid(&hidguid); + + found = FindMatchingDevice(&hidguid, &file); + if (found) { + printf("...sending control request to our device\n"); + + // + // Get/Set feature loopback + // + bSuccess = GetFeature(file); + if (bSuccess == FALSE) { + goto cleanup; + } + + bSuccess = SetFeature(file); + if (bSuccess == FALSE) { + goto cleanup; + } + + bSuccess = GetFeature(file); + if (bSuccess == FALSE) { + goto cleanup; + } + + // + // Get/Set report loopback + // + bSuccess = GetInputReport(file); + if (bSuccess == FALSE) { + goto cleanup; + } + + bSuccess = SetOutputReport(file); + if (bSuccess == FALSE) { + goto cleanup; + } + + bSuccess = GetInputReport(file); + if (bSuccess == FALSE) { + goto cleanup; + } + + // + // Read/Write report loopback + // + bSuccess = ReadInputData(file); + if (bSuccess == FALSE) { + goto cleanup; + } + + bSuccess = WriteOutputData(file); + if (bSuccess == FALSE) { + goto cleanup; + } + + bSuccess = ReadInputData(file); + if (bSuccess == FALSE) { + goto cleanup; + } + + // + // Get Strings + // + bSuccess = GetIndexedString(file); + if (bSuccess == FALSE) { + goto cleanup; + } + + bSuccess = GetStrings(file); + if (bSuccess == FALSE) { + goto cleanup; + } + + } + else { + printf("Failure: Could not find our HID device \n"); + } + +cleanup: + + if (found && bSuccess == FALSE) { + printf("****** Failure: one or more commands to device failed *******\n"); + } + + if (file != INVALID_HANDLE_VALUE) { + CloseHandle(file); + } + + return (bSuccess ? 0 : 1); +} + +BOOLEAN +FindMatchingDevice( + _In_ LPGUID InterfaceGuid, + _Out_ HANDLE* Handle +) +{ + CONFIGRET cr = CR_SUCCESS; + PWSTR deviceInterfaceList = NULL; + ULONG deviceInterfaceListLength = 0; + PWSTR currentInterface; + BOOLEAN bRet = FALSE; + HANDLE devHandle = INVALID_HANDLE_VALUE; + + if (NULL == Handle) { + printf("Error: Invalid device handle parameter\n"); + return FALSE; + } + + *Handle = INVALID_HANDLE_VALUE; + + cr = CM_Get_Device_Interface_List_Size( + &deviceInterfaceListLength, + InterfaceGuid, + NULL, + CM_GET_DEVICE_INTERFACE_LIST_PRESENT); + if (cr != CR_SUCCESS) { + printf("Error 0x%x retrieving device interface list size.\n", cr); + goto clean0; + } + + if (deviceInterfaceListLength <= 1) { + bRet = FALSE; + printf("Error: No active device interfaces found.\n" + " Is the sample driver loaded?"); + goto clean0; + } + + deviceInterfaceList = (PWSTR)malloc(deviceInterfaceListLength * sizeof(WCHAR)); + if (deviceInterfaceList == NULL) { + printf("Error allocating memory for device interface list.\n"); + goto clean0; + } + ZeroMemory(deviceInterfaceList, deviceInterfaceListLength * sizeof(WCHAR)); + + cr = CM_Get_Device_Interface_List( + InterfaceGuid, + NULL, + deviceInterfaceList, + deviceInterfaceListLength, + CM_GET_DEVICE_INTERFACE_LIST_PRESENT); + if (cr != CR_SUCCESS) { + printf("Error 0x%x retrieving device interface list.\n", cr); + goto clean0; + } + + // + // Enumerate devices of this interface class + // + printf("\n....looking for our HID device (with UP=0x%04X " + "and Usage=0x%02X)\n", g_MyUsagePage, g_MyUsage); + + for (currentInterface = deviceInterfaceList; + *currentInterface; + currentInterface += wcslen(currentInterface) + 1) { + + devHandle = CreateFile(currentInterface, + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, // no SECURITY_ATTRIBUTES structure + OPEN_EXISTING, // No special create flags + 0, // No special attributes + NULL); // No template file + + if (INVALID_HANDLE_VALUE == devHandle) { + printf("Warning: CreateFile failed: %d\n", GetLastError()); + continue; + } + + if (CheckIfOurDevice(devHandle)) { + bRet = TRUE; + *Handle = devHandle; + } + else { + CloseHandle(devHandle); + } + } + +clean0: + if (deviceInterfaceList != NULL) { + free(deviceInterfaceList); + } + if (CR_SUCCESS != cr) { + bRet = FALSE; + } + return bRet; +} + +BOOLEAN +CheckIfOurDevice( + HANDLE file) +{ + PHIDP_PREPARSED_DATA Ppd; // The opaque parser info describing this device + HIDP_CAPS Caps; // The Capabilities of this hid device. + HIDD_ATTRIBUTES attr; // Device attributes + + if (!HidD_GetAttributes(file, &attr)) + { + printf("Error: HidD_GetAttributes failed \n"); + return FALSE; + } + + printf("Device Attributes - PID: 0x%x, VID: 0x%x \n", attr.ProductID, attr.VendorID); + if ((attr.VendorID != HIDMINI_DEFAULT_VID) || (attr.ProductID != HIDMINI_DEFAULT_PID)) + { + printf("Device attributes doesn't match the sample \n"); + return FALSE; + } + + if (!HidD_GetPreparsedData (file, &Ppd)) + { + printf("Error: HidD_GetPreparsedData failed \n"); + return FALSE; + } + + if (!HidP_GetCaps (Ppd, &Caps)) + { + printf("Error: HidP_GetCaps failed \n"); + HidD_FreePreparsedData (Ppd); + return FALSE; + } + + if ((Caps.UsagePage == g_MyUsagePage) && (Caps.Usage == g_MyUsage)){ + printf("Success: Found my device.. \n"); + return TRUE; + + } + + return FALSE; + +} + +BOOLEAN +GetFeature( + HANDLE file + ) +{ + PMY_DEVICE_ATTRIBUTES myDevAttributes = NULL; + ULONG bufferSize; + PUCHAR buffer; + BOOLEAN bSuccess; + + // + // Allocate memory equal to 1 byte for report ID + size of + // feature report. Buffer size for get feature should be atleast equal to + // the size of feature report. + // + bufferSize = FEATURE_REPORT_SIZE_CB + 1; + buffer = (PUCHAR) malloc (bufferSize); + if (!buffer ) + { + printf("malloc failed\n"); + return FALSE; + } + + ZeroMemory(buffer, bufferSize); + + // + // Fill the first byte with report ID of control collection + // + buffer[0] = CONTROL_COLLECTION_REPORT_ID; + + // + // Send Hid control code thru HidD_GetFeature API + // + bSuccess = HidD_GetFeature(file, // HidDeviceObject, + buffer, // ReportBuffer, + bufferSize // ReportBufferLength + ); + if (!bSuccess) + { + printf("failed HidD_GetFeature\n"); + } + else + { + myDevAttributes = (PMY_DEVICE_ATTRIBUTES) (buffer + 1); // +1 to skip report id + + printf("Received following feature attributes from device: \n" + " VendorID: 0x%x, \n" + " ProductID: 0x%x, \n" + " VersionNumber: 0x%x\n", + myDevAttributes->VendorID, + myDevAttributes->ProductID, + myDevAttributes->VersionNumber); + } + + free(buffer); + return bSuccess; +} + +BOOLEAN +SetFeature( + HANDLE file + ) +{ + PHIDMINI_CONTROL_INFO controlInfo = NULL; + PMY_DEVICE_ATTRIBUTES myDevAttributes = NULL; + ULONG bufferSize; + BOOLEAN bSuccess; + + // + // Allocate memory equal to HIDMINI_CONTROL_INFO + // + bufferSize = sizeof(HIDMINI_CONTROL_INFO); + controlInfo = (PHIDMINI_CONTROL_INFO) malloc (bufferSize); + if (!controlInfo ) + { + printf("malloc failed\n"); + return FALSE; + } + + ZeroMemory(controlInfo, bufferSize); + + // + // Fill the control structure with the report ID of the control collection and + // the control code. + // + controlInfo->ReportId = CONTROL_COLLECTION_REPORT_ID; + controlInfo->ControlCode = HIDMINI_CONTROL_CODE_SET_ATTRIBUTES; + myDevAttributes = (PMY_DEVICE_ATTRIBUTES)&controlInfo->u.Attributes; + myDevAttributes->VendorID = HIDMINI_TEST_VID; + myDevAttributes->ProductID = HIDMINI_TEST_PID; + myDevAttributes->VersionNumber = HIDMINI_TEST_VERSION; + + // + // Set feature + // + bSuccess = HidD_SetFeature(file, // HidDeviceObject, + controlInfo, // ReportBuffer, + bufferSize // ReportBufferLength + ); + if (!bSuccess) + { + printf("failed HidD_SetFeature \n"); + } + else + { + printf("Set following feature attributes on device: \n" + " VendorID: 0x%x, \n" + " ProductID: 0x%x, \n" + " VersionNumber: 0x%x\n", + myDevAttributes->VendorID, + myDevAttributes->ProductID, + myDevAttributes->VersionNumber); + } + + free(controlInfo); + + return bSuccess; +} + +BOOLEAN +GetInputReport( + HANDLE file + ) +{ + ULONG bufferSize; + PUCHAR buffer; + BOOLEAN bSuccess; + + // + // Allocate memory + // + bufferSize = sizeof(HIDMINI_INPUT_REPORT); + buffer = (PUCHAR) malloc (bufferSize); + if (!buffer ) + { + printf("malloc failed\n"); + return FALSE; + } + + ZeroMemory(buffer, bufferSize); + + // + // Fill the first byte with report ID of collection + // + buffer[0] = CONTROL_COLLECTION_REPORT_ID; + + // + // Send Hid control code + // + bSuccess = HidD_GetInputReport(file, // HidDeviceObject, + buffer, // ReportBuffer, + bufferSize // ReportBufferLength + ); + if (!bSuccess) + { + printf("failed HidD_GetInputReport\n"); + } + else + { + printf("Received following data in input report: %d\n", + ((PHIDMINI_INPUT_REPORT) buffer)->Data); + } + + free(buffer); + return bSuccess; +} + + +BOOLEAN +SetOutputReport( + HANDLE file + ) +{ + ULONG bufferSize; + PHIDMINI_OUTPUT_REPORT buffer; + BOOLEAN bSuccess; + + // + // Allocate memory + // + bufferSize = sizeof(HIDMINI_OUTPUT_REPORT); + buffer = (PHIDMINI_OUTPUT_REPORT) malloc (bufferSize); + if (!buffer ) + { + printf("malloc failed\n"); + return FALSE; + } + + ZeroMemory(buffer, bufferSize); + + // + // Fill the report + // + buffer->ReportId = CONTROL_COLLECTION_REPORT_ID; + buffer->Data = (UCHAR) (rand() % UCHAR_MAX); + + // + // Send Hid control code + // + bSuccess = HidD_SetOutputReport(file, // HidDeviceObject, + buffer, // ReportBuffer, + bufferSize // ReportBufferLength + ); + if (!bSuccess) + { + printf("failed HidD_SetOutputReport\n"); + } + else + { + printf("Set following data in output report: %d\n", + ((PHIDMINI_OUTPUT_REPORT) buffer)->Data); + } + + free(buffer); + return bSuccess; +} + +BOOLEAN +ReadInputData( + _In_ HANDLE file + ) +{ + PHIDMINI_INPUT_REPORT report; + ULONG bufferSize; + BOOL bSuccess; + DWORD bytesRead; + + // + // Allocate memory + // + bufferSize = sizeof(HIDMINI_INPUT_REPORT); + report = (PHIDMINI_INPUT_REPORT) malloc (bufferSize); + if (!report ) + { + printf("malloc failed\n"); + return FALSE; + } + + ZeroMemory(report, bufferSize); + + report->ReportId = CONTROL_COLLECTION_REPORT_ID; + + // + // get input data. + // + bSuccess = ReadFile( + file, // HANDLE hFile, + report, // LPVOID lpBuffer, + bufferSize, // DWORD nNumberOfBytesToRead, + &bytesRead, // LPDWORD lpNumberOfBytesRead, + NULL // LPOVERLAPPED lpOverlapped + ); + + if (!bSuccess) + { + printf("failed ReadFile \n"); + } + else + { + printf("Read following byte from device: %d\n", + report->Data); + } + + free(report); + + return (BOOLEAN) bSuccess; +} + +BOOLEAN +WriteOutputData( + _In_ HANDLE file + ) +{ + PHIDMINI_OUTPUT_REPORT outputReport; + ULONG outputReportSize; + BOOL bSuccess; + DWORD bytesWritten; + + // + // Allocate memory for outtput report + // + outputReportSize = sizeof(HIDMINI_OUTPUT_REPORT); + outputReport = (PHIDMINI_OUTPUT_REPORT) malloc (outputReportSize); + if (!outputReport ) + { + printf("malloc failed\n"); + return FALSE; + } + + ZeroMemory(outputReport, outputReportSize); + + outputReport->ReportId = CONTROL_COLLECTION_REPORT_ID; + outputReport->Data = (UCHAR) (rand() % UCHAR_MAX); + + // + // Wrute output data. + // + bSuccess = WriteFile( + file, // HANDLE hFile, + (PVOID) outputReport, // LPVOID lpBuffer, + outputReportSize, // DWORD nNumberOfBytesToRead, + &bytesWritten, // LPDWORD lpNumberOfBytesRead, + NULL // LPOVERLAPPED lpOverlapped + ); + + if (!bSuccess) + { + printf("failed WriteFile \n"); + } + else + { + printf("Wrote following byte to device: %d\n", + outputReport->Data); + } + + free(outputReport); + + return (BOOLEAN) bSuccess; +} + +BOOLEAN +GetIndexedString( + HANDLE File + ) +{ + BOOLEAN bSuccess; + BYTE* buffer; + ULONG bufferLength; + + bufferLength = MAXIMUM_STRING_LENGTH; + buffer = malloc(bufferLength); + if (!buffer ) + { + printf("malloc failed\n"); + return FALSE; + } + + ZeroMemory(buffer, bufferLength); + + bSuccess = HidD_GetIndexedString( + File, + VHIDMINI_DEVICE_STRING_INDEX, // IN ULONG StringIndex, + (PVOID) buffer, //OUT PVOID Buffer, + bufferLength // IN ULONG BufferLength + ) ; + + if (!bSuccess) + { + printf("failed WriteFile \n"); + } + else + { + printf("Indexed string: %S\n", (PWSTR) buffer); + } + + free(buffer); + + return bSuccess; +} + +BOOLEAN +GetStrings( + HANDLE File + ) +{ + BOOLEAN bSuccess; + BYTE* buffer; + ULONG bufferLength; + + bufferLength = MAXIMUM_STRING_LENGTH; + buffer = malloc(bufferLength); + if (!buffer ) + { + printf("malloc failed\n"); + return FALSE; + } + + ZeroMemory(buffer, bufferLength); + bSuccess = HidD_GetProductString( + File, + (PVOID) buffer, //OUT PVOID Buffer, + bufferLength // IN ULONG BufferLength + ); + + if (!bSuccess) + { + printf("failed HidD_GetProductString \n"); + goto exit; + } + else + { + printf("Product string: %S\n", (PWSTR) buffer); + } + + ZeroMemory(buffer, bufferLength); + bSuccess = HidD_GetSerialNumberString( + File, + (PVOID) buffer, //OUT PVOID Buffer, + bufferLength // IN ULONG BufferLength + ); + + if (!bSuccess) + { + printf("failed HidD_GetSerialNumberString \n"); + goto exit; + } + else + { + printf("Serial number string: %S\n", (PWSTR) buffer); + } + + ZeroMemory(buffer, bufferLength); + bSuccess = HidD_GetManufacturerString( + File, + (PVOID) buffer, //OUT PVOID Buffer, + bufferLength // IN ULONG BufferLength + ); + + if (!bSuccess) + { + printf("failed HidD_GetManufacturerString \n"); + goto exit; + } + else + { + printf("Manufacturer string: %S\n", (PWSTR) buffer); + } + +exit: + + free(buffer); + + return bSuccess; +} + + diff --git a/hid/vhidmini2/app/testvhid.rc b/hid/vhidmini2/app/testvhid.rc new file mode 100644 index 00000000..37e1b8ab --- /dev/null +++ b/hid/vhidmini2/app/testvhid.rc @@ -0,0 +1,12 @@ +#include + +#include + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN +#define VER_FILEDESCRIPTION_STR "Test Program for hidmini (vhidmini.sys) Driver" +#define VER_INTERNALNAME_STR "testvhid.exe" +#define VER_ORIGINALFILENAME_STR "testvhid.exe" + +#include + diff --git a/hid/vhidmini2/app/testvhid.vcxproj b/hid/vhidmini2/app/testvhid.vcxproj new file mode 100644 index 00000000..c076e315 --- /dev/null +++ b/hid/vhidmini2/app/testvhid.vcxproj @@ -0,0 +1,188 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {33D1A6C5-8347-43BB-853C-0820EF7203C6} + $(MSBuildProjectName) + Debug + Win32 + {B610E167-90BB-4434-B532-3E50E9698B60} + + + + Windows10 + False + Universal + + WindowsApplicationForDrivers10.0 + Application + + + Windows10 + True + Universal + + WindowsApplicationForDrivers10.0 + Application + + + Windows10 + False + Universal + + WindowsApplicationForDrivers10.0 + Application + + + Windows10 + True + Universal + + WindowsApplicationForDrivers10.0 + Application + + + + $(IntDir) + + + + + + + + + + + + + + + + testvhid + + + testvhid + + + testvhid + + + testvhid + + + + %(AdditionalDependencies);hid.lib;mincore.lib;comdlg32.lib + 0x400000 + + + %(AdditionalIncludeDirectories);..\inc + %(PreprocessorDefinitions);UNICODE;_UNICODE + + + %(AdditionalIncludeDirectories);..\inc + %(PreprocessorDefinitions);UNICODE;_UNICODE + + + + + %(AdditionalIncludeDirectories);..\inc + %(PreprocessorDefinitions);UNICODE;_UNICODE + + + + + %(AdditionalDependencies);hid.lib;mincore.lib;comdlg32.lib + 0x400000 + + + %(AdditionalIncludeDirectories);..\inc + %(PreprocessorDefinitions);UNICODE;_UNICODE + + + %(AdditionalIncludeDirectories);..\inc + %(PreprocessorDefinitions);UNICODE;_UNICODE + + + + + %(AdditionalIncludeDirectories);..\inc + %(PreprocessorDefinitions);UNICODE;_UNICODE + + + + + %(AdditionalDependencies);hid.lib;mincore.lib;comdlg32.lib + 0x400000 + + + %(AdditionalIncludeDirectories);..\inc + %(PreprocessorDefinitions);UNICODE;_UNICODE + + + %(AdditionalIncludeDirectories);..\inc + %(PreprocessorDefinitions);UNICODE;_UNICODE + + + + + %(AdditionalIncludeDirectories);..\inc + %(PreprocessorDefinitions);UNICODE;_UNICODE + + + + + %(AdditionalDependencies);hid.lib;mincore.lib;comdlg32.lib + 0x400000 + + + %(AdditionalIncludeDirectories);..\inc + %(PreprocessorDefinitions);UNICODE;_UNICODE + + + %(AdditionalIncludeDirectories);..\inc + %(PreprocessorDefinitions);UNICODE;_UNICODE + + + + + %(AdditionalIncludeDirectories);..\inc + %(PreprocessorDefinitions);UNICODE;_UNICODE + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/hid/vhidmini2/app/testvhid.vcxproj.Filters b/hid/vhidmini2/app/testvhid.vcxproj.Filters new file mode 100644 index 00000000..ab638492 --- /dev/null +++ b/hid/vhidmini2/app/testvhid.vcxproj.Filters @@ -0,0 +1,27 @@ + + + + + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* + {E0769A0A-01B1-4870-A7A0-251E075207E9} + + + h;hpp;hxx;hm;inl;inc;xsd + {1E43CCDB-2472-497A-AE91-22BD2D4C046C} + + + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml + {EEC98E9E-7C67-4A59-917F-31BCA04175E9} + + + + + Source Files + + + + + Resource Files + + + \ No newline at end of file diff --git a/hid/vhidmini2/driver/kmdf/util.c b/hid/vhidmini2/driver/kmdf/util.c new file mode 100644 index 00000000..1245fd7d --- /dev/null +++ b/hid/vhidmini2/driver/kmdf/util.c @@ -0,0 +1,84 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved. + +Module Name: + + util.cpp + +Abstract: + + This module contains the implementation of the driver + +Environment: + + Windows Driver Framework (WDF) + +--*/ + +#include "vhidmini.h" + +// +// First let's review Buffer Descriptions for I/O Control Codes +// +// METHOD_BUFFERED +// - Input buffer: Irp->AssociatedIrp.SystemBuffer +// - Output buffer: Irp->AssociatedIrp.SystemBuffer +// +// METHOD_IN_DIRECT or METHOD_OUT_DIRECT +// - Input buffer: Irp->AssociatedIrp.SystemBuffer +// - Second buffer: Irp->MdlAddress +// +// METHOD_NEITHER +// - Input buffer: Parameters.DeviceIoControl.Type3InputBuffer; +// - Output buffer: Irp->UserBuffer +// +// HID minidriver IOCTL stores a pointer to HID_XFER_PACKET in Irp->UserBuffer. +// For IOCTLs like IOCTL_HID_GET_FEATURE (which is METHOD_OUT_DIRECT) this is +// not the expected buffer location. So we cannot retrieve UserBuffer from the +// IRP using WdfRequestXxx functions. Instead, we have to escape to WDM. +// + +NTSTATUS +RequestGetHidXferPacket_ToReadFromDevice( + _In_ WDFREQUEST Request, + _Out_ HID_XFER_PACKET *Packet + ) +{ + NTSTATUS status; + WDF_REQUEST_PARAMETERS params; + + WDF_REQUEST_PARAMETERS_INIT(¶ms); + WdfRequestGetParameters(Request, ¶ms); + + if (params.Parameters.DeviceIoControl.OutputBufferLength < sizeof(HID_XFER_PACKET)) { + status = STATUS_BUFFER_TOO_SMALL; + KdPrint(("RequestGetHidXferPacket: invalid HID_XFER_PACKET\n")); + return status; + } + + RtlCopyMemory(Packet, WdfRequestWdmGetIrp(Request)->UserBuffer, sizeof(HID_XFER_PACKET)); + return STATUS_SUCCESS; +} + +NTSTATUS +RequestGetHidXferPacket_ToWriteToDevice( + _In_ WDFREQUEST Request, + _Out_ HID_XFER_PACKET *Packet + ) +{ + NTSTATUS status; + WDF_REQUEST_PARAMETERS params; + + WDF_REQUEST_PARAMETERS_INIT(¶ms); + WdfRequestGetParameters(Request, ¶ms); + + if (params.Parameters.DeviceIoControl.InputBufferLength < sizeof(HID_XFER_PACKET)) { + status = STATUS_BUFFER_TOO_SMALL; + KdPrint(("RequestGetHidXferPacket: invalid HID_XFER_PACKET\n")); + return status; + } + + RtlCopyMemory(Packet, WdfRequestWdmGetIrp(Request)->UserBuffer, sizeof(HID_XFER_PACKET)); + return STATUS_SUCCESS; +} diff --git a/hid/vhidmini2/driver/kmdf/vhidmini.inx b/hid/vhidmini2/driver/kmdf/vhidmini.inx new file mode 100644 index 00000000..c4f776f6 --- /dev/null +++ b/hid/vhidmini2/driver/kmdf/vhidmini.inx @@ -0,0 +1,96 @@ +;/*++ +; +;Copyright (c) Microsoft Corporation All rights Reserved +; +;Module Name: +; +; vihidmini.inf +; +;Abstract: +; INF file for installing HID minidriver (KMDF version) +; +;Installation Notes: +; Using Devcon: Type "devcon install vhidmini.inf root\vhidmini" to install +; +;--*/ +[Version] +Signature="$WINDOWS NT$" +Class=Sample +ClassGuid={78A1C341-4539-11d3-B88D-00C04FAD5171} +Provider=%MSFT% +DriverVer=10/01/2002,6.0.5058.0 +CatalogFile=wudf.cat + +; ================= Class section ===================== + +[ClassInstall32] +Addreg=SampleClassReg + +[SampleClassReg] +HKR,,,0,%ClassName% +HKR,,Icon,,-5 + +; ================= Device section ===================== + +[Manufacturer] +%MfgName%=Microsoft,NT$ARCH$.6.1 + +; Works on Win7 and later because we use inbox HID-KMDF mapper +[Microsoft.NT$ARCH$.6.1] +%DeviceDesc%=vhidmini, root\vhidmini + +[vhidmini.NT] +CopyFiles=KMDriverCopy + +[vhidmini.NT.hw] +AddReg=vhidmini_AddReg + +[vhidmini.NT.Services] +AddService=vhidmini,0,vhidmini_Service_Inst, +AddService=mshidkmdf,0x00000002,mshidkmdf_Service_Inst ;flag 0x2 sets this as the service for the device + +[vhidmini_AddReg] +HKR,,"LowerFilters",0x00010008,"vhidmini" ; FLG_ADDREG_TYPE_MULTI_SZ | FLG_ADDREG_APPEND + +[mshidkmdf_Service_Inst] +ServiceType = 1 ; SERVICE_KERNEL_DRIVER +StartType = 3 ; SERVICE_DEMAND_START +ErrorControl = 1 ; SERVICE_ERROR_NORMAL +ServiceBinary = %12%\mshidkmdf.sys + +[vhidmini_Service_Inst] +DisplayName = %ServiceDesc% +ServiceType = 1 +StartType = 3 +ErrorControl = 1 +ServiceBinary = %12%\vhidmini.sys + +[vhidmini.NT.Wdf] +KmdfService=vhidmini, vhidmini_wdfsect + +[vhidmini_wdfsect] +KmdfLibraryVersion=$KMDFVERSION$ + +; ================= copy files ===================== + +[KMDriverCopy] +vhidmini.sys + +[SourceDisksNames] +1=%DiskDesc%,,, + +[SourceDisksFiles] +vhidmini.sys=1 + +[DestinationDirs] +KMDriverCopy=12 + +;---------------------------------------------------------------; + +[Strings] +MSFT = "Microsoft" +MfgName = "Microsoft" +ClassName = "Sample Device" +DeviceDesc = "HID minidriver (KMDF version) Device" +ServiceDesc= "HID minidriver (KMDF version) Service" +DiskDesc = "HID minidriver (KMDF version) Installation Disk" diff --git a/hid/vhidmini2/driver/kmdf/vhidmini.rc b/hid/vhidmini2/driver/kmdf/vhidmini.rc new file mode 100644 index 00000000..6131d387 --- /dev/null +++ b/hid/vhidmini2/driver/kmdf/vhidmini.rc @@ -0,0 +1,16 @@ +//--------------------------------------------------------------------------- +// vhidmini.rc +// +// Copyright (c) Microsoft Corporation, All Rights Reserved +//--------------------------------------------------------------------------- + + +#include +#include + +#define VER_FILETYPE VFT_DRV +#define VER_FILESUBTYPE VFT2_DRV_SYSTEM +#define VER_FILEDESCRIPTION_STR "HID minidriver (KMDF version)" +#define VER_INTERNALNAME_STR "vhidmini.sys" + +#include "common.ver" diff --git a/hid/vhidmini2/driver/kmdf/vhidmini.vcxproj b/hid/vhidmini2/driver/kmdf/vhidmini.vcxproj new file mode 100644 index 00000000..98ed709a --- /dev/null +++ b/hid/vhidmini2/driver/kmdf/vhidmini.vcxproj @@ -0,0 +1,180 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {20843589-DA00-4ADD-BDA0-62C7065C80CB} + $(MSBuildProjectName) + 1 + Debug + Win32 + {60CAABFB-B417-4ED4-816E-6E6F27119888} + + + + Windows10 + False + Desktop + KMDF + WindowsKernelModeDriver10.0 + Driver + + + Windows10 + True + Desktop + KMDF + WindowsKernelModeDriver10.0 + Driver + + + Windows10 + False + Desktop + KMDF + WindowsKernelModeDriver10.0 + Driver + + + Windows10 + True + Desktop + KMDF + WindowsKernelModeDriver10.0 + Driver + + + + $(IntDir) + + + + + + + + + + + + + + + + $(InfArch) + true + .\$(IntDir)\vhidmini.inf + + + + vhidmini + + + vhidmini + + + vhidmini + + + vhidmini + + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + %(AdditionalIncludeDirectories);..\..\inc;.. + + + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + %(AdditionalIncludeDirectories);..\..\inc;.. + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + %(AdditionalIncludeDirectories);..\..\inc;.. + + + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + %(AdditionalIncludeDirectories);..\..\inc;.. + + + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + %(AdditionalIncludeDirectories);..\..\inc;.. + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + %(AdditionalIncludeDirectories);..\..\inc;.. + + + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + %(AdditionalIncludeDirectories);..\..\inc;.. + + + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + %(AdditionalIncludeDirectories);..\..\inc;.. + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + %(AdditionalIncludeDirectories);..\..\inc;.. + + + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + %(AdditionalIncludeDirectories);..\..\inc;.. + + + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + %(AdditionalIncludeDirectories);..\..\inc;.. + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + %(AdditionalIncludeDirectories);..\..\inc;.. + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/hid/vhidmini2/driver/kmdf/vhidmini.vcxproj.Filters b/hid/vhidmini2/driver/kmdf/vhidmini.vcxproj.Filters new file mode 100644 index 00000000..d658706d --- /dev/null +++ b/hid/vhidmini2/driver/kmdf/vhidmini.vcxproj.Filters @@ -0,0 +1,42 @@ + + + + + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* + {529C6B82-33F1-447C-8745-EA15DF3B320A} + + + h;hpp;hxx;hm;inl;inc;xsd + {14FD4557-FD3C-46E8-91BC-EB85C1102DEC} + + + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml + {120DA6E4-65A4-4995-ACDA-1401660F7DE9} + + + inf;inv;inx;mof;mc; + {9161B866-C7A9-49F8-99BF-816F32DCDC37} + + + + + Driver Files + + + Driver Files + + + + + Source Files + + + Source Files + + + + + Resource Files + + + \ No newline at end of file diff --git a/hid/vhidmini2/driver/umdf2/VhidminiUm.inx b/hid/vhidmini2/driver/umdf2/VhidminiUm.inx new file mode 100644 index 00000000..48512f38 --- /dev/null +++ b/hid/vhidmini2/driver/umdf2/VhidminiUm.inx @@ -0,0 +1,101 @@ +;/*++ +; +;Copyright (c) Microsoft Corporation All rights Reserved +; +;Module Name: +; +; VhidminiUm.inf +; +;Abstract: +; INF file for installing HID minidriver (UMDF 2 version) +; +;Installation Notes: +; Using Devcon: Type "devcon install VhidminiUm.inf root\VhidminiUm" to install +; +;--*/ +[Version] +Signature="$WINDOWS NT$" +Class=Sample +ClassGuid={78A1C341-4539-11d3-B88D-00C04FAD5171} +Provider=%MSFT% +DriverVer=10/01/2002,6.0.5058.0 +CatalogFile=wudf.cat + +; ================= Class section ===================== + +[ClassInstall32] +Addreg=SampleClassReg + +[SampleClassReg] +HKR,,,0,%ClassName% +HKR,,Icon,,-5 + +; ================= Device section ===================== + +[Manufacturer] +%MfgName%=Microsoft, NT$ARCH$.6.3 + +[Microsoft.NT$ARCH$.6.3] +%DeviceDesc%=VhidminiUm, root\VhidminiUm + +[VhidminiUm.NT] +CopyFiles=UMDriverCopy + +[VhidminiUm.NT.hw] +AddReg=VhidminiUm_AddReg + +[VhidminiUm.NT.Services] +AddService=WUDFRd,0x000001f8,WUDFRD_ServiceInstall +AddService=mshidumdf, 0x000001fa, mshidumdf.AddService ;flag 0x2 sets this as the service for the device + +[VhidminiUm_AddReg] +HKR,,"LowerFilters",0x00010008,"WUDFRd" ; FLG_ADDREG_TYPE_MULTI_SZ | FLG_ADDREG_APPEND + +[mshidumdf.AddService] +ServiceType = 1 ; SERVICE_KERNEL_DRIVER +StartType = 3 ; SERVICE_DEMAND_START +ErrorControl = 1 ; SERVICE_ERROR_NORMAL +ServiceBinary = %12%\mshidumdf.sys + +[WUDFRD_ServiceInstall] +DisplayName = %WudfRdDisplayName% +ServiceType = 1 +StartType = 3 +ErrorControl = 1 +ServiceBinary = %12%\WUDFRd.sys + +[VhidminiUm.NT.Wdf] +UmdfService="VhidminiUm", VhidminiUm_Install +UmdfServiceOrder=VhidminiUm +UmdfKernelModeClientPolicy=AllowKernelModeClients +UmdfFileObjectPolicy=AllowNullAndUnknownFileObjects +UmdfMethodNeitherAction=Copy +UmdfFsContextUsePolicy=CanUseFsContext2 + +[VhidminiUm_Install] +UmdfLibraryVersion=$UMDFVERSION$ +ServiceBinary="%12%\UMDF\VhidminiUm.dll" + +; ================= copy files ===================== + +[UMDriverCopy] +VhidminiUm.dll,,,0x00004000 ; COPYFLG_IN_USE_RENAME + +[SourceDisksNames] +1=%Disk_Description%,,, + +[SourceDisksFiles] +VhidminiUm.dll=1 + +[DestinationDirs] +UMDriverCopy=12,UMDF ; copy to drivers\umdf + +;---------------------------------------------------------------; + +[Strings] +MSFT="Microsoft" +MfgName="Microsoft" +ClassName="Sample Device" +Disk_Description ="HID minidriver (UMDF v2) Installation Disk" +DeviceDesc ="HID minidriver (UMDF v2) Device" +WudfRdDisplayName="Windows Driver Foundation - User-mode Driver Framework Reflector" diff --git a/hid/vhidmini2/driver/umdf2/VhidminiUm.vcxproj b/hid/vhidmini2/driver/umdf2/VhidminiUm.vcxproj new file mode 100644 index 00000000..4e183bbb --- /dev/null +++ b/hid/vhidmini2/driver/umdf2/VhidminiUm.vcxproj @@ -0,0 +1,208 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {80837437-FDA1-43E1-9656-79CA6F3C84DA} + $(MSBuildProjectName) + 2 + Debug + Win32 + {449E70EF-5742-49E4-9EC9-022E79311E53} + + + + Windows10 + False + Universal + UMDF + WindowsUserModeDriver10.0 + DynamicLibrary + + + Windows10 + True + Universal + UMDF + WindowsUserModeDriver10.0 + DynamicLibrary + + + Windows10 + False + Universal + UMDF + WindowsUserModeDriver10.0 + DynamicLibrary + + + Windows10 + True + Universal + UMDF + WindowsUserModeDriver10.0 + DynamicLibrary + + + + $(IntDir) + + + + + + + + + + + + + + + + $(InfArch) + true + .\$(IntDir)\VhidminiUm.inf + + + + VhidminiUm + + + VhidminiUm + + + VhidminiUm + + + VhidminiUm + + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(DDK_INC_PATH)\wdm;..\..\inc;.. + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(DDK_INC_PATH)\wdm;..\..\inc;.. + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(DDK_INC_PATH)\wdm;..\..\inc;.. + + + %(AdditionalDependencies);$(SDK_LIB_PATH)\mincore.lib + + + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(DDK_INC_PATH)\wdm;..\..\inc;.. + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(DDK_INC_PATH)\wdm;..\..\inc;.. + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(DDK_INC_PATH)\wdm;..\..\inc;.. + + + %(AdditionalDependencies);$(SDK_LIB_PATH)\mincore.lib + + + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(DDK_INC_PATH)\wdm;..\..\inc;.. + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(DDK_INC_PATH)\wdm;..\..\inc;.. + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(DDK_INC_PATH)\wdm;..\..\inc;.. + + + %(AdditionalDependencies);$(SDK_LIB_PATH)\mincore.lib + + + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(DDK_INC_PATH)\wdm;..\..\inc;.. + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(DDK_INC_PATH)\wdm;..\..\inc;.. + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(DDK_INC_PATH)\wdm;..\..\inc;.. + + + %(AdditionalDependencies);$(SDK_LIB_PATH)\mincore.lib + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/hid/vhidmini2/driver/umdf2/VhidminiUm.vcxproj.Filters b/hid/vhidmini2/driver/umdf2/VhidminiUm.vcxproj.Filters new file mode 100644 index 00000000..5ef2ab6a --- /dev/null +++ b/hid/vhidmini2/driver/umdf2/VhidminiUm.vcxproj.Filters @@ -0,0 +1,42 @@ + + + + + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* + {1E695972-0767-48CC-92BD-16A66C3FEFB5} + + + h;hpp;hxx;hm;inl;inc;xsd + {AA23C292-0CD2-4784-A71A-43C0B1A98BDE} + + + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml + {09822CD3-C75B-411F-A5C9-D1957BBD9B81} + + + inf;inv;inx;mof;mc; + {CF1C68C7-1F4A-49CB-9417-711A4031F270} + + + + + Driver Files + + + Driver Files + + + + + Source Files + + + Source Files + + + + + Resource Files + + + \ No newline at end of file diff --git a/hid/vhidmini2/driver/umdf2/util.c b/hid/vhidmini2/driver/umdf2/util.c new file mode 100644 index 00000000..6d0eb419 --- /dev/null +++ b/hid/vhidmini2/driver/umdf2/util.c @@ -0,0 +1,149 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved. + +Module Name: + + util.cpp + +Abstract: + + This module contains the implementation of the driver + +Environment: + + Windows Driver Framework (WDF) + +--*/ + +#include "vhidmini.h" + +// +// HID minidriver IOCTL uses HID_XFER_PACKET which contains an embedded pointer. +// +// typedef struct _HID_XFER_PACKET { +// PUCHAR reportBuffer; +// ULONG reportBufferLen; +// UCHAR reportId; +// } HID_XFER_PACKET, *PHID_XFER_PACKET; +// +// UMDF cannot handle embedded pointers when marshalling buffers between processes. +// Therefore a special driver mshidumdf.sys is introduced to convert such IRPs to +// new IRPs (with new IOCTL name like IOCTL_UMDF_HID_Xxxx) where: +// +// reportBuffer - passed as one buffer inside the IRP +// reportId - passed as a second buffer inside the IRP +// +// The new IRP is then passed to UMDF host and driver for further processing. +// + +NTSTATUS +RequestGetHidXferPacket_ToReadFromDevice( + _In_ WDFREQUEST Request, + _Out_ HID_XFER_PACKET *Packet + ) +{ + // + // Driver need to write to the output buffer (so that App can read from it) + // + // Report Buffer: Output Buffer + // Report Id : Input Buffer + // + + NTSTATUS status; + WDFMEMORY inputMemory; + WDFMEMORY outputMemory; + size_t inputBufferLength; + size_t outputBufferLength; + PVOID inputBuffer; + PVOID outputBuffer; + + // + // Get report Id from input buffer + // + status = WdfRequestRetrieveInputMemory(Request, &inputMemory); + if( !NT_SUCCESS(status) ) { + KdPrint(("WdfRequestRetrieveInputMemory failed 0x%x\n",status)); + return status; + } + inputBuffer = WdfMemoryGetBuffer(inputMemory, &inputBufferLength); + + if (inputBufferLength < sizeof(UCHAR)) { + status = STATUS_INVALID_BUFFER_SIZE; + KdPrint(("WdfRequestRetrieveInputMemory: invalid input buffer. size %d, expect %d\n", + (int)inputBufferLength, (int)sizeof(UCHAR))); + return status; + } + + Packet->reportId = *(PUCHAR)inputBuffer; + + // + // Get report buffer from output buffer + // + status = WdfRequestRetrieveOutputMemory(Request, &outputMemory); + if( !NT_SUCCESS(status) ) { + KdPrint(("WdfRequestRetrieveOutputMemory failed 0x%x\n",status)); + return status; + } + + outputBuffer = WdfMemoryGetBuffer(outputMemory, &outputBufferLength); + + Packet->reportBuffer = (PUCHAR) outputBuffer; + Packet->reportBufferLen = (ULONG) outputBufferLength; + + return status; +} + +NTSTATUS +RequestGetHidXferPacket_ToWriteToDevice( + _In_ WDFREQUEST Request, + _Out_ HID_XFER_PACKET *Packet + ) +{ + // + // Driver need to read from the input buffer (which was written by App) + // + // Report Buffer: Input Buffer + // Report Id : Output Buffer Length + // + // Note that the report id is not stored inside the output buffer, as the + // driver has no read-access right to the output buffer, and trying to read + // from the buffer will cause an access violation error. + // + // The workaround is to store the report id in the OutputBufferLength field, + // to which the driver does have read-access right. + // + + NTSTATUS status; + WDFMEMORY inputMemory; + WDFMEMORY outputMemory; + size_t inputBufferLength; + size_t outputBufferLength; + PVOID inputBuffer; + + // + // Get report Id from output buffer length + // + status = WdfRequestRetrieveOutputMemory(Request, &outputMemory); + if( !NT_SUCCESS(status) ) { + KdPrint(("WdfRequestRetrieveOutputMemory failed 0x%x\n",status)); + return status; + } + WdfMemoryGetBuffer(outputMemory, &outputBufferLength); + Packet->reportId = (UCHAR) outputBufferLength; + + // + // Get report buffer from input buffer + // + status = WdfRequestRetrieveInputMemory(Request, &inputMemory); + if( !NT_SUCCESS(status) ) { + KdPrint(("WdfRequestRetrieveInputMemory failed 0x%x\n",status)); + return status; + } + inputBuffer = WdfMemoryGetBuffer(inputMemory, &inputBufferLength); + + Packet->reportBuffer = (PUCHAR) inputBuffer; + Packet->reportBufferLen = (ULONG) inputBufferLength; + + return status; +} diff --git a/hid/vhidmini2/driver/umdf2/vhidmini.rc b/hid/vhidmini2/driver/umdf2/vhidmini.rc new file mode 100644 index 00000000..3721ac98 --- /dev/null +++ b/hid/vhidmini2/driver/umdf2/vhidmini.rc @@ -0,0 +1,16 @@ +//--------------------------------------------------------------------------- +// vhidmini.rc +// +// Copyright (c) Microsoft Corporation, All Rights Reserved +//--------------------------------------------------------------------------- + + +#include +#include + +#define VER_FILETYPE VFT_DLL +#define VER_FILESUBTYPE VFT_UNKNOWN +#define VER_FILEDESCRIPTION_STR "HID minidriver (UMDF 2 version)" +#define VER_INTERNALNAME_STR "VhidminiUm.dll" + +#include "common.ver" diff --git a/hid/vhidmini2/driver/vhidmini.c b/hid/vhidmini2/driver/vhidmini.c new file mode 100644 index 00000000..f1aa4fc8 --- /dev/null +++ b/hid/vhidmini2/driver/vhidmini.c @@ -0,0 +1,1493 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved. + +Module Name: + + vhidmini.cpp + +Abstract: + + This module contains the implementation of the driver + +Environment: + + Windows Driver Framework (WDF) + +--*/ + +#include "vhidmini.h" + +// +// This is the default report descriptor for the virtual Hid device returned +// by the mini driver in response to IOCTL_HID_GET_REPORT_DESCRIPTOR. +// +HID_REPORT_DESCRIPTOR G_DefaultReportDescriptor[] = { + 0x06,0x00, 0xFF, // USAGE_PAGE (Vender Defined Usage Page) + 0x09,0x01, // USAGE (Vendor Usage 0x01) + 0xA1,0x01, // COLLECTION (Application) + 0x85,CONTROL_FEATURE_REPORT_ID, // REPORT_ID (1) + 0x09,0x01, // USAGE (Vendor Usage 0x01) + 0x15,0x00, // LOGICAL_MINIMUM(0) + 0x26,0xff, 0x00, // LOGICAL_MAXIMUM(255) + 0x75,0x08, // REPORT_SIZE (0x08) + 0x96,(FEATURE_REPORT_SIZE_CB & 0xff), (FEATURE_REPORT_SIZE_CB >> 8), // REPORT_COUNT + 0xB1,0x00, // FEATURE (Data,Ary,Abs) + 0x09,0x01, // USAGE (Vendor Usage 0x01) + 0x75,0x08, // REPORT_SIZE (0x08) + 0x96,(INPUT_REPORT_SIZE_CB & 0xff), (INPUT_REPORT_SIZE_CB >> 8), // REPORT_COUNT + 0x81,0x00, // INPUT (Data,Ary,Abs) + 0x09,0x01, // USAGE (Vendor Usage 0x01) + 0x75,0x08, // REPORT_SIZE (0x08) + 0x96,(OUTPUT_REPORT_SIZE_CB & 0xff), (OUTPUT_REPORT_SIZE_CB >> 8), // REPORT_COUNT + 0x91,0x00, // OUTPUT (Data,Ary,Abs) + 0xC0, // END_COLLECTION +}; + +// +// This is the default HID descriptor returned by the mini driver +// in response to IOCTL_HID_GET_DEVICE_DESCRIPTOR. The size +// of report descriptor is currently the size of G_DefaultReportDescriptor. +// + +HID_DESCRIPTOR G_DefaultHidDescriptor = { + 0x09, // length of HID descriptor + 0x21, // descriptor type == HID 0x21 + 0x0100, // hid spec release + 0x00, // country code == Not Specified + 0x01, // number of HID class descriptors + { //DescriptorList[0] + 0x22, //report descriptor type 0x22 + sizeof(G_DefaultReportDescriptor) //total length of report descriptor + } +}; + +NTSTATUS +DriverEntry( + _In_ PDRIVER_OBJECT DriverObject, + _In_ PUNICODE_STRING RegistryPath + ) +/*++ + +Routine Description: + DriverEntry initializes the driver and is the first routine called by the + system after the driver is loaded. DriverEntry specifies the other entry + points in the function driver, such as EvtDevice and DriverUnload. + +Parameters Description: + + DriverObject - represents the instance of the function driver that is loaded + into memory. DriverEntry must initialize members of DriverObject before it + returns to the caller. DriverObject is allocated by the system before the + driver is loaded, and it is released by the system after the system unloads + the function driver from memory. + + RegistryPath - represents the driver specific path in the Registry. + The function driver can use the path to store driver related data between + reboots. The path does not store hardware instance specific data. + +Return Value: + + STATUS_SUCCESS, or another status value for which NT_SUCCESS(status) equals + TRUE if successful, + + STATUS_UNSUCCESSFUL, or another status for which NT_SUCCESS(status) equals + FALSE otherwise. + +--*/ +{ + WDF_DRIVER_CONFIG config; + NTSTATUS status; + + KdPrint(("DriverEntry for VHidMini\n")); + + WDF_DRIVER_CONFIG_INIT(&config, EvtDeviceAdd); + + status = WdfDriverCreate(DriverObject, + RegistryPath, + WDF_NO_OBJECT_ATTRIBUTES, + &config, + WDF_NO_HANDLE); + if (!NT_SUCCESS(status)) { + KdPrint(("Error: WdfDriverCreate failed 0x%x\n", status)); + return status; + } + + return status; +} + +NTSTATUS +EvtDeviceAdd( + _In_ WDFDRIVER Driver, + _Inout_ PWDFDEVICE_INIT DeviceInit + ) +/*++ +Routine Description: + + EvtDeviceAdd is called by the framework in response to AddDevice + call from the PnP manager. We create and initialize a device object to + represent a new instance of the device. + +Arguments: + + Driver - Handle to a framework driver object created in DriverEntry + + DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure. + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status; + WDF_OBJECT_ATTRIBUTES deviceAttributes; + WDFDEVICE device; + PDEVICE_CONTEXT deviceContext; + PHID_DEVICE_ATTRIBUTES hidAttributes; + UNREFERENCED_PARAMETER (Driver); + + KdPrint(("Enter EvtDeviceAdd\n")); + + // + // Mark ourselves as a filter, which also relinquishes power policy ownership + // + WdfFdoInitSetFilter(DeviceInit); + + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE( + &deviceAttributes, + DEVICE_CONTEXT); + + status = WdfDeviceCreate(&DeviceInit, + &deviceAttributes, + &device); + if (!NT_SUCCESS(status)) { + KdPrint(("Error: WdfDeviceCreate failed 0x%x\n", status)); + return status; + } + + deviceContext = GetDeviceContext(device); + deviceContext->Device = device; + deviceContext->DeviceData = 0; + + hidAttributes = &deviceContext->HidDeviceAttributes; + RtlZeroMemory(hidAttributes, sizeof(HID_DEVICE_ATTRIBUTES)); + hidAttributes->Size = sizeof(HID_DEVICE_ATTRIBUTES); + hidAttributes->VendorID = HIDMINI_VID; + hidAttributes->ProductID = HIDMINI_PID; + hidAttributes->VersionNumber = HIDMINI_VERSION; + + status = QueueCreate(device, + &deviceContext->DefaultQueue); + if( !NT_SUCCESS(status) ) { + return status; + } + + status = ManualQueueCreate(device, + &deviceContext->ManualQueue); + if( !NT_SUCCESS(status) ) { + return status; + } + + // + // Use default "HID Descriptor" (hardcoded). We will set the + // wReportLength memeber of HID descriptor when we read the + // the report descriptor either from registry or the hard-coded + // one. + // + deviceContext->HidDescriptor = G_DefaultHidDescriptor; + + // + // Check to see if we need to read the Report Descriptor from + // registry. If the "ReadFromRegistry" flag in the registry is set + // then we will read the descriptor from registry using routine + // ReadDescriptorFromRegistry(). Otherwise, we will use the + // hard-coded default report descriptor. + // + + status = CheckRegistryForDescriptor(device); + if (NT_SUCCESS(status)){ + // + // We need to read read descriptor from registry + // + status = ReadDescriptorFromRegistry(device); + if (!NT_SUCCESS(status)){ + KdPrint(("Failed to read descriptor from registry\n")); + } + } + + // + // We will use hard-coded report descriptor if registry one is not used. + // + if (!NT_SUCCESS(status)){ + deviceContext->ReportDescriptor = G_DefaultReportDescriptor; + KdPrint(("Using Hard-coded Report descriptor\n")); + status = STATUS_SUCCESS; + } + + return status; +} + +#ifdef _KERNEL_MODE +EVT_WDF_IO_QUEUE_IO_INTERNAL_DEVICE_CONTROL EvtIoDeviceControl; +#else +EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL EvtIoDeviceControl; +#endif + +NTSTATUS +QueueCreate( + _In_ WDFDEVICE Device, + _Out_ WDFQUEUE *Queue + ) +/*++ +Routine Description: + + This function creates a default, parallel I/O queue to proces IOCTLs + from hidclass.sys. + +Arguments: + + Device - Handle to a framework device object. + + Queue - Output pointer to a framework I/O queue handle, on success. + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status; + WDF_IO_QUEUE_CONFIG queueConfig; + WDF_OBJECT_ATTRIBUTES queueAttributes; + WDFQUEUE queue; + PQUEUE_CONTEXT queueContext; + + WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE( + &queueConfig, + WdfIoQueueDispatchParallel); + +#ifdef _KERNEL_MODE + queueConfig.EvtIoInternalDeviceControl = EvtIoDeviceControl; +#else + // + // HIDclass uses INTERNAL_IOCTL which is not supported by UMDF. Therefore + // the hidumdf.sys changes the IOCTL type to DEVICE_CONTROL for next stack + // and sends it down + // + queueConfig.EvtIoDeviceControl = EvtIoDeviceControl; +#endif + + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE( + &queueAttributes, + QUEUE_CONTEXT); + + status = WdfIoQueueCreate( + Device, + &queueConfig, + &queueAttributes, + &queue); + + if( !NT_SUCCESS(status) ) { + KdPrint(("WdfIoQueueCreate failed 0x%x\n",status)); + return status; + } + + queueContext = GetQueueContext(queue); + queueContext->Queue = queue; + queueContext->DeviceContext = GetDeviceContext(Device); + queueContext->OutputReport = 0; + + *Queue = queue; + return status; +} + +VOID +EvtIoDeviceControl( + _In_ WDFQUEUE Queue, + _In_ WDFREQUEST Request, + _In_ size_t OutputBufferLength, + _In_ size_t InputBufferLength, + _In_ ULONG IoControlCode + ) +/*++ +Routine Description: + + This event callback function is called when the driver receives an + + (KMDF) IOCTL_HID_Xxx code when handlng IRP_MJ_INTERNAL_DEVICE_CONTROL + (UMDF) IOCTL_HID_Xxx, IOCTL_UMDF_HID_Xxx when handling IRP_MJ_DEVICE_CONTROL + +Arguments: + + Queue - A handle to the queue object that is associated with the I/O request + + Request - A handle to a framework request object. + + OutputBufferLength - The length, in bytes, of the request's output buffer, + if an output buffer is available. + + InputBufferLength - The length, in bytes, of the request's input buffer, if + an input buffer is available. + + IoControlCode - The driver or system defined IOCTL associated with the request + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status; + BOOLEAN completeRequest = TRUE; + WDFDEVICE device = WdfIoQueueGetDevice(Queue); + PDEVICE_CONTEXT deviceContext = NULL; + PQUEUE_CONTEXT queueContext = GetQueueContext(Queue); + UNREFERENCED_PARAMETER (OutputBufferLength); + UNREFERENCED_PARAMETER (InputBufferLength); + + deviceContext = GetDeviceContext(device); + + switch (IoControlCode) + { + case IOCTL_HID_GET_DEVICE_DESCRIPTOR: // METHOD_NEITHER + // + // Retrieves the device's HID descriptor. + // + _Analysis_assume_(deviceContext->HidDescriptor.bLength != 0); + status = RequestCopyFromBuffer(Request, + &deviceContext->HidDescriptor, + deviceContext->HidDescriptor.bLength); + break; + + case IOCTL_HID_GET_DEVICE_ATTRIBUTES: // METHOD_NEITHER + // + //Retrieves a device's attributes in a HID_DEVICE_ATTRIBUTES structure. + // + status = RequestCopyFromBuffer(Request, + &queueContext->DeviceContext->HidDeviceAttributes, + sizeof(HID_DEVICE_ATTRIBUTES)); + break; + + case IOCTL_HID_GET_REPORT_DESCRIPTOR: // METHOD_NEITHER + // + //Obtains the report descriptor for the HID device. + // + status = RequestCopyFromBuffer(Request, + deviceContext->ReportDescriptor, + deviceContext->HidDescriptor.DescriptorList[0].wReportLength); + break; + + case IOCTL_HID_READ_REPORT: // METHOD_NEITHER + // + // Returns a report from the device into a class driver-supplied + // buffer. + // + status = ReadReport(queueContext, Request, &completeRequest); + break; + + case IOCTL_HID_WRITE_REPORT: // METHOD_NEITHER + // + // Transmits a class driver-supplied report to the device. + // + status = WriteReport(queueContext, Request); + break; + +#ifdef _KERNEL_MODE + + case IOCTL_HID_GET_FEATURE: // METHOD_OUT_DIRECT + + status = GetFeature(queueContext, Request); + break; + + case IOCTL_HID_SET_FEATURE: // METHOD_IN_DIRECT + + status = SetFeature(queueContext, Request); + break; + + case IOCTL_HID_GET_INPUT_REPORT: // METHOD_OUT_DIRECT + + status = GetInputReport(queueContext, Request); + break; + + case IOCTL_HID_SET_OUTPUT_REPORT: // METHOD_IN_DIRECT + + status = SetOutputReport(queueContext, Request); + break; + +#else // UMDF specific + + // + // HID minidriver IOCTL uses HID_XFER_PACKET which contains an embedded pointer. + // + // typedef struct _HID_XFER_PACKET { + // PUCHAR reportBuffer; + // ULONG reportBufferLen; + // UCHAR reportId; + // } HID_XFER_PACKET, *PHID_XFER_PACKET; + // + // UMDF cannot handle embedded pointers when marshalling buffers between processes. + // Therefore a special driver mshidumdf.sys is introduced to convert such IRPs to + // new IRPs (with new IOCTL name like IOCTL_UMDF_HID_Xxxx) where: + // + // reportBuffer - passed as one buffer inside the IRP + // reportId - passed as a second buffer inside the IRP + // + // The new IRP is then passed to UMDF host and driver for further processing. + // + + case IOCTL_UMDF_HID_GET_FEATURE: // METHOD_NEITHER + + status = GetFeature(queueContext, Request); + break; + + case IOCTL_UMDF_HID_SET_FEATURE: // METHOD_NEITHER + + status = SetFeature(queueContext, Request); + break; + + case IOCTL_UMDF_HID_GET_INPUT_REPORT: // METHOD_NEITHER + + status = GetInputReport(queueContext, Request); + break; + + case IOCTL_UMDF_HID_SET_OUTPUT_REPORT: // METHOD_NEITHER + + status = SetOutputReport(queueContext, Request); + break; + +#endif // _KERNEL_MODE + + case IOCTL_HID_GET_STRING: // METHOD_NEITHER + + status = GetString(Request); + break; + + case IOCTL_HID_GET_INDEXED_STRING: // METHOD_OUT_DIRECT + + status = GetIndexedString(Request); + break; + + case IOCTL_HID_SEND_IDLE_NOTIFICATION_REQUEST: // METHOD_NEITHER + // + // This has the USBSS Idle notification callback. If the lower driver + // can handle it (e.g. USB stack can handle it) then pass it down + // otherwise complete it here as not inplemented. For a virtual + // device, idling is not needed. + // + // Not implemented. fall through... + // + case IOCTL_HID_ACTIVATE_DEVICE: // METHOD_NEITHER + case IOCTL_HID_DEACTIVATE_DEVICE: // METHOD_NEITHER + case IOCTL_GET_PHYSICAL_DESCRIPTOR: // METHOD_OUT_DIRECT + // + // We don't do anything for these IOCTLs but some minidrivers might. + // + // Not implemented. fall through... + // + default: + status = STATUS_NOT_IMPLEMENTED; + break; + } + + // + // Complete the request. Information value has already been set by request + // handlers. + // + if (completeRequest) { + WdfRequestComplete(Request, status); + } +} + +NTSTATUS +RequestCopyFromBuffer( + _In_ WDFREQUEST Request, + _In_ PVOID SourceBuffer, + _When_(NumBytesToCopyFrom == 0, __drv_reportError(NumBytesToCopyFrom cannot be zero)) + _In_ size_t NumBytesToCopyFrom + ) +/*++ + +Routine Description: + + A helper function to copy specified bytes to the request's output memory + +Arguments: + + Request - A handle to a framework request object. + + SourceBuffer - The buffer to copy data from. + + NumBytesToCopyFrom - The length, in bytes, of data to be copied. + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status; + WDFMEMORY memory; + size_t outputBufferLength; + + status = WdfRequestRetrieveOutputMemory(Request, &memory); + if( !NT_SUCCESS(status) ) { + KdPrint(("WdfRequestRetrieveOutputMemory failed 0x%x\n",status)); + return status; + } + + WdfMemoryGetBuffer(memory, &outputBufferLength); + if (outputBufferLength < NumBytesToCopyFrom) { + status = STATUS_INVALID_BUFFER_SIZE; + KdPrint(("RequestCopyFromBuffer: buffer too small. Size %d, expect %d\n", + (int)outputBufferLength, (int)NumBytesToCopyFrom)); + return status; + } + + status = WdfMemoryCopyFromBuffer(memory, + 0, + SourceBuffer, + NumBytesToCopyFrom); + if( !NT_SUCCESS(status) ) { + KdPrint(("WdfMemoryCopyFromBuffer failed 0x%x\n",status)); + return status; + } + + WdfRequestSetInformation(Request, NumBytesToCopyFrom); + return status; +} + +NTSTATUS +ReadReport( + _In_ PQUEUE_CONTEXT QueueContext, + _In_ WDFREQUEST Request, + _Always_(_Out_) + BOOLEAN* CompleteRequest + ) +/*++ + +Routine Description: + + Handles IOCTL_HID_READ_REPORT for the HID collection. Normally the request + will be forwarded to a manual queue for further process. In that case, the + caller should not try to complete the request at this time, as the request + will later be retrieved back from the manually queue and completed there. + However, if for some reason the forwarding fails, the caller still need + to complete the request with proper error code immediately. + +Arguments: + + QueueContext - The object context associated with the queue + + Request - Pointer to Request Packet. + + CompleteRequest - A boolean output value, indicating whether the caller + should complete the request or not + +Return Value: + + NT status code. + +--*/ +{ + NTSTATUS status; + + KdPrint(("ReadReport\n")); + + // + // forward the request to manual queue + // + status = WdfRequestForwardToIoQueue( + Request, + QueueContext->DeviceContext->ManualQueue); + if( !NT_SUCCESS(status) ) { + KdPrint(("WdfRequestForwardToIoQueue failed with 0x%x\n", status)); + *CompleteRequest = TRUE; + } + else { + *CompleteRequest = FALSE; + } + + return status; +} + +NTSTATUS +WriteReport( + _In_ PQUEUE_CONTEXT QueueContext, + _In_ WDFREQUEST Request + ) +/*++ + +Routine Description: + + Handles IOCTL_HID_WRITE_REPORT all the collection. + +Arguments: + + QueueContext - The object context associated with the queue + + Request - Pointer to Request Packet. + +Return Value: + + NT status code. + +--*/ + +{ + NTSTATUS status; + HID_XFER_PACKET packet; + ULONG reportSize; + PHIDMINI_OUTPUT_REPORT outputReport; + + KdPrint(("WriteReport\n")); + + status = RequestGetHidXferPacket_ToWriteToDevice( + Request, + &packet); + if( !NT_SUCCESS(status) ) { + return status; + } + + if (packet.reportId != CONTROL_COLLECTION_REPORT_ID) { + // + // Return error for unknown collection + // + status = STATUS_INVALID_PARAMETER; + KdPrint(("WriteReport: unkown report id %d\n", packet.reportId)); + return status; + } + + // + // before touching buffer make sure buffer is big enough. + // + reportSize = sizeof(HIDMINI_OUTPUT_REPORT); + + if (packet.reportBufferLen < reportSize) { + status = STATUS_INVALID_BUFFER_SIZE; + KdPrint(("WriteReport: invalid input buffer. size %d, expect %d\n", + packet.reportBufferLen, reportSize)); + return status; + } + + outputReport = (PHIDMINI_OUTPUT_REPORT)packet.reportBuffer; + + // + // Store the device data in device extension. + // + QueueContext->DeviceContext->DeviceData = outputReport->Data; + + // + // set status and information + // + WdfRequestSetInformation(Request, reportSize); + return status; +} + + +HRESULT +GetFeature( + _In_ PQUEUE_CONTEXT QueueContext, + _In_ WDFREQUEST Request + ) +/*++ + +Routine Description: + + Handles IOCTL_HID_GET_FEATURE for all the collection. + +Arguments: + + QueueContext - The object context associated with the queue + + Request - Pointer to Request Packet. + +Return Value: + + NT status code. + +--*/ +{ + NTSTATUS status; + HID_XFER_PACKET packet; + ULONG reportSize; + PMY_DEVICE_ATTRIBUTES myAttributes; + PHID_DEVICE_ATTRIBUTES hidAttributes = &QueueContext->DeviceContext->HidDeviceAttributes; + + KdPrint(("GetFeature\n")); + + status = RequestGetHidXferPacket_ToReadFromDevice( + Request, + &packet); + if( !NT_SUCCESS(status) ) { + return status; + } + + if (packet.reportId != CONTROL_COLLECTION_REPORT_ID) { + // + // If collection ID is not for control collection then handle + // this request just as you would for a regular collection. + // + status = STATUS_INVALID_PARAMETER; + KdPrint(("GetFeature: invalid report id %d\n", packet.reportId)); + return status; + } + + // + // Since output buffer is for write only (no read allowed by UMDF in output + // buffer), any read from output buffer would be reading garbage), so don't + // let app embed custom control code in output buffer. The minidriver can + // support multiple features using separate report ID instead of using + // custom control code. Since this is targeted at report ID 1, we know it + // is a request for getting attributes. + // + // While KMDF does not enforce the rule (disallow read from output buffer), + // it is good practice to not do so. + // + + reportSize = sizeof(MY_DEVICE_ATTRIBUTES) + sizeof(packet.reportId); + if (packet.reportBufferLen < reportSize) { + status = STATUS_INVALID_BUFFER_SIZE; + KdPrint(("GetFeature: output buffer too small. Size %d, expect %d\n", + packet.reportBufferLen, reportSize)); + return status; + } + + // + // Since this device has one report ID, hidclass would pass on the report + // ID in the buffer (it wouldn't if report descriptor did not have any report + // ID). However, since UMDF allows only writes to an output buffer, we can't + // "read" the report ID from "output" buffer. There is no need to read the + // report ID since we get it other way as shown above, however this is + // something to keep in mind. + // + myAttributes = (PMY_DEVICE_ATTRIBUTES)(packet.reportBuffer + sizeof(packet.reportId)); + myAttributes->ProductID = hidAttributes->ProductID; + myAttributes->VendorID = hidAttributes->VendorID; + myAttributes->VersionNumber = hidAttributes->VersionNumber; + + // + // Report how many bytes were copied + // + WdfRequestSetInformation(Request, reportSize); + return status; +} + +NTSTATUS +SetFeature( + _In_ PQUEUE_CONTEXT QueueContext, + _In_ WDFREQUEST Request + ) +/*++ + +Routine Description: + + Handles IOCTL_HID_SET_FEATURE for all the collection. + For control collection (custom defined collection) it handles + the user-defined control codes for sideband communication + +Arguments: + + QueueContext - The object context associated with the queue + + Request - Pointer to Request Packet. + +Return Value: + + NT status code. + +--*/ +{ + NTSTATUS status; + HID_XFER_PACKET packet; + ULONG reportSize; + PHIDMINI_CONTROL_INFO controlInfo; + PHID_DEVICE_ATTRIBUTES hidAttributes = &QueueContext->DeviceContext->HidDeviceAttributes; + + KdPrint(("SetFeature\n")); + + status = RequestGetHidXferPacket_ToWriteToDevice( + Request, + &packet); + if( !NT_SUCCESS(status) ) { + return status; + } + + if (packet.reportId != CONTROL_COLLECTION_REPORT_ID) { + // + // If collection ID is not for control collection then handle + // this request just as you would for a regular collection. + // + status = STATUS_INVALID_PARAMETER; + KdPrint(("SetFeature: invalid report id %d\n", packet.reportId)); + return status; + } + + // + // before touching control code make sure buffer is big enough. + // + reportSize = sizeof(HIDMINI_CONTROL_INFO); + + if (packet.reportBufferLen < reportSize) { + status = STATUS_INVALID_BUFFER_SIZE; + KdPrint(("SetFeature: invalid input buffer. size %d, expect %d\n", + packet.reportBufferLen, reportSize)); + return status; + } + + controlInfo = (PHIDMINI_CONTROL_INFO)packet.reportBuffer; + + switch(controlInfo->ControlCode) + { + case HIDMINI_CONTROL_CODE_SET_ATTRIBUTES: + // + // Store the device attributes in device extension + // + hidAttributes->ProductID = controlInfo->u.Attributes.ProductID; + hidAttributes->VendorID = controlInfo->u.Attributes.VendorID; + hidAttributes->VersionNumber = controlInfo->u.Attributes.VersionNumber; + + // + // set status and information + // + WdfRequestSetInformation(Request, reportSize); + break; + + case HIDMINI_CONTROL_CODE_DUMMY1: + status = STATUS_NOT_IMPLEMENTED; + KdPrint(("SetFeature: HIDMINI_CONTROL_CODE_DUMMY1\n")); + break; + + case HIDMINI_CONTROL_CODE_DUMMY2: + status = STATUS_NOT_IMPLEMENTED; + KdPrint(("SetFeature: HIDMINI_CONTROL_CODE_DUMMY2\n")); + break; + + default: + status = STATUS_NOT_IMPLEMENTED; + KdPrint(("SetFeature: Unknown control Code 0x%x\n", + controlInfo->ControlCode)); + break; + } + + return status; +} + +NTSTATUS +GetInputReport( + _In_ PQUEUE_CONTEXT QueueContext, + _In_ WDFREQUEST Request + ) +/*++ + +Routine Description: + + Handles IOCTL_HID_GET_INPUT_REPORT for all the collection. + +Arguments: + + QueueContext - The object context associated with the queue + + Request - Pointer to Request Packet. + +Return Value: + + NT status code. + +--*/ +{ + NTSTATUS status; + HID_XFER_PACKET packet; + ULONG reportSize; + PHIDMINI_INPUT_REPORT reportBuffer; + + KdPrint(("GetInputReport\n")); + + status = RequestGetHidXferPacket_ToReadFromDevice( + Request, + &packet); + if( !NT_SUCCESS(status) ) { + return status; + } + + if (packet.reportId != CONTROL_COLLECTION_REPORT_ID) { + // + // If collection ID is not for control collection then handle + // this request just as you would for a regular collection. + // + status = STATUS_INVALID_PARAMETER; + KdPrint(("GetInputReport: invalid report id %d\n", packet.reportId)); + return status; + } + + reportSize = sizeof(HIDMINI_INPUT_REPORT); + if (packet.reportBufferLen < reportSize) { + status = STATUS_INVALID_BUFFER_SIZE; + KdPrint(("GetInputReport: output buffer too small. Size %d, expect %d\n", + packet.reportBufferLen, reportSize)); + return status; + } + + reportBuffer = (PHIDMINI_INPUT_REPORT)(packet.reportBuffer); + + reportBuffer->ReportId = CONTROL_COLLECTION_REPORT_ID; + reportBuffer->Data = QueueContext->OutputReport; + + // + // Report how many bytes were copied + // + WdfRequestSetInformation(Request, reportSize); + return status; +} + + +NTSTATUS +SetOutputReport( + _In_ PQUEUE_CONTEXT QueueContext, + _In_ WDFREQUEST Request + ) +/*++ + +Routine Description: + + Handles IOCTL_HID_SET_OUTPUT_REPORT for all the collection. + +Arguments: + + QueueContext - The object context associated with the queue + + Request - Pointer to Request Packet. + +Return Value: + + NT status code. + +--*/ +{ + NTSTATUS status; + HID_XFER_PACKET packet; + ULONG reportSize; + PHIDMINI_OUTPUT_REPORT reportBuffer; + + KdPrint(("SetOutputReport\n")); + + status = RequestGetHidXferPacket_ToWriteToDevice( + Request, + &packet); + if( !NT_SUCCESS(status) ) { + return status; + } + + if (packet.reportId != CONTROL_COLLECTION_REPORT_ID) { + // + // If collection ID is not for control collection then handle + // this request just as you would for a regular collection. + // + status = STATUS_INVALID_PARAMETER; + KdPrint(("SetOutputReport: unkown report id %d\n", packet.reportId)); + return status; + } + + // + // before touching buffer make sure buffer is big enough. + // + reportSize = sizeof(HIDMINI_OUTPUT_REPORT); + + if (packet.reportBufferLen < reportSize) { + status = STATUS_INVALID_BUFFER_SIZE; + KdPrint(("SetOutputReport: invalid input buffer. size %d, expect %d\n", + packet.reportBufferLen, reportSize)); + return status; + } + + reportBuffer = (PHIDMINI_OUTPUT_REPORT)packet.reportBuffer; + + QueueContext->OutputReport = reportBuffer->Data; + + // + // Report how many bytes were copied + // + WdfRequestSetInformation(Request, reportSize); + return status; +} + + +NTSTATUS +GetStringId( + _In_ WDFREQUEST Request, + _Out_ ULONG *StringId, + _Out_ ULONG *LanguageId + ) +/*++ + +Routine Description: + + Helper routine to decode IOCTL_HID_GET_INDEXED_STRING and IOCTL_HID_GET_STRING. + +Arguments: + + Request - Pointer to Request Packet. + +Return Value: + + NT status code. + +--*/ +{ + NTSTATUS status; + ULONG inputValue; + +#ifdef _KERNEL_MODE + + WDF_REQUEST_PARAMETERS requestParameters; + + // + // IOCTL_HID_GET_STRING: // METHOD_NEITHER + // IOCTL_HID_GET_INDEXED_STRING: // METHOD_OUT_DIRECT + // + // The string id (or string index) is passed in Parameters.DeviceIoControl. + // Type3InputBuffer. However, Parameters.DeviceIoControl.InputBufferLength + // was not initialized by hidclass.sys, therefore trying to access the + // buffer with WdfRequestRetrieveInputMemory will fail + // + // Another problem with IOCTL_HID_GET_INDEXED_STRING is that METHOD_OUT_DIRECT + // expects the input buffer to be Irp->AssociatedIrp.SystemBuffer instead of + // Type3InputBuffer. That will also fail WdfRequestRetrieveInputMemory. + // + // The solution to the above two problems is to get Type3InputBuffer directly + // + // Also note that instead of the buffer's content, it is the buffer address + // that was used to store the string id (or index) + // + + WDF_REQUEST_PARAMETERS_INIT(&requestParameters); + WdfRequestGetParameters(Request, &requestParameters); + + inputValue = (ULONG)requestParameters.Parameters.DeviceIoControl.Type3InputBuffer; + + status = STATUS_SUCCESS; + +#else + + WDFMEMORY inputMemory; + size_t inputBufferLength; + PVOID inputBuffer; + + // + // mshidumdf.sys updates the IRP and passes the string id (or index) through + // the input buffer correctly based on the IOCTL buffer type + // + + status = WdfRequestRetrieveInputMemory(Request, &inputMemory); + if( !NT_SUCCESS(status) ) { + KdPrint(("WdfRequestRetrieveInputMemory failed 0x%x\n",status)); + return status; + } + inputBuffer = WdfMemoryGetBuffer(inputMemory, &inputBufferLength); + + // + // make sure buffer is big enough. + // + if (inputBufferLength < sizeof(ULONG)) + { + status = STATUS_INVALID_BUFFER_SIZE; + KdPrint(("GetStringId: invalid input buffer. size %d, expect %d\n", + (int)inputBufferLength, (int)sizeof(ULONG))); + return status; + } + + inputValue = (*(PULONG)inputBuffer); + +#endif + + // + // The least significant two bytes of the INT value contain the string id. + // + *StringId = (inputValue & 0x0ffff); + + // + // The most significant two bytes of the INT value contain the language + // ID (for example, a value of 1033 indicates English). + // + *LanguageId = (inputValue >> 16); + + return status; +} + + +NTSTATUS +GetIndexedString( + _In_ WDFREQUEST Request + ) +/*++ + +Routine Description: + + Handles IOCTL_HID_GET_INDEXED_STRING + +Arguments: + + Request - Pointer to Request Packet. + +Return Value: + + NT status code. + +--*/ +{ + NTSTATUS status; + ULONG languageId, stringIndex; + + status = GetStringId(Request, &stringIndex, &languageId); + + // While we don't use the language id, some minidrivers might. + // + UNREFERENCED_PARAMETER(languageId); + + if (NT_SUCCESS(status)) { + + if (stringIndex != VHIDMINI_DEVICE_STRING_INDEX) + { + status = STATUS_INVALID_PARAMETER; + KdPrint(("GetString: unkown string index %d\n", stringIndex)); + return status; + } + + status = RequestCopyFromBuffer(Request, VHIDMINI_DEVICE_STRING, sizeof(VHIDMINI_DEVICE_STRING)); + } + return status; +} + + +NTSTATUS +GetString( + _In_ WDFREQUEST Request + ) +/*++ + +Routine Description: + + Handles IOCTL_HID_GET_STRING. + +Arguments: + + Request - Pointer to Request Packet. + +Return Value: + + NT status code. + +--*/ +{ + NTSTATUS status; + ULONG languageId, stringId; + size_t stringSizeCb; + PWSTR string; + + status = GetStringId(Request, &stringId, &languageId); + + // While we don't use the language id, some minidrivers might. + // + UNREFERENCED_PARAMETER(languageId); + + if (!NT_SUCCESS(status)) { + return status; + } + + switch (stringId){ + case HID_STRING_ID_IMANUFACTURER: + stringSizeCb = sizeof(VHIDMINI_MANUFACTURER_STRING); + string = VHIDMINI_MANUFACTURER_STRING; + break; + case HID_STRING_ID_IPRODUCT: + stringSizeCb = sizeof(VHIDMINI_PRODUCT_STRING); + string = VHIDMINI_PRODUCT_STRING; + break; + case HID_STRING_ID_ISERIALNUMBER: + stringSizeCb = sizeof(VHIDMINI_SERIAL_NUMBER_STRING); + string = VHIDMINI_SERIAL_NUMBER_STRING; + break; + default: + status = STATUS_INVALID_PARAMETER; + KdPrint(("GetString: unkown string id %d\n", stringId)); + return status; + } + + status = RequestCopyFromBuffer(Request, string, stringSizeCb); + return status; +} + + +NTSTATUS +ManualQueueCreate( + _In_ WDFDEVICE Device, + _Out_ WDFQUEUE *Queue + ) +/*++ +Routine Description: + + This function creates a manual I/O queue to receive IOCTL_HID_READ_REPORT + forwarded from the device's default queue handler. + + It also creates a periodic timer to check the queue and complete any pending + request with data from the device. Here timer expiring is used to simulate + a hardware event that new data is ready. + + The workflow is like this: + + - Hidclass.sys sends an ioctl to the miniport to read input report. + + - The request reaches the driver's default queue. As data may not be avaiable + yet, the request is forwarded to a second manual queue temporarily. + + - Later when data is ready (as simulated by timer expiring), the driver + checks for any pending request in the manual queue, and then completes it. + + - Hidclass gets notified for the read request completion and return data to + the caller. + + On the other hand, for IOCTL_HID_WRITE_REPORT request, the driver simply + sends the request to the hardware (as simulated by storing the data at + DeviceContext->DeviceData) and completes the request immediately. There is + no need to use another queue for write operation. + +Arguments: + + Device - Handle to a framework device object. + + Queue - Output pointer to a framework I/O queue handle, on success. + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status; + WDF_IO_QUEUE_CONFIG queueConfig; + WDF_OBJECT_ATTRIBUTES queueAttributes; + WDFQUEUE queue; + PMANUAL_QUEUE_CONTEXT queueContext; + WDF_TIMER_CONFIG timerConfig; + WDF_OBJECT_ATTRIBUTES timerAttributes; + ULONG timerPeriodInSeconds = 5; + + WDF_IO_QUEUE_CONFIG_INIT( + &queueConfig, + WdfIoQueueDispatchManual); + + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE( + &queueAttributes, + MANUAL_QUEUE_CONTEXT); + + status = WdfIoQueueCreate( + Device, + &queueConfig, + &queueAttributes, + &queue); + + if( !NT_SUCCESS(status) ) { + KdPrint(("WdfIoQueueCreate failed 0x%x\n",status)); + return status; + } + + queueContext = GetManualQueueContext(queue); + queueContext->Queue = queue; + queueContext->DeviceContext = GetDeviceContext(Device); + + WDF_TIMER_CONFIG_INIT_PERIODIC( + &timerConfig, + EvtTimerFunc, + timerPeriodInSeconds * 1000); + + WDF_OBJECT_ATTRIBUTES_INIT(&timerAttributes); + timerAttributes.ParentObject = queue; + status = WdfTimerCreate(&timerConfig, + &timerAttributes, + &queueContext->Timer); + + if( !NT_SUCCESS(status) ) { + KdPrint(("WdfTimerCreate failed 0x%x\n",status)); + return status; + } + + WdfTimerStart(queueContext->Timer, WDF_REL_TIMEOUT_IN_SEC(1)); + + *Queue = queue; + + return status; +} + +void +EvtTimerFunc( + _In_ WDFTIMER Timer + ) +/*++ +Routine Description: + + This periodic timer callback routine checks the device's manual queue and + completes any pending request with data from the device. + +Arguments: + + Timer - Handle to a timer object that was obtained from WdfTimerCreate. + +Return Value: + + VOID + +--*/ +{ + NTSTATUS status; + WDFQUEUE queue; + PMANUAL_QUEUE_CONTEXT queueContext; + WDFREQUEST request; + HIDMINI_INPUT_REPORT readReport; + + KdPrint(("EvtTimerFunc\n")); + + queue = (WDFQUEUE)WdfTimerGetParentObject(Timer); + queueContext = GetManualQueueContext(queue); + + // + // see if we have a request in manual queue + // + status = WdfIoQueueRetrieveNextRequest( + queueContext->Queue, + &request); + + if (NT_SUCCESS(status)) { + + readReport.ReportId = CONTROL_FEATURE_REPORT_ID; + readReport.Data = queueContext->DeviceContext->DeviceData; + + status = RequestCopyFromBuffer(request, + &readReport, + sizeof(readReport)); + + WdfRequestComplete(request, status); + } +} + +NTSTATUS +CheckRegistryForDescriptor( + WDFDEVICE Device + ) +/*++ + +Routine Description: + + Read "ReadFromRegistry" key value from device parameters in the registry. + +Arguments: + + device - pointer to a device object. + +Return Value: + + NT status code. + +--*/ + +{ + WDFKEY hKey = NULL; + NTSTATUS status; + UNICODE_STRING valueName; + ULONG value; + + status = WdfDeviceOpenRegistryKey(Device, + PLUGPLAY_REGKEY_DEVICE, + KEY_READ, + WDF_NO_OBJECT_ATTRIBUTES, + &hKey); + if (NT_SUCCESS(status)) { + + RtlInitUnicodeString(&valueName, L"ReadFromRegistry"); + + status = WdfRegistryQueryULong (hKey, + &valueName, + &value); + + if (NT_SUCCESS (status)) { + if (value == 0) { + status = STATUS_UNSUCCESSFUL; + } + } + + WdfRegistryClose(hKey); + } + + return status; +} + +NTSTATUS +ReadDescriptorFromRegistry( + WDFDEVICE Device + ) +/*++ + +Routine Description: + + Read HID report descriptor from registry + +Arguments: + + device - pointer to a device object. + +Return Value: + + NT status code. + +--*/ +{ + WDFKEY hKey = NULL; + NTSTATUS status; + UNICODE_STRING valueName; + WDFMEMORY memory; + size_t bufferSize; + PVOID reportDescriptor; + PDEVICE_CONTEXT deviceContext; + WDF_OBJECT_ATTRIBUTES attributes; + + deviceContext = GetDeviceContext(Device); + + status = WdfDeviceOpenRegistryKey(Device, + PLUGPLAY_REGKEY_DEVICE, + KEY_READ, + WDF_NO_OBJECT_ATTRIBUTES, + &hKey); + + if (NT_SUCCESS(status)) { + + RtlInitUnicodeString(&valueName, L"MyReportDescriptor"); + + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + attributes.ParentObject = Device; + + status = WdfRegistryQueryMemory (hKey, + &valueName, + NonPagedPool, + &attributes, + &memory, + NULL); + + if (NT_SUCCESS (status)) { + + reportDescriptor = WdfMemoryGetBuffer(memory, &bufferSize); + + KdPrint(("No. of report descriptor bytes copied: %d\n", (INT) bufferSize)); + + // + // Store the registry report descriptor in the device extension + // + deviceContext->ReadReportDescFromRegistry = TRUE; + deviceContext->ReportDescriptor = reportDescriptor; + deviceContext->HidDescriptor.DescriptorList[0].wReportLength = (USHORT)bufferSize; + } + + WdfRegistryClose(hKey); + } + + return status; +} + diff --git a/hid/vhidmini2/driver/vhidmini.h b/hid/vhidmini2/driver/vhidmini.h new file mode 100644 index 00000000..118f6c4c --- /dev/null +++ b/hid/vhidmini2/driver/vhidmini.h @@ -0,0 +1,180 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved + +Module Name: + + vhidmini.h + +Abstract: + + This module contains the type definitions for the driver + +Environment: + + Windows Driver Framework (WDF) + +--*/ + +#ifdef _KERNEL_MODE +#include +#else +#include +#endif + +#include + +#include // located in $(DDK_INC_PATH)/wdm + +#include "common.h" + +typedef UCHAR HID_REPORT_DESCRIPTOR, *PHID_REPORT_DESCRIPTOR; + +DRIVER_INITIALIZE DriverEntry; +EVT_WDF_DRIVER_DEVICE_ADD EvtDeviceAdd; +EVT_WDF_TIMER EvtTimerFunc; + +typedef struct _DEVICE_CONTEXT +{ + WDFDEVICE Device; + WDFQUEUE DefaultQueue; + WDFQUEUE ManualQueue; + HID_DEVICE_ATTRIBUTES HidDeviceAttributes; + BYTE DeviceData; + HID_DESCRIPTOR HidDescriptor; + PHID_REPORT_DESCRIPTOR ReportDescriptor; + BOOLEAN ReadReportDescFromRegistry; + +} DEVICE_CONTEXT, *PDEVICE_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(DEVICE_CONTEXT, GetDeviceContext); + +typedef struct _QUEUE_CONTEXT +{ + WDFQUEUE Queue; + PDEVICE_CONTEXT DeviceContext; + UCHAR OutputReport; + +} QUEUE_CONTEXT, *PQUEUE_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(QUEUE_CONTEXT, GetQueueContext); + +NTSTATUS +QueueCreate( + _In_ WDFDEVICE Device, + _Out_ WDFQUEUE *Queue + ); + +typedef struct _MANUAL_QUEUE_CONTEXT +{ + WDFQUEUE Queue; + PDEVICE_CONTEXT DeviceContext; + WDFTIMER Timer; + +} MANUAL_QUEUE_CONTEXT, *PMANUAL_QUEUE_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(MANUAL_QUEUE_CONTEXT, GetManualQueueContext); + +NTSTATUS +ManualQueueCreate( + _In_ WDFDEVICE Device, + _Out_ WDFQUEUE *Queue + ); + +NTSTATUS +ReadReport( + _In_ PQUEUE_CONTEXT QueueContext, + _In_ WDFREQUEST Request, + _Always_(_Out_) + BOOLEAN* CompleteRequest + ); + +NTSTATUS +WriteReport( + _In_ PQUEUE_CONTEXT QueueContext, + _In_ WDFREQUEST Request + ); + +NTSTATUS +GetFeature( + _In_ PQUEUE_CONTEXT QueueContext, + _In_ WDFREQUEST Request + ); + +NTSTATUS +SetFeature( + _In_ PQUEUE_CONTEXT QueueContext, + _In_ WDFREQUEST Request + ); + +NTSTATUS +GetInputReport( + _In_ PQUEUE_CONTEXT QueueContext, + _In_ WDFREQUEST Request + ); + +NTSTATUS +SetOutputReport( + _In_ PQUEUE_CONTEXT QueueContext, + _In_ WDFREQUEST Request + ); + +NTSTATUS +GetString( + _In_ WDFREQUEST Request + ); + +NTSTATUS +GetIndexedString( + _In_ WDFREQUEST Request + ); + +NTSTATUS +GetStringId( + _In_ WDFREQUEST Request, + _Out_ ULONG *StringId, + _Out_ ULONG *LanguageId + ); + +NTSTATUS +RequestCopyFromBuffer( + _In_ WDFREQUEST Request, + _In_ PVOID SourceBuffer, + _When_(NumBytesToCopyFrom == 0, __drv_reportError(NumBytesToCopyFrom cannot be zero)) + _In_ size_t NumBytesToCopyFrom + ); + +NTSTATUS +RequestGetHidXferPacket_ToReadFromDevice( + _In_ WDFREQUEST Request, + _Out_ HID_XFER_PACKET *Packet + ); + +NTSTATUS +RequestGetHidXferPacket_ToWriteToDevice( + _In_ WDFREQUEST Request, + _Out_ HID_XFER_PACKET *Packet + ); + +NTSTATUS +CheckRegistryForDescriptor( + _In_ WDFDEVICE Device + ); + +NTSTATUS +ReadDescriptorFromRegistry( + _In_ WDFDEVICE Device + ); + +// +// Misc definitions +// +#define CONTROL_FEATURE_REPORT_ID 0x01 + +// +// These are the device attributes returned by the mini driver in response +// to IOCTL_HID_GET_DEVICE_ATTRIBUTES. +// +#define HIDMINI_PID 0xFEED +#define HIDMINI_VID 0xDEED +#define HIDMINI_VERSION 0x0101 diff --git a/hid/vhidmini2/inc/common.h b/hid/vhidmini2/inc/common.h new file mode 100644 index 00000000..1a9eca1a --- /dev/null +++ b/hid/vhidmini2/inc/common.h @@ -0,0 +1,120 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + common.h + +Environment: + + User mode + +--*/ + +#ifndef __VHIDMINI_COMMON_H__ +#define __VHIDMINI_COMMON_H__ + +// +// Custom control codes are defined here. They are to be used for sideband +// communication with the hid minidriver. These control codes are sent to +// the hid minidriver using Hid_SetFeature() API to a custom collection +// defined especially to handle such requests. +// +#define HIDMINI_CONTROL_CODE_SET_ATTRIBUTES 0x00 +#define HIDMINI_CONTROL_CODE_DUMMY1 0x01 +#define HIDMINI_CONTROL_CODE_DUMMY2 0x02 + +// +// This is the report id of the collection to which the control codes are sent +// +#define CONTROL_COLLECTION_REPORT_ID 0x01 +#define TEST_COLLECTION_REPORT_ID 0x02 + +#define MAXIMUM_STRING_LENGTH (126 * sizeof(WCHAR)) +#define VHIDMINI_DEVICE_STRING L"UMDF Virtual hidmini device" +#define VHIDMINI_MANUFACTURER_STRING L"UMDF Virtual hidmini device Manufacturer string" +#define VHIDMINI_PRODUCT_STRING L"UMDF Virtual hidmini device Product string" +#define VHIDMINI_SERIAL_NUMBER_STRING L"UMDF Virtual hidmini device Serial Number string" +#define VHIDMINI_DEVICE_STRING L"UMDF Virtual hidmini device" +#define VHIDMINI_DEVICE_STRING_INDEX 5 +#include + +typedef struct _MY_DEVICE_ATTRIBUTES { + + USHORT VendorID; + USHORT ProductID; + USHORT VersionNumber; + +} MY_DEVICE_ATTRIBUTES, *PMY_DEVICE_ATTRIBUTES; + +typedef struct _HIDMINI_CONTROL_INFO { + + // + //report ID of the collection to which the control request is sent + // + UCHAR ReportId; + + // + // One byte control code (user-defined) for communication with hid + // mini driver + // + UCHAR ControlCode; + + // + // This union contains input data for the control request. + // + union { + MY_DEVICE_ATTRIBUTES Attributes; + struct { + ULONG Dummy1; + ULONG Dummy2; + } Dummy; + } u; + +} HIDMINI_CONTROL_INFO, * PHIDMINI_CONTROL_INFO; + +// +// input from device to system +// +typedef struct _HIDMINI_INPUT_REPORT { + + UCHAR ReportId; + + UCHAR Data; + +} HIDMINI_INPUT_REPORT, *PHIDMINI_INPUT_REPORT; + +// +// output to device from system +// +typedef struct _HIDMINI_OUTPUT_REPORT { + + UCHAR ReportId; + + UCHAR Data; + + USHORT Pad1; + + ULONG Pad2; + +} HIDMINI_OUTPUT_REPORT, *PHIDMINI_OUTPUT_REPORT; + +#include + +// +// SetFeature request requires that the feature report buffer size be exactly +// same as the size of report described in the hid report descriptor ( +// excluding the report ID). Since HIDMINI_CONTROL_INFO includes report ID, +// we subtract one from the size. +// +#define FEATURE_REPORT_SIZE_CB ((USHORT)(sizeof(HIDMINI_CONTROL_INFO) - 1)) +#define INPUT_REPORT_SIZE_CB ((USHORT)(sizeof(HIDMINI_INPUT_REPORT) - 1)) +#define OUTPUT_REPORT_SIZE_CB ((USHORT)(sizeof(HIDMINI_OUTPUT_REPORT) - 1)) + +#endif //__VHIDMINI_COMMON_H__ diff --git a/hid/vhidmini2/vhidmini2.sln b/hid/vhidmini2/vhidmini2.sln new file mode 100644 index 00000000..e8e2bbf6 --- /dev/null +++ b/hid/vhidmini2/vhidmini2.sln @@ -0,0 +1,63 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0 +MinimumVisualStudioVersion = 12.0 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "App", "App", "{72955C82-582A-4ECE-AB2B-5F17AA6A7D35}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Umdf2", "Umdf2", "{EE026314-C7B7-4A0C-949F-8A8BD0232329}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Driver", "Driver", "{B9945C2D-CF78-4A77-8474-D872AF45B5AF}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Kmdf", "Kmdf", "{283408F4-D822-4E3C-A0F4-4466FDB51D25}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testvhid", "app\testvhid.vcxproj", "{33D1A6C5-8347-43BB-853C-0820EF7203C6}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "VhidminiUm", "driver\umdf2\VhidminiUm.vcxproj", "{80837437-FDA1-43E1-9656-79CA6F3C84DA}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vhidmini", "driver\kmdf\vhidmini.vcxproj", "{20843589-DA00-4ADD-BDA0-62C7065C80CB}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {33D1A6C5-8347-43BB-853C-0820EF7203C6}.Debug|Win32.ActiveCfg = Debug|Win32 + {33D1A6C5-8347-43BB-853C-0820EF7203C6}.Debug|Win32.Build.0 = Debug|Win32 + {33D1A6C5-8347-43BB-853C-0820EF7203C6}.Release|Win32.ActiveCfg = Release|Win32 + {33D1A6C5-8347-43BB-853C-0820EF7203C6}.Release|Win32.Build.0 = Release|Win32 + {33D1A6C5-8347-43BB-853C-0820EF7203C6}.Debug|x64.ActiveCfg = Debug|x64 + {33D1A6C5-8347-43BB-853C-0820EF7203C6}.Debug|x64.Build.0 = Debug|x64 + {33D1A6C5-8347-43BB-853C-0820EF7203C6}.Release|x64.ActiveCfg = Release|x64 + {33D1A6C5-8347-43BB-853C-0820EF7203C6}.Release|x64.Build.0 = Release|x64 + {80837437-FDA1-43E1-9656-79CA6F3C84DA}.Debug|Win32.ActiveCfg = Debug|Win32 + {80837437-FDA1-43E1-9656-79CA6F3C84DA}.Debug|Win32.Build.0 = Debug|Win32 + {80837437-FDA1-43E1-9656-79CA6F3C84DA}.Release|Win32.ActiveCfg = Release|Win32 + {80837437-FDA1-43E1-9656-79CA6F3C84DA}.Release|Win32.Build.0 = Release|Win32 + {80837437-FDA1-43E1-9656-79CA6F3C84DA}.Debug|x64.ActiveCfg = Debug|x64 + {80837437-FDA1-43E1-9656-79CA6F3C84DA}.Debug|x64.Build.0 = Debug|x64 + {80837437-FDA1-43E1-9656-79CA6F3C84DA}.Release|x64.ActiveCfg = Release|x64 + {80837437-FDA1-43E1-9656-79CA6F3C84DA}.Release|x64.Build.0 = Release|x64 + {20843589-DA00-4ADD-BDA0-62C7065C80CB}.Debug|Win32.ActiveCfg = Debug|Win32 + {20843589-DA00-4ADD-BDA0-62C7065C80CB}.Debug|Win32.Build.0 = Debug|Win32 + {20843589-DA00-4ADD-BDA0-62C7065C80CB}.Release|Win32.ActiveCfg = Release|Win32 + {20843589-DA00-4ADD-BDA0-62C7065C80CB}.Release|Win32.Build.0 = Release|Win32 + {20843589-DA00-4ADD-BDA0-62C7065C80CB}.Debug|x64.ActiveCfg = Debug|x64 + {20843589-DA00-4ADD-BDA0-62C7065C80CB}.Debug|x64.Build.0 = Debug|x64 + {20843589-DA00-4ADD-BDA0-62C7065C80CB}.Release|x64.ActiveCfg = Release|x64 + {20843589-DA00-4ADD-BDA0-62C7065C80CB}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {33D1A6C5-8347-43BB-853C-0820EF7203C6} = {72955C82-582A-4ECE-AB2B-5F17AA6A7D35} + {80837437-FDA1-43E1-9656-79CA6F3C84DA} = {EE026314-C7B7-4A0C-949F-8A8BD0232329} + {20843589-DA00-4ADD-BDA0-62C7065C80CB} = {283408F4-D822-4E3C-A0F4-4466FDB51D25} + {EE026314-C7B7-4A0C-949F-8A8BD0232329} = {B9945C2D-CF78-4A77-8474-D872AF45B5AF} + {283408F4-D822-4E3C-A0F4-4466FDB51D25} = {B9945C2D-CF78-4A77-8474-D872AF45B5AF} + EndGlobalSection +EndGlobal diff --git a/network/config/bindview/bindview.sln b/network/config/bindview/bindview.sln index 021f4efb..921d1d4f 100644 --- a/network/config/bindview/bindview.sln +++ b/network/config/bindview/bindview.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bindview", "bindview.vcxproj", "{C8EC04C0-EF77-4CD4-8072-F7F8A9125822}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bindview", "bindview.vcxproj", "{34897AE3-000C-4986-8DA8-45DA5317354F}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +13,14 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {C8EC04C0-EF77-4CD4-8072-F7F8A9125822}.Debug|Win32.ActiveCfg = Debug|Win32 - {C8EC04C0-EF77-4CD4-8072-F7F8A9125822}.Debug|Win32.Build.0 = Debug|Win32 - {C8EC04C0-EF77-4CD4-8072-F7F8A9125822}.Release|Win32.ActiveCfg = Release|Win32 - {C8EC04C0-EF77-4CD4-8072-F7F8A9125822}.Release|Win32.Build.0 = Release|Win32 - {C8EC04C0-EF77-4CD4-8072-F7F8A9125822}.Debug|x64.ActiveCfg = Debug|x64 - {C8EC04C0-EF77-4CD4-8072-F7F8A9125822}.Debug|x64.Build.0 = Debug|x64 - {C8EC04C0-EF77-4CD4-8072-F7F8A9125822}.Release|x64.ActiveCfg = Release|x64 - {C8EC04C0-EF77-4CD4-8072-F7F8A9125822}.Release|x64.Build.0 = Release|x64 + {34897AE3-000C-4986-8DA8-45DA5317354F}.Debug|Win32.ActiveCfg = Debug|Win32 + {34897AE3-000C-4986-8DA8-45DA5317354F}.Debug|Win32.Build.0 = Debug|Win32 + {34897AE3-000C-4986-8DA8-45DA5317354F}.Release|Win32.ActiveCfg = Release|Win32 + {34897AE3-000C-4986-8DA8-45DA5317354F}.Release|Win32.Build.0 = Release|Win32 + {34897AE3-000C-4986-8DA8-45DA5317354F}.Debug|x64.ActiveCfg = Debug|x64 + {34897AE3-000C-4986-8DA8-45DA5317354F}.Debug|x64.Build.0 = Debug|x64 + {34897AE3-000C-4986-8DA8-45DA5317354F}.Release|x64.ActiveCfg = Release|x64 + {34897AE3-000C-4986-8DA8-45DA5317354F}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/network/config/bindview/bindview.vcxproj b/network/config/bindview/bindview.vcxproj index 767d2a89..8bb38928 100644 --- a/network/config/bindview/bindview.vcxproj +++ b/network/config/bindview/bindview.vcxproj @@ -19,11 +19,11 @@
- {C8EC04C0-EF77-4CD4-8072-F7F8A9125822} + {34897AE3-000C-4986-8DA8-45DA5317354F} $(MSBuildProjectName) Debug Win32 - {224CF8FD-5538-4B7E-81AF-44805B4722EA} + {142C0734-824B-4C41-9B69-E7F6D7214F0F} diff --git a/network/config/bindview/bindview.vcxproj.Filters b/network/config/bindview/bindview.vcxproj.Filters index 964d777e..82255772 100644 --- a/network/config/bindview/bindview.vcxproj.Filters +++ b/network/config/bindview/bindview.vcxproj.Filters @@ -3,15 +3,15 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {4372001E-614D-43C8-ACA0-0ACF46A23F6E} + {DD6BF01A-E882-42FA-9582-205A36B5FDE9} h;hpp;hxx;hm;inl;inc;xsd - {98620252-1A3C-4A35-8A10-A2376A0D90BF} + {3AA8C4B2-E02E-4C24-BF11-8C30E62ED7FB} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {CC73B9F9-A9E1-4AA1-88AE-951314EA9903} + {860821E6-FF0C-4292-B8E6-144043F7E832} diff --git a/network/modem/fakemodem/fakemodem.htm b/network/modem/fakemodem/fakemodem.htm new file mode 100644 index 00000000..add195f7 --- /dev/null +++ b/network/modem/fakemodem/fakemodem.htm @@ -0,0 +1,926 @@ + + + + + + + +UNIMODEM sample controller-less modem driver (fakemodem) + + + + + + + + + +
+ +

UNIMODEM sample controller-less modem driver (Fakemodem)

+ +

SUMMARY         

+ +

This +sample demonstrates a simple controller-less modem driver. This +driver supports sending and receiving AT commands using the ReadFile/WriteFile calls or via a TAPI interface using an +application such as HyperTerminal.

+ +

BUILDING THE SAMPLE

+ +

Click +the Free Build Environment or Checked Build Environment icon under Development +Kits program group to set basic environment variables.

+ +

Change +to the directory containing the device source code, such as CD src\wdf\fakemodem. +

+ +

Run build +-ceZ, or use the macro BLD. This command +invokes the Microsoft make routines to build the components. If the build succeeds, you will find the driver, fakemodem.sys, placed in a platform +specific subdirectory +src\network\modem\fakemodem\$(OBJ_PATH)\$O. If it fails you can find errors and warnings in the +buildxxx.err and buildxxx.err respectively, where xxx is either chk or fre depending on the build +environment.

+ +

INSTALLATION

+ +

To +install and test this driver, you do not need any real hardware. You can +install this driver either using Devcon.exe (ddk\tools\devcon) utility from the DDK or using toaster bus driver +sample.

+ +

To install the bus driver on Windows XP and Windows Server 2003:

+ +
    +
  • Double-click the ‘Add Hardware’ + wizard in Control Panel.
  • +
  • At the 'Welcome to the Add + Hardware Wizard', click ‘Next’.
  • +
  • Select 'Yes, I have already + connected the hardware', then click Next.
  • +
  • Select ‘Add a new hardware + device’ from the list, then click Next.
  • +
  • Select ‘Install the hardware + that I manually select from a list(Advanced),' and then click next.
  • +
  • Select ‘Modems’, then click + Next.
  • +
  • Check the box which says + "Don't detect my modems; I will select it from a list.", then + click Next.
  • +
  • Click 'Have Disk', make sure + that 'A:\' is in the "Copy manufacturer's files from:" box, and + click OK.
  • +
  • Click on the desired entry, and + then click Next.
  • +
  • At 'The wizard is ready to + install your hardware', click Next.
  • +
  • Click Finish at 'Completing the + Add/Remove Hardware Wizard.'
  • +
+ +

To install the +driver using toaster bus:

+ +

·         +Install the toaster bus driver. +Information on how to install the toaster bus driver is given in src\general\toaster\toaster.htm readme file.

+ +

·         +Run the notify.exe (src\general\toaster\exe\notify) and choose Plug In a device +in the Bus menu.

+ +

·         +In the plug in dialog, specify +{b85b7c50-6a01-11d2-b841-00c04fad5171}\fakemodem as +the Hardware Id and click okay.

+ +

The bus driver will enumerate a +device with the hardware id provided by the application. At this point:

+ +

On +Windows XP and later:

+ +
    +
  • "Found New Hardware Wizard" + dialog box will appear. Here select the radio button labeled "Install + from a list of specific location (Advanced)" and then hit the + "Next" button.
  • +
  • In the following screen select the + radio button labeled " Search the best driver in these + locations" and then select "Include this location in the search + path" and specify the target media or the directory where the KMDF + coinstaller (wdfcoinstallerMMmmm.dll), INF and SYS files are copied and + then hit the "Next" button.
  • +
  • The system will scan the directory and + pick up the matching INF and start the installation. You will get a + Hardware Installation Warning dialog stating that your driver has not + passed Windows Logo Testing. Hit "Continue Anyway" button.
  • +
  • The system will copy the driver, INF + file, load the driver and start the device. If every thing goes fine, you + will get "Completing the Found New Hardware Wizard". Hit the + "Finish" button and the installation is complete.
  • +
  • You should be able to see the device + in the Device manager under "Modems"
  • +
+ +

On +Windows 2000:

+ +
    +
  • "Found New Hardware Wizard" + dialog box will appear with the description of the device. Here click + "Next" button.
  • +
  • In the following screen "Install + Hardware Device Driver", select the radio button labeled "Display + a list of known drivers for this device..." and then click + "Next" button.
  • +
  • In the following dialog on + "Hardware Type", select "Other Devices" from the list + and click "Next".
  • +
  • In the dialog on "Select a Device + Driver", click on "Have Disk".
  • +
  • Specify the target media or the + directory where the KMDF coinstaller (wdfcoinstallerMMmmm.dll), INF and + SYS files are copied and then hit the "Okay" button.
  • +
  • Select "OSR" in the + Manufacture section selection and click "Next".
  • +
  • Click "Next" on the + "Start Device Driver Installation" dialog.
  • +
  • Click Finish at 'Completing the + Add/Remove Hardware Wizard.'
  • +
+ +

Note that if you get a warning dialog with +regards to Windows Logo, or unsigned drivers, testing then click on continue.

+ +

USAGE

+ +

Once +installed, you can talk to the fakemodem driver +through HyperTerminal, or via ReadFile/WriteFile calls.  The +AT command set supported by fakemodem includes:

+ +

          AT                         returns OK
+
+          ATA                       returns CONNECT

+ +

            ATD<number>                  returns CONNECT

+ +

CODE +TOUR

+ +

File +Manifest

+ +
File           Description
readwrit.c    Routines for receiving and sending text. This includes processing AT commands.
Driver.c              Fakemodem driver initialization entry points and for handling Plug & Play events.
ioctl.c               Routines to handle IOCTL messages.
mdmfake.inf   INF file for installing the fakemodem driver
+ +

Top +of page

+ + + + + +
+

 

+
+ +

© Microsoft +Corporation 2000 +

+ +
+ + + + diff --git a/network/modem/fakemodem/fakemodem.sln b/network/modem/fakemodem/fakemodem.sln index 6804feb5..e521285a 100644 --- a/network/modem/fakemodem/fakemodem.sln +++ b/network/modem/fakemodem/fakemodem.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fakemodem", "fakemodem.vcxproj", "{3744C5BD-A12A-429F-9312-DFD04AC69078}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fakemodem", "fakemodem.vcxproj", "{021EA388-9BD1-4B52-A954-AF1ECC14959A}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +13,14 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {3744C5BD-A12A-429F-9312-DFD04AC69078}.Debug|Win32.ActiveCfg = Debug|Win32 - {3744C5BD-A12A-429F-9312-DFD04AC69078}.Debug|Win32.Build.0 = Debug|Win32 - {3744C5BD-A12A-429F-9312-DFD04AC69078}.Release|Win32.ActiveCfg = Release|Win32 - {3744C5BD-A12A-429F-9312-DFD04AC69078}.Release|Win32.Build.0 = Release|Win32 - {3744C5BD-A12A-429F-9312-DFD04AC69078}.Debug|x64.ActiveCfg = Debug|x64 - {3744C5BD-A12A-429F-9312-DFD04AC69078}.Debug|x64.Build.0 = Debug|x64 - {3744C5BD-A12A-429F-9312-DFD04AC69078}.Release|x64.ActiveCfg = Release|x64 - {3744C5BD-A12A-429F-9312-DFD04AC69078}.Release|x64.Build.0 = Release|x64 + {021EA388-9BD1-4B52-A954-AF1ECC14959A}.Debug|Win32.ActiveCfg = Debug|Win32 + {021EA388-9BD1-4B52-A954-AF1ECC14959A}.Debug|Win32.Build.0 = Debug|Win32 + {021EA388-9BD1-4B52-A954-AF1ECC14959A}.Release|Win32.ActiveCfg = Release|Win32 + {021EA388-9BD1-4B52-A954-AF1ECC14959A}.Release|Win32.Build.0 = Release|Win32 + {021EA388-9BD1-4B52-A954-AF1ECC14959A}.Debug|x64.ActiveCfg = Debug|x64 + {021EA388-9BD1-4B52-A954-AF1ECC14959A}.Debug|x64.Build.0 = Debug|x64 + {021EA388-9BD1-4B52-A954-AF1ECC14959A}.Release|x64.ActiveCfg = Release|x64 + {021EA388-9BD1-4B52-A954-AF1ECC14959A}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/network/modem/fakemodem/fakemodem.vcxproj b/network/modem/fakemodem/fakemodem.vcxproj index c2a2dd8d..0c24e2d3 100644 --- a/network/modem/fakemodem/fakemodem.vcxproj +++ b/network/modem/fakemodem/fakemodem.vcxproj @@ -19,12 +19,12 @@
- {3744C5BD-A12A-429F-9312-DFD04AC69078} + {021EA388-9BD1-4B52-A954-AF1ECC14959A} $(MSBuildProjectName) 1 Debug Win32 - {74C5BB58-0CB8-4E8E-8FD7-065CBE6051A7} + {40F9DBFF-3A37-43BB-A11E-8C4F0672CAE2} diff --git a/network/modem/fakemodem/fakemodem.vcxproj.Filters b/network/modem/fakemodem/fakemodem.vcxproj.Filters index 7c8d71ab..5a8b5bf5 100644 --- a/network/modem/fakemodem/fakemodem.vcxproj.Filters +++ b/network/modem/fakemodem/fakemodem.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {66A2BE8B-87F0-4F4B-AB28-9C66471A8B7B} + {B7848512-B788-41BD-B77C-7E17CD2BD418} h;hpp;hxx;hm;inl;inc;xsd - {F31D838F-78A7-4140-B15C-4C9485DDB150} + {3C0E579D-D582-4FF2-A923-CF6AA3816295} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {8A726BCF-D9F0-4948-8219-B0CCAC8AA786} + {7868BAAE-9CBF-493B-A1FA-7B4DC86F11D3} inf;inv;inx;mof;mc; - {A5962758-E097-4C00-A4FB-3A630B0E5405} + {204657EA-2714-45FB-A126-7BE909214868} diff --git a/network/ndis/extension/base/sxbase.vcxproj b/network/ndis/extension/base/sxbase.vcxproj index 4c81ea79..d49f21c6 100644 --- a/network/ndis/extension/base/sxbase.vcxproj +++ b/network/ndis/extension/base/sxbase.vcxproj @@ -11,11 +11,11 @@ - {63FF1428-95CA-4751-A701-244D54A31BD9} + {0AF344BA-2F72-4E63-85D3-6C649C493113} $(MSBuildProjectName) Debug x64 - {8C4C832A-4638-47E9-B2AC-6FA6FC1D958B} + {5E6D6149-F14D-47BE-A505-3C14582EB73D} diff --git a/network/ndis/extension/base/sxbase.vcxproj.Filters b/network/ndis/extension/base/sxbase.vcxproj.Filters index 1291527a..fa2b2bc8 100644 --- a/network/ndis/extension/base/sxbase.vcxproj.Filters +++ b/network/ndis/extension/base/sxbase.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {74637802-97A6-4EEE-A780-7AFC24D63060} + {06AF9F9E-A01B-4811-AC1D-93436B508BA2} h;hpp;hxx;hm;inl;inc;xsd - {7417E375-1992-4C4B-A4AB-C0C8E00F9AAA} + {8622716C-DDFC-41F0-AA13-E1FA6FF65319} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {73A4206C-20D4-4AB0-B133-03D222981702} + {A71D839D-75EE-4F0F-AEF8-2892391ED123} inf;inv;inx;mof;mc; - {CB4FE68B-83B4-4336-A241-94F6955D198A} + {6647DA6B-FEFD-492E-B3FD-A3AFCDAC7AFD} diff --git a/network/ndis/extension/extensions.sln b/network/ndis/extension/extensions.sln index cc6ab362..2ebff25c 100644 --- a/network/ndis/extension/extensions.sln +++ b/network/ndis/extension/extensions.sln @@ -3,24 +3,24 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Base", "Base", "{1C3E1DE9-A703-46CB-B4E4-8CD906C9E6FE}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Base", "Base", "{91A9E693-3D97-4069-B2A4-84CD10712B8E}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Forward", "Forward", "{433D0832-2B1B-46AB-94E8-0A7979ACA4CA}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Forward", "Forward", "{5CC88476-FA8E-43F7-BE93-29147910AE87}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{BC0A3E55-CAE0-4CCE-BA15-0784AEF76215}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{0357B6CB-FF60-41D3-8879-A04837F014CD}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Passthrough", "Passthrough", "{7C717732-18C9-4892-A6FF-B4DD1D72C12B}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Passthrough", "Passthrough", "{7A74F8F6-D891-40BB-9CB5-308ACDA3B778}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sxbase", "base\sxbase.vcxproj", "{63FF1428-95CA-4751-A701-244D54A31BD9}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sxbase", "base\sxbase.vcxproj", "{0AF344BA-2F72-4E63-85D3-6C649C493113}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "msforwardext", "samples\forward\msforwardext.vcxproj", "{404E1399-EA48-4CEE-A59E-EA0D4C01928A}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "msforwardext", "samples\forward\msforwardext.vcxproj", "{947BD508-8C40-4109-AA40-0E6B54FD7E07}" ProjectSection(ProjectDependencies) = postProject - {63FF1428-95CA-4751-A701-244D54A31BD9} = {63FF1428-95CA-4751-A701-244D54A31BD9} + {0AF344BA-2F72-4E63-85D3-6C649C493113} = {0AF344BA-2F72-4E63-85D3-6C649C493113} EndProjectSection EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mspassthroughext", "samples\passthrough\mspassthroughext.vcxproj", "{2339B4A8-60AF-4172-AC68-3159E6D001EC}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mspassthroughext", "samples\passthrough\mspassthroughext.vcxproj", "{33DC46DA-90C8-42E0-9411-8CE8A02519C2}" ProjectSection(ProjectDependencies) = postProject - {63FF1428-95CA-4751-A701-244D54A31BD9} = {63FF1428-95CA-4751-A701-244D54A31BD9} + {0AF344BA-2F72-4E63-85D3-6C649C493113} = {0AF344BA-2F72-4E63-85D3-6C649C493113} EndProjectSection EndProject Global @@ -29,27 +29,27 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {63FF1428-95CA-4751-A701-244D54A31BD9}.Debug|x64.ActiveCfg = Debug|x64 - {63FF1428-95CA-4751-A701-244D54A31BD9}.Debug|x64.Build.0 = Debug|x64 - {63FF1428-95CA-4751-A701-244D54A31BD9}.Release|x64.ActiveCfg = Release|x64 - {63FF1428-95CA-4751-A701-244D54A31BD9}.Release|x64.Build.0 = Release|x64 - {404E1399-EA48-4CEE-A59E-EA0D4C01928A}.Debug|x64.ActiveCfg = Debug|x64 - {404E1399-EA48-4CEE-A59E-EA0D4C01928A}.Debug|x64.Build.0 = Debug|x64 - {404E1399-EA48-4CEE-A59E-EA0D4C01928A}.Release|x64.ActiveCfg = Release|x64 - {404E1399-EA48-4CEE-A59E-EA0D4C01928A}.Release|x64.Build.0 = Release|x64 - {2339B4A8-60AF-4172-AC68-3159E6D001EC}.Debug|x64.ActiveCfg = Debug|x64 - {2339B4A8-60AF-4172-AC68-3159E6D001EC}.Debug|x64.Build.0 = Debug|x64 - {2339B4A8-60AF-4172-AC68-3159E6D001EC}.Release|x64.ActiveCfg = Release|x64 - {2339B4A8-60AF-4172-AC68-3159E6D001EC}.Release|x64.Build.0 = Release|x64 + {0AF344BA-2F72-4E63-85D3-6C649C493113}.Debug|x64.ActiveCfg = Debug|x64 + {0AF344BA-2F72-4E63-85D3-6C649C493113}.Debug|x64.Build.0 = Debug|x64 + {0AF344BA-2F72-4E63-85D3-6C649C493113}.Release|x64.ActiveCfg = Release|x64 + {0AF344BA-2F72-4E63-85D3-6C649C493113}.Release|x64.Build.0 = Release|x64 + {947BD508-8C40-4109-AA40-0E6B54FD7E07}.Debug|x64.ActiveCfg = Debug|x64 + {947BD508-8C40-4109-AA40-0E6B54FD7E07}.Debug|x64.Build.0 = Debug|x64 + {947BD508-8C40-4109-AA40-0E6B54FD7E07}.Release|x64.ActiveCfg = Release|x64 + {947BD508-8C40-4109-AA40-0E6B54FD7E07}.Release|x64.Build.0 = Release|x64 + {33DC46DA-90C8-42E0-9411-8CE8A02519C2}.Debug|x64.ActiveCfg = Debug|x64 + {33DC46DA-90C8-42E0-9411-8CE8A02519C2}.Debug|x64.Build.0 = Debug|x64 + {33DC46DA-90C8-42E0-9411-8CE8A02519C2}.Release|x64.ActiveCfg = Release|x64 + {33DC46DA-90C8-42E0-9411-8CE8A02519C2}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {63FF1428-95CA-4751-A701-244D54A31BD9} = {1C3E1DE9-A703-46CB-B4E4-8CD906C9E6FE} - {404E1399-EA48-4CEE-A59E-EA0D4C01928A} = {433D0832-2B1B-46AB-94E8-0A7979ACA4CA} - {2339B4A8-60AF-4172-AC68-3159E6D001EC} = {7C717732-18C9-4892-A6FF-B4DD1D72C12B} - {433D0832-2B1B-46AB-94E8-0A7979ACA4CA} = {BC0A3E55-CAE0-4CCE-BA15-0784AEF76215} - {7C717732-18C9-4892-A6FF-B4DD1D72C12B} = {BC0A3E55-CAE0-4CCE-BA15-0784AEF76215} + {0AF344BA-2F72-4E63-85D3-6C649C493113} = {91A9E693-3D97-4069-B2A4-84CD10712B8E} + {947BD508-8C40-4109-AA40-0E6B54FD7E07} = {5CC88476-FA8E-43F7-BE93-29147910AE87} + {33DC46DA-90C8-42E0-9411-8CE8A02519C2} = {7A74F8F6-D891-40BB-9CB5-308ACDA3B778} + {5CC88476-FA8E-43F7-BE93-29147910AE87} = {0357B6CB-FF60-41D3-8879-A04837F014CD} + {7A74F8F6-D891-40BB-9CB5-308ACDA3B778} = {0357B6CB-FF60-41D3-8879-A04837F014CD} EndGlobalSection EndGlobal diff --git a/network/ndis/extension/samples/forward/msforwardext.vcxproj b/network/ndis/extension/samples/forward/msforwardext.vcxproj index af65e5ba..5117b28a 100644 --- a/network/ndis/extension/samples/forward/msforwardext.vcxproj +++ b/network/ndis/extension/samples/forward/msforwardext.vcxproj @@ -11,11 +11,11 @@ - {404E1399-EA48-4CEE-A59E-EA0D4C01928A} + {947BD508-8C40-4109-AA40-0E6B54FD7E07} $(MSBuildProjectName) Debug x64 - {E7755C69-DA3A-4E6B-9C38-0435AC07863F} + {B5988C94-9BF7-4CAC-AC9A-12A76777AAA2} diff --git a/network/ndis/extension/samples/forward/msforwardext.vcxproj.Filters b/network/ndis/extension/samples/forward/msforwardext.vcxproj.Filters index a4de6bd4..41e0eaf2 100644 --- a/network/ndis/extension/samples/forward/msforwardext.vcxproj.Filters +++ b/network/ndis/extension/samples/forward/msforwardext.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {AE574627-04F4-423B-B254-44BD4A41BF5D} + {C51012E1-9AEC-4F0F-A787-C2268CE8C1A9} h;hpp;hxx;hm;inl;inc;xsd - {50E67A30-537B-4C27-BDFD-110A25C9A725} + {DAABAD75-23CE-441B-8FBE-035AE3D33165} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {83FDCB52-42AC-4B2D-9A09-F917F36CFA49} + {ED47846F-6D56-4808-A9C1-D6868F535E4B} inf;inv;inx;mof;mc; - {362EB8F8-E693-45BC-9EE5-1ED0A9776739} + {AFD09367-9B69-4871-AB79-6D868F6FB8FD} diff --git a/network/ndis/extension/samples/passthrough/mspassthroughext.vcxproj b/network/ndis/extension/samples/passthrough/mspassthroughext.vcxproj index cda7cbbf..fd443f8b 100644 --- a/network/ndis/extension/samples/passthrough/mspassthroughext.vcxproj +++ b/network/ndis/extension/samples/passthrough/mspassthroughext.vcxproj @@ -11,11 +11,11 @@ - {2339B4A8-60AF-4172-AC68-3159E6D001EC} + {33DC46DA-90C8-42E0-9411-8CE8A02519C2} $(MSBuildProjectName) Debug x64 - {DA3F14BC-0746-46C8-99E7-339173543E27} + {1B22CD34-E0FD-4F26-B929-B65361F77899} diff --git a/network/ndis/extension/samples/passthrough/mspassthroughext.vcxproj.Filters b/network/ndis/extension/samples/passthrough/mspassthroughext.vcxproj.Filters index b43daf1e..b4236aa6 100644 --- a/network/ndis/extension/samples/passthrough/mspassthroughext.vcxproj.Filters +++ b/network/ndis/extension/samples/passthrough/mspassthroughext.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {555B7D63-D8B9-4382-8D6E-A97AC09CE282} + {B04858F7-C21F-4968-B318-A24019C8BA93} h;hpp;hxx;hm;inl;inc;xsd - {797B07B8-0B76-4BA6-BDF4-45786B031900} + {533FF752-AB17-45D8-BB7F-A79F3526AEE3} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {D95F4A4C-E2E8-4108-86FB-C568FA437FA1} + {B8C9F068-4F22-4D43-9727-2DE3BEE27340} inf;inv;inx;mof;mc; - {F05BF5D9-0765-4293-B2AB-41B06C544956} + {7BBC969B-9C83-4B37-816D-2A5D73801C39} diff --git a/network/ndis/filter/filter.htm b/network/ndis/filter/filter.htm new file mode 100644 index 00000000..998c5b49 --- /dev/null +++ b/network/ndis/filter/filter.htm @@ -0,0 +1,152 @@ + + + + + +NDISLWF + + + + +

NDISLWF.SYS - Sample NDIS 6.0 Filter Driver

+ +

Note: the sample driver contains some extra code for demonstration purposes. +You should remove unneeded optional sections from a production driver.

+ +

SUMMARY

+ +

Ndislwf NDIS 6.0 Filter Driver

+ +

The Ndislwf sample is currently a do-nothing pass-through NDIS 6 filter +driver that demonstrates the basic principles underlying an NDIS 6.0 Filter +driver. The sample is a replacement of NDIS 5 Sample Intermediate +Driver (Passthru driver).

+ +

Although the filter driver is a Modifying filter driver, the filter driver +currently doesn’t modify any packets and it only re-packages and sends down all +OID requests. You may easily update this filter driver to change packets +before passing them along. Or you may use the filter to originate new packets +to send or receive. For example, the filter could encrypt/compress outgoing and +decrypt/decompress incoming data.

+ +

BUILDING THE SAMPLE

+ +

Run the build command from this directory to build the +sample—it creates the binary Ndislwf.sys.

+ +

To install this driver on Windows Vista (or above), use netlwf.INF also +found in this DDK.

+ +

INSTALLING THE SAMPLE

+ +

Ndislwf is installed as a service (called “NDIS Sample LightWeight Filter” +in the supplied INF). To install, follow the steps below:

+ +
    + +
  1. Prepare a an installation directory that contains these files: netlwf.inf +and ndislwf.sys.
  2. + +
  3. On the desktop, click Start, then open Control Panel, then +open Network and Internet Connections, then open Network +Connections, then right-click on the relevant Local Area Connection icon +and choose Properties.
  4. + +
  5. Click Install, then Service, then Add, then Have +Disk.
  6. + +
  7. Browse to the drive/directory containing the files listed above. Click +OK. This should show “NDIS Sample LightWeight Filter” in a list of +Network Services. Highlight this and click OK. This should install the +Ndislwf filter driver.
  8. + +
  9. Click OK or Yes each time if the system prompts with a warning +regarding installation of unsigned files. This is necessary because binaries +generated via the LDK build environment are not signed.
  10. + +
+ +

CODE TOUR

+ +

File Manifest

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileDescription
makefileUsed during compilation to create the object and sys +files
filter.cFilter driver entry points and related functions in +the Ndislwf filter driver
netlwf.infInstallation INF for the service
device.cVirtual device related routines such as registering a +device and handling IOCTLs
filter.hPrototypes of all functions and data structures used +by the Ndislwf driver
filter.htmDocumentation for the filter driver (this + file)
filter.rcResource file for the Ndislwf driver
precomp.hPrecompile header file
flt_dbg.cDebug-related code
flt_dbg.hDebug code definitions and structures
sourcesList of source files that are compiled and linked to +create the ndislwf driver.
+ +

Programming Tour

+ +

Basic steps in attaching and detaching of Ndislwf driver:

+ +
    + +
  1. During DriverEntry, the ndislwf driver registers as a NDIS 6 filter +driver.
  2. + +
  3. Later on, NDIS calls Ndislwf FilterAttach handler, for each underlying NDIS +adapter on which it is configured to attach.
  4. + +
  5. In the context of FilterAttach Handler, filter driver call NdisFAttribute +to register its filter module context with NDIS. After that, filter driver can +read its own setting in registry by calling NdisOpenConfigurationEx, and calls +NdisXXX functions.
  6. + +
  7. After FilterAttach successfully returns, NDIS restarts the filter later by +calling FilterRestart handler. FilterRestart should prepare to handle +send/receive data. After restart return successfully, filter driver should be +able to process send/receive.
  8. + +
  9. All requests and sends coming from overlying drivers for the Ndislwf filter +driver are repackaged if necessary and sent down to NDIS, to be passed to the +underlying NDIS driver.
  10. + +
  11. All indications arriving from an underlying NDIS driver are forwarded up by +Ndislwf filter driver.
  12. + +
  13. NDIS call FilterPause handler when NDIS needs to detach the filter from the +stack or there is some configuration changes in the stack. In processing the +pause request from NDIS, the Ndislwf driver waits for all its own outstanding +requests to be completed before it completes the pause request.
  14. + +
  15. NDIS calls the Ndislwf driver’s FilterDetach entry point when NDIS needs to +detach a filter module from NDIS stack. FilterDetach handler should free all +the memory allocation done in FilterAttach, and undo the operations it did in +FilterAttach Handler.
  16. + +
+ +

© Microsoft Corporation

+ + + + diff --git a/network/ndis/filter/filter.sln b/network/ndis/filter/filter.sln index 90e2be1f..1c4ff1c4 100644 --- a/network/ndis/filter/filter.sln +++ b/network/ndis/filter/filter.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ndislwf", "ndislwf.vcxproj", "{D6A797EC-4BD1-4448-8C69-AAD0F18252E3}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ndislwf", "ndislwf.vcxproj", "{0984ADBF-81CE-478A-9D69-CFDA813C015F}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +13,14 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {D6A797EC-4BD1-4448-8C69-AAD0F18252E3}.Debug|Win32.ActiveCfg = Debug|Win32 - {D6A797EC-4BD1-4448-8C69-AAD0F18252E3}.Debug|Win32.Build.0 = Debug|Win32 - {D6A797EC-4BD1-4448-8C69-AAD0F18252E3}.Release|Win32.ActiveCfg = Release|Win32 - {D6A797EC-4BD1-4448-8C69-AAD0F18252E3}.Release|Win32.Build.0 = Release|Win32 - {D6A797EC-4BD1-4448-8C69-AAD0F18252E3}.Debug|x64.ActiveCfg = Debug|x64 - {D6A797EC-4BD1-4448-8C69-AAD0F18252E3}.Debug|x64.Build.0 = Debug|x64 - {D6A797EC-4BD1-4448-8C69-AAD0F18252E3}.Release|x64.ActiveCfg = Release|x64 - {D6A797EC-4BD1-4448-8C69-AAD0F18252E3}.Release|x64.Build.0 = Release|x64 + {0984ADBF-81CE-478A-9D69-CFDA813C015F}.Debug|Win32.ActiveCfg = Debug|Win32 + {0984ADBF-81CE-478A-9D69-CFDA813C015F}.Debug|Win32.Build.0 = Debug|Win32 + {0984ADBF-81CE-478A-9D69-CFDA813C015F}.Release|Win32.ActiveCfg = Release|Win32 + {0984ADBF-81CE-478A-9D69-CFDA813C015F}.Release|Win32.Build.0 = Release|Win32 + {0984ADBF-81CE-478A-9D69-CFDA813C015F}.Debug|x64.ActiveCfg = Debug|x64 + {0984ADBF-81CE-478A-9D69-CFDA813C015F}.Debug|x64.Build.0 = Debug|x64 + {0984ADBF-81CE-478A-9D69-CFDA813C015F}.Release|x64.ActiveCfg = Release|x64 + {0984ADBF-81CE-478A-9D69-CFDA813C015F}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/network/ndis/filter/ndislwf.vcxproj b/network/ndis/filter/ndislwf.vcxproj index 6998e55b..982667ca 100644 --- a/network/ndis/filter/ndislwf.vcxproj +++ b/network/ndis/filter/ndislwf.vcxproj @@ -19,11 +19,11 @@
- {D6A797EC-4BD1-4448-8C69-AAD0F18252E3} + {0984ADBF-81CE-478A-9D69-CFDA813C015F} $(MSBuildProjectName) Debug Win32 - {D42F08CB-C626-4709-A3FB-F3A6AC78F6BE} + {612455BF-B8D2-4EF2-B654-C71F38EB41E6} diff --git a/network/ndis/filter/ndislwf.vcxproj.Filters b/network/ndis/filter/ndislwf.vcxproj.Filters index 1258cc3b..33446f05 100644 --- a/network/ndis/filter/ndislwf.vcxproj.Filters +++ b/network/ndis/filter/ndislwf.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {CCCEB33C-30D7-4D55-9C51-2503E8422C74} + {165E8E33-1000-4BA1-B9C0-13563E035EDF} h;hpp;hxx;hm;inl;inc;xsd - {F2D27727-5C77-4D5A-8C78-D4977DA98B1E} + {DBD7275E-19E6-4008-B9DB-F4BA06822D7B} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {D2E50D90-0B4D-449A-8527-9EA78D1C23F7} + {C863DF64-1C80-42D6-80E1-A06EE203FD47} inf;inv;inx;mof;mc; - {3EF75BEF-85CD-4689-B551-9CFC67497380} + {CE7F2FE4-DF42-4BE1-9027-2941C09DED39} diff --git a/network/ndis/mux/driver/60/novlan/mux.vcxproj b/network/ndis/mux/driver/60/novlan/mux.vcxproj index fdc926c1..75fc3431 100644 --- a/network/ndis/mux/driver/60/novlan/mux.vcxproj +++ b/network/ndis/mux/driver/60/novlan/mux.vcxproj @@ -19,11 +19,11 @@ - {3316ED07-27E3-4AE6-BE12-E8A5F9ADE789} + {397D0084-5C84-4AD1-87DF-2B3C669BCA78} $(MSBuildProjectName) Debug Win32 - {D85A6A77-174C-4C80-8646-06E04ECCBAE8} + {CB06DB9D-C97D-417D-8752-1CBC12C4226B} diff --git a/network/ndis/mux/driver/60/novlan/mux.vcxproj.Filters b/network/ndis/mux/driver/60/novlan/mux.vcxproj.Filters index 3a8f8458..812a5c6b 100644 --- a/network/ndis/mux/driver/60/novlan/mux.vcxproj.Filters +++ b/network/ndis/mux/driver/60/novlan/mux.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {DFD5078D-1185-4EEB-97B6-950B984EBE1A} + {18AD59A7-F2A1-4691-AA03-199BD103CF5A} h;hpp;hxx;hm;inl;inc;xsd - {4B2DF463-FC38-42F8-A082-E219782CD292} + {E6656927-1183-47F1-85CE-57A302CBDA79} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {80BDAADE-F802-425A-A59E-5A93D4FA068E} + {0E73A07F-C22B-466E-B6B2-2D47F04BC109} inf;inv;inx;mof;mc; - {D133C63A-21C1-48F5-AFC1-F852277E2B49} + {7C6C2990-74A1-4E06-AD1B-02AD245372EC} diff --git a/network/ndis/mux/driver/60/vlan/muxvlan.vcxproj b/network/ndis/mux/driver/60/vlan/muxvlan.vcxproj index 83e3f351..8f79c893 100644 --- a/network/ndis/mux/driver/60/vlan/muxvlan.vcxproj +++ b/network/ndis/mux/driver/60/vlan/muxvlan.vcxproj @@ -19,11 +19,11 @@ - {F277EC93-B131-4A8E-8899-C62F31AE70EC} + {D6FCE02C-B772-45F2-9941-F5E6B1E32877} $(MSBuildProjectName) Debug Win32 - {22F44364-DB40-46E1-8E05-EBCB1DDEC8E5} + {47080E55-F8E1-4968-8893-18ADE0ED7268} diff --git a/network/ndis/mux/driver/60/vlan/muxvlan.vcxproj.Filters b/network/ndis/mux/driver/60/vlan/muxvlan.vcxproj.Filters index fad75bc6..97e1f9ff 100644 --- a/network/ndis/mux/driver/60/vlan/muxvlan.vcxproj.Filters +++ b/network/ndis/mux/driver/60/vlan/muxvlan.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {1AADD0B1-7A47-42D2-95E3-7F106683CF72} + {45E3DA30-48FB-4471-9DF1-F983CB9A3286} h;hpp;hxx;hm;inl;inc;xsd - {181362AF-397B-4B8F-A43F-8E9D2962680E} + {6490648B-7BD7-4B6D-A5E7-3B3AC865A4E6} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {1E01B05D-68A4-4A5F-B969-3B6FD90223DF} + {22C10F71-ECE2-4C46-9255-E145C77B5EE2} inf;inv;inx;mof;mc; - {966F89E0-3A82-4396-9FD3-3F8EB1BB58D9} + {90F61B4E-C8EC-4AAF-92C9-5808F7EBDB2C} diff --git a/network/ndis/mux/mux.sln b/network/ndis/mux/mux.sln index 47d46e28..56ec1e72 100644 --- a/network/ndis/mux/mux.sln +++ b/network/ndis/mux/mux.sln @@ -3,21 +3,21 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Vlan", "Vlan", "{54A94908-2C5F-4A7A-811A-853AE27B7850}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Vlan", "Vlan", "{5649382B-2263-47B2-9B96-EC867F4948B6}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "60", "60", "{0FCA78EE-A888-441E-A320-83951CF296AC}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "60", "60", "{77C1D298-5F95-4683-922F-D345F833177C}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Driver", "Driver", "{B3A64960-7B29-4262-9833-F1A493D5CCFC}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Driver", "Driver", "{A47240B9-D403-4B0B-B4CD-DC7B8A0C19B6}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Novlan", "Novlan", "{3D789463-134E-4028-BC7C-20B1BFA46278}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Novlan", "Novlan", "{DCE5E59B-B3F0-4698-9A27-7D9A68A41C83}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Notifyob", "Notifyob", "{DAE5645C-5ADF-4048-8010-39A47184E5C9}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Notifyob", "Notifyob", "{91B5E151-6E95-4C95-9D34-35D1AEB20F39}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "muxvlan", "driver\60\vlan\muxvlan.vcxproj", "{F277EC93-B131-4A8E-8899-C62F31AE70EC}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "muxvlan", "driver\60\vlan\muxvlan.vcxproj", "{D6FCE02C-B772-45F2-9941-F5E6B1E32877}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mux", "driver\60\novlan\mux.vcxproj", "{3316ED07-27E3-4AE6-BE12-E8A5F9ADE789}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mux", "driver\60\novlan\mux.vcxproj", "{397D0084-5C84-4AD1-87DF-2B3C669BCA78}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mux", "notifyob\mux.vcxproj", "{CE2FDBC5-FB0E-4B75-9D1F-60BE72C639A6}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mux", "notifyob\mux.vcxproj", "{0124A324-0D8F-4DAC-B63A-4615FFB9DCA6}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -27,40 +27,40 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {F277EC93-B131-4A8E-8899-C62F31AE70EC}.Debug|Win32.ActiveCfg = Debug|Win32 - {F277EC93-B131-4A8E-8899-C62F31AE70EC}.Debug|Win32.Build.0 = Debug|Win32 - {F277EC93-B131-4A8E-8899-C62F31AE70EC}.Release|Win32.ActiveCfg = Release|Win32 - {F277EC93-B131-4A8E-8899-C62F31AE70EC}.Release|Win32.Build.0 = Release|Win32 - {F277EC93-B131-4A8E-8899-C62F31AE70EC}.Debug|x64.ActiveCfg = Debug|x64 - {F277EC93-B131-4A8E-8899-C62F31AE70EC}.Debug|x64.Build.0 = Debug|x64 - {F277EC93-B131-4A8E-8899-C62F31AE70EC}.Release|x64.ActiveCfg = Release|x64 - {F277EC93-B131-4A8E-8899-C62F31AE70EC}.Release|x64.Build.0 = Release|x64 - {3316ED07-27E3-4AE6-BE12-E8A5F9ADE789}.Debug|Win32.ActiveCfg = Debug|Win32 - {3316ED07-27E3-4AE6-BE12-E8A5F9ADE789}.Debug|Win32.Build.0 = Debug|Win32 - {3316ED07-27E3-4AE6-BE12-E8A5F9ADE789}.Release|Win32.ActiveCfg = Release|Win32 - {3316ED07-27E3-4AE6-BE12-E8A5F9ADE789}.Release|Win32.Build.0 = Release|Win32 - {3316ED07-27E3-4AE6-BE12-E8A5F9ADE789}.Debug|x64.ActiveCfg = Debug|x64 - {3316ED07-27E3-4AE6-BE12-E8A5F9ADE789}.Debug|x64.Build.0 = Debug|x64 - {3316ED07-27E3-4AE6-BE12-E8A5F9ADE789}.Release|x64.ActiveCfg = Release|x64 - {3316ED07-27E3-4AE6-BE12-E8A5F9ADE789}.Release|x64.Build.0 = Release|x64 - {CE2FDBC5-FB0E-4B75-9D1F-60BE72C639A6}.Debug|Win32.ActiveCfg = Debug|Win32 - {CE2FDBC5-FB0E-4B75-9D1F-60BE72C639A6}.Debug|Win32.Build.0 = Debug|Win32 - {CE2FDBC5-FB0E-4B75-9D1F-60BE72C639A6}.Release|Win32.ActiveCfg = Release|Win32 - {CE2FDBC5-FB0E-4B75-9D1F-60BE72C639A6}.Release|Win32.Build.0 = Release|Win32 - {CE2FDBC5-FB0E-4B75-9D1F-60BE72C639A6}.Debug|x64.ActiveCfg = Debug|x64 - {CE2FDBC5-FB0E-4B75-9D1F-60BE72C639A6}.Debug|x64.Build.0 = Debug|x64 - {CE2FDBC5-FB0E-4B75-9D1F-60BE72C639A6}.Release|x64.ActiveCfg = Release|x64 - {CE2FDBC5-FB0E-4B75-9D1F-60BE72C639A6}.Release|x64.Build.0 = Release|x64 + {D6FCE02C-B772-45F2-9941-F5E6B1E32877}.Debug|Win32.ActiveCfg = Debug|Win32 + {D6FCE02C-B772-45F2-9941-F5E6B1E32877}.Debug|Win32.Build.0 = Debug|Win32 + {D6FCE02C-B772-45F2-9941-F5E6B1E32877}.Release|Win32.ActiveCfg = Release|Win32 + {D6FCE02C-B772-45F2-9941-F5E6B1E32877}.Release|Win32.Build.0 = Release|Win32 + {D6FCE02C-B772-45F2-9941-F5E6B1E32877}.Debug|x64.ActiveCfg = Debug|x64 + {D6FCE02C-B772-45F2-9941-F5E6B1E32877}.Debug|x64.Build.0 = Debug|x64 + {D6FCE02C-B772-45F2-9941-F5E6B1E32877}.Release|x64.ActiveCfg = Release|x64 + {D6FCE02C-B772-45F2-9941-F5E6B1E32877}.Release|x64.Build.0 = Release|x64 + {397D0084-5C84-4AD1-87DF-2B3C669BCA78}.Debug|Win32.ActiveCfg = Debug|Win32 + {397D0084-5C84-4AD1-87DF-2B3C669BCA78}.Debug|Win32.Build.0 = Debug|Win32 + {397D0084-5C84-4AD1-87DF-2B3C669BCA78}.Release|Win32.ActiveCfg = Release|Win32 + {397D0084-5C84-4AD1-87DF-2B3C669BCA78}.Release|Win32.Build.0 = Release|Win32 + {397D0084-5C84-4AD1-87DF-2B3C669BCA78}.Debug|x64.ActiveCfg = Debug|x64 + {397D0084-5C84-4AD1-87DF-2B3C669BCA78}.Debug|x64.Build.0 = Debug|x64 + {397D0084-5C84-4AD1-87DF-2B3C669BCA78}.Release|x64.ActiveCfg = Release|x64 + {397D0084-5C84-4AD1-87DF-2B3C669BCA78}.Release|x64.Build.0 = Release|x64 + {0124A324-0D8F-4DAC-B63A-4615FFB9DCA6}.Debug|Win32.ActiveCfg = Debug|Win32 + {0124A324-0D8F-4DAC-B63A-4615FFB9DCA6}.Debug|Win32.Build.0 = Debug|Win32 + {0124A324-0D8F-4DAC-B63A-4615FFB9DCA6}.Release|Win32.ActiveCfg = Release|Win32 + {0124A324-0D8F-4DAC-B63A-4615FFB9DCA6}.Release|Win32.Build.0 = Release|Win32 + {0124A324-0D8F-4DAC-B63A-4615FFB9DCA6}.Debug|x64.ActiveCfg = Debug|x64 + {0124A324-0D8F-4DAC-B63A-4615FFB9DCA6}.Debug|x64.Build.0 = Debug|x64 + {0124A324-0D8F-4DAC-B63A-4615FFB9DCA6}.Release|x64.ActiveCfg = Release|x64 + {0124A324-0D8F-4DAC-B63A-4615FFB9DCA6}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {F277EC93-B131-4A8E-8899-C62F31AE70EC} = {54A94908-2C5F-4A7A-811A-853AE27B7850} - {3316ED07-27E3-4AE6-BE12-E8A5F9ADE789} = {3D789463-134E-4028-BC7C-20B1BFA46278} - {CE2FDBC5-FB0E-4B75-9D1F-60BE72C639A6} = {DAE5645C-5ADF-4048-8010-39A47184E5C9} - {54A94908-2C5F-4A7A-811A-853AE27B7850} = {0FCA78EE-A888-441E-A320-83951CF296AC} - {0FCA78EE-A888-441E-A320-83951CF296AC} = {B3A64960-7B29-4262-9833-F1A493D5CCFC} - {3D789463-134E-4028-BC7C-20B1BFA46278} = {0FCA78EE-A888-441E-A320-83951CF296AC} + {D6FCE02C-B772-45F2-9941-F5E6B1E32877} = {5649382B-2263-47B2-9B96-EC867F4948B6} + {397D0084-5C84-4AD1-87DF-2B3C669BCA78} = {DCE5E59B-B3F0-4698-9A27-7D9A68A41C83} + {0124A324-0D8F-4DAC-B63A-4615FFB9DCA6} = {91B5E151-6E95-4C95-9D34-35D1AEB20F39} + {5649382B-2263-47B2-9B96-EC867F4948B6} = {77C1D298-5F95-4683-922F-D345F833177C} + {77C1D298-5F95-4683-922F-D345F833177C} = {A47240B9-D403-4B0B-B4CD-DC7B8A0C19B6} + {DCE5E59B-B3F0-4698-9A27-7D9A68A41C83} = {77C1D298-5F95-4683-922F-D345F833177C} EndGlobalSection EndGlobal diff --git a/network/ndis/mux/notifyob/mux.vcxproj b/network/ndis/mux/notifyob/mux.vcxproj index eb3db887..a52d3dfa 100644 --- a/network/ndis/mux/notifyob/mux.vcxproj +++ b/network/ndis/mux/notifyob/mux.vcxproj @@ -19,11 +19,11 @@ - {CE2FDBC5-FB0E-4B75-9D1F-60BE72C639A6} + {0124A324-0D8F-4DAC-B63A-4615FFB9DCA6} $(MSBuildProjectName) Debug Win32 - {B6C3DAD5-A1FA-45F1-98F8-66CD4FEDD014} + {1EB42396-C115-40FD-9536-AB4C17CD9579} diff --git a/network/ndis/mux/notifyob/mux.vcxproj.Filters b/network/ndis/mux/notifyob/mux.vcxproj.Filters index ae8436c6..2dfc715b 100644 --- a/network/ndis/mux/notifyob/mux.vcxproj.Filters +++ b/network/ndis/mux/notifyob/mux.vcxproj.Filters @@ -3,15 +3,15 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {7CBE03EB-893C-48D0-9792-100241030FDE} + {3070F81A-13F3-4A51-B701-3CF116C59B41} h;hpp;hxx;hm;inl;inc;xsd - {819C3038-4DC6-4786-98BA-ADC2B360C2BB} + {9F1DE3DD-04BA-4F2B-9E2F-9CD8949EA47C} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {416958BA-8A0D-44E3-8B1E-F089723BC01A} + {D3F79307-0791-4B6C-8EB7-8483DC785BA7} diff --git a/network/ndis/ndisprot/6x/ndisprot.htm b/network/ndis/ndisprot/6x/ndisprot.htm new file mode 100644 index 00000000..3e854693 --- /dev/null +++ b/network/ndis/ndisprot/6x/ndisprot.htm @@ -0,0 +1,393 @@ + + + + + + + + +Sample NDIS connection-less protocol driver sample + + + + + + + +
+ +

NDIS connection-less protocol driver +sample

+ +

SUMMARY

+ +

This sample demonstrates +a connection-less NDIS 6.0 protocol. The driver supports sending and receiving +raw Ethernet frames using ReadFile/WriteFile calls from user-mode. It only +receives frames with a specific EtherType field. As an NDIS protocol, it +illustrates how to establish and tear down bindings to Ethernet adapters, i.e. +those that export medium type NdisMedium802_3. It shows how to set a +packet filter, send and receive data, and handle plug-and-play events.

+ +

BUILDING THE SAMPLE

+ +

From the +Free or Checked Build environment, execute build -ceZ in the ndisprot +directory.

+ +

INSTALLATION

+ +

The driver is installed +using the INF file ndisprot.inf, which is provided in the driver directory. In +Network Connections UI, select an adapter and open Properties.

+ +

Click Install, +then Protocol, then Add, and then Have disk. Then point to +the location of the .inf and driver.

+ +

Select Sample NDIS +Protocol Driver and click OK. After installing the protocol, copy +over the test application prottest.exe to a convenient location. Please note +that the driver service has been set to manual start in the INF file. As a +result, it doesn't get loaded automatically when you install.

+ +

USAGE

+ +

To start +the driver, type

+ +

          Net start ndisprot

+ +

 

+ +

To stop +the driver, type

+ +

          Net stop ndisprot

+ +

 

+ +

To test +the driver, run prottest. For help on usage, run prottest -?

+ +

 

+ +
usage: PROTTEST [options] <devicename>
options:
       -e: Enumerate devices
       -r: Read
       -w: Write (default)
       -l <length>: length of each packet (default: 100)
       -n <count>: number of packets (defaults to infinity)
       -m <MAC address> (defaults to local MAC)
+ +

 

+ +

Prottest exercises the IOCTLs supported +by NDISPROT, and sends and/or receives data on the selected device. In order to +use prottest, the user must have administrative privilege. Users should pass +down a big enough buffer in order to receive the entire received data. If the +length of the buffer passed down is smaller than the length of the received +data, NDISPROT will only copy part of the data and discard the rest when the +given buffer is full.

+ +

 

+ +

 

+ +

Use the –e option to enumerate all +devices to which NDISPROT is bound:

+ +
C:\prot>prottest -e
 0. \DEVICE\{9273DA7D-5275-4B9A-AC56-68A49D121F1F}
     - Intel-Based 10/100 Ethernet Card
+ +

 

+ +

The +following command sends and receives 2 packets on a device). Since these packets are sent to +the local MAC address (default), both packets are received. The device +name parameter to prottest is picked up from the output of prottest –e (see +above).

+ +

 

+ +
C:\prot>prottest -n 2 \DEVICE\{9273DA7D-5275-4B9A-AC56-68A49D121F1F}
DoWriteProc: finished sending 2 packets of 100 bytes each
DoReadProc finished: read 2 packets
+ +

For +security reasons, this driver does not allow packets with fake MAC addresses to +be sent from usermode applications.

+ +

TIPS

+ +

With a checked version of +ndisprot.sys, you can control the volume of debug information generated by +changing the variable ndisprotDebugLevel. Refer to debug.h for more +information.

+ +

CODE TOUR

+ +

File Manifest

+ +
Directory: Test
+
+
 
 
 
 
 
 
 
 
 
File             Description      
prottest.c       User-mode test application
 
 
Directory: Sys
+
+
 
 
 
 
 
 
 
 
 
File             Description      
debug.c          Routines to aid debugging
debug.h          Debug macro definitions
macros.h         Spinlock, event, referencing macros
ndisbind.c       NDIS protocol entry points to handle binding/unbinding from adapters
ndisprot.h       Data structure definitions
ndisprot.inf     INF file for installing NDISPROT
ntdisp.c         NT Entry points and dispatch routines for NDISPROT
protuser.h       IOCTL and associated structure definitions
recv.c           NDIS protocol entry points for receiving data, and IRP_MJ_READ processing
send.c           NDIS protocol routines for sending data, and IRP_MJ_WRITE processing
 
+ +

Top of page

+ + + + + +
+

 

+
+ +

© Microsoft Corporation +2000

+ +
+ + + + diff --git a/network/ndis/ndisprot/6x/ndisprot60.sln b/network/ndis/ndisprot/6x/ndisprot60.sln index cc13f976..3bf5708e 100644 --- a/network/ndis/ndisprot/6x/ndisprot60.sln +++ b/network/ndis/ndisprot/6x/ndisprot60.sln @@ -3,19 +3,19 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "60", "60", "{39A2B1A3-5281-47DF-A0A5-B08E1F979C9E}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "60", "60", "{DAF28310-CB34-4AD4-9B7A-04E46AF3AA20}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Sys", "Sys", "{C09D8AF9-55C0-4192-A787-B6CA08D83AD0}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Sys", "Sys", "{EA1F1CD0-CDF2-48BD-853C-3012A20E5CE6}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "630", "630", "{7BA6C25F-BBE2-4331-B598-C5F03E11B45D}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "630", "630", "{082733D0-2C57-4E4D-A3FA-AF692CF90E8A}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{A41A7FEE-D4C4-4D9E-B7B3-679200586B93}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{A171447E-D0A4-4F2A-8900-6473D81C0269}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ndisprot60", "sys\60\ndisprot60.vcxproj", "{74918B99-A7A2-4462-9330-D61ED648B991}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ndisprot60", "sys\60\ndisprot60.vcxproj", "{7EA443E2-5964-417F-B418-CCFC6C30BF45}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ndisprot630", "sys\630\ndisprot630.vcxproj", "{DB252AE8-E32C-4E60-B0EB-33A2CB80861C}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ndisprot630", "sys\630\ndisprot630.vcxproj", "{310AF693-B1C5-4CF1-A7E4-99F9D18D1574}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "prottest", "test\prottest.vcxproj", "{0AD0B8E0-5A3E-43FE-8E27-E5BB3DB184B0}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "prottest", "test\prottest.vcxproj", "{C5DBFAFB-4867-4605-B432-337BD17B972C}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -25,39 +25,39 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {74918B99-A7A2-4462-9330-D61ED648B991}.Debug|Win32.ActiveCfg = Debug|Win32 - {74918B99-A7A2-4462-9330-D61ED648B991}.Debug|Win32.Build.0 = Debug|Win32 - {74918B99-A7A2-4462-9330-D61ED648B991}.Release|Win32.ActiveCfg = Release|Win32 - {74918B99-A7A2-4462-9330-D61ED648B991}.Release|Win32.Build.0 = Release|Win32 - {74918B99-A7A2-4462-9330-D61ED648B991}.Debug|x64.ActiveCfg = Debug|x64 - {74918B99-A7A2-4462-9330-D61ED648B991}.Debug|x64.Build.0 = Debug|x64 - {74918B99-A7A2-4462-9330-D61ED648B991}.Release|x64.ActiveCfg = Release|x64 - {74918B99-A7A2-4462-9330-D61ED648B991}.Release|x64.Build.0 = Release|x64 - {DB252AE8-E32C-4E60-B0EB-33A2CB80861C}.Debug|Win32.ActiveCfg = Debug|Win32 - {DB252AE8-E32C-4E60-B0EB-33A2CB80861C}.Debug|Win32.Build.0 = Debug|Win32 - {DB252AE8-E32C-4E60-B0EB-33A2CB80861C}.Release|Win32.ActiveCfg = Release|Win32 - {DB252AE8-E32C-4E60-B0EB-33A2CB80861C}.Release|Win32.Build.0 = Release|Win32 - {DB252AE8-E32C-4E60-B0EB-33A2CB80861C}.Debug|x64.ActiveCfg = Debug|x64 - {DB252AE8-E32C-4E60-B0EB-33A2CB80861C}.Debug|x64.Build.0 = Debug|x64 - {DB252AE8-E32C-4E60-B0EB-33A2CB80861C}.Release|x64.ActiveCfg = Release|x64 - {DB252AE8-E32C-4E60-B0EB-33A2CB80861C}.Release|x64.Build.0 = Release|x64 - {0AD0B8E0-5A3E-43FE-8E27-E5BB3DB184B0}.Debug|Win32.ActiveCfg = Debug|Win32 - {0AD0B8E0-5A3E-43FE-8E27-E5BB3DB184B0}.Debug|Win32.Build.0 = Debug|Win32 - {0AD0B8E0-5A3E-43FE-8E27-E5BB3DB184B0}.Release|Win32.ActiveCfg = Release|Win32 - {0AD0B8E0-5A3E-43FE-8E27-E5BB3DB184B0}.Release|Win32.Build.0 = Release|Win32 - {0AD0B8E0-5A3E-43FE-8E27-E5BB3DB184B0}.Debug|x64.ActiveCfg = Debug|x64 - {0AD0B8E0-5A3E-43FE-8E27-E5BB3DB184B0}.Debug|x64.Build.0 = Debug|x64 - {0AD0B8E0-5A3E-43FE-8E27-E5BB3DB184B0}.Release|x64.ActiveCfg = Release|x64 - {0AD0B8E0-5A3E-43FE-8E27-E5BB3DB184B0}.Release|x64.Build.0 = Release|x64 + {7EA443E2-5964-417F-B418-CCFC6C30BF45}.Debug|Win32.ActiveCfg = Debug|Win32 + {7EA443E2-5964-417F-B418-CCFC6C30BF45}.Debug|Win32.Build.0 = Debug|Win32 + {7EA443E2-5964-417F-B418-CCFC6C30BF45}.Release|Win32.ActiveCfg = Release|Win32 + {7EA443E2-5964-417F-B418-CCFC6C30BF45}.Release|Win32.Build.0 = Release|Win32 + {7EA443E2-5964-417F-B418-CCFC6C30BF45}.Debug|x64.ActiveCfg = Debug|x64 + {7EA443E2-5964-417F-B418-CCFC6C30BF45}.Debug|x64.Build.0 = Debug|x64 + {7EA443E2-5964-417F-B418-CCFC6C30BF45}.Release|x64.ActiveCfg = Release|x64 + {7EA443E2-5964-417F-B418-CCFC6C30BF45}.Release|x64.Build.0 = Release|x64 + {310AF693-B1C5-4CF1-A7E4-99F9D18D1574}.Debug|Win32.ActiveCfg = Debug|Win32 + {310AF693-B1C5-4CF1-A7E4-99F9D18D1574}.Debug|Win32.Build.0 = Debug|Win32 + {310AF693-B1C5-4CF1-A7E4-99F9D18D1574}.Release|Win32.ActiveCfg = Release|Win32 + {310AF693-B1C5-4CF1-A7E4-99F9D18D1574}.Release|Win32.Build.0 = Release|Win32 + {310AF693-B1C5-4CF1-A7E4-99F9D18D1574}.Debug|x64.ActiveCfg = Debug|x64 + {310AF693-B1C5-4CF1-A7E4-99F9D18D1574}.Debug|x64.Build.0 = Debug|x64 + {310AF693-B1C5-4CF1-A7E4-99F9D18D1574}.Release|x64.ActiveCfg = Release|x64 + {310AF693-B1C5-4CF1-A7E4-99F9D18D1574}.Release|x64.Build.0 = Release|x64 + {C5DBFAFB-4867-4605-B432-337BD17B972C}.Debug|Win32.ActiveCfg = Debug|Win32 + {C5DBFAFB-4867-4605-B432-337BD17B972C}.Debug|Win32.Build.0 = Debug|Win32 + {C5DBFAFB-4867-4605-B432-337BD17B972C}.Release|Win32.ActiveCfg = Release|Win32 + {C5DBFAFB-4867-4605-B432-337BD17B972C}.Release|Win32.Build.0 = Release|Win32 + {C5DBFAFB-4867-4605-B432-337BD17B972C}.Debug|x64.ActiveCfg = Debug|x64 + {C5DBFAFB-4867-4605-B432-337BD17B972C}.Debug|x64.Build.0 = Debug|x64 + {C5DBFAFB-4867-4605-B432-337BD17B972C}.Release|x64.ActiveCfg = Release|x64 + {C5DBFAFB-4867-4605-B432-337BD17B972C}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {74918B99-A7A2-4462-9330-D61ED648B991} = {39A2B1A3-5281-47DF-A0A5-B08E1F979C9E} - {DB252AE8-E32C-4E60-B0EB-33A2CB80861C} = {7BA6C25F-BBE2-4331-B598-C5F03E11B45D} - {0AD0B8E0-5A3E-43FE-8E27-E5BB3DB184B0} = {A41A7FEE-D4C4-4D9E-B7B3-679200586B93} - {39A2B1A3-5281-47DF-A0A5-B08E1F979C9E} = {C09D8AF9-55C0-4192-A787-B6CA08D83AD0} - {7BA6C25F-BBE2-4331-B598-C5F03E11B45D} = {C09D8AF9-55C0-4192-A787-B6CA08D83AD0} + {7EA443E2-5964-417F-B418-CCFC6C30BF45} = {DAF28310-CB34-4AD4-9B7A-04E46AF3AA20} + {310AF693-B1C5-4CF1-A7E4-99F9D18D1574} = {082733D0-2C57-4E4D-A3FA-AF692CF90E8A} + {C5DBFAFB-4867-4605-B432-337BD17B972C} = {A171447E-D0A4-4F2A-8900-6473D81C0269} + {DAF28310-CB34-4AD4-9B7A-04E46AF3AA20} = {EA1F1CD0-CDF2-48BD-853C-3012A20E5CE6} + {082733D0-2C57-4E4D-A3FA-AF692CF90E8A} = {EA1F1CD0-CDF2-48BD-853C-3012A20E5CE6} EndGlobalSection EndGlobal diff --git a/network/ndis/ndisprot/6x/sys/60/ndisprot60.vcxproj b/network/ndis/ndisprot/6x/sys/60/ndisprot60.vcxproj index 068f19e0..9fb2af46 100644 --- a/network/ndis/ndisprot/6x/sys/60/ndisprot60.vcxproj +++ b/network/ndis/ndisprot/6x/sys/60/ndisprot60.vcxproj @@ -19,11 +19,11 @@
- {74918B99-A7A2-4462-9330-D61ED648B991} + {7EA443E2-5964-417F-B418-CCFC6C30BF45} $(MSBuildProjectName) Debug Win32 - {F57A9742-AE91-4E5C-AAF8-582BEC93A8CA} + {BF705255-3868-4036-A1E7-638D7932F1A5} diff --git a/network/ndis/ndisprot/6x/sys/60/ndisprot60.vcxproj.Filters b/network/ndis/ndisprot/6x/sys/60/ndisprot60.vcxproj.Filters index e971259b..6e7019c5 100644 --- a/network/ndis/ndisprot/6x/sys/60/ndisprot60.vcxproj.Filters +++ b/network/ndis/ndisprot/6x/sys/60/ndisprot60.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {FC988553-FCE1-455C-A2B8-4253B2E40339} + {BB88F7B9-FEE7-4A81-BF8E-B5660FC419B0} h;hpp;hxx;hm;inl;inc;xsd - {CA13EBCF-7249-4085-AEED-A9AB9756BBDF} + {B0674E26-B054-4482-B925-109A349CB29C} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {B5901951-2387-48ED-83C6-A5D259BF7E0D} + {E6E18B22-C6BF-4A30-8120-E0706E138F57} inf;inv;inx;mof;mc; - {FCDA9B5C-B135-477F-BC65-BE9761005881} + {31078238-19E1-4DD5-9F8B-29286B133DF4} diff --git a/network/ndis/ndisprot/6x/sys/630/ndisprot630.vcxproj b/network/ndis/ndisprot/6x/sys/630/ndisprot630.vcxproj index 5a913947..12fc5739 100644 --- a/network/ndis/ndisprot/6x/sys/630/ndisprot630.vcxproj +++ b/network/ndis/ndisprot/6x/sys/630/ndisprot630.vcxproj @@ -19,11 +19,11 @@ - {DB252AE8-E32C-4E60-B0EB-33A2CB80861C} + {310AF693-B1C5-4CF1-A7E4-99F9D18D1574} $(MSBuildProjectName) Debug Win32 - {FA9D6F91-6B1C-4EFF-BAEA-E67F4CFE9D3E} + {1AA7BDDF-4140-446D-A380-EDC92457D53B} diff --git a/network/ndis/ndisprot/6x/sys/630/ndisprot630.vcxproj.Filters b/network/ndis/ndisprot/6x/sys/630/ndisprot630.vcxproj.Filters index bbdb53e8..770220ac 100644 --- a/network/ndis/ndisprot/6x/sys/630/ndisprot630.vcxproj.Filters +++ b/network/ndis/ndisprot/6x/sys/630/ndisprot630.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {088C6D92-3084-464D-B6CD-B47E67D278B5} + {6703BE47-96E4-43E8-A07F-66EDCDE49673} h;hpp;hxx;hm;inl;inc;xsd - {EDCAD0DA-E747-487E-8458-BAC6BA5E5744} + {3C46BFAA-5B89-490D-97E0-683EBE47B2F7} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {9F1E323E-8118-4CAC-8124-DA41F78075BE} + {FCADAC43-F392-48DD-80AC-5956347871B5} inf;inv;inx;mof;mc; - {5EA1AAE7-3C58-475C-84F0-40DCDF8823E9} + {AB5F4882-673A-4F5F-AA55-82ECF7EC3896} diff --git a/network/ndis/ndisprot/6x/test/prottest.vcxproj b/network/ndis/ndisprot/6x/test/prottest.vcxproj index 7706c8e3..c4d5dde3 100644 --- a/network/ndis/ndisprot/6x/test/prottest.vcxproj +++ b/network/ndis/ndisprot/6x/test/prottest.vcxproj @@ -19,11 +19,11 @@ - {0AD0B8E0-5A3E-43FE-8E27-E5BB3DB184B0} + {C5DBFAFB-4867-4605-B432-337BD17B972C} $(MSBuildProjectName) Debug Win32 - {B8B7CF7B-163A-4705-B726-3B7251D8BD10} + {5F9D6D0B-B0FB-4DB3-BCBC-062001EC3BB3} diff --git a/network/ndis/ndisprot/6x/test/prottest.vcxproj.Filters b/network/ndis/ndisprot/6x/test/prottest.vcxproj.Filters index 8b87abfa..298052d2 100644 --- a/network/ndis/ndisprot/6x/test/prottest.vcxproj.Filters +++ b/network/ndis/ndisprot/6x/test/prottest.vcxproj.Filters @@ -3,15 +3,15 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {5DB43F2D-E248-4063-B2E6-D0F81FCF5D84} + {0061A859-F60A-4C25-BEBE-07969B9A5F3F} h;hpp;hxx;hm;inl;inc;xsd - {3B8958F0-D888-4CE4-9473-3300FDF5A2B3} + {DC35B160-6C91-4008-98BB-CA550D5A4B2E} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {35E32097-01E2-4113-877C-7E88FDCD0FAA} + {3E18084F-3C14-4C0D-98A1-490E38D175D7} diff --git a/network/ndis/netvmini/6x/60/netvmini60.vcxproj b/network/ndis/netvmini/6x/60/netvmini60.vcxproj index 34fbc15f..b5bf188f 100644 --- a/network/ndis/netvmini/6x/60/netvmini60.vcxproj +++ b/network/ndis/netvmini/6x/60/netvmini60.vcxproj @@ -19,11 +19,11 @@ - {E1613ED0-DFEF-4C4D-8E06-6DB68964EE8B} + {4D117295-96D2-498D-BDE1-C560BFA3C03B} $(MSBuildProjectName) Debug Win32 - {FB69D6D4-CF9F-4C63-9FEA-D7D1B1F73BFF} + {25A2CEE6-93FE-4CB1-B8FD-8C1718FD45AD} diff --git a/network/ndis/netvmini/6x/60/netvmini60.vcxproj.Filters b/network/ndis/netvmini/6x/60/netvmini60.vcxproj.Filters index 36412ff4..664e91f7 100644 --- a/network/ndis/netvmini/6x/60/netvmini60.vcxproj.Filters +++ b/network/ndis/netvmini/6x/60/netvmini60.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {60D1BC26-8429-4B71-B0A4-A09C81AA9006} + {8262BA1D-7108-4104-949F-865D05666127} h;hpp;hxx;hm;inl;inc;xsd - {C5B761C0-3390-4C0D-92B3-296CBE739D12} + {1AFDB572-ED64-40CA-9AB7-020E47C3489D} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {2837E1B4-FB49-43C4-B0DA-0459E959F944} + {CE5B8EAF-CC06-4B59-9BC0-2C3A29D3CCDC} inf;inv;inx;mof;mc; - {78CC6DBE-CEE8-4DB1-BD8D-4C3C3551030A} + {753BD939-F310-44FF-9240-B67FF5C8417C} diff --git a/network/ndis/netvmini/6x/620/netvmini620.vcxproj b/network/ndis/netvmini/6x/620/netvmini620.vcxproj index dda1e977..aab56143 100644 --- a/network/ndis/netvmini/6x/620/netvmini620.vcxproj +++ b/network/ndis/netvmini/6x/620/netvmini620.vcxproj @@ -19,11 +19,11 @@ - {9DA1838D-2D4D-4357-9E4A-49BF1A8E6B7D} + {B4150693-0DE4-4CE8-8FFB-183E2A0DFFF8} $(MSBuildProjectName) Debug Win32 - {7039332E-F9EF-43DD-8AEC-4478C735DF1D} + {BBE8763B-C933-4BD8-93FA-001C816AACA6} diff --git a/network/ndis/netvmini/6x/620/netvmini620.vcxproj.Filters b/network/ndis/netvmini/6x/620/netvmini620.vcxproj.Filters index 3237b662..2dbcbafa 100644 --- a/network/ndis/netvmini/6x/620/netvmini620.vcxproj.Filters +++ b/network/ndis/netvmini/6x/620/netvmini620.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {703913F3-8635-4541-B263-C02BD6486AA1} + {5B72A6DB-853E-4641-BCA1-10EF5DD4E413} h;hpp;hxx;hm;inl;inc;xsd - {A1EB0C9F-4422-445A-8E6C-268C9DF3497F} + {A4A9A35F-8A74-4BE3-9EB0-E626ECDA38BD} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {175D5117-B719-462D-AD06-09F8EDFF3688} + {EB77FECD-C552-486B-9539-1E9B52B3466B} inf;inv;inx;mof;mc; - {C815125B-DF87-4E45-8C33-58380D5859E2} + {02165F6F-54E8-4D4C-832B-CDF2877A781B} diff --git a/network/ndis/netvmini/6x/630/netvmini630.vcxproj b/network/ndis/netvmini/6x/630/netvmini630.vcxproj index b881fbd6..17b4f6ac 100644 --- a/network/ndis/netvmini/6x/630/netvmini630.vcxproj +++ b/network/ndis/netvmini/6x/630/netvmini630.vcxproj @@ -19,11 +19,11 @@ - {20227FE5-F4F3-4980-98C2-B860C8B2F62C} + {FD239BD3-EB8B-4BAA-BC83-43F1E1D1EE89} $(MSBuildProjectName) Debug Win32 - {2C8923A5-C60B-45DE-AF84-B27B1BECA400} + {F1A4113F-E795-4CA8-AF38-FBA3D9B88251} diff --git a/network/ndis/netvmini/6x/630/netvmini630.vcxproj.Filters b/network/ndis/netvmini/6x/630/netvmini630.vcxproj.Filters index 93779b42..fba2414b 100644 --- a/network/ndis/netvmini/6x/630/netvmini630.vcxproj.Filters +++ b/network/ndis/netvmini/6x/630/netvmini630.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {9D259E56-FF93-4ED4-B79E-BE9390D6F96E} + {ABA6EAD2-FED4-495B-8FA0-1529A966F67E} h;hpp;hxx;hm;inl;inc;xsd - {2D6DC915-1942-425E-87CD-DC9F26064AED} + {B0D5F6C7-747C-4556-9082-1BC1AC0D4FA1} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {2DBFC871-0321-474E-ACAA-EF309426BBED} + {77321221-711B-4C2A-B73F-69E0D1F99853} inf;inv;inx;mof;mc; - {8493E657-4501-41D4-8F6A-B7527F30AA2D} + {60C02FC3-8D34-4BD3-8E28-866B4C29D3E0} diff --git a/network/ndis/netvmini/6x/netvmini.sln b/network/ndis/netvmini/6x/netvmini.sln index 0485a5a1..fbbe870c 100644 --- a/network/ndis/netvmini/6x/netvmini.sln +++ b/network/ndis/netvmini/6x/netvmini.sln @@ -3,17 +3,17 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "60", "60", "{FB1356F7-2404-4CF8-8FF8-D9D99AB89F12}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "60", "60", "{5F9487AF-05E7-4436-B499-5EE19925E384}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "620", "620", "{9164ECBF-12E2-44DA-8038-3BD0F347C637}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "620", "620", "{EC37AF20-58A7-44FE-AA97-7EBB2736E9DD}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "630", "630", "{2212DE82-26A1-46C0-810A-809089EC5623}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "630", "630", "{7F09E94A-63F3-442B-ABEB-843EF656383E}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "netvmini60", "60\netvmini60.vcxproj", "{E1613ED0-DFEF-4C4D-8E06-6DB68964EE8B}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "netvmini60", "60\netvmini60.vcxproj", "{4D117295-96D2-498D-BDE1-C560BFA3C03B}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "netvmini620", "620\netvmini620.vcxproj", "{9DA1838D-2D4D-4357-9E4A-49BF1A8E6B7D}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "netvmini620", "620\netvmini620.vcxproj", "{B4150693-0DE4-4CE8-8FFB-183E2A0DFFF8}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "netvmini630", "630\netvmini630.vcxproj", "{20227FE5-F4F3-4980-98C2-B860C8B2F62C}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "netvmini630", "630\netvmini630.vcxproj", "{FD239BD3-EB8B-4BAA-BC83-43F1E1D1EE89}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -23,37 +23,37 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {E1613ED0-DFEF-4C4D-8E06-6DB68964EE8B}.Debug|Win32.ActiveCfg = Debug|Win32 - {E1613ED0-DFEF-4C4D-8E06-6DB68964EE8B}.Debug|Win32.Build.0 = Debug|Win32 - {E1613ED0-DFEF-4C4D-8E06-6DB68964EE8B}.Release|Win32.ActiveCfg = Release|Win32 - {E1613ED0-DFEF-4C4D-8E06-6DB68964EE8B}.Release|Win32.Build.0 = Release|Win32 - {E1613ED0-DFEF-4C4D-8E06-6DB68964EE8B}.Debug|x64.ActiveCfg = Debug|x64 - {E1613ED0-DFEF-4C4D-8E06-6DB68964EE8B}.Debug|x64.Build.0 = Debug|x64 - {E1613ED0-DFEF-4C4D-8E06-6DB68964EE8B}.Release|x64.ActiveCfg = Release|x64 - {E1613ED0-DFEF-4C4D-8E06-6DB68964EE8B}.Release|x64.Build.0 = Release|x64 - {9DA1838D-2D4D-4357-9E4A-49BF1A8E6B7D}.Debug|Win32.ActiveCfg = Debug|Win32 - {9DA1838D-2D4D-4357-9E4A-49BF1A8E6B7D}.Debug|Win32.Build.0 = Debug|Win32 - {9DA1838D-2D4D-4357-9E4A-49BF1A8E6B7D}.Release|Win32.ActiveCfg = Release|Win32 - {9DA1838D-2D4D-4357-9E4A-49BF1A8E6B7D}.Release|Win32.Build.0 = Release|Win32 - {9DA1838D-2D4D-4357-9E4A-49BF1A8E6B7D}.Debug|x64.ActiveCfg = Debug|x64 - {9DA1838D-2D4D-4357-9E4A-49BF1A8E6B7D}.Debug|x64.Build.0 = Debug|x64 - {9DA1838D-2D4D-4357-9E4A-49BF1A8E6B7D}.Release|x64.ActiveCfg = Release|x64 - {9DA1838D-2D4D-4357-9E4A-49BF1A8E6B7D}.Release|x64.Build.0 = Release|x64 - {20227FE5-F4F3-4980-98C2-B860C8B2F62C}.Debug|Win32.ActiveCfg = Debug|Win32 - {20227FE5-F4F3-4980-98C2-B860C8B2F62C}.Debug|Win32.Build.0 = Debug|Win32 - {20227FE5-F4F3-4980-98C2-B860C8B2F62C}.Release|Win32.ActiveCfg = Release|Win32 - {20227FE5-F4F3-4980-98C2-B860C8B2F62C}.Release|Win32.Build.0 = Release|Win32 - {20227FE5-F4F3-4980-98C2-B860C8B2F62C}.Debug|x64.ActiveCfg = Debug|x64 - {20227FE5-F4F3-4980-98C2-B860C8B2F62C}.Debug|x64.Build.0 = Debug|x64 - {20227FE5-F4F3-4980-98C2-B860C8B2F62C}.Release|x64.ActiveCfg = Release|x64 - {20227FE5-F4F3-4980-98C2-B860C8B2F62C}.Release|x64.Build.0 = Release|x64 + {4D117295-96D2-498D-BDE1-C560BFA3C03B}.Debug|Win32.ActiveCfg = Debug|Win32 + {4D117295-96D2-498D-BDE1-C560BFA3C03B}.Debug|Win32.Build.0 = Debug|Win32 + {4D117295-96D2-498D-BDE1-C560BFA3C03B}.Release|Win32.ActiveCfg = Release|Win32 + {4D117295-96D2-498D-BDE1-C560BFA3C03B}.Release|Win32.Build.0 = Release|Win32 + {4D117295-96D2-498D-BDE1-C560BFA3C03B}.Debug|x64.ActiveCfg = Debug|x64 + {4D117295-96D2-498D-BDE1-C560BFA3C03B}.Debug|x64.Build.0 = Debug|x64 + {4D117295-96D2-498D-BDE1-C560BFA3C03B}.Release|x64.ActiveCfg = Release|x64 + {4D117295-96D2-498D-BDE1-C560BFA3C03B}.Release|x64.Build.0 = Release|x64 + {B4150693-0DE4-4CE8-8FFB-183E2A0DFFF8}.Debug|Win32.ActiveCfg = Debug|Win32 + {B4150693-0DE4-4CE8-8FFB-183E2A0DFFF8}.Debug|Win32.Build.0 = Debug|Win32 + {B4150693-0DE4-4CE8-8FFB-183E2A0DFFF8}.Release|Win32.ActiveCfg = Release|Win32 + {B4150693-0DE4-4CE8-8FFB-183E2A0DFFF8}.Release|Win32.Build.0 = Release|Win32 + {B4150693-0DE4-4CE8-8FFB-183E2A0DFFF8}.Debug|x64.ActiveCfg = Debug|x64 + {B4150693-0DE4-4CE8-8FFB-183E2A0DFFF8}.Debug|x64.Build.0 = Debug|x64 + {B4150693-0DE4-4CE8-8FFB-183E2A0DFFF8}.Release|x64.ActiveCfg = Release|x64 + {B4150693-0DE4-4CE8-8FFB-183E2A0DFFF8}.Release|x64.Build.0 = Release|x64 + {FD239BD3-EB8B-4BAA-BC83-43F1E1D1EE89}.Debug|Win32.ActiveCfg = Debug|Win32 + {FD239BD3-EB8B-4BAA-BC83-43F1E1D1EE89}.Debug|Win32.Build.0 = Debug|Win32 + {FD239BD3-EB8B-4BAA-BC83-43F1E1D1EE89}.Release|Win32.ActiveCfg = Release|Win32 + {FD239BD3-EB8B-4BAA-BC83-43F1E1D1EE89}.Release|Win32.Build.0 = Release|Win32 + {FD239BD3-EB8B-4BAA-BC83-43F1E1D1EE89}.Debug|x64.ActiveCfg = Debug|x64 + {FD239BD3-EB8B-4BAA-BC83-43F1E1D1EE89}.Debug|x64.Build.0 = Debug|x64 + {FD239BD3-EB8B-4BAA-BC83-43F1E1D1EE89}.Release|x64.ActiveCfg = Release|x64 + {FD239BD3-EB8B-4BAA-BC83-43F1E1D1EE89}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {E1613ED0-DFEF-4C4D-8E06-6DB68964EE8B} = {FB1356F7-2404-4CF8-8FF8-D9D99AB89F12} - {9DA1838D-2D4D-4357-9E4A-49BF1A8E6B7D} = {9164ECBF-12E2-44DA-8038-3BD0F347C637} - {20227FE5-F4F3-4980-98C2-B860C8B2F62C} = {2212DE82-26A1-46C0-810A-809089EC5623} + {4D117295-96D2-498D-BDE1-C560BFA3C03B} = {5F9487AF-05E7-4436-B499-5EE19925E384} + {B4150693-0DE4-4CE8-8FFB-183E2A0DFFF8} = {EC37AF20-58A7-44FE-AA97-7EBB2736E9DD} + {FD239BD3-EB8B-4BAA-BC83-43F1E1D1EE89} = {7F09E94A-63F3-442B-ABEB-843EF656383E} EndGlobalSection EndGlobal diff --git a/network/radio/HidSwitchDriverSample/HidSwitchDriverSample.sln b/network/radio/HidSwitchDriverSample/HidSwitchDriverSample.sln new file mode 100644 index 00000000..63278f58 --- /dev/null +++ b/network/radio/HidSwitchDriverSample/HidSwitchDriverSample.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0 +MinimumVisualStudioVersion = 12.0 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RadioSwitchHidUsbFx2", "RadioSwitchHidUsbFx2.vcxproj", "{299CE7FF-033A-4968-906D-5B8D00C1FE0C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {299CE7FF-033A-4968-906D-5B8D00C1FE0C}.Debug|Win32.ActiveCfg = Debug|Win32 + {299CE7FF-033A-4968-906D-5B8D00C1FE0C}.Debug|Win32.Build.0 = Debug|Win32 + {299CE7FF-033A-4968-906D-5B8D00C1FE0C}.Release|Win32.ActiveCfg = Release|Win32 + {299CE7FF-033A-4968-906D-5B8D00C1FE0C}.Release|Win32.Build.0 = Release|Win32 + {299CE7FF-033A-4968-906D-5B8D00C1FE0C}.Debug|x64.ActiveCfg = Debug|x64 + {299CE7FF-033A-4968-906D-5B8D00C1FE0C}.Debug|x64.Build.0 = Debug|x64 + {299CE7FF-033A-4968-906D-5B8D00C1FE0C}.Release|x64.ActiveCfg = Release|x64 + {299CE7FF-033A-4968-906D-5B8D00C1FE0C}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/network/radio/HidSwitchDriverSample/READFIRST_InstructionsForDevelopingHIDDriver.htm b/network/radio/HidSwitchDriverSample/READFIRST_InstructionsForDevelopingHIDDriver.htm new file mode 100644 index 00000000..77351c56 --- /dev/null +++ b/network/radio/HidSwitchDriverSample/READFIRST_InstructionsForDevelopingHIDDriver.htm @@ -0,0 +1,944 @@ + + + + + + + + +HID USB FX2 Sample + + + + + + + + + + +
+ +

Radio +Switch Driver Development

+ +

 

+ +

Sample +HID driver for Radio Management

+ +

 

+ +

There +are several steps that must be followed to create a HID driver for the hardware +wireless switch:

+ +

 

+ +

1)    Update System BIOS

+ +

2)    Develop HID driver

+ +

3)    Validate HID driver +functionality

+ +

 

+ +

 

+ +

Update +System BIOS

+ +

The system BIOS needs to be updated in order to +report the radio hardware button/switch to software – that is, the switch must +be exposed via ACPI.

+ +

 

+ +

BIOS must not control the radios directly, but must +rely on Windows 8 software to control the state of the radios via the HID +driver.

+ +

 

+ +

 

+ +

Develop +the HID driver for the hardware wireless switch

+ +

Use the HID driver sample to develop your +HID-compliant driver that communicates with your proprietary interface (embedded +controller) on the bottom edge and is wireless HID switch compliant on the +upper edge.

+ +

 

+ +

Important +note: if you are developing a HID driver for an A-B +switch, your proprietary embedded controller must report the correct state of +the switch at all times by sending a HID message to the HID driver, including +every time the PC is turned on back on. Reporting the state of the A-B switch +when the computer is turned back on is especially important in the case that +the switch changed states while the PC was in states S3/S4/S5.

+ +

 

+ +

 

+ +

Validate +HID driver functionality

+ +

Logo tests are available in the Windows Hardware +Certification Kit to validate the functionality of your HID driver.

+ +

 

+ +

 

+ +

 

+ +

 

+ +
+ + + + diff --git a/network/radio/HidSwitchDriverSample/README.htm b/network/radio/HidSwitchDriverSample/README.htm new file mode 100644 index 00000000..ef09a38e --- /dev/null +++ b/network/radio/HidSwitchDriverSample/README.htm @@ -0,0 +1,1437 @@ + + + + + + + + +HID USB FX2 Sample + + + + + + + + + +
+ +

Radio +Switch Test Driver for OSR USB-FX2 Development Board

+ +

 

+ +

Before +developing the HID driver, please make sure you read the READFIRST document, +which indicates the steps that must be taken in order to correctly develop a +HID driver.

+ +

 

+ +

Sample HID +driver for Radio Management

+ +

 

+ +

This +sample demonstrates how to structure a HID driver for radio switches for the +OSR USB-FX2 Development Board.

+ +

 

+ +

On +Windows 8 and later, the hardware switch or button to control wireless +transmission and the global software switch (Airplane mode switch) in the Radio +Management User Interface must be synchronized. To ensure the hardware and +software switches that control radio transmission are synchronized, the +hardware switch or button must have a HID-compliant driver.

+ +

 

+ +

Switch +Pack Mapping

+ +

 

+ +

 

+ + + + + + + + + + + + + + + + + + + + + + + + +
+

Switch

+
+

1

+
+

2

+
+

3

+
+

4

+
+

5

+
+

6

+
+

7

+
+

8

+
+

Mapping

+
+

Mode Select

+

Bit 3

+
+

Mode Select

+

Bit 2

+
+

Mode Select

+

Bit 1

+
+

-

+
+

-

+
+

-

+
+

-

+
+

Radio Switch

+
+ +

 

+ +

 

+ +

Sample Language Implementation

+ +

          C++

+ +

 

+ +

Prerequisites +for Installation

+ +

1.    +Windows 8 Developer Preview x86

+ +

2.    +Visual Studio 11 Developer Preview

+ +

3.    +Windows 8 WDK

+ +

 

+ +

Building +the Driver

+ +

1.    +Open the RadioSwitchHidUsbFx2.VcxProj

+ +

2.    +Use Visual Studio 11 to build the project

+ +

 

+ +

Installing +the Driver

+ +

 

+ +

To +install the driver, you must:

+ +
    +
  1. Build the driver using Visual Studio 11 Developer + Preview and copy the following installation files to a folder on your hard + drive:
  2. +
      +
    • RadioSwitchHidUsbFx2.inf
    • +
    • RadioSwitchHidUsbFx2.sys
    • +
    +
+ +

 

+ +
    +
  1. Plug in the device and do the following, depending on + the operating system that you are using:
  2. +
      +
        +
      1. Launch Device Manager by executing command devmgmt.msc in a command window, or from Hardware and Sound program group in Control Panel.
      2. +
      3. Select OSR USB-FX2 device from Other Devices category and click Update Driver Software… from right-click menu.
      4. +
      5. Select Browse my computer for + software and provide the location of the driver files.
      6. +
      7. Select Install this driver software anyway when + the Windows + Security dialog box appears.
      8. +
      9. After the driver is installed, you should see the + device in Device Manager under "Human Interface Devices".
      10. +
      +
    +
+ +

Testing

+ +

 

+ +

Testing +Modes

+ +

 

+ +

The +driver supports five modes representing the valid combinations of HID +descriptors that we have defined for the USB forum.

+ +

Modes +are selected using switches 1, 2, and 3 on the switch pack.

+ +

 

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Switch

+
+

1

+
+

2

+
+

3

+
+

Mode

+
+

Mapping

+
+

0

+
+

0

+
+

0

+
+

Mode 1

+
+

 

+
+

0

+
+

0

+
+

1

+
+

Mode 1

+
+

 

+
+

0

+
+

1

+
+

0

+
+

Mode 2

+
+

 

+
+

0

+
+

1

+
+

1

+
+

Mode 3

+
+

 

+
+

1

+
+

0

+
+

0

+
+

Mode 4

+
+

 

+
+

1

+
+

0

+
+

1

+
+

Mode 5

+
+

 

+
+

1

+
+

1

+
+

0

+
+

Mode 1

+
+

 

+
+

1

+
+

1

+
+

1

+
+

Mode 1

+
+ +

 

+ +

The +Mode in use is displayed on the boards seven segment display.

+ +

Mode +is determined at startup, so to change mode the board must be unplugged & +then re-connected

+ +

 

+ +

Mode +1 Radio Push Button

+ +

In +this mode the radio switch (switch 8 on the switch pack) represents a momentary +push button.

+ +

A +HID report is generated when the switch transitions to the On +state (switch down).

+ +

 

+ +

Mode +2 Radio Push Button & LED

+ +

In +this mode the radio switch (switch 8 on the switch pack) represents a momentary +push button.

+ +

A +HID report is generated when the switch transitions to the On +state (switch down).

+ +

In +addition, the LED array will reflect the state of the Radio LED: either all on +or all off (note that the top 2 LEDs never illuminate as these are not wired +in).

+ +

 

+ +

Mode +3 Radio Slider Switch

+ +

In +this mode the radio switch (switch 8 on the switch pack) represents an A-B +slider switch.

+ +

A +HID report is generated in both cases: when the switch transitions to the On state (switch down) and to the Off state (switch up).

+ +

 

+ +

Mode +4 Radio Slider Switch & LED

+ +

In +this mode the radio switch (switch 8 on the switch pack) represents an A-B +slider switch.

+ +

A +HID report is generated in both cases: when the switch transitions to the On state (switch down) and to the Off state (switch up).

+ +

In +addition the LED array will reflect the state of the Radio LED: either all on +or all off (note that the top 2 LEDs never illuminate as these are not wired +in).

+ +

 

+ +

Mode +5 LED only

+ +

In +this mode the radio switch (switch 8 on the switch pack) is ignored.

+ +

The +LED array will reflect the state of the Radio LED: either all on or all off +(note that the top 2 LEDs never illuminate as these are not wired in).

+ +
+ + + + diff --git a/network/radio/HidSwitchDriverSample/RadioSwitchHidUsbFx2.h b/network/radio/HidSwitchDriverSample/RadioSwitchHidUsbFx2.h new file mode 100644 index 00000000..ce92cfff --- /dev/null +++ b/network/radio/HidSwitchDriverSample/RadioSwitchHidUsbFx2.h @@ -0,0 +1,156 @@ +#ifndef _RADIOSWITCHHIDUSBFX2_H_ +#define _RADIOSWITCHHIDUSBFX2_H_ + +#include +#include +#include "usbdi.h" +#include "usbdlib.h" +#include +#include "wdfusb.h" +#include +#define NTSTRSAFE_LIB +#include +#include "trace.h" + + +#define HID_CLASS_SPEC_RELEASE_1_00 0x0100 // HID Class Specification release 1.00 +#define HID_COUNTRY_NON_LOCALIZED 0x00 // Hardware is not localized + +#define GENERIC_DESKTOP_REPORT_ID 0x01 + +#define GENERIC_DESKTOP_USAGE_PAGE 0x01 +#define WIRELESS_RADIO_CONTROLS_USAGE 0x0C +#define WIRELESS_RADIO_BUTTON_USAGE 0xC6 +#define WIRELESS_RADIO_LED_USAGE 0xC7 +#define WIRELESS_RADIO_SLIDER_USAGE 0xC8 + + +#define MODE_SELECTION_BUTTONS_BIT_MASK 0xE0 +#define RADIO_SWITCH_BUTTONS_BIT_MASK 0x01 +#define SWITCHPACK_SELECTION_FOR_MODE2 0x40 +#define SWITCHPACK_SELECTION_FOR_MODE3 0x60 +#define SWITCHPACK_SELECTION_FOR_MODE4 0x80 +#define SWITCHPACK_SELECTION_FOR_MODE5 0xA0 + +#define INTERRUPT_ENDPOINT_INDEX (0) + +#define SWITCHPACK_DEBOUNCE_TIME 10 // in millseconds + +// Define the vendor commands supported by device +#define HIDFX2_READ_SWITCH_STATE 0xD6 +#define HIDFX2_READ_7SEGMENT_DISPLAY 0xD4 +#define HIDFX2_READ_BARGRAPH_DISPLAY 0xD7 +#define HIDFX2_SET_BARGRAPH_DISPLAY 0xD8 +#define HIDFX2_IS_HIGH_SPEED 0xD9 +#define HIDFX2_REENUMERATE 0xDA +#define HIDFX2_SET_7SEGMENT_DISPLAY 0xDB + +// Bit masks for 7 segment display to be used with vendor command +#define SEG_TOP 0x1 +#define SEG_R_UPPER 0x2 +#define SEG_R_LOWER 0x4 +#define SEG_DOT 0x8 +#define SEG_L_LOWER 0x10 +#define SEG_MID 0x20 +#define SEG_L_UPPER 0x40 +#define SEG_BASE 0x80 + +#define SEGMENT_DISPLAY_1 SEG_R_UPPER | SEG_R_LOWER +#define SEGMENT_DISPLAY_2 SEG_TOP | SEG_R_UPPER | SEG_MID | SEG_L_LOWER | SEG_BASE +#define SEGMENT_DISPLAY_3 SEG_TOP | SEG_R_UPPER | SEG_MID | SEG_R_LOWER | SEG_BASE +#define SEGMENT_DISPLAY_4 SEG_R_UPPER | SEG_R_LOWER | SEG_MID | SEG_L_UPPER +#define SEGMENT_DISPLAY_5 SEG_TOP | SEG_R_LOWER | SEG_MID | SEG_L_UPPER | SEG_BASE +#define SEGMENT_DISPLAY_6 SEG_TOP | SEG_R_LOWER | SEG_L_LOWER | SEG_MID | SEG_L_UPPER | SEG_BASE +#define SEGMENT_DISPLAY_7 SEG_TOP | SEG_R_UPPER | SEG_R_LOWER +#define SEGMENT_DISPLAY_8 SEG_TOP | SEG_R_UPPER | SEG_R_LOWER | SEG_L_UPPER | SEG_L_LOWER | SEG_MID | SEG_BASE + +#define BARGRAPH_LED_ALL_ON 0xff +#define BARGRAPH_LED_ALL_OFF 0x00 + + +typedef UCHAR HID_REPORT_DESCRIPTOR, *PHID_REPORT_DESCRIPTOR; + +#include // make sure packing is handled correctly + +typedef struct _HIDFX2_IO_REPORT +{ + unsigned char bReportId; //Report ID for the collection + unsigned char bData; //one-byte data for switch/LED +}HIDFX2_IO_REPORT, *PHIDFX2_IO_REPORT; + + +typedef enum _DRIVER_MODE +{ + DM_BUTTON = 1, + DM_BUTTON_AND_LED, + DM_SLIDER_SWITCH, + DM_SLIDER_SWITCH_AND_LED, + DM_LED_ONLY +} DRIVER_MODE; + +#include + +typedef struct _DEVICE_EXTENSION +{ + WDFUSBDEVICE hUsbDevice; //WDF handles for USB Target + WDFUSBINTERFACE hUsbInterface; + WDFUSBPIPE hInterruptPipe; + WDFMEMORY hDeviceDescriptor; // Device descriptor for the USB device + unsigned char bCurrentSwitchState; // Switch state. + unsigned char bLatestToggledSwitch; // State for the switch that got toggled most recently + BOOLEAN fIsPowerUpSwitchState; //Interrupt endpoints sends switch state when first started .we ignore this + WDFTIMER hDebounceTimer; // Handle debouncing of switchpack + WDFQUEUE hInterruptMsgQueue; // WDF Queue for read IOCTLs from hidclass that get satisfied from USB interrupt endpoint + DRIVER_MODE driverMode; +} DEVICE_EXTENSION, *PDEVICE_EXTENSION; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(DEVICE_EXTENSION, GetDeviceContext) + + +// +// Driver routines +// +DRIVER_INITIALIZE DriverEntry; + +EVT_WDF_DRIVER_DEVICE_ADD HidFx2EvtDeviceAdd; + +EVT_WDF_IO_QUEUE_IO_INTERNAL_DEVICE_CONTROL HidFx2EvtInternalDeviceControl; + +EVT_WDF_DEVICE_PREPARE_HARDWARE HidFx2EvtDevicePrepareHardware; + +EVT_WDF_DEVICE_D0_ENTRY HidFx2EvtDeviceD0Entry; + +EVT_WDF_DEVICE_D0_EXIT HidFx2EvtDeviceD0Exit; + +EVT_WDF_USB_READER_COMPLETION_ROUTINE HidFx2EvtUsbInterruptPipeReadComplete; + +EVT_WDF_TIMER HidFx2EvtTimerFunction; + +EVT_WDF_OBJECT_CONTEXT_CLEANUP HidFx2EvtDriverContextCleanup; + +EVT_WDF_IO_QUEUE_IO_CANCELED_ON_QUEUE HidFx2EvtIoCanceledOnQueue; + + +NTSTATUS HidFx2GetHidDescriptor(_In_ WDFDEVICE hDevice, _In_ WDFREQUEST hRequest); + +NTSTATUS HidFx2GetReportDescriptor(_In_ WDFDEVICE hDevice, _In_ WDFREQUEST hRequest); + +NTSTATUS HidFx2GetDeviceAttributes(_In_ WDFREQUEST hRequest); + +NTSTATUS HidFx2ConfigContReaderForInterruptEndPoint(PDEVICE_EXTENSION pDeviceContext); + +NTSTATUS HidFx2SendIdleNotification(_In_ WDFREQUEST hRequest); + +NTSTATUS HidFx2SetOutput(_In_ WDFREQUEST hRequest); + +NTSTATUS HidFx2GetInput(_In_ WDFREQUEST hRequest); + +NTSTATUS HidFx2GetSwitchState(_In_ WDFDEVICE hDevice, _Out_ unsigned char *pbSwitchState); + +NTSTATUS SendVendorCommand(_In_ WDFDEVICE hDevice, _In_ unsigned char bVendorCommand, _In_ unsigned char bCommandData); + +PCWSTR DbgDevicePowerString(_In_ WDF_POWER_DEVICE_STATE powerState); + +#endif //_RADIOSWITCHHIDUSBFX2_H_ + + diff --git a/network/radio/HidSwitchDriverSample/RadioSwitchHidUsbFx2.inx b/network/radio/HidSwitchDriverSample/RadioSwitchHidUsbFx2.inx new file mode 100644 index 00000000..5089dfdd --- /dev/null +++ b/network/radio/HidSwitchDriverSample/RadioSwitchHidUsbFx2.inx @@ -0,0 +1,114 @@ +[Version] +Signature="$Windows NT$" +Class=HIDClass +ClassGuid={745a17a0-74d3-11d0-b6fe-00a0c90f57da} +Provider=%VENDOR% +DriverVer=5/3/2011,1.0.0.0 +CatalogFile=HidRadioSwitchDrv.cat + + +[SourceDisksFiles] +RadioSwitchHidUsbFx2.sys = 99 + +[SourceDisksNames] +99 = %DISK_NAME%,,,"" + +[DestinationDirs] +CopyFunctionDriver = 12 +CopyFilterDriver = 12 + +[Manufacturer] +%VENDOR%=Vendor, NT$ARCH$.6.1 + +; For Win7 and later so that we can use inbox HID-KMDF mapper +[Vendor.NT$ARCH$.6.1] +%RadioSwitchHidUsbFx2% = RadioSwitchHidUsbFx2.Inst.Win7, USB\VID_0547&PID_1002 +%customCollection% = customCollection.Inst, HID_DEVICE_UP:FF00_U:0001 + +;=============================================================== +; RadioSwitchHidUsbFx2 for Win7 +; Instead of using hidkmdf.sys as a filter, use the inbox +; mshidkmdf.sys as a mapper filter +;=============================================================== +[RadioSwitchHidUsbFx2.Inst.Win7.NT] +; Just copy the driver. No neeed to copy other system binaries. +CopyFiles = CopyFunctionDriver + +[RadioSwitchHidUsbFx2.Inst.Win7.NT.HW] +AddReg = RadioSwitchHidUsbFx2_Win7_Parameters.AddReg + +; +; hidkmdf is the function driver and RadioSwitchHidUsbFx2 is the lower filter +; +[RadioSwitchHidUsbFx2.Inst.Win7.NT.Services] +AddService = RadioSwitchHidUsbFx2,0x00000002, RadioSwitchHidUsbFx2_Service_Inst + +[RadioSwitchHidUsbFx2_Win7_Parameters.AddReg] +HKR,,"UpperFilters",0x00010000,"mshidkmdf" + +;=============================================================== +; Sections common to all OS versions +;=============================================================== + +[CopyFunctionDriver] +RadioSwitchHidUsbFx2.sys + +[RadioSwitchHidUsbFx2_Service_Inst] +DisplayName = %RadioSwitchHidUsbFx2% +ServiceType = %SERVICE_KERNEL_DRIVER% +StartType = %SERVICE_DEMAND_START% +ErrorControl = %SERVICE_ERROR_IGNORE% +ServiceBinary = %12%\RadioSwitchHidUsbFx2.sys + +;=============================================================== +; Custom Collection install section +; - Only a Null service is installed. +;=============================================================== +[customCollection.Inst.NT] +; NULL section + +[customCollection.Inst.NT.HW] +AddReg = customCollection.Inst.AddReg.NT.HW + +[customCollection.Inst.AddReg.NT.HW] +HKR,,"SelectiveSuspendEnabled",0x00000001,0x1 + +[customCollection.Inst.NT.Services] +AddService = ,0x00000002, ; NULL Service + +;================================================================ +;--- WDF Coinstaller installation ------ +; +[DestinationDirs] +RadioSwitchHidUsbFx2.Inst_CoInstaller_CopyFiles = 11 + +[SourceDisksFiles] +WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll=99 ; make sure the number matches with SourceDisksNames + +[Strings] +; *******Localizable Strings******* +VENDOR = "Vendor Name" +RadioSwitchHidUsbFx2 = "Radio Switch HID Mini-driver for OSR USB-FX-2 Device" +customCollection = "Radio Switch Collection for OSR USB-FX-2" +DISK_NAME = "HID Radio Switch USB FX-2 Install Disk" + +; *******Non Localizable Strings******* + +SERVICE_BOOT_START = 0x0 +SERVICE_SYSTEM_START = 0x1 +SERVICE_AUTO_START = 0x2 +SERVICE_DEMAND_START = 0x3 +SERVICE_DISABLED = 0x4 + +SERVICE_KERNEL_DRIVER = 0x1 +SERVICE_ERROR_IGNORE = 0x0 +SERVICE_ERROR_NORMAL = 0x1 +SERVICE_ERROR_SEVERE = 0x2 +SERVICE_ERROR_CRITICAL = 0x3 + +REG_EXPAND_SZ = 0x00020000 +REG_DWORD = 0x00010001 +REG_MULTI_SZ = 0x00010000 +REG_BINARY = 0x00000001 +REG_SZ = 0x00000000 + diff --git a/network/radio/HidSwitchDriverSample/RadioSwitchHidUsbFx2.rc b/network/radio/HidSwitchDriverSample/RadioSwitchHidUsbFx2.rc new file mode 100644 index 00000000..6737f603 --- /dev/null +++ b/network/radio/HidSwitchDriverSample/RadioSwitchHidUsbFx2.rc @@ -0,0 +1,11 @@ +#include + +#include + +#define VER_FILETYPE VFT_DRV +#define VER_FILESUBTYPE VFT2_DRV_SYSTEM +#define VER_FILEDESCRIPTION_STR "HID Radio Switch mini driver for USB Fx2 Device" +#define VER_INTERNALNAME_STR "RadioSwitchHidUsbFx2.sys" + +#include "common.ver" + diff --git a/network/radio/HidSwitchDriverSample/RadioSwitchHidUsbFx2.vcxproj b/network/radio/HidSwitchDriverSample/RadioSwitchHidUsbFx2.vcxproj new file mode 100644 index 00000000..690f4f3f --- /dev/null +++ b/network/radio/HidSwitchDriverSample/RadioSwitchHidUsbFx2.vcxproj @@ -0,0 +1,182 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {299CE7FF-033A-4968-906D-5B8D00C1FE0C} + $(MSBuildProjectName) + 1 + Debug + Win32 + {060E6040-ACF0-4A53-A87E-2D541F54BDC3} + + + + Windows10 + False + Desktop + KMDF + WindowsKernelModeDriver10.0 + Driver + + + Windows10 + True + Desktop + KMDF + WindowsKernelModeDriver10.0 + Driver + + + Windows10 + False + Desktop + KMDF + WindowsKernelModeDriver10.0 + Driver + + + Windows10 + True + Desktop + KMDF + WindowsKernelModeDriver10.0 + Driver + + + + $(IntDir) + + + + + + + + + + + + + + + + true + true + TraceEvents(LEVEL,FLAGS,MSG,...);TraceErr{LEVEL=TRACE_LEVEL_ERROR}(FLAGS,MSG,...);TraceWarning{LEVEL=TRACE_LEVEL_WARNING}(FLAGS,MSG,...);TraceInfo{LEVEL=TRACE_LEVEL_INFORMATION}(FLAGS,MSG,...);TraceVerbose{LEVEL=TRACE_LEVEL_VERBOSE}(FLAGS,MSG,...) + {km-WdfDefault.tpl}*.tmh + + + $(InfArch) + true + .\$(IntDir)\RadioSwitchHidUsbFx2.inf + + + true + true + TraceEvents(LEVEL,FLAGS,MSG,...);TraceErr{LEVEL=TRACE_LEVEL_ERROR}(FLAGS,MSG,...);TraceWarning{LEVEL=TRACE_LEVEL_WARNING}(FLAGS,MSG,...);TraceInfo{LEVEL=TRACE_LEVEL_INFORMATION}(FLAGS,MSG,...);TraceVerbose{LEVEL=TRACE_LEVEL_VERBOSE}(FLAGS,MSG,...) + {km-WdfDefault.tpl}*.tmh + + + + RadioSwitchHidUsbFx2 + + + RadioSwitchHidUsbFx2 + + + RadioSwitchHidUsbFx2 + + + RadioSwitchHidUsbFx2 + + + + %(AdditionalDependencies);$(DDK_LIB_PATH)\hidclass.lib;$(DDK_LIB_PATH)\ntstrsafe.lib + + + + + %(AdditionalDependencies);$(DDK_LIB_PATH)\hidclass.lib;$(DDK_LIB_PATH)\ntstrsafe.lib + + + + + %(AdditionalDependencies);$(DDK_LIB_PATH)\hidclass.lib;$(DDK_LIB_PATH)\ntstrsafe.lib + + + + + %(AdditionalDependencies);$(DDK_LIB_PATH)\hidclass.lib;$(DDK_LIB_PATH)\ntstrsafe.lib + + + + 1 + + + 1 + + + 1 + + + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/network/radio/HidSwitchDriverSample/RadioSwitchHidUsbFx2.vcxproj.Filters b/network/radio/HidSwitchDriverSample/RadioSwitchHidUsbFx2.vcxproj.Filters new file mode 100644 index 00000000..b4198ba4 --- /dev/null +++ b/network/radio/HidSwitchDriverSample/RadioSwitchHidUsbFx2.vcxproj.Filters @@ -0,0 +1,45 @@ + + + + + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* + {FDCC489B-556E-43F5-BD3B-71316D442DEA} + + + h;hpp;hxx;hm;inl;inc;xsd + {18150D25-6522-47D8-9CB4-5108F5F98F28} + + + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml + {A79E57E4-3B90-45E9-95EB-A0541E4A8DF4} + + + inf;inv;inx;mof;mc; + {0F70BE0E-ED35-4FD6-88BE-92687BE1BBB6} + + + + + Source Files + + + Source Files + + + Source Files + + + + + Driver Files + + + Driver Files + + + + + Resource Files + + + \ No newline at end of file diff --git a/network/radio/HidSwitchDriverSample/ReadMe.md b/network/radio/HidSwitchDriverSample/ReadMe.md new file mode 100644 index 00000000..5a94b523 --- /dev/null +++ b/network/radio/HidSwitchDriverSample/ReadMe.md @@ -0,0 +1,74 @@ +Radio Switch Test Driver for OSR USB-FX2 Development Board +========================================================== + +This sample demonstrates how to structure a HID driver for radio switches for the OSR USB-FX2 Development Board. + +Starting with Windows 8.1, the hardware switch or button to control wireless transmission and the global software switch (Airplane mode switch) in the Radio Management User Interface must be synchronized. To ensure the hardware and software switches that control radio transmission are synchronized, the hardware switch or button must have a HID-compliant driver. + + +Testing +------- + +### Testing Modes + +The driver supports five modes representing the valid combinations of HID descriptors that we have defined for the USB forum. Modes are selected using switches 1, 2, and 3 on the switch pack. + +### Switch Mapping + + ++++++ + + + + + + + + + + + + + +
1 +2 +3 +Mode
0 +0 +0 +Mode 10 +0 +1 +Mode 10 +1 +0 +Mode 20 +1 +1 +Mode 3
+ +### Mode 1 Radio Push Button + +In this mode the radio switch (switch 8 on the switch pack) represents a momentary push button. A HID report is generated when the switch transitions to the On state (switch down). + +### Mode 2 Radio Push Button & LED + +In this mode the radio switch (switch 8 on the switch pack) represents a momentary push button. A HID report is generated when the switch transitions to the On state (switch down). In addition, the LED array will reflect the state of the Radio LED: either all on or all off (note that the top 2 LEDs never illuminate as these are not wired in). + +### Mode 3 Radio Slider Switch + +In this mode the radio switch (switch 8 on the switch pack) represents a momentary push button. A HID report is generated when the switch transitions to the On state (switch down). + +### Mode 4 Radio Slider Switch & LED + +In this mode the radio switch (switch 8 on the switch pack) represents an A-B slider switch. A HID report is generated in both cases: when the switch transitions to the On state (switch down) and to the Off state (switch up). In addition the LED array will reflect the state of the Radio LED: either all on or all off (note that the top 2 LEDs never illuminate as these are not wired in). + +### Mode 5 LED only + +In this mode the radio switch (switch 8 on the switch pack) is ignored. The LED array will reflect the state of the Radio LED: either all on or all off (note that the top 2 LEDs never illuminate as these are not wired in). + diff --git a/network/radio/HidSwitchDriverSample/driver.c b/network/radio/HidSwitchDriverSample/driver.c new file mode 100644 index 00000000..a14d4fc4 --- /dev/null +++ b/network/radio/HidSwitchDriverSample/driver.c @@ -0,0 +1,156 @@ +#include +#pragma warning(disable:28252) +#pragma warning(disable:28253) +#include "driver.tmh" + + +#ifdef ALLOC_PRAGMA + #pragma alloc_text(INIT, DriverEntry) + #pragma alloc_text(PAGE, HidFx2EvtDriverContextCleanup) + #pragma alloc_text(PAGE, HidFx2EvtDeviceAdd) +#endif + + + +//Installable driver initialization entry point. This entry point is called directly by the I/O system. +// +NTSTATUS DriverEntry (_In_ PDRIVER_OBJECT pDriverObject, _In_ PUNICODE_STRING pszRegistryPath) +{ + NTSTATUS status = STATUS_SUCCESS; + WDF_DRIVER_CONFIG config; + WDF_OBJECT_ATTRIBUTES attributes; + + + // Initialize WPP Tracing + WPP_INIT_TRACING(pDriverObject, pszRegistryPath); + + TraceInfo(DBG_INIT, "(%!FUNC!) Enter -Sample Built %s %s\n", __DATE__, __TIME__); + + WDF_DRIVER_CONFIG_INIT(&config, HidFx2EvtDeviceAdd); + + // Register a cleanup callback so that we can call WPP_CLEANUP when the framework driver object is deleted during driver unload. + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + attributes.EvtCleanupCallback = HidFx2EvtDriverContextCleanup; + + // Create a framework driver object to represent our driver. + status = WdfDriverCreate(pDriverObject, + pszRegistryPath, + &attributes, // Driver Attributes + &config, // Driver Config Info + WDF_NO_HANDLE + ); + if (!NT_SUCCESS(status)) + { + TraceErr(DBG_INIT, "(%!FUNC!)WdfDriverCreate failed with status %!STATUS!\n", status); + WPP_CLEANUP(pDriverObject); + } + + TraceVerbose(DBG_INIT, "(%!FUNC!) Exit\n"); + return status; +} + + + +//Free resources allocated in DriverEntry that are not automatically cleaned up framework. +// +void HidFx2EvtDriverContextCleanup(_In_ WDFOBJECT hDriver) +{ + PAGED_CODE (); + + TraceVerbose(DBG_INIT, "(%!FUNC!) Enter/Exit\n"); + + WPP_CLEANUP(WdfDriverWdmGetDriverObject(hDriver)); +} + + + +//HidFx2EvtDeviceAdd is called by the framework in response to AddDevicecall from the PnP manager. +//We create and initialize a WDF device object to represent a new instance of device. +// +NTSTATUS HidFx2EvtDeviceAdd(_In_ WDFDRIVER hDriver, _Inout_ PWDFDEVICE_INIT pDeviceInit) +{ + NTSTATUS status = STATUS_SUCCESS; + WDF_IO_QUEUE_CONFIG queueConfig; + WDF_OBJECT_ATTRIBUTES attributes; + WDFDEVICE hDevice; + PDEVICE_EXTENSION pDevContext = NULL; + WDFQUEUE hQueue; + WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks; + WDF_TIMER_CONFIG timerConfig; + WDFTIMER hTimer; + + UNREFERENCED_PARAMETER(hDriver); + + PAGED_CODE(); + + TraceVerbose(DBG_PNP, "(%!FUNC!) Enter\n"); + + // Tell framework this is a filter driver. + WdfFdoInitSetFilter(pDeviceInit); + + // Initialize pnp-power callbacks, attributes and a context area for the device object. + WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks); + + // For usb devices, PrepareHardware callback is the to place select the interface and configure the device. + pnpPowerCallbacks.EvtDevicePrepareHardware = HidFx2EvtDevicePrepareHardware; + + // These two callbacks start and stop the wdfusb pipe continuous reader as we go in and out of the D0-working state. + pnpPowerCallbacks.EvtDeviceD0Entry = HidFx2EvtDeviceD0Entry; + pnpPowerCallbacks.EvtDeviceD0Exit = HidFx2EvtDeviceD0Exit; + + WdfDeviceInitSetPnpPowerEventCallbacks(pDeviceInit, &pnpPowerCallbacks); + + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, DEVICE_EXTENSION); + + // Create a framework device object.This call will in turn create a WDM device object, attach to the lower stack. + status = WdfDeviceCreate(&pDeviceInit, &attributes, &hDevice); + if (!NT_SUCCESS(status)) + { + TraceErr(DBG_PNP, "(%!FUNC!) WdfDeviceCreate failed with status code %!STATUS!\n", status); + return status; + } + + pDevContext = GetDeviceContext(hDevice); + + WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&queueConfig, WdfIoQueueDispatchParallel); + queueConfig.EvtIoInternalDeviceControl = HidFx2EvtInternalDeviceControl; + + status = WdfIoQueueCreate(hDevice, &queueConfig, WDF_NO_OBJECT_ATTRIBUTES, &hQueue); + if (!NT_SUCCESS (status)) + { + TraceErr(DBG_PNP, "(%!FUNC!) WdfIoQueueCreate failed 0x%x\n", status); + return status; + } + + // Register a manual I/O queue for handling Interrupt Message Read Requests. + WDF_IO_QUEUE_CONFIG_INIT(&queueConfig, WdfIoQueueDispatchManual); + + // This queue is used for requests that dont directly access the device. + // The requests in this queue are serviced only when the device is in a fully powered state and sends an interrupt. + queueConfig.PowerManaged = WdfFalse; + + status = WdfIoQueueCreate(hDevice, &queueConfig, WDF_NO_OBJECT_ATTRIBUTES, &pDevContext->hInterruptMsgQueue); + if (!NT_SUCCESS(status)) + { + TraceErr(DBG_PNP, "(%!FUNC!) WdfIoQueueCreate failed %!STATUS!\n", status); + return status; + } + + // Create a timer to handle debouncing of switchpack + WDF_TIMER_CONFIG_INIT(&timerConfig, HidFx2EvtTimerFunction); + timerConfig.AutomaticSerialization = FALSE; + + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + attributes.ParentObject = hDevice; + status = WdfTimerCreate(&timerConfig, &attributes, &hTimer); + if (!NT_SUCCESS(status)) + { + TraceErr(DBG_PNP, "(%!FUNC!) WdfTimerCreate failed status:%!STATUS!\n", status); + return status; + } + + pDevContext->hDebounceTimer = hTimer; + + TraceVerbose(DBG_PNP, "(%!FUNC!) Exit\n"); + return status; +} diff --git a/network/radio/HidSwitchDriverSample/hid.c b/network/radio/HidSwitchDriverSample/hid.c new file mode 100644 index 00000000..27fcefea --- /dev/null +++ b/network/radio/HidSwitchDriverSample/hid.c @@ -0,0 +1,659 @@ +#include +#include "hid.tmh" + +// Radio Management Collection - Scenario 1 control collection (Button only) +// +const HID_REPORT_DESCRIPTOR c_ButtonDescriptor[] = { + 0x05, GENERIC_DESKTOP_USAGE_PAGE, // USAGE_PAGE (Generic Desktop) + 0x09, WIRELESS_RADIO_CONTROLS_USAGE,// USAGE (Wireless Radio Controls) + 0xA1, 0x01, // COLLECTION (Application) + 0x85, GENERIC_DESKTOP_REPORT_ID, // REPORT_ID + 0x15, 0x00, // LOGICAL_MINIMUM(0) + 0x25, 0x01, // LOGICAL_MAXIMUM(1) + // + 0x09, WIRELESS_RADIO_BUTTON_USAGE, // USAGE (Wireless Radio Button) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x81, 0x06, // INPUT (Data, Variable, Rel) - button bit + 0x75, 0x07, // REPORT_SIZE (7) + 0x81, 0x03, // INPUT (const, var, abs) -7 bits of padding + 0xC0 // END_COLLECTION +}; + + +// Radio Management Collection - Scenario 2 control collection (Button with LED) +// +const HID_REPORT_DESCRIPTOR c_ButtonWithLedDescriptor[] = { + 0x05, GENERIC_DESKTOP_USAGE_PAGE, // USAGE_PAGE (Generic Desktop) + 0x09, WIRELESS_RADIO_CONTROLS_USAGE,// USAGE (Wireless Radio Controls) + 0xA1, 0x01, // COLLECTION (Application) + 0x85, GENERIC_DESKTOP_REPORT_ID, // REPORT_ID + 0x15, 0x00, // LOGICAL_MINIMUM(0) + 0x25, 0x01, // LOGICAL_MAXIMUM(1) + // + 0x09, WIRELESS_RADIO_BUTTON_USAGE, // USAGE (Wireless Radio Button) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x81, 0x06, // INPUT (Data, Variable, Rel) - button bit + 0x75, 0x07, // REPORT_SIZE (7) + 0x81, 0x03, // INPUT (const, var, abs) -7 bits of padding + // + 0x09, WIRELESS_RADIO_LED_USAGE, // USAGE (Wireless Radio LED) + 0x75, 0x01, // REPORT_SIZE (1) + 0x91, 0x02, // OUTPUT (Data, Variable, Rel) -led bit + 0x75, 0x07, // REPORT_SIZE (7) + 0x91, 0x03, // OUTPUT (const, var, abs) -7 bits of padding + 0xC0 // END_COLLECTION +}; + + +// Radio Management Collection - Scenario 3 control collection (Slider Switch) +// +const HID_REPORT_DESCRIPTOR c_SliderSwitchDescriptor[] = { + 0x05, GENERIC_DESKTOP_USAGE_PAGE, // USAGE_PAGE (Generic Desktop) + 0x09, WIRELESS_RADIO_CONTROLS_USAGE,// USAGE (Wireless Radio Controls) + 0xA1, 0x01, // COLLECTION (Application) + 0x85, GENERIC_DESKTOP_REPORT_ID, // REPORT_ID + 0x15, 0x00, // LOGICAL_MINIMUM(0) + 0x25, 0x01, // LOGICAL_MAXIMUM(1) + // + 0x09, WIRELESS_RADIO_SLIDER_USAGE, // USAGE (Wireless Radio Slider Switch) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x81, 0x02, // INPUT (Data, Variable, Abs) -switch bit + 0x75, 0x07, // REPORT_SIZE (7) + 0x81, 0x03, // INPUT (const, var, abs) -7 bits of padding + 0xC0 // END_COLLECTION +}; + + +// Radio Management Collection - Scenario 4 control collection (Slider Switch with LED) +// +const HID_REPORT_DESCRIPTOR c_SliderSwitchWithLedDescriptor[] = { + 0x05, GENERIC_DESKTOP_USAGE_PAGE, // USAGE_PAGE (Generic Desktop) + 0x09, WIRELESS_RADIO_CONTROLS_USAGE,// USAGE (Wireless Radio Controls) + 0xA1, 0x01, // COLLECTION (Application) + 0x85, GENERIC_DESKTOP_REPORT_ID, // REPORT_ID + 0x15, 0x00, // LOGICAL_MINIMUM(0) + 0x25, 0x01, // LOGICAL_MAXIMUM(1) + // + 0x09, WIRELESS_RADIO_SLIDER_USAGE, // USAGE (Wireless Radio Slider Switch) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x81, 0x02, // INPUT (Data, Variable, Abs) -switch bit + 0x75, 0x07, // REPORT_SIZE (7) + 0x81, 0x03, // INPUT (const, var, abs) -7 bits of padding + // + 0x09, WIRELESS_RADIO_LED_USAGE, // USAGE (Wireless Radio LED) + 0x75, 0x01, // REPORT_SIZE (1) + 0x91, 0x02, // OUTPUT (Data, Variable, Rel) -led bit + 0x75, 0x07, // REPORT_SIZE (7) + 0x91, 0x03, // OUTPUT (const, var, abs) -7 bits of padding + 0xC0 // END_COLLECTION +}; + + +// Radio Management Collection - Scenario 5 control collection (LED only) +// +const HID_REPORT_DESCRIPTOR c_LedOnlyDescriptor[] = { + 0x05, GENERIC_DESKTOP_USAGE_PAGE, // USAGE_PAGE (Generic Desktop) + 0x09, WIRELESS_RADIO_CONTROLS_USAGE,// USAGE (Wireless Radio Controls) + 0xA1, 0x01, // COLLECTION (Application) + 0x85, GENERIC_DESKTOP_REPORT_ID, // REPORT_ID + 0x15, 0x00, // LOGICAL_MINIMUM(0) + 0x25, 0x01, // LOGICAL_MAXIMUM(1) + // + 0x09, WIRELESS_RADIO_LED_USAGE, // USAGE (Wireless Radio LED) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x91, 0x02, // OUTPUT (Data, Variable, Rel) -led bit + 0x75, 0x07, // REPORT_SIZE (7) + 0x91, 0x03, // OUTPUT (const, var, abs) -7 bits of padding + 0xC0 // END_COLLECTION +}; + + +#ifdef ALLOC_PRAGMA + #pragma alloc_text(PAGE, HidFx2SetOutput) + #pragma alloc_text(PAGE, HidFx2GetInput) + #pragma alloc_text(PAGE, SendVendorCommand) +#endif + + +// This event is called when the framework receives IRP_MJ_INTERNAL DEVICE_CONTROL requests from the system. +// +void HidFx2EvtInternalDeviceControl( + _In_ WDFQUEUE hQueue, + _In_ WDFREQUEST hRequest, + _In_ size_t cOutputBufferLength, + _In_ size_t cInputBufferLength, + _In_ ULONG ulIoControlCode + ) +{ + NTSTATUS status = STATUS_SUCCESS; + WDFDEVICE hDevice; + PDEVICE_EXTENSION pDevContext = NULL; + + UNREFERENCED_PARAMETER(cOutputBufferLength); + UNREFERENCED_PARAMETER(cInputBufferLength); + + TraceVerbose(DBG_IOCTL, "(%!FUNC!) Enter\n"); + + hDevice = WdfIoQueueGetDevice(hQueue); + pDevContext = GetDeviceContext(hDevice); + + TraceInfo(DBG_IOCTL, "(%!FUNC!) Queue:0x%p, Request:0x%p\n", hQueue, hRequest); + + switch (ulIoControlCode) + { + case IOCTL_HID_GET_DEVICE_DESCRIPTOR: + TraceInfo(DBG_IOCTL, "IOCTL_HID_GET_DEVICE_DESCRIPTOR\n"); + status = HidFx2GetHidDescriptor(hDevice, hRequest); + WdfRequestComplete(hRequest, status); + break; + + case IOCTL_HID_GET_DEVICE_ATTRIBUTES: + TraceInfo(DBG_IOCTL, "IOCTL_HID_GET_DEVICE_ATTRIBUTES\n"); + status = HidFx2GetDeviceAttributes(hRequest); + WdfRequestComplete(hRequest, status); + break; + + case IOCTL_HID_GET_REPORT_DESCRIPTOR: + TraceInfo(DBG_IOCTL, "IOCTL_HID_GET_REPORT_DESCRIPTOR\n"); + status = HidFx2GetReportDescriptor(hDevice, hRequest); + WdfRequestComplete(hRequest, status); + break; + + case IOCTL_HID_READ_REPORT: + TraceInfo(DBG_IOCTL, "IOCTL_HID_READ_REPORT\n"); + status = WdfRequestForwardToIoQueue(hRequest, pDevContext->hInterruptMsgQueue); + if (!NT_SUCCESS(status)) + { + TraceErr(DBG_IOCTL, "WdfRequestForwardToIoQueue failed with status: %!STATUS!\n", status); + WdfRequestComplete(hRequest, status); + } + break; + + case IOCTL_HID_SEND_IDLE_NOTIFICATION_REQUEST: + TraceInfo(DBG_IOCTL, "IOCTL_HID_SEND_IDLE_NOTIFICATION_REQUEST\n"); + status = HidFx2SendIdleNotification(hRequest); + if (!NT_SUCCESS(status)) + { + TraceErr(DBG_IOCTL, "SendIdleNotification failed with status: %!STATUS!\n", status); + WdfRequestComplete(hRequest, status); + } + break; + + case IOCTL_HID_GET_INPUT_REPORT: + TraceInfo(DBG_IOCTL, "IOCTL_HID_GET_INPUT_REPORT\n"); + HidFx2GetInput(hRequest); + WdfRequestComplete(hRequest, status); + break; + + case IOCTL_HID_SET_OUTPUT_REPORT: + TraceInfo(DBG_IOCTL, "IOCTL_HID_SET_OUTPUT_REPORT\n"); + status = HidFx2SetOutput(hRequest); + WdfRequestComplete(hRequest, status); + break; + + default: + TraceInfo(DBG_IOCTL, "IOCTL Not Supported 0x%X\n", ulIoControlCode); + status = STATUS_NOT_SUPPORTED; + WdfRequestComplete(hRequest, status); + break; + } + + TraceVerbose(DBG_IOCTL, "(%!FUNC!) Exit\n"); + return; +} + + + +NTSTATUS HidFx2GetInput(_In_ WDFREQUEST hRequest) +{ + NTSTATUS status = STATUS_SUCCESS; + WDF_REQUEST_PARAMETERS params; + WDFDEVICE hDevice; + PHID_XFER_PACKET pTransferPacket = NULL; + PHIDFX2_IO_REPORT pOutputReport = NULL; + unsigned char bSwitchState = 0; + + PAGED_CODE(); + + TraceVerbose(DBG_IOCTL, "(%!FUNC!) Enter\n"); + + hDevice = WdfIoQueueGetDevice(WdfRequestGetIoQueue(hRequest)); + + WDF_REQUEST_PARAMETERS_INIT(¶ms); + WdfRequestGetParameters(hRequest, ¶ms); + + + if (params.Parameters.DeviceIoControl.OutputBufferLength < sizeof(HID_XFER_PACKET)) + { + status = STATUS_BUFFER_TOO_SMALL; + TraceErr(DBG_IOCTL, "(%!FUNC!) Userbuffer is small %!STATUS!\n", status); + return status; + } + + pTransferPacket = (PHID_XFER_PACKET) WdfRequestWdmGetIrp(hRequest)->UserBuffer; + if (pTransferPacket == NULL) + { + status = STATUS_INVALID_DEVICE_REQUEST; + TraceErr(DBG_IOCTL, "(%!FUNC!) Irp->UserBuffer is NULL %!STATUS!\n", status); + return status; + } + + if (pTransferPacket->reportBufferLen == 0) + { + status = STATUS_BUFFER_TOO_SMALL; + TraceErr(DBG_IOCTL, "(%!FUNC!) HID_XFER_PACKET->reportBufferLen is 0, %!STATUS!\n", status); + return status; + } + + if (pTransferPacket->reportBufferLen < sizeof(UCHAR)) + { + status = STATUS_BUFFER_TOO_SMALL; + TraceErr(DBG_IOCTL, "(%!FUNC!) HID_XFER_PACKET->reportBufferLen is too small, %!STATUS!\n", status); + return status; + } + + if (pTransferPacket->reportId != GENERIC_DESKTOP_REPORT_ID) + { + status = STATUS_INVALID_DEVICE_REQUEST; + TraceErr(DBG_IOCTL, "(%!FUNC!) Incorrect report ID, %!STATUS!\n", status); + return status; + } + + pOutputReport = (PHIDFX2_IO_REPORT)pTransferPacket->reportBuffer; + + // Get the switch state directly from the hardware + status = HidFx2GetSwitchState(hDevice, &bSwitchState); + TraceVerbose(DBG_IOCTL, "(%!FUNC!) switch state 0x%x\n", bSwitchState); + + //Mask off everything except the actual switch bit + bSwitchState &= RADIO_SWITCH_BUTTONS_BIT_MASK; + TraceVerbose(DBG_IOCTL, "(%!FUNC!) maskedswitch state 0x%x\n", bSwitchState); + + pOutputReport->bReportId = GENERIC_DESKTOP_REPORT_ID; + pOutputReport->bData = bSwitchState; + + TraceVerbose(DBG_IOCTL, "(%!FUNC!) Exit status %!STATUS!\n", status); + return status; +} + + + +NTSTATUS HidFx2SetOutput(_In_ WDFREQUEST hRequest) +{ + NTSTATUS status = STATUS_SUCCESS; + PHID_XFER_PACKET pTransferPacket = NULL; + WDF_REQUEST_PARAMETERS params; + PHIDFX2_IO_REPORT pOutputReport = NULL; + WDFDEVICE hDevice; + + PAGED_CODE(); + + TraceVerbose(DBG_IOCTL, "(%!FUNC!) Enter\n"); + + hDevice = WdfIoQueueGetDevice(WdfRequestGetIoQueue(hRequest)); + + WDF_REQUEST_PARAMETERS_INIT(¶ms); + WdfRequestGetParameters(hRequest, ¶ms); + + if (params.Parameters.DeviceIoControl.InputBufferLength < sizeof(HID_XFER_PACKET)) + { + status = STATUS_BUFFER_TOO_SMALL; + TraceErr(DBG_IOCTL, "(%!FUNC!) Userbuffer is small %!STATUS!\n", status); + return status; + } + + pTransferPacket = (PHID_XFER_PACKET) WdfRequestWdmGetIrp(hRequest)->UserBuffer; + if (pTransferPacket == NULL) + { + status = STATUS_INVALID_DEVICE_REQUEST; + TraceErr(DBG_IOCTL, "(%!FUNC!) Irp->UserBuffer is NULL %!STATUS!\n", status); + return status; + } + + if (pTransferPacket->reportBufferLen == 0) + { + status = STATUS_BUFFER_TOO_SMALL; + TraceErr(DBG_IOCTL, "(%!FUNC!) HID_XFER_PACKET->reportBufferLen is 0, %!STATUS!\n", status); + return status; + } + + if (pTransferPacket->reportBufferLen < sizeof(UCHAR)) + { + status = STATUS_BUFFER_TOO_SMALL; + TraceErr(DBG_IOCTL, "(%!FUNC!) HID_XFER_PACKET->reportBufferLen is too small, %!STATUS!\n", status); + return status; + } + + if (pTransferPacket->reportId != GENERIC_DESKTOP_REPORT_ID) + { + status = STATUS_INVALID_DEVICE_REQUEST; + TraceErr(DBG_IOCTL, "(%!FUNC!) Incorrect report ID, %!STATUS!\n", status); + return status; + } + + pOutputReport = (PHIDFX2_IO_REPORT)pTransferPacket->reportBuffer; + + if (pOutputReport->bData == 0) + { + status = SendVendorCommand(hDevice, HIDFX2_SET_BARGRAPH_DISPLAY, BARGRAPH_LED_ALL_OFF); + } + else + { + status = SendVendorCommand(hDevice, HIDFX2_SET_BARGRAPH_DISPLAY, BARGRAPH_LED_ALL_ON); + } + + TraceVerbose(DBG_IOCTL, "(%!FUNC!) Exit status %!STATUS!\n", status); + return status; +} + + + +//This routine sets the state of the Feature: in this case Segment Display on the USB FX2 board. +NTSTATUS SendVendorCommand(_In_ WDFDEVICE hDevice, _In_ unsigned char bVendorCommand, _In_ unsigned char bCommandData) +{ + NTSTATUS status = STATUS_SUCCESS; + ULONG cBytesTransferred = 0; + PDEVICE_EXTENSION pDevContext = NULL; + WDF_MEMORY_DESCRIPTOR memDesc; + WDF_USB_CONTROL_SETUP_PACKET controlSetupPacket; + WDF_REQUEST_SEND_OPTIONS sendOptions; + + PAGED_CODE(); + + TraceVerbose(DBG_IOCTL, "(%!FUNC!) Enter\n"); + + pDevContext = GetDeviceContext(hDevice); + + TraceInfo(DBG_IOCTL, "(%!FUNC!): Command:0x%x, data: 0x%x\n", bVendorCommand, bCommandData); + + // Send the I/O with a timeout. + // We do that because we send the I/O in the context of the user thread and if it gets stuck, it would prevent the user process from existing. + WDF_REQUEST_SEND_OPTIONS_INIT(&sendOptions, WDF_REQUEST_SEND_OPTION_TIMEOUT); + + WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&sendOptions, WDF_REL_TIMEOUT_IN_SEC(5)); + + WDF_USB_CONTROL_SETUP_PACKET_INIT_VENDOR(&controlSetupPacket, + BmRequestHostToDevice, + BmRequestToDevice, + bVendorCommand, // Request + 0, // Value + 0); // Index + + WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&memDesc, &bCommandData, sizeof(bCommandData)); + + status = WdfUsbTargetDeviceSendControlTransferSynchronously(pDevContext->hUsbDevice, + WDF_NO_HANDLE, // Optional WDFREQUEST + &sendOptions, // PWDF_REQUEST_SEND_OPTIONS + &controlSetupPacket, + &memDesc, + &cBytesTransferred); + if (!NT_SUCCESS(status)) + { + TraceErr(DBG_IOCTL, "(%!FUNC!): Failed to set Segment Display state - %!STATUS!\n", status); + } + + TraceVerbose(DBG_IOCTL, "(%!FUNC!) Exit\n"); + + return status; +} + + + +// Finds the HID descriptor and copies it into the buffer provided by the Request. +// +NTSTATUS HidFx2GetHidDescriptor(_In_ WDFDEVICE hDevice, _In_ WDFREQUEST hRequest) +{ + NTSTATUS status = STATUS_SUCCESS; + size_t cBytesToCopy = 0; + WDFMEMORY memory; + PDEVICE_EXTENSION pDevContext = NULL; + HID_DESCRIPTOR hidDescriptor; + + + TraceVerbose(DBG_IOCTL, "(%!FUNC!) Entry\n"); + + status = WdfRequestRetrieveOutputMemory(hRequest, &memory); + if (NT_SUCCESS(status)) + { + hidDescriptor.bLength= sizeof(hidDescriptor); // length of HID descriptor + hidDescriptor.bDescriptorType= HID_HID_DESCRIPTOR_TYPE; // descriptor type == HID 0x21 + hidDescriptor.bcdHID= HID_CLASS_SPEC_RELEASE_1_00; // hid spec release + hidDescriptor.bCountry= HID_COUNTRY_NON_LOCALIZED; // country code + hidDescriptor.bNumDescriptors= 0x01; // number of HID class descriptors + hidDescriptor.DescriptorList[0].bReportType =HID_REPORT_DESCRIPTOR_TYPE; + hidDescriptor.DescriptorList[0].wReportLength = sizeof(c_ButtonDescriptor); + + pDevContext = GetDeviceContext(hDevice); + if (pDevContext != NULL) + { + // Set length of non default report descriptor + switch (pDevContext->driverMode) + { + case DM_BUTTON_AND_LED: + hidDescriptor.DescriptorList[0].wReportLength = sizeof(c_ButtonWithLedDescriptor); + break; + case DM_SLIDER_SWITCH: + hidDescriptor.DescriptorList[0].wReportLength = sizeof(c_SliderSwitchDescriptor); + break; + case DM_SLIDER_SWITCH_AND_LED: + hidDescriptor.DescriptorList[0].wReportLength = sizeof(c_SliderSwitchWithLedDescriptor); + break; + case DM_LED_ONLY: + hidDescriptor.DescriptorList[0].wReportLength = sizeof(c_LedOnlyDescriptor); + break; + default: + break; + } + } + cBytesToCopy = hidDescriptor.bLength; + if (cBytesToCopy != 0) + { + status = WdfMemoryCopyFromBuffer(memory, 0, (PVOID)&hidDescriptor, cBytesToCopy); + if (NT_SUCCESS(status)) + { + // Report how many bytes were copied + WdfRequestSetInformation(hRequest, cBytesToCopy); + } + else // WdfMemoryCopyFromBuffer failed + { + TraceErr(DBG_IOCTL, "(%!FUNC!) WdfMemoryCopyFromBuffer failed %!STATUS!\n", status); + return status; + } + } + else // length is zero + { + status = STATUS_INVALID_DEVICE_STATE; + TraceErr(DBG_IOCTL, "(%!FUNC!) c_DefaultHidDescriptor is zero, %!STATUS!\n", status); + return status; + } + + } + else // WdfRequestRetrieveOutputMemory failed + { + TraceErr(DBG_IOCTL, " (%!FUNC!) WdfRequestRetrieveOutputMemory failed %!STATUS!\n", status); + return status; + } + + TraceVerbose(DBG_IOCTL, " (%!FUNC!) HidFx2GetHidDescriptor Exit = %!STATUS!\n", status); + return status; +} + + + +// Finds the Report descriptor and copies it into the buffer provided by the Request. +// +NTSTATUS HidFx2GetReportDescriptor(_In_ WDFDEVICE hDevice, _In_ WDFREQUEST hRequest) +{ + NTSTATUS status = STATUS_SUCCESS; + WDFMEMORY memory; + PDEVICE_EXTENSION pDevContext = NULL; + PVOID pBuffer = (PVOID)c_ButtonDescriptor; + size_t cBytesToCopy = sizeof(c_ButtonDescriptor); + + + TraceVerbose(DBG_IOCTL, "(%!FUNC!) Entry\n"); + + status = WdfRequestRetrieveOutputMemory(hRequest, &memory); + if (NT_SUCCESS(status)) + { + pDevContext = GetDeviceContext(hDevice); + if (pDevContext != NULL) + { + // Select a non default report descriptor + switch (pDevContext->driverMode) + { + case DM_BUTTON_AND_LED: + pBuffer = (PVOID)c_ButtonWithLedDescriptor; + cBytesToCopy = sizeof(c_ButtonWithLedDescriptor); + break; + case DM_SLIDER_SWITCH: + pBuffer = (PVOID)c_SliderSwitchDescriptor; + cBytesToCopy = sizeof(c_SliderSwitchDescriptor); + break; + case DM_SLIDER_SWITCH_AND_LED: + pBuffer = (PVOID)c_SliderSwitchWithLedDescriptor; + cBytesToCopy = sizeof(c_SliderSwitchWithLedDescriptor); + break; + case DM_LED_ONLY: + pBuffer = (PVOID)c_LedOnlyDescriptor; + cBytesToCopy = sizeof(c_LedOnlyDescriptor); + break; + default: + break; + } + } + if (cBytesToCopy != 0) + { + status = WdfMemoryCopyFromBuffer(memory, 0, pBuffer, cBytesToCopy); + if (NT_SUCCESS(status)) + { + // Report how many bytes were copied + WdfRequestSetInformation(hRequest, cBytesToCopy); + } + else // WdfMemoryCopyFromBuffer failed + { + TraceErr(DBG_IOCTL, "(%!FUNC!) WdfMemoryCopyFromBuffer failed %!STATUS!\n", status); + } + } + else // report length is zero + { + status = STATUS_INVALID_DEVICE_STATE; + TraceErr(DBG_IOCTL, "(%!FUNC!) c_DefaultHidDescriptor's reportLength is zero, %!STATUS!\n", status); + } + } + else // WdfRequestRetrieveOutputMemory failed + { + TraceErr(DBG_IOCTL, "(%!FUNC!)WdfRequestRetrieveOutputMemory failed %!STATUS!\n", status); + + } + + TraceVerbose(DBG_IOCTL, "(%!FUNC!) Exit = %!STATUS!\n", status); + return status; +} + + + +// Fill in the given struct _HID_DEVICE_ATTRIBUTES +// +NTSTATUS HidFx2GetDeviceAttributes(_In_ WDFREQUEST hRequest) +{ + NTSTATUS status = STATUS_SUCCESS; + PHID_DEVICE_ATTRIBUTES pDeviceAttributes = NULL; + PUSB_DEVICE_DESCRIPTOR pUsbDeviceDescriptor = NULL; + PDEVICE_EXTENSION pDeviceInfo = NULL; + + TraceVerbose(DBG_IOCTL, "(%!FUNC!) Entry\n"); + + pDeviceInfo = GetDeviceContext(WdfIoQueueGetDevice(WdfRequestGetIoQueue(hRequest))); + status = WdfRequestRetrieveOutputBuffer(hRequest, sizeof (HID_DEVICE_ATTRIBUTES), &pDeviceAttributes, NULL); + if (NT_SUCCESS(status)) + { + // Retrieve USB device descriptor saved in device context + pUsbDeviceDescriptor = WdfMemoryGetBuffer(pDeviceInfo->hDeviceDescriptor, NULL); + pDeviceAttributes->Size = sizeof (HID_DEVICE_ATTRIBUTES); + pDeviceAttributes->VendorID = pUsbDeviceDescriptor->idVendor; + pDeviceAttributes->ProductID = pUsbDeviceDescriptor->idProduct; + pDeviceAttributes->VersionNumber = pUsbDeviceDescriptor->bcdDevice; + // Report how many bytes were copied + WdfRequestSetInformation(hRequest, sizeof (HID_DEVICE_ATTRIBUTES)); + } + else // WdfRequestRetrieveOutputBuffer failed + { + TraceErr(DBG_IOCTL, "(%!FUNC!) WdfRequestRetrieveOutputBuffer failed %!STATUS!\n", status); + } + + TraceVerbose(DBG_IOCTL, "(%!FUNC!) Exit = %!STATUS!\n", status); + return status; +} + + + +// Pass down Idle notification request to lower driver +// +NTSTATUS HidFx2SendIdleNotification(_In_ WDFREQUEST hRequest) +{ + NTSTATUS status = STATUS_SUCCESS; + WDF_REQUEST_SEND_OPTIONS options; + WDFIOTARGET hNextLowerDriver; + WDFDEVICE hDevice; + PIO_STACK_LOCATION pCurrentIrpStack = NULL; + IO_STACK_LOCATION nextIrpStack; + + TraceVerbose(DBG_IOCTL, "(%!FUNC!) Entry\n"); + + hDevice = WdfIoQueueGetDevice(WdfRequestGetIoQueue(hRequest)); + pCurrentIrpStack = IoGetCurrentIrpStackLocation(WdfRequestWdmGetIrp(hRequest)); + + // Convert the request to corresponding USB Idle notification request + if (pCurrentIrpStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(HID_SUBMIT_IDLE_NOTIFICATION_CALLBACK_INFO)) + { + ASSERT(sizeof(HID_SUBMIT_IDLE_NOTIFICATION_CALLBACK_INFO) == sizeof(USB_IDLE_CALLBACK_INFO)); + #pragma warning(suppress :4127) // conditional expression is constant warning + if (sizeof(HID_SUBMIT_IDLE_NOTIFICATION_CALLBACK_INFO) == sizeof(USB_IDLE_CALLBACK_INFO)) + { + // prepare next stack location + RtlZeroMemory(&nextIrpStack, sizeof(IO_STACK_LOCATION)); + nextIrpStack.MajorFunction = pCurrentIrpStack->MajorFunction; + nextIrpStack.Parameters.DeviceIoControl.InputBufferLength = pCurrentIrpStack->Parameters.DeviceIoControl.InputBufferLength; + nextIrpStack.Parameters.DeviceIoControl.Type3InputBuffer = pCurrentIrpStack->Parameters.DeviceIoControl.Type3InputBuffer; + nextIrpStack.Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION; + nextIrpStack.DeviceObject = WdfIoTargetWdmGetTargetDeviceObject(WdfDeviceGetIoTarget(hDevice)); + + // Format the I/O request for the driver's local I/O target by using the contents of the specified WDM I/O stack location structure. + WdfRequestWdmFormatUsingStackLocation(hRequest, &nextIrpStack); + + // Send the request down using Fire and forget option. + WDF_REQUEST_SEND_OPTIONS_INIT(&options, WDF_REQUEST_SEND_OPTION_SEND_AND_FORGET); + hNextLowerDriver = WdfDeviceGetIoTarget(hDevice); + if (WdfRequestSend(hRequest, hNextLowerDriver, &options) == FALSE) + { + status = STATUS_UNSUCCESSFUL; + } + } + else // Incorrect DeviceIoControl.InputBufferLength + { + status = STATUS_INFO_LENGTH_MISMATCH; + TraceErr(DBG_IOCTL, "(%!FUNC!) Incorrect DeviceIoControl.InputBufferLength, %!STATUS!\n", status); + return status; + } + } + else // DeviceIoControl.InputBufferLength too small + { + status = STATUS_BUFFER_TOO_SMALL; + TraceErr(DBG_IOCTL, "(%!FUNC!) DeviceIoControl.InputBufferLength too small, %!STATUS!\n", status); + return status; + } + + TraceVerbose(DBG_IOCTL, "(%!FUNC!) Exit = %!STATUS!\n", status); + return status; +} + + + + + diff --git a/network/radio/HidSwitchDriverSample/trace.h b/network/radio/HidSwitchDriverSample/trace.h new file mode 100644 index 00000000..0ec09b91 --- /dev/null +++ b/network/radio/HidSwitchDriverSample/trace.h @@ -0,0 +1,13 @@ +#pragma once + +#define WPP_CHECK_FOR_NULL_STRING //to prevent exceptions due to NULL strings + +#define WPP_CONTROL_GUIDS \ + WPP_DEFINE_CONTROL_GUID(HidUsbFx2TraceGuid, (091182d7, 5167, 4e77, aa80, ca6c1e6201e9), \ + WPP_DEFINE_BIT(DBG_INIT) \ + WPP_DEFINE_BIT(DBG_PNP) \ + WPP_DEFINE_BIT(DBG_IOCTL) \ + ) + +#define WPP_LEVEL_FLAGS_LOGGER(lvl,flags) WPP_LEVEL_LOGGER(flags) +#define WPP_LEVEL_FLAGS_ENABLED(lvl, flags) (WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level >= lvl) diff --git a/network/radio/HidSwitchDriverSample/usb.c b/network/radio/HidSwitchDriverSample/usb.c new file mode 100644 index 00000000..e6ac2da7 --- /dev/null +++ b/network/radio/HidSwitchDriverSample/usb.c @@ -0,0 +1,466 @@ +#include +#include "usb.tmh" + + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE, HidFx2EvtDevicePrepareHardware) +#pragma alloc_text(PAGE, HidFx2EvtDeviceD0Exit) +#pragma alloc_text(PAGE, HidFx2ConfigContReaderForInterruptEndPoint) +#endif + + +// In this callback, the driver does whatever is necessary to make the hardware ready to use. +// In the case of a USB device, this involves reading and selecting descriptors. +NTSTATUS +HidFx2EvtDevicePrepareHardware( + _In_ WDFDEVICE hDevice, + _In_ WDFCMRESLIST hResourceList, + _In_ WDFCMRESLIST hResourceListTranslated + ) +{ + NTSTATUS status = STATUS_SUCCESS; + PDEVICE_EXTENSION pDevContext = NULL; + WDF_USB_DEVICE_SELECT_CONFIG_PARAMS configParams; + WDF_OBJECT_ATTRIBUTES attributes; + PUSB_DEVICE_DESCRIPTOR pUsbDeviceDescriptor = NULL; + + UNREFERENCED_PARAMETER(hResourceList); + UNREFERENCED_PARAMETER(hResourceListTranslated); + + PAGED_CODE (); + + TraceVerbose(DBG_INIT, "(%!FUNC!) Enter\n"); + + pDevContext = GetDeviceContext(hDevice); + + // Create a WDFUSBDEVICE object. WdfUsbTargetDeviceCreate obtains the USB device descriptor and the first USB configuration + //descriptor from the device and stores them. It also creates a framework USB interface object for each interface in the device's first configuration. + // + // The parent of each USB device object is the driver's framework driver object. The driver cannot change this parent, and the ParentObject + // member or the WDF_OBJECT_ATTRIBUTES structure must be NULL. + // + // We only create device the first time PrepareHardware is called. If the device is restarted by pnp manager for resource rebalance, we + // will use the same device handle but then select the interfaces again because the USB stack could reconfigure the device on restart. + if (pDevContext->hUsbDevice == NULL) + { + status = WdfUsbTargetDeviceCreate(hDevice, WDF_NO_OBJECT_ATTRIBUTES, &pDevContext->hUsbDevice); + if (!NT_SUCCESS(status)) + { + TraceErr(DBG_PNP, "(%!FUNC!) WdfUsbTargetDeviceCreate failed %!STATUS!\n", status); + return status; + } + } + + // Select a device configuration by using a WDF_USB_DEVICE_SELECT_CONFIG_PARAMS + WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_INIT_SINGLE_INTERFACE(&configParams); + status = WdfUsbTargetDeviceSelectConfig(pDevContext->hUsbDevice, WDF_NO_OBJECT_ATTRIBUTES, &configParams); + if (!NT_SUCCESS(status)) + { + TraceErr(DBG_PNP, "(%!FUNC!) WdfUsbTargetDeviceSelectConfig failed %!STATUS!\n", status); + return status; + } + + pDevContext->hUsbInterface = configParams.Types.SingleInterface.ConfiguredUsbInterface; + + // Get the device descriptor and store it in device context + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + attributes.ParentObject = hDevice; + status = WdfMemoryCreate(&attributes, + NonPagedPool, + 0, + sizeof(USB_DEVICE_DESCRIPTOR), + &pDevContext->hDeviceDescriptor, + &pUsbDeviceDescriptor); + if (!NT_SUCCESS(status)) + { + TraceErr(DBG_PNP, "(%!FUNC!) WdfMemoryCreate for Device Descriptor failed %!STATUS!\n", status); + return status; + } + + WdfUsbTargetDeviceGetDeviceDescriptor(pDevContext->hUsbDevice, pUsbDeviceDescriptor); + + // Get the Interrupt pipe. There are other endpoints but we are only interested in interrupt endpoint since our HID data comes from this + pDevContext->hInterruptPipe = WdfUsbInterfaceGetConfiguredPipe(pDevContext->hUsbInterface, INTERRUPT_ENDPOINT_INDEX, NULL); + if (NULL == pDevContext->hInterruptPipe) + { + TraceErr(DBG_PNP, "(%!FUNC!) Failed to get interrupt pipe info\n"); + status = STATUS_INVALID_DEVICE_STATE; + return status; + } + + // Tell the framework that it's okay to read less than MaximumPacketSize + WdfUsbTargetPipeSetNoMaximumPacketSizeCheck(pDevContext->hInterruptPipe); + + //configure continuous reader + status = HidFx2ConfigContReaderForInterruptEndPoint(pDevContext); + + TraceVerbose(DBG_INIT, "(%!FUNC!) Exit, Status: %!STATUS!\n", status); + + return status; +} + + + +// This routine configures a continuous reader on the interrupt endpoint. It's called from the PrepareHarware event. +// +NTSTATUS HidFx2ConfigContReaderForInterruptEndPoint(PDEVICE_EXTENSION pDeviceContext) +{ + WDF_USB_CONTINUOUS_READER_CONFIG contReaderConfig; + NTSTATUS status = STATUS_SUCCESS; + + PAGED_CODE (); + + TraceVerbose(DBG_INIT, "(%!FUNC!) Enter\n"); + + WDF_USB_CONTINUOUS_READER_CONFIG_INIT(&contReaderConfig, + HidFx2EvtUsbInterruptPipeReadComplete, + pDeviceContext, // Context + sizeof(UCHAR)); // TransferLength + + status = WdfUsbTargetPipeConfigContinuousReader(pDeviceContext->hInterruptPipe, &contReaderConfig); + if (!NT_SUCCESS(status)) + { + TraceErr(DBG_INIT, "(%!FUNC!) failed %!STATUS!\n", status); + } + + TraceVerbose(DBG_INIT, "(%!FUNC!) Exit, status: %!STATUS!\n", status); + + return status; +} + + + +// This the completion routine of the continuous reader. This can called concurrently on multiprocessor system if there are +// more than one readers configured. So make sure to protect access to global resources. +// +void HidFx2EvtUsbInterruptPipeReadComplete( + WDFUSBPIPE hPipe, + WDFMEMORY hBuffer, + size_t cNumBytesTransferred, + WDFCONTEXT pContext + ) +{ + PDEVICE_EXTENSION pDevContext = pContext; + BOOLEAN fInTimerQueue; + unsigned char *pbSwitchState = NULL; + unsigned char bCurrentSwitchState = 0; + unsigned char bPrevSwitchState = 0; + unsigned char bToggledSwitch = 0; + + UNREFERENCED_PARAMETER(cNumBytesTransferred); + UNREFERENCED_PARAMETER(hPipe); + + TraceVerbose(DBG_INIT, "(%!FUNC!) Enter\n"); + + // Interrupt endpoints sends switch state when first started or when resuming from suspend. + // We need to ignore that data since user did not change the switch state. + if (pDevContext->fIsPowerUpSwitchState) + { + pDevContext->fIsPowerUpSwitchState = FALSE; + TraceInfo(DBG_INIT, "(%!FUNC!) Dropping interrupt message since received during powerup/resume\n"); + return; + } + + + // Make sure that there is data in the read packet. + // Depending on the device specification, it is possible for it to return a 0 length read in certain conditions. + if (cNumBytesTransferred == 0) + { + TraceWarning(DBG_INIT, "(%!FUNC!) Zero length read occured on the Interrupt Pipe's Continuous Reader\n"); + return; + } + + pbSwitchState = WdfMemoryGetBuffer(hBuffer, NULL); + bCurrentSwitchState = ~(*pbSwitchState); // switchs are inverted on hardware boards + bCurrentSwitchState &= RADIO_SWITCH_BUTTONS_BIT_MASK; //Mask off everything except the actual radio switch bit + bPrevSwitchState = pDevContext->bCurrentSwitchState; + + if (bPrevSwitchState ^ bCurrentSwitchState) // make sure we toggled the radio switch + { + switch(pDevContext->driverMode) + { + // If it's a slider switch we want 0->1 and 1->0 transitions. + case DM_SLIDER_SWITCH: + case DM_SLIDER_SWITCH_AND_LED: + bToggledSwitch = bCurrentSwitchState; + // A timer is started for 10 ms everytime there is a switch toggled + fInTimerQueue = WdfTimerStart(pDevContext->hDebounceTimer, WDF_REL_TIMEOUT_IN_MS(SWITCHPACK_DEBOUNCE_TIME)); + TraceInfo(DBG_INIT, "(%!FUNC!) Debounce Timer started. Existing -%!bool!\n", fInTimerQueue); + break; + //If it's a button so we only report 0->1 transitions + case DM_BUTTON: + case DM_BUTTON_AND_LED: + bToggledSwitch = (bPrevSwitchState ^ bCurrentSwitchState) & bCurrentSwitchState; + if (bToggledSwitch != 0) + { + // A timer is started for 10 ms everytime there is a switch toggled on + fInTimerQueue = WdfTimerStart(pDevContext->hDebounceTimer, WDF_REL_TIMEOUT_IN_MS(SWITCHPACK_DEBOUNCE_TIME)); + TraceInfo(DBG_INIT, "(%!FUNC!) Debounce Timer started. Existing -%!bool!\n", fInTimerQueue); + } + break; + // Ignore button presses if LED only + case DM_LED_ONLY: + default: + break; + } + + // Store switch state in device context + pDevContext->bCurrentSwitchState = bCurrentSwitchState; + pDevContext->bLatestToggledSwitch = bToggledSwitch; + } + else + { + TraceInfo(DBG_INIT, "(%!FUNC!) Not a radio switch toggle\n"); + } + TraceInfo(DBG_INIT, "(%!FUNC!) Switch 0x%x, prevSwitch:0x%x, X0R:0x%x\n", bCurrentSwitchState, bPrevSwitchState, bToggledSwitch); + + TraceVerbose(DBG_INIT, "(%!FUNC!) Exit\n"); +} + + + +// This function gets called when the timeout period of debounce timer elapses. +// It reports a switch change by completing a pending request +// +void HidFx2EvtTimerFunction(_In_ WDFTIMER hTimer) +{ + WDFDEVICE hDevice = NULL; + WDFREQUEST hRequest; + PDEVICE_EXTENSION pDevContext = NULL; + NTSTATUS status = STATUS_SUCCESS; + size_t cBytesReturned = 0; + unsigned char bToggledSwitch = 0; + ULONG cBytesToCopy = 0; + PHIDFX2_IO_REPORT pInputReport = NULL; + + TraceVerbose(DBG_IOCTL, "(%!FUNC!) Enter\n"); + + + hDevice = WdfTimerGetParentObject(hTimer); + pDevContext = GetDeviceContext(hDevice); + + bToggledSwitch = pDevContext->bLatestToggledSwitch; + TraceInfo(DBG_IOCTL, "(%!FUNC!) mode %d switch %d\n", pDevContext->driverMode, bToggledSwitch); + + if (!((pDevContext->driverMode == DM_BUTTON || pDevContext->driverMode == DM_BUTTON_AND_LED) && bToggledSwitch == 0)) + { + // Check if there are any pending requests in the Interrupt Message Queue. + // If a request is found then complete the pending request. + status = WdfIoQueueRetrieveNextRequest(pDevContext->hInterruptMsgQueue, &hRequest); + if (NT_SUCCESS(status)) + { + cBytesToCopy = sizeof(pInputReport[0]); + status = WdfRequestRetrieveOutputBuffer(hRequest, + cBytesToCopy, + &pInputReport, + &cBytesReturned); // BufferLength + if (NT_SUCCESS(status)) + { + TraceInfo(DBG_IOCTL, "(%!FUNC!) WdfRequestRetrieveOutputBuffer switch %d\n", bToggledSwitch); + + pInputReport->bReportId = GENERIC_DESKTOP_REPORT_ID; + pInputReport->bData = bToggledSwitch; + cBytesReturned = cBytesToCopy; + } + else // WdfRequestRetrieveOutputBuffer failed + { + TraceErr(DBG_IOCTL, "(%!FUNC!) WdfRequestRetrieveOutputBuffer failed with status: %!STATUS!\n", status); + } + + WdfRequestCompleteWithInformation(hRequest, status, cBytesReturned); + + } + else if (status != STATUS_NO_MORE_ENTRIES) + { + TraceErr(DBG_IOCTL, "(%!FUNC!) WdfIoQueueRetrieveNextRequest status %!STATUS!\n", status); + } + } + else + { + TraceInfo(DBG_IOCTL, "(%!FUNC!) ignore switch"); + } + + TraceVerbose(DBG_IOCTL, "(%!FUNC!) Exit\n"); +} + + + +// This function gets the switch state of the USB device directly from the hardware +// +NTSTATUS HidFx2GetSwitchState(_In_ WDFDEVICE hDevice, _Out_ unsigned char *pbSwitchState) +{ + PDEVICE_EXTENSION pDevContext = NULL; + NTSTATUS status = STATUS_SUCCESS; + WDF_MEMORY_DESCRIPTOR memDesc; + WDF_USB_CONTROL_SETUP_PACKET controlSetupPacket; + ULONG cBytesTransferred = 0; + + if(pbSwitchState != NULL) + { + *pbSwitchState = 0; + } + + TraceVerbose(DBG_IOCTL, "(%!FUNC!) Entry\n"); + + pDevContext = GetDeviceContext(hDevice); + + // set the segment state on the USB device + WDF_USB_CONTROL_SETUP_PACKET_INIT_VENDOR(&controlSetupPacket, + BmRequestDeviceToHost, + BmRequestToDevice, + HIDFX2_READ_SWITCH_STATE, // Request + 0, // Value + 0); // Index + + WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&memDesc, pbSwitchState, sizeof(*pbSwitchState)); + + status = WdfUsbTargetDeviceSendControlTransferSynchronously(pDevContext->hUsbDevice, + NULL, // Optional WDFREQUEST + NULL, // PWDF_REQUEST_SEND_OPTIONS + &controlSetupPacket, + &memDesc, + &cBytesTransferred); + + if (!NT_SUCCESS(status)) + { + TraceErr(DBG_IOCTL, "(%!FUNC!) Failed to read switch state - %!STATUS! \n", status); + } + else + { + TraceVerbose(DBG_IOCTL, "(%!FUNC!) Switch state is 0x%x\n", *pbSwitchState); + *pbSwitchState = ~(*pbSwitchState); // switchs are inverted on hardware boards + TraceVerbose(DBG_IOCTL, "(%!FUNC!) Switch state is 0x%x\n", *pbSwitchState); + } + + TraceVerbose(DBG_IOCTL, "(%!FUNC!) Exit, status: %!STATUS!\n", status); + return status; +} + + + +// EvtDeviceD0Entry event callback must perform any operations that are necessary before the specified device is used. +// Called every time the hardware needs to be initialized/reinitialized. +// This function is not marked pageable because this function is in the device power up path. +// This function runs at PASSIVE_LEVEL, even though it is not paged. +// +NTSTATUS HidFx2EvtDeviceD0Entry(_In_ WDFDEVICE hDevice, _In_ WDF_POWER_DEVICE_STATE previousState) +{ + PDEVICE_EXTENSION pDevContext = NULL; + NTSTATUS status = STATUS_SUCCESS; + unsigned char bSwitchState = 0; + unsigned char bMode = 0; + + pDevContext = GetDeviceContext(hDevice); + + TraceVerbose(DBG_PNP, "(%!FUNC!) Enter - coming from %S\n", DbgDevicePowerString(previousState)); + + SendVendorCommand(hDevice, HIDFX2_SET_BARGRAPH_DISPLAY, BARGRAPH_LED_ALL_OFF); + + // Retrieve the current switch state and store it in device context + status = HidFx2GetSwitchState(hDevice, &bSwitchState); + if (NT_SUCCESS(status)) + { + // Left most switches define Mode + bMode = bSwitchState & MODE_SELECTION_BUTTONS_BIT_MASK; + switch (bMode) + { + case SWITCHPACK_SELECTION_FOR_MODE2: + pDevContext->driverMode = DM_BUTTON_AND_LED; + SendVendorCommand(hDevice, HIDFX2_SET_7SEGMENT_DISPLAY, SEGMENT_DISPLAY_2); + break; + case SWITCHPACK_SELECTION_FOR_MODE3: + pDevContext->driverMode = DM_SLIDER_SWITCH; + SendVendorCommand(hDevice, HIDFX2_SET_7SEGMENT_DISPLAY, SEGMENT_DISPLAY_3); + break; + case SWITCHPACK_SELECTION_FOR_MODE4: + pDevContext->driverMode = DM_SLIDER_SWITCH_AND_LED; + SendVendorCommand(hDevice, HIDFX2_SET_7SEGMENT_DISPLAY, SEGMENT_DISPLAY_4); + break; + case SWITCHPACK_SELECTION_FOR_MODE5: + pDevContext->driverMode = DM_LED_ONLY; + SendVendorCommand(hDevice, HIDFX2_SET_7SEGMENT_DISPLAY, SEGMENT_DISPLAY_5); + break; + default: + pDevContext->driverMode = DM_BUTTON; + SendVendorCommand(hDevice, HIDFX2_SET_7SEGMENT_DISPLAY, SEGMENT_DISPLAY_1); + break; + } + + pDevContext->bCurrentSwitchState = bSwitchState; + + // Start the target. This will start the continuous reader + status = WdfIoTargetStart(WdfUsbTargetPipeGetIoTarget(pDevContext->hInterruptPipe)); + if (NT_SUCCESS(status)) + { + pDevContext->fIsPowerUpSwitchState = TRUE; + } + } + else + { + TraceErr(DBG_PNP, "(%!FUNC!) Failed to get current switch state, status: %!STATUS!\n", status); + } + + TraceVerbose(DBG_PNP, "(%!FUNC!) Exit, status: %!STATUS!\n", status); + return status; +} + + + +/* +This routine undoes anything done in EvtDeviceD0Entry. It is called whenever the device leaves the D0 state, which happens when the device is +stopped, when it is removed, and when it is powered off. + +The device is still in D0 when this callback is invoked, which means that the driver can still touch hardware in this routine. + +EvtDeviceD0Exit event callback must perform any operations that are necessary before the specified device is moved out of the D0 state. +If the driver needs to save hardware state before the device is powered down, then that should be done here. + +This function runs at PASSIVE_LEVEL, though it is generally not paged. A driver can optionally make this function pageable if DO_POWER_PAGABLE is set. + +Even if DO_POWER_PAGABLE isn't set, this function still runs at PASSIVE_LEVEL. +In this case, though, the function absolutely must not do anything that will cause a page fault. +*/ +NTSTATUS HidFx2EvtDeviceD0Exit(_In_ WDFDEVICE hDevice, _In_ WDF_POWER_DEVICE_STATE targetState) +{ + PDEVICE_EXTENSION pDevContext; + + PAGED_CODE(); + + TraceVerbose(DBG_PNP, "(%!FUNC!) Enter- moving to %S\n", DbgDevicePowerString(targetState)); + + pDevContext = GetDeviceContext(hDevice); + + WdfIoTargetStop(WdfUsbTargetPipeGetIoTarget(pDevContext->hInterruptPipe), WdfIoTargetCancelSentIo); + + TraceVerbose(DBG_PNP, "(%!FUNC!) Exit\n"); + + return STATUS_SUCCESS; +} + + + +PCWSTR DbgDevicePowerString(_In_ WDF_POWER_DEVICE_STATE powerState) +{ + switch (powerState) + { + case WdfPowerDeviceInvalid: + return L"WdfPowerDeviceInvalid"; + case WdfPowerDeviceD0: + return L"WdfPowerDeviceD0"; + case PowerDeviceD1: + return L"WdfPowerDeviceD1"; + case WdfPowerDeviceD2: + return L"WdfPowerDeviceD2"; + case WdfPowerDeviceD3: + return L"WdfPowerDeviceD3"; + case WdfPowerDeviceD3Final: + return L"WdfPowerDeviceD3Final"; + case WdfPowerDevicePrepareForHibernation: + return L"WdfPowerDevicePrepareForHibernation"; + case WdfPowerDeviceMaximum: + return L"PowerDeviceMaximum"; + default: + return L"UnKnown Device Power State"; + } +} + diff --git a/network/radio/RadioManagerSample/RadioManagerSample.sln b/network/radio/RadioManagerSample/RadioManagerSample.sln new file mode 100644 index 00000000..d5d0a144 --- /dev/null +++ b/network/radio/RadioManagerSample/RadioManagerSample.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0 +MinimumVisualStudioVersion = 12.0 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SampleRM", "cpp\SampleRM.vcxproj", "{165D39D6-68AC-4E1F-89ED-483E13E84F9B}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {165D39D6-68AC-4E1F-89ED-483E13E84F9B}.Debug|Win32.ActiveCfg = Debug|Win32 + {165D39D6-68AC-4E1F-89ED-483E13E84F9B}.Debug|Win32.Build.0 = Debug|Win32 + {165D39D6-68AC-4E1F-89ED-483E13E84F9B}.Release|Win32.ActiveCfg = Release|Win32 + {165D39D6-68AC-4E1F-89ED-483E13E84F9B}.Release|Win32.Build.0 = Release|Win32 + {165D39D6-68AC-4E1F-89ED-483E13E84F9B}.Debug|x64.ActiveCfg = Debug|x64 + {165D39D6-68AC-4E1F-89ED-483E13E84F9B}.Debug|x64.Build.0 = Debug|x64 + {165D39D6-68AC-4E1F-89ED-483E13E84F9B}.Release|x64.ActiveCfg = Release|x64 + {165D39D6-68AC-4E1F-89ED-483E13E84F9B}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/network/radio/RadioManagerSample/ReadMe.md b/network/radio/RadioManagerSample/ReadMe.md new file mode 100644 index 00000000..4c481bbd --- /dev/null +++ b/network/radio/RadioManagerSample/ReadMe.md @@ -0,0 +1,171 @@ +Windows Radio Management Sample +=============================== + +The Radio Manager sample demonstrates how to structure a Radio Manager for use with the Windows 8.1 Radio Management APIs. + +Starting with Windows 8.1, the operating system contains a set of APIs which are used as a software mechanism to control the various radios found on the machine. The APIs work by communicating with a Radio Manager, which is a COM object that relays commands from the APIs to turn the radio on or off, and reports back radio information to the APIs. This feature is designed in such a way that a separate Radio Manager is required for each radio media type. For example, a WLAN radio will be controlled by a different Radio Manager than a GPS radio. If there are 2 WLAN radios and a GPS radio, the 2 WLAN radios will be controlled by one Radio Manager, and the GPS radio will be controlled by a different Radio Manager. The Radio Manager must be able to run correctly within Local Service Account context. Under this context, the Radio Manager will have the minimum privilege on the local computer. + +When the user turns the radio off (either by using the specific radio software switch or the airplane mode switch), radio transmission must be turned off. The device can be powered off as long as the radio switch does not disappear from the UI. It is very important that the radio manager developer ensures that when the device is powered off, the radio switch does not disappear from the UI. If the radio switch disappears from the UI when the radio is turned off by the user, then user has no way to turn the radio back on! If it is desired to conserve power by cutting power to the device when the radio is turned off, but the device cannot be completely powered off because it disappears from the UI, then the solution would be to put the device in a low power state (e.g. D3). + +**Important**  The radio manager MUST be given a name. This is the name of the radio switch that is displayed to the user in the Wireless page of PC Settings. The name must be simple, yet descriptive of what the radio is. For example, for NFC radios, the value of the name field should be "NFC", and for GPS radios, the value of the name field should be "GPS" or "GNSS", whichever is more appropriate. The name must not include the word "radio" or the manufacturer's name or some other word related to the functionality of the radio (e.g. "Location" OR "port"). + + +Installation +------------ + +The sample contains a script, *install.cmd*, which copies the radio manager DLL to the system directory, registers as a COM component, and configures the registry. + +Copy the *install.cmd*, *SampleRM.reg* and *SampleRM.dll* files to a directory. Run *install.cmd*. + +Code Tour +--------- + +File + +Description + +install.cmd + +Installation script. Copies and registers the dll and executes SampleRM.reg. + +SampleRM.reg + +script to install the Sample Radio Manager into the registry, along with 2 radio instances. + +SampleRM.sln + +The Visual Studio solution file for building the Sample Radio Manager dll. + +sampleRM.idl + +The interface definition for the Sample Radio Manager. + +RadioMgr.idl + +The interface definition for a Windows Radio Manager. + +SampleRadioManager.h + +Header file for the functions required for a Radio Manager. + +SampleRadioInstance.h + +Header file for the functions required for a Radio Instance. + +SampleInstanceCollection.h + +Header file for the functions required for a Collection of Radio Instances. + +precomp.h + +Common header file. + +InternalInterfaces.h + +Header file for internal interface used for this sample. + +dllmain.cpp + +Standard dllmain. + +SampleRadioManager.cpp + +Implementation details for the Sample Radio Manager. Important concepts include: + +- Utilizing [IMediaRadioManagerNotifySink](http://msdn.microsoft.com/en-us/library/windows/hardware/hh406534) for radio instance events +- Adding/Removing radio instances +- Queuing and deploying worker jobs for system events + +SampleRadioInstance.cpp + +Implementation details for the Sample Radio Instance. Important concepts include: + +- Accessors & Modifiers for radio information +- Instance change functions + +SampleInstanceCollection.cpp + +Implementation details for the Sample Instance Collection. Important concepts include:l + +- Radio Instance discovery and retrieval + +RadioMgr\_interface.cpp + +Helper source file to include the MIDL-generated files. + +Run the sample +-------------- + +Operation +--------- + +This sample Radio Manager does not operate on an actual radio. Instead, it uses registry keys to act as virtual radios. + +Each "radio" instance can have the following values: + +Name + +RadioState + +PreviousRadioState + +IsMultiComm + +IsAssociatingDevice + +\*\*\* It is required that the registry key has AT LEAST a Name value, otherwise the Sample Radio Manager will fail to initialize. \*\*\* + +**Important**  The radio manager must be given a name and the registry key must have, as a minimum, a Name value. Otherwise, the Sample Radio Manager will fail to initialize. This is the name of the radio switch that is displayed to the user in the Wireless page of PC Settings. The name must be simple, yet descriptive of what the radio is. For example, for NFC radios, the value of the name field should be "NFC", and for GPS radios, the value of the name field should be "GPS" or "GNSS", whichever is more appropriate. The name must not include the word "radio" or the manufacturer's name or some other word related to the functionality of the radio (e.g. "Location" OR "port"). + +When the Radio Manager is initialized, it uses these registry keys to retrieve the "radio" information. The radio state values can be any of the following enum values: + + +++ + + + + + + + + + + +
C++
typedef enum _DEVICE_RADIO_STATE
+{
+    DRS_RADIO_ON                    = 0,
+    DRS_SW_RADIO_OFF                = 1,
+    DRS_HW_RADIO_OFF                = 2,
+    DRS_SW_HW_RADIO_OFF             = 3,
+    DRS_HW_RADIO_ON_UNCONTROLLABLE  = 4,
+    DRS_RADIO_INVALID               = 5,
+    DRS_HW_RADIO_OFF_UNCONTROLLABLE = 6,
+    DRS_RADIO_MAX                   = DRS_HW_RADIO_OFF_UNCONTROLLABLE
+} DEVICE_RADIO_STATE;
+ +For IsMultiComm and IsAssociatingDevice, a value of 0 means 'no' and 1 means 'yes'. + +Adding and Setting a Radio Instance +----------------------------------- + +To add a new radio instance, add a new instance key to the registry key like the following entry: + +``` {.syntax xml:space="preserve"} +[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\RadioManagement\Misc\SampleRadioManager\SampleRadioX] +"RadioState"=dword:00000000 +"Name"="SampleRadioX" +"IsMultiComm"=dword:00000000 +``` + +Editing a Radio Instance +------------------------ + +Simply change the values in the registry. For example, change the radio state from DRS\_RADIO\_ON to DRS\_SW\_RADIO\_OFF by changing the 'RadioState' value from 0 to 1. + +Removing a Radio Instance +------------------------- + +Delete the corresponding registry key. + diff --git a/network/radio/RadioManagerSample/SampleRM.reg b/network/radio/RadioManagerSample/SampleRM.reg new file mode 100644 index 00000000..3ba004f1 Binary files /dev/null and b/network/radio/RadioManagerSample/SampleRM.reg differ diff --git a/network/radio/RadioManagerSample/cpp/InternalInterfaces.h b/network/radio/RadioManagerSample/cpp/InternalInterfaces.h new file mode 100644 index 00000000..6e7f7b02 --- /dev/null +++ b/network/radio/RadioManagerSample/cpp/InternalInterfaces.h @@ -0,0 +1,23 @@ +#pragma once + +interface __declspec(uuid("{931D7B9C-11FB-45B6-97DA-47894D597F39}")) ISampleRadioInstanceInternal : public IUnknown +{ + IFACEMETHOD(OnSysRadioChange)(_In_ SYSTEM_RADIO_STATE sysRadioState) = 0; +}; + +interface __declspec(uuid("{98595167-4F34-4247-A669-CA41ABBC479A}")) ISampleRadioManagerInternal : public IUnknown +{ + IFACEMETHOD(OnInstanceRadioChange)(_In_ BSTR bstrRadioInstanceID, _In_ DEVICE_RADIO_STATE radioState) = 0; +}; + + +HRESULT CSampleRadioInstance_CreateInstance( + _In_ PCWSTR pszKeyName, + _In_ ISampleRadioManagerInternal *pParentManager, + _COM_Outptr_ ISampleRadioInstanceInternal **ppRadioInstance); + +HRESULT CRadioInstanceCollection_CreateInstance( + _In_ DWORD cInstances, + _In_reads_(cInstances) IRadioInstance **rgpIRadioInstance, + _COM_Outptr_ IRadioInstanceCollection **ppInstanceCollection); + diff --git a/network/radio/RadioManagerSample/cpp/RadioMgr.idl b/network/radio/RadioManagerSample/cpp/RadioMgr.idl new file mode 100644 index 00000000..5c7b5866 --- /dev/null +++ b/network/radio/RadioManagerSample/cpp/RadioMgr.idl @@ -0,0 +1,155 @@ +// +// Microsoft Windows +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: RadioMgr.idl +// +//---------------------------------------------------------------------------- + + +cpp_quote("//+-------------------------------------------------------------------------") +cpp_quote("//") +cpp_quote("// Microsoft Windows") +cpp_quote("// Copyright (c) Microsoft Corporation. All rights reserved.") +cpp_quote("//") +cpp_quote("//--------------------------------------------------------------------------") + +cpp_quote("#if (NTDDI_VERSION >= NTDDI_WIN8)") + +import "oaidl.idl"; +import "wtypes.idl"; + + +interface IMediaRadioManager; +interface IRadioInstanceCollection; +interface IRadioInstance; +interface IMediaRadioManagerNotifySink; + +typedef enum _DEVICE_RADIO_STATE +{ + DRS_RADIO_ON = 0, + DRS_SW_RADIO_OFF = 1, + DRS_HW_RADIO_OFF = 2, + DRS_SW_HW_RADIO_OFF = 3, + DRS_HW_RADIO_ON_UNCONTROLLABLE = 4, + DRS_RADIO_INVALID = 5, + DRS_HW_RADIO_OFF_UNCONTROLLABLE = 6, + DRS_RADIO_MAX = DRS_HW_RADIO_OFF_UNCONTROLLABLE +} DEVICE_RADIO_STATE; + +typedef enum _SYSTEM_RADIO_STATE +{ + SRS_RADIO_ENABLED = 0, + SRS_RADIO_DISABLED = 1, +} SYSTEM_RADIO_STATE; + +//+-------------------------------------------------------------------------------- +// IMediaRadioManager -- Represents high level radio operations on each radio type. +// The object implementing this interface will implement a Connection point (IConnectionPoint) +// for IMediaRadioManagerNotifySink. +// Each IMediaRadioManager object controls several or no IRadioInstance objects. +[ + local, + object, + uuid(6CFDCAB5-FC47-42A5-9241-074B58830E73), + pointer_default(unique) +] +interface IMediaRadioManager : IUnknown +{ + HRESULT GetRadioInstances( + [out] IRadioInstanceCollection **ppCollection + ); + + HRESULT OnSystemRadioStateChange( + [in] SYSTEM_RADIO_STATE sysRadioState, + [in] UINT32 uTimeoutSec + ); + +}; + + +//+--------------------------------------------------------------------------- +// IRadioInstanceCollection -- a flat list of radio instances +// +[ + local, + object, + uuid(E5791FAE-5665-4E0C-95BE-5FDE31644185), + pointer_default(unique) +] +interface IRadioInstanceCollection : IUnknown +{ + HRESULT GetCount( + [out] UINT32 *pcInstance + ); + + HRESULT GetAt( + [in] UINT32 uIndex, + [out] IRadioInstance **ppRadioInstance + ); +}; + +//+--------------------------------------------------------------------------- +// IRadioInstance -- Interface to control specific radio instance +// +[ + local, + object, + uuid(70AA1C9E-F2B4-4C61-86D3-6B9FB75FD1A2), + pointer_default(unique) +] +interface IRadioInstance : IUnknown +{ + HRESULT GetRadioManagerSignature( + [out] GUID *pguidSignature + ); + + HRESULT GetInstanceSignature( + [out, string] BSTR *pbstrId + ); + + HRESULT GetFriendlyName( + [in] LCID lcid, + [out, string] BSTR *pbstrName + ); + + HRESULT GetRadioState( + [out] DEVICE_RADIO_STATE *pRadioState + ); + + HRESULT SetRadioState( + [in] DEVICE_RADIO_STATE radioState, + [in] UINT32 uTimeoutSec + ); + + BOOL IsMultiComm(); + + BOOL IsAssociatingDevice(); +} + +//+--------------------------------------------------------------------------- +// IMediaRadioManagerNotifySink -- notify instance add/remove and radio state change event +// +[ + local, + object, + uuid(89D81F5F-C147-49ED-A11C-77B20C31E7C9), + pointer_default(unique) +] +interface IMediaRadioManagerNotifySink : IUnknown +{ + HRESULT OnInstanceAdd( + [in] IRadioInstance *pRadioInstance + ); + + HRESULT OnInstanceRemove( + [in, string] BSTR bstrRadioInstanceId + ); + + HRESULT OnInstanceRadioChange( + [in, string] BSTR bstrRadioInstanceId, + [in] DEVICE_RADIO_STATE radioState + ); +}; + +cpp_quote("#endif // (NTDDI >= NTDDI_WIN8)") diff --git a/network/radio/RadioManagerSample/cpp/RadioMgr_interface.cpp b/network/radio/RadioManagerSample/cpp/RadioMgr_interface.cpp new file mode 100644 index 00000000..427e27fe --- /dev/null +++ b/network/radio/RadioManagerSample/cpp/RadioMgr_interface.cpp @@ -0,0 +1,3 @@ +#include "precomp.h" +#pragma hdrstop +#include "RadioMgr_i.c" \ No newline at end of file diff --git a/network/radio/RadioManagerSample/cpp/SampleInstanceCollection.cpp b/network/radio/RadioManagerSample/cpp/SampleInstanceCollection.cpp new file mode 100644 index 00000000..5a4371de --- /dev/null +++ b/network/radio/RadioManagerSample/cpp/SampleInstanceCollection.cpp @@ -0,0 +1,102 @@ +#include "precomp.h" +#pragma hdrstop + +HRESULT CRadioInstanceCollection_CreateInstance( + _In_ DWORD cInstances, + _In_reads_(cInstances) IRadioInstance **rgpIRadioInstance, + _COM_Outptr_ IRadioInstanceCollection **ppInstanceCollection) +{ + return CRadioInstanceCollection::CreateInstance(cInstances, rgpIRadioInstance, ppInstanceCollection); +} + +void CRadioInstanceCollection::FinalRelease() +{ + POSITION p; + while (nullptr != (p = _listRadioInstances.GetHeadPosition())) + { + IRadioInstance *pRadioInstance = _listRadioInstances.GetAt(p); + pRadioInstance->Release(); + _listRadioInstances.SetAt(p, nullptr); + _listRadioInstances.RemoveHeadNoReturn(); + } +} + +// static +HRESULT CRadioInstanceCollection::CreateInstance( + _In_ DWORD cInstances, + _In_reads_(cInstances) IRadioInstance **rgpIRadioInstance, + _COM_Outptr_ IRadioInstanceCollection **ppInstanceCollection) +{ + HRESULT hr; + CComObject *pInstanceCollection; + CComPtr spInstanceCollection; + + *ppInstanceCollection = nullptr; + + hr = CComObject::CreateInstance(&pInstanceCollection); + + if (SUCCEEDED(hr) && (pInstanceCollection != nullptr)) + { + hr = pInstanceCollection->QueryInterface(IID_PPV_ARGS(&spInstanceCollection)); + } + + if (SUCCEEDED(hr) && (pInstanceCollection != nullptr)) + { + for (DWORD dwIndex = 0; dwIndex < cInstances; dwIndex++) + { + _ATLTRY + { + pInstanceCollection->_listRadioInstances.AddTail(rgpIRadioInstance[dwIndex]); + rgpIRadioInstance[dwIndex]->AddRef(); + } + _ATLCATCH(e) + { + hr = e; + break; + } + } + } + + if (SUCCEEDED(hr)) + { + *ppInstanceCollection = spInstanceCollection.Detach(); + } + + return hr; +} + +IFACEMETHODIMP CRadioInstanceCollection::GetCount(_Out_ UINT32 *pcInstance) +{ + if (nullptr == pcInstance) + { + return E_INVALIDARG; + } + + *pcInstance = static_cast(_listRadioInstances.GetCount()); + return S_OK; +} + +IFACEMETHODIMP CRadioInstanceCollection::GetAt(_In_ UINT32 uIndex, _COM_Outptr_ IRadioInstance **ppRadioInstance) +{ + if (nullptr == ppRadioInstance) + { + return E_INVALIDARG; + } + + HRESULT hr; + *ppRadioInstance = nullptr; + + POSITION p = _listRadioInstances.FindIndex(uIndex); + *ppRadioInstance = _listRadioInstances.GetAt(p); + if (nullptr != *ppRadioInstance) + { + (*ppRadioInstance)->AddRef(); + hr = S_OK; + } + else + { + hr = E_FAIL; + } + + return hr; +} diff --git a/network/radio/RadioManagerSample/cpp/SampleInstanceCollection.h b/network/radio/RadioManagerSample/cpp/SampleInstanceCollection.h new file mode 100644 index 00000000..b210adcb --- /dev/null +++ b/network/radio/RadioManagerSample/cpp/SampleInstanceCollection.h @@ -0,0 +1,32 @@ +#pragma once + +class ATL_NO_VTABLE CRadioInstanceCollection : + public CComObjectRootEx, + public CComCoClass, + public IRadioInstanceCollection +{ +public: + DECLARE_CLASSFACTORY() + DECLARE_NOT_AGGREGATABLE(CRadioInstanceCollection) + + DECLARE_NO_REGISTRY() + + BEGIN_COM_MAP(CRadioInstanceCollection) + COM_INTERFACE_ENTRY(IRadioInstanceCollection) + END_COM_MAP() + + DECLARE_PROTECT_FINAL_CONSTRUCT() + + void FinalRelease(); + + static HRESULT CreateInstance( + _In_ DWORD cInstances, + _In_reads_(cInstances) IRadioInstance **rgpIRadioInstance, + _COM_Outptr_ IRadioInstanceCollection **ppInstanceCollection); + + IFACEMETHOD(GetCount)(_Out_ UINT32 *pcInstance); + IFACEMETHOD(GetAt)(_In_ UINT32 uIndex, _COM_Outptr_ IRadioInstance **ppRadioInstance); + +private: + CAtlList _listRadioInstances; +}; diff --git a/network/radio/RadioManagerSample/cpp/SampleRM.def b/network/radio/RadioManagerSample/cpp/SampleRM.def new file mode 100644 index 00000000..535078cd --- /dev/null +++ b/network/radio/RadioManagerSample/cpp/SampleRM.def @@ -0,0 +1,8 @@ +LIBRARY SampleRM + +EXPORTS + DllCanUnloadNow PRIVATE + DllGetClassObject PRIVATE + DllRegisterServer PRIVATE + DllUnregisterServer PRIVATE + diff --git a/network/radio/RadioManagerSample/cpp/SampleRM.rc b/network/radio/RadioManagerSample/cpp/SampleRM.rc new file mode 100644 index 00000000..2f491770 --- /dev/null +++ b/network/radio/RadioManagerSample/cpp/SampleRM.rc @@ -0,0 +1,10 @@ +#include +#include + +#define VER_FILETYPE VFT_DLL +#define VER_FILESUBTYPE VFT2_UNKNOWN +#define VER_FILEDESCRIPTION_STR "Sample Radio Manager" +#define VER_INTERNALNAME_STR "SampleRM.dll" + +#include + diff --git a/network/radio/RadioManagerSample/cpp/SampleRM.vcxproj b/network/radio/RadioManagerSample/cpp/SampleRM.vcxproj new file mode 100644 index 00000000..f26b9385 --- /dev/null +++ b/network/radio/RadioManagerSample/cpp/SampleRM.vcxproj @@ -0,0 +1,326 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {165D39D6-68AC-4E1F-89ED-483E13E84F9B} + $(MSBuildProjectName) + Debug + Win32 + {6D846F43-0EBE-4FCD-90E5-915DE0BCBA42} + + + + Windows10 + False + Desktop + + WindowsApplicationForDrivers10.0 + DynamicLibrary + + + Windows10 + True + Desktop + + WindowsApplicationForDrivers10.0 + DynamicLibrary + + + Windows10 + False + Desktop + + WindowsApplicationForDrivers10.0 + DynamicLibrary + + + Windows10 + True + Desktop + + WindowsApplicationForDrivers10.0 + DynamicLibrary + + + + $(IntDir) + + + + + + + + + + + + + + + + SampleRM + + + SampleRM + + + SampleRM + + + SampleRM + + + + Sync + + + + + Sync + + + + + Sync + + + + + Sync + + + + + %(AdditionalOptions) -N + + + + + %(AdditionalOptions) -N + + + + + %(AdditionalOptions) -N + + + + + %(AdditionalOptions) -N + + + + Dynamic + + + Dynamic + + + Dynamic + + + Dynamic + + + + %(PreprocessorDefinitions);WIN32;UNICODE;_UNICODE;_NTSDK=1;WPP_USE_NTDLL_FUNCTIONS + + + %(PreprocessorDefinitions);WIN32;UNICODE;_UNICODE;_NTSDK=1;WPP_USE_NTDLL_FUNCTIONS + + + %(PreprocessorDefinitions);WIN32;UNICODE;_UNICODE;_NTSDK=1;WPP_USE_NTDLL_FUNCTIONS + + + + + %(PreprocessorDefinitions);WIN32;UNICODE;_UNICODE;_NTSDK=1;WPP_USE_NTDLL_FUNCTIONS + + + %(PreprocessorDefinitions);WIN32;UNICODE;_UNICODE;_NTSDK=1;WPP_USE_NTDLL_FUNCTIONS + + + %(PreprocessorDefinitions);WIN32;UNICODE;_UNICODE;_NTSDK=1;WPP_USE_NTDLL_FUNCTIONS + + + + + %(PreprocessorDefinitions);WIN32;UNICODE;_UNICODE;_NTSDK=1;WPP_USE_NTDLL_FUNCTIONS + + + %(PreprocessorDefinitions);WIN32;UNICODE;_UNICODE;_NTSDK=1;WPP_USE_NTDLL_FUNCTIONS + + + %(PreprocessorDefinitions);WIN32;UNICODE;_UNICODE;_NTSDK=1;WPP_USE_NTDLL_FUNCTIONS + + + + + %(PreprocessorDefinitions);WIN32;UNICODE;_UNICODE;_NTSDK=1;WPP_USE_NTDLL_FUNCTIONS + + + %(PreprocessorDefinitions);WIN32;UNICODE;_UNICODE;_NTSDK=1;WPP_USE_NTDLL_FUNCTIONS + + + %(PreprocessorDefinitions);WIN32;UNICODE;_UNICODE;_NTSDK=1;WPP_USE_NTDLL_FUNCTIONS + + + + + _DllMainCRTStartup@12 + _DllMainCRTStartup + + + + + _DllMainCRTStartup@12 + _DllMainCRTStartup + + + + + _DllMainCRTStartup@12 + _DllMainCRTStartup + + + + + _DllMainCRTStartup@12 + _DllMainCRTStartup + + + + + true + Level4 + %(AdditionalIncludeDirectories) + + + %(AdditionalDependencies);ntdll.lib;Kernel32.lib;advapi32.lib;oleaut32.lib;ole32.lib;uuid.lib;User32.lib + SampleRM.def + + + %(AdditionalIncludeDirectories) + + + %(AdditionalIncludeDirectories) + + + + + true + Level4 + %(AdditionalIncludeDirectories) + + + %(AdditionalDependencies);ntdll.lib;Kernel32.lib;advapi32.lib;oleaut32.lib;ole32.lib;uuid.lib;User32.lib + SampleRM.def + + + %(AdditionalIncludeDirectories) + + + %(AdditionalIncludeDirectories) + + + + + true + Level4 + %(AdditionalIncludeDirectories) + + + %(AdditionalDependencies);ntdll.lib;Kernel32.lib;advapi32.lib;oleaut32.lib;ole32.lib;uuid.lib;User32.lib + SampleRM.def + + + %(AdditionalIncludeDirectories) + + + %(AdditionalIncludeDirectories) + + + + + true + Level4 + %(AdditionalIncludeDirectories) + + + %(AdditionalDependencies);ntdll.lib;Kernel32.lib;advapi32.lib;oleaut32.lib;ole32.lib;uuid.lib;User32.lib + SampleRM.def + + + %(AdditionalIncludeDirectories) + + + %(AdditionalIncludeDirectories) + + + + + ;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ;%(AdditionalIncludeDirectories) + precomp.h + Create + $(IntDir)\precomp.h.pch + + + ;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/network/radio/RadioManagerSample/cpp/SampleRM.vcxproj.Filters b/network/radio/RadioManagerSample/cpp/SampleRM.vcxproj.Filters new file mode 100644 index 00000000..837a0aab --- /dev/null +++ b/network/radio/RadioManagerSample/cpp/SampleRM.vcxproj.Filters @@ -0,0 +1,45 @@ + + + + + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* + {6C044E6F-8320-46E5-9EBE-BDB0427DF29D} + + + h;hpp;hxx;hm;inl;inc;xsd + {55F7F46D-B2E7-422F-8140-2F6D4D30D4FE} + + + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml + {EB9B7D59-264D-421A-8077-FA89E50F57CF} + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Resource Files + + + \ No newline at end of file diff --git a/network/radio/RadioManagerSample/cpp/SampleRadioInstance.cpp b/network/radio/RadioManagerSample/cpp/SampleRadioInstance.cpp new file mode 100644 index 00000000..08f7e285 --- /dev/null +++ b/network/radio/RadioManagerSample/cpp/SampleRadioInstance.cpp @@ -0,0 +1,523 @@ +#include "precomp.h" +#pragma hdrstop + +HRESULT CSampleRadioInstance_CreateInstance( + _In_ PCWSTR pszKeyName, + _In_ ISampleRadioManagerInternal *pParentManager, + _COM_Outptr_ ISampleRadioInstanceInternal **ppRadioInstance) +{ + return CSampleRadioInstance::CreateInstance(pszKeyName, pParentManager, ppRadioInstance); +} + +PCWSTR CSampleRadioInstance::s_pszInstanceName = L"Name"; +PCWSTR CSampleRadioInstance::s_pszInstanceRadioState = L"RadioState"; +PCWSTR CSampleRadioInstance::s_pszPreviousRadioState = L"PreviousRadioState"; +PCWSTR CSampleRadioInstance::s_pszMultiComm = L"IsMultiComm"; +PCWSTR CSampleRadioInstance::s_pszAssocatingDevice = L"IsAssociatingDevice"; + +CSampleRadioInstance::CSampleRadioInstance() + : _pParentManager(nullptr), + _fClosing(false), + _fIsMultiCommDevice(false) +{ +} + +void CSampleRadioInstance::FinalRelease() +{ + if ((nullptr != _hRegChangeEvent) && (nullptr != _hEventThread)) + { + { + // Critical section scope. + CComCritSecLock lock(_criticalSection); + _fClosing = true; + SetEvent(_hRegChangeEvent); + } + WaitForSingleObject(_hEventThread, INFINITE); + } + + _Cleanup(); +} + +// static +HRESULT CSampleRadioInstance::CreateInstance( + _In_ PCWSTR pszKeyName, + _In_ ISampleRadioManagerInternal *pParentManager, + _COM_Outptr_ ISampleRadioInstanceInternal **ppRadioInstance) +{ + HRESULT hr; + CComObject *pRadioInstance; + CComPtr spRadioInstanceInternal; + + *ppRadioInstance = nullptr; + + hr = CComObject::CreateInstance(&pRadioInstance); + if (SUCCEEDED(hr) && (pRadioInstance != nullptr)) + { + hr = pRadioInstance->QueryInterface(IID_PPV_ARGS(&spRadioInstanceInternal)); + } + if (SUCCEEDED(hr) && (pRadioInstance != nullptr)) + { + hr = pRadioInstance->_Init(pszKeyName, pParentManager); + } + if (SUCCEEDED(hr)) + { + *ppRadioInstance = spRadioInstanceInternal.Detach(); + } + + return hr; +} + +HRESULT CSampleRadioInstance::_Init(_In_ PCWSTR pszKeyName, _In_ ISampleRadioManagerInternal *pParentManager) +{ + HRESULT hr; + DWORD dwError; + WCHAR szInstanceName[128] = {}; + DWORD cchInstanceName = ARRAYSIZE(szInstanceName); + + _ATLTRY + { + _strInstanceId = pszKeyName; + } + _ATLCATCH(e) + { + return e; + } + + _pParentManager = pParentManager; + + dwError = _hKeyRoot.Open(HKEY_LOCAL_MACHINE, _strInstanceId, KEY_ALL_ACCESS); + + + if (ERROR_SUCCESS == dwError) + { + dwError = _hKeyRoot.QueryStringValue(s_pszInstanceName, szInstanceName, &cchInstanceName); + + if (ERROR_SUCCESS == dwError) + { + _ATLTRY + { + _strInstanceName = szInstanceName; + } + _ATLCATCH(e) + { + UNREFERENCED_PARAMETER(e); + dwError = ERROR_OUTOFMEMORY; + } + + if (ERROR_SUCCESS == dwError) + { + DWORD dwTemp = 0; + dwError = _hKeyRoot.QueryDWORDValue(s_pszMultiComm, dwTemp); + // only when key read successfully with non zero value, we regard device as multicomm chip + if ((ERROR_SUCCESS == dwError) && (0 != dwTemp)) + { + _fIsMultiCommDevice = true; + } + + // ignore the case when there is no IsMultiComm value in the registry, set ERROR_SUCCESS to continue with _Init + dwError = ERROR_SUCCESS; + } + } + } + + // register the regkey value change event + if (ERROR_SUCCESS == dwError) + { + HANDLE hRegChangeEvent = ::CreateEvent(nullptr, TRUE, FALSE, nullptr); + if ((NULL == hRegChangeEvent) || (INVALID_HANDLE_VALUE == hRegChangeEvent)) + { + dwError = GetLastError(); + } + else + { + _hRegChangeEvent.Attach(hRegChangeEvent); + } + } + + if (ERROR_SUCCESS == dwError) + { + HANDLE hThread= ::CreateThread(nullptr, + 0, + CSampleRadioInstance::s_ThreadInstanceChange, + reinterpret_cast(this), + 0, + nullptr); + + if ((NULL == hThread) || (INVALID_HANDLE_VALUE == hThread)) + { + dwError = GetLastError(); + } + else + { + _hEventThread.Attach(hThread); + } + + } + + hr = HRESULT_FROM_WIN32(dwError); + + if (FAILED(hr)) + { + _Cleanup(); + } + + return hr; +} + +void CSampleRadioInstance::_Cleanup() +{ + if (nullptr != _pParentManager) + { + _pParentManager = nullptr; + } +} + +IFACEMETHODIMP CSampleRadioInstance::GetRadioManagerSignature(_Out_ GUID *pguidSignature) +{ + if (nullptr == pguidSignature) + { + return E_INVALIDARG; + } + + *pguidSignature = __uuidof(SampleRadioManager); + + return S_OK; +} + +IFACEMETHODIMP CSampleRadioInstance::GetInstanceSignature(_Out_ BSTR *pbstrID) +{ + if (nullptr == pbstrID) + { + return E_INVALIDARG; + } + + HRESULT hr = S_OK; + + *pbstrID = _strInstanceId.AllocSysString(); + if (nullptr == *pbstrID) + { + hr = E_OUTOFMEMORY; + } + + return hr; +} + +IFACEMETHODIMP CSampleRadioInstance::GetFriendlyName(_In_ LCID /* lcid*/, _Out_ BSTR *pbstrName) +{ + if (nullptr == pbstrName) + { + return E_INVALIDARG; + } + + HRESULT hr = S_OK; + + *pbstrName = _strInstanceName.AllocSysString(); + if (nullptr == *pbstrName) + { + hr = E_OUTOFMEMORY; + } + + return hr; +} + +IFACEMETHODIMP CSampleRadioInstance::GetRadioState(_Out_ DEVICE_RADIO_STATE *pRadioState) +{ + if (nullptr == pRadioState) + { + return E_INVALIDARG; + } + + DWORD dwRadioState; + DEVICE_RADIO_STATE radioState = DRS_RADIO_ON; + + *pRadioState = DRS_RADIO_ON; + + // Read radio state directly from device. we do not save radio state in our module to avoid out of sync + DWORD dwError = _hKeyRoot.QueryDWORDValue(s_pszInstanceRadioState, dwRadioState); + + if (ERROR_SUCCESS == dwError) + { + if ((dwRadioState > DRS_RADIO_MAX) || (dwRadioState == DRS_RADIO_INVALID)) + { + radioState = DRS_HW_RADIO_ON_UNCONTROLLABLE; + } + else + { + radioState = static_cast(dwRadioState); + } + + *pRadioState = radioState; + } + + return HRESULT_FROM_WIN32(dwError); +} + + +IFACEMETHODIMP CSampleRadioInstance::SetRadioState(_In_ DEVICE_RADIO_STATE radioState, _In_ UINT32 uTimeoutSec) +{ + if ((radioState != DRS_RADIO_ON) && (radioState != DRS_SW_RADIO_OFF)) + { + return E_INVALIDARG; // invalid input + } + + DEVICE_RADIO_STATE drsCurrent; + bool fRefAdded = false; + HRESULT hr = GetRadioState(&drsCurrent); + + // fail to get current radio state or current radio state is uncontrollable + if (FAILED(hr) || (drsCurrent & DRS_HW_RADIO_ON_UNCONTROLLABLE)) + { + return E_FAIL; + } + + if ((drsCurrent & DRS_SW_RADIO_OFF) == radioState) + { + return S_OK; // current software radio is same as target software radio + } + + // Keep all other bits same, only change the last bit of radio state to represent software radio change + DEVICE_RADIO_STATE drsState = static_cast((drsCurrent & DRS_HW_RADIO_OFF) | radioState); + + CAutoPtr spSetDeviceRadioJob; + + spSetDeviceRadioJob.Attach(new SET_DEVICE_RADIO_JOB); + if (nullptr == spSetDeviceRadioJob) + { + hr = E_OUTOFMEMORY; + } + + if (SUCCEEDED(hr)) + { + spSetDeviceRadioJob->hr = E_FAIL; + spSetDeviceRadioJob->drsTarget = drsState; + spSetDeviceRadioJob->pInstance = this; + + // Let working thread hold ref on object such that object won't be released before working thread return. + this->AddRef(); + fRefAdded = true; + + HANDLE hEvent = ::CreateEvent(nullptr, TRUE, FALSE, nullptr); + if (nullptr == hEvent) + { + hr = HRESULT_FROM_WIN32(GetLastError()); + } + else + { + spSetDeviceRadioJob->hEvent.Attach(hEvent); + } + } + + if (SUCCEEDED(hr)) + { + if (!QueueUserWorkItem(CSampleRadioInstance::s_ThreadSetRadio, spSetDeviceRadioJob, WT_EXECUTEDEFAULT)) + { + hr = HRESULT_FROM_WIN32(GetLastError()); + } + } + + if (SUCCEEDED(hr)) + { + DWORD dwIgnore; + hr = CoWaitForMultipleHandles(0, + uTimeoutSec * 1000, + 1, + reinterpret_cast(&(spSetDeviceRadioJob->hEvent)), + &dwIgnore); + if (RPC_S_CALLPENDING == hr) + { + spSetDeviceRadioJob.Detach(); + } + else + { + hr = spSetDeviceRadioJob->hr; + } + } + + if (fRefAdded) + { + this->Release(); + } + return hr; +} + +IFACEMETHODIMP_(BOOL) CSampleRadioInstance::IsMultiComm() +{ + return _fIsMultiCommDevice ? TRUE : FALSE; +} + +IFACEMETHODIMP_(BOOL) CSampleRadioInstance::IsAssociatingDevice() +{ + BOOL fIsAssociatingDevice = FALSE; + DWORD dwAssociatingDevice = 0; + + DWORD dwError = _hKeyRoot.QueryDWORDValue(s_pszAssocatingDevice, dwAssociatingDevice); + + // When key read successfully with non zero value, we regard device associating now. + if ((ERROR_SUCCESS == dwError) && (0 != dwAssociatingDevice)) + { + fIsAssociatingDevice = TRUE; + } + + return fIsAssociatingDevice; +} + +IFACEMETHODIMP CSampleRadioInstance::OnSysRadioChange(_In_ SYSTEM_RADIO_STATE sysRadioState) +{ + if ((sysRadioState != SRS_RADIO_ENABLED) && (sysRadioState != SRS_RADIO_DISABLED)) + { + return E_INVALIDARG; + } + + DEVICE_RADIO_STATE drsCurrent; + DWORD dwError = ERROR_SUCCESS; + DEVICE_RADIO_STATE drsTarget = DRS_RADIO_ON; + DEVICE_RADIO_STATE drsPrevious = DRS_RADIO_ON; + DWORD dwPreviousState; + bool fSetRadioState = false; + + HRESULT hr = GetRadioState(&drsCurrent); + + // fail to get current radio state or current radio state is uncontrollable, ignore this call + if (FAILED(hr) || (drsCurrent & DRS_HW_RADIO_ON_UNCONTROLLABLE)) + { + return S_OK; + } + + if (SRS_RADIO_ENABLED == sysRadioState) + { + // If device current software radio is already on during system radio enabled, + // we ignore the saved previous radio state and do nothing. + // radio state will be updated only when current state is off during system radio enabling. + if (DRS_RADIO_ON != (drsCurrent & DRS_SW_RADIO_OFF)) + { + // System radio enable, need get previous radio state and set to previous radio state. + // If fail to get previous radio state, assume previous radio state is software radio on. + dwError = _hKeyRoot.QueryDWORDValue(s_pszPreviousRadioState, dwPreviousState); + + if (ERROR_SUCCESS == dwError) + { + if ((DRS_RADIO_ON == dwPreviousState) || (DRS_SW_RADIO_OFF == dwPreviousState)) + { + drsPrevious = static_cast(dwPreviousState); + } + } + + if ((drsCurrent & DRS_SW_RADIO_OFF) != drsPrevious) + { + drsTarget = static_cast((drsCurrent & DRS_HW_RADIO_OFF) | drsPrevious); + fSetRadioState = true; + } + } + } + else + { // System radio disable, need record previous radio state. + _hKeyRoot.SetDWORDValue(s_pszPreviousRadioState, static_cast(drsCurrent)); + + if ((drsCurrent & DRS_SW_RADIO_OFF) != DRS_SW_RADIO_OFF) + { + drsTarget = static_cast((drsCurrent & DRS_HW_RADIO_OFF) | DRS_SW_RADIO_OFF); + fSetRadioState = true; + } + } + + if (fSetRadioState) + { + dwError = _hKeyRoot.SetDWORDValue(s_pszInstanceRadioState, static_cast(drsTarget)); + } + + return HRESULT_FROM_WIN32(dwError); +} + +HRESULT CSampleRadioInstance::_SetRadioState(_In_ DEVICE_RADIO_STATE radioState) +{ + DWORD dwError = _hKeyRoot.SetDWORDValue(s_pszInstanceRadioState, static_cast(radioState)); + + return HRESULT_FROM_WIN32(dwError); +} + +void CSampleRadioInstance::_OnInstanceUpdate() +{ + DWORD dwError; + DWORD dwRadioState = 0; + DEVICE_RADIO_STATE drsCurrent; + + dwError = _hKeyRoot.QueryDWORDValue(s_pszInstanceRadioState, dwRadioState); + + if (ERROR_SUCCESS == dwError) + { + if ((dwRadioState > DRS_RADIO_MAX) || (dwRadioState == DRS_RADIO_INVALID)) + { + drsCurrent = DRS_HW_RADIO_ON_UNCONTROLLABLE; + } + else + { + drsCurrent = static_cast(dwRadioState); + } + CComBSTR sbstrID = _strInstanceId.AllocSysString(); + + if (nullptr != sbstrID) + { + _pParentManager->OnInstanceRadioChange(sbstrID, drsCurrent); + } + } +} + +DWORD WINAPI CSampleRadioInstance::s_ThreadInstanceChange(LPVOID pThis) +{ + CSampleRadioInstance *pRadioInstance = reinterpret_cast(pThis); + DWORD dwError = ERROR_SUCCESS; + + { + CComCritSecLock lock(pRadioInstance->_criticalSection); + if (pRadioInstance->_fClosing) + { + dwError = ERROR_APP_INIT_FAILURE; + } + else + { + dwError = pRadioInstance->_hKeyRoot.NotifyChangeKeyValue(FALSE, + REG_NOTIFY_CHANGE_LAST_SET, + pRadioInstance->_hRegChangeEvent, + TRUE); + } + } + + if (ERROR_SUCCESS != dwError) + { + return dwError; + } + + + while (ERROR_SUCCESS == dwError) + { + WaitForSingleObject(pRadioInstance->_hRegChangeEvent, INFINITE); + + { + CComCritSecLock lock(pRadioInstance->_criticalSection); + if (pRadioInstance->_fClosing) + { + break; + } + + ResetEvent(pRadioInstance->_hRegChangeEvent); + + dwError = pRadioInstance->_hKeyRoot.NotifyChangeKeyValue(FALSE, + REG_NOTIFY_CHANGE_LAST_SET, + pRadioInstance->_hRegChangeEvent, + TRUE); + } + pRadioInstance->_OnInstanceUpdate(); + } + + return dwError; +} + +DWORD WINAPI CSampleRadioInstance::s_ThreadSetRadio(LPVOID pThis) +{ + SET_DEVICE_RADIO_JOB *pJob = reinterpret_cast(pThis); + + pJob->hr = pJob->pInstance->_SetRadioState(pJob->drsTarget); + + SetEvent(pJob->hEvent); + return ERROR_SUCCESS; +} diff --git a/network/radio/RadioManagerSample/cpp/SampleRadioInstance.h b/network/radio/RadioManagerSample/cpp/SampleRadioInstance.h new file mode 100644 index 00000000..176aca3c --- /dev/null +++ b/network/radio/RadioManagerSample/cpp/SampleRadioInstance.h @@ -0,0 +1,71 @@ +#pragma once + +class ATL_NO_VTABLE CSampleRadioInstance : + public CComObjectRootEx, + public CComCoClass, + public IRadioInstance, + public ISampleRadioInstanceInternal +{ +public: + DECLARE_CLASSFACTORY() + DECLARE_NOT_AGGREGATABLE(CSampleRadioInstance) + DECLARE_NO_REGISTRY() + + BEGIN_COM_MAP(CSampleRadioInstance) + COM_INTERFACE_ENTRY(IRadioInstance) + COM_INTERFACE_ENTRY(ISampleRadioInstanceInternal) + END_COM_MAP() + + CSampleRadioInstance(); + + void FinalRelease(); + + static HRESULT CreateInstance( + _In_ PCWSTR pszKeyName, + _In_ ISampleRadioManagerInternal *pParentManager, + _COM_Outptr_ ISampleRadioInstanceInternal **pRadioInstance); + + // IRadioInstance + IFACEMETHOD(GetRadioManagerSignature)(_Out_ GUID *pguidSignature); + IFACEMETHOD(GetInstanceSignature)(_Out_ BSTR *pbstrID); + IFACEMETHOD(GetFriendlyName)(_In_ LCID lcid, _Out_ BSTR *pbstrName); + IFACEMETHOD(GetRadioState)(_Out_ DEVICE_RADIO_STATE *pRadioState); + IFACEMETHOD(SetRadioState)(_In_ DEVICE_RADIO_STATE radioState, _In_ UINT32 uTimeoutSec); + IFACEMETHOD_(BOOL, IsMultiComm)(); + IFACEMETHOD_(BOOL, IsAssociatingDevice)(); + + // ISampleRadioInstanceInternal + IFACEMETHOD(OnSysRadioChange)(_In_ SYSTEM_RADIO_STATE sysRadioSate); + +private: + HRESULT _Init(_In_ PCWSTR pszKeyName, _In_ ISampleRadioManagerInternal *pParentManager); + void _Cleanup(); + void _OnInstanceUpdate(); + HRESULT _SetRadioState(_In_ DEVICE_RADIO_STATE radioState); + static DWORD WINAPI s_ThreadInstanceChange(LPVOID pThis); + static DWORD WINAPI s_ThreadSetRadio(LPVOID pThis); + + ISampleRadioManagerInternal *_pParentManager; + CComAutoCriticalSection _criticalSection; + CString _strInstanceId; + CString _strInstanceName; + bool _fIsMultiCommDevice; + + CHandle _hEventThread; + bool _fClosing; // object is closing + CHandle _hRegChangeEvent; + CRegKey _hKeyRoot; + static PCWSTR s_pszInstanceName; + static PCWSTR s_pszInstanceRadioState; + static PCWSTR s_pszPreviousRadioState; + static PCWSTR s_pszMultiComm; + static PCWSTR s_pszAssocatingDevice; +}; + +typedef struct _SET_DEVICE_RADIO_JOB{ + HRESULT hr; + CHandle hEvent; + CSampleRadioInstance *pInstance; + DEVICE_RADIO_STATE drsTarget; +} SET_DEVICE_RADIO_JOB; + diff --git a/network/radio/RadioManagerSample/cpp/SampleRadioManager.cpp b/network/radio/RadioManagerSample/cpp/SampleRadioManager.cpp new file mode 100644 index 00000000..53bc4757 --- /dev/null +++ b/network/radio/RadioManagerSample/cpp/SampleRadioManager.cpp @@ -0,0 +1,570 @@ +#include "precomp.h" +#pragma hdrstop + +PCWSTR CSampleRadioManager::s_pszRootKey = L"SYSTEM\\CurrentControlSet\\Control\\RadioManagement\\Misc\\SampleRadioManager"; + +CSampleRadioManager::CSampleRadioManager() + : _fClosing(false) +{ +} + +HRESULT CSampleRadioManager::FinalConstruct() +{ + DWORD dwError; + HRESULT hr = S_OK; + WCHAR szSubKeyName[128]; + DWORD cchSubKeyName; + + dwError = _hKeyRoot.Open(HKEY_LOCAL_MACHINE, s_pszRootKey, KEY_ALL_ACCESS); + + + if (ERROR_SUCCESS == dwError) + { + + // Enumerate all instances + DWORD dwCount = 0; + while (true) + { + cchSubKeyName = ARRAYSIZE(szSubKeyName); + dwError = _hKeyRoot.EnumKey(dwCount, szSubKeyName, &cchSubKeyName, NULL); + + if (ERROR_SUCCESS == dwError) + { + CString strSubKeyName; + _ATLTRY + { + strSubKeyName.Format(L"%s\\%s", s_pszRootKey, szSubKeyName); + } + _ATLCATCH(e) + { + hr = e; + } + if (SUCCEEDED(hr)) + { + hr = _AddInstance(strSubKeyName, nullptr); + } + + dwCount++; + } + else + { + dwError = ERROR_SUCCESS; + break; + } + } + + } + + // register the regkey subkey add/remove event + if (ERROR_SUCCESS == dwError) + { + HANDLE hRegChangeEvent = ::CreateEvent(nullptr, TRUE, FALSE, nullptr); + if (nullptr == hRegChangeEvent) + { + dwError = GetLastError(); + } + else + { + _hRegChangeEvent.Attach(hRegChangeEvent); + } + } + + if (ERROR_SUCCESS == dwError) + { + HANDLE hThread = ::CreateThread(nullptr, + 0, + CSampleRadioManager::s_ThreadRegChange, + reinterpret_cast(this), + 0, + nullptr); + + if (nullptr == hThread) + { + dwError = GetLastError(); + } + else + { + _hEventThread.Attach(hThread); + } + } + + hr = HRESULT_FROM_WIN32(dwError); + + if (FAILED(hr)) + { + _Cleanup(); + } + + return hr; +} + +void CSampleRadioManager::FinalRelease() +{ + if ((nullptr != _hRegChangeEvent) && (nullptr != _hEventThread)) + { + { + CComCritSecLock lock(_criticalSection); + + _fClosing = true; + SetEvent(_hRegChangeEvent); // inform reg listening thread obj is leaving + } + + WaitForSingleObject(_hEventThread, INFINITE); // wait reg listening thread finish + } + + _Cleanup(); +} + +void CSampleRadioManager::_Cleanup() +{ + POSITION p; + while (nullptr != (p = _listRadioInstances.GetHeadPosition())) + { + INSTANCE_LIST_OBJ *pListObj = _listRadioInstances.GetAt(p); + if (nullptr != pListObj) + { + _listRadioInstances.SetAt(p, nullptr); + _listRadioInstances.RemoveHeadNoReturn(); + delete pListObj; + } + } +} + +IFACEMETHODIMP CSampleRadioManager::GetRadioInstances(_Out_ IRadioInstanceCollection **ppCollection) +{ + CAutoVectorPtr rgpIRadioInstance; + HRESULT hr = S_OK; + DWORD cInstance; + + if (nullptr == ppCollection) + { + return E_INVALIDARG; + } + + *ppCollection = nullptr; + + CComCritSecLock lock(_criticalSection); + cInstance = static_cast(_listRadioInstances.GetCount()); + if (cInstance > 0) + { + if (!rgpIRadioInstance.Allocate(cInstance)) + { + hr = E_OUTOFMEMORY; + } + if (SUCCEEDED(hr)) + { + ZeroMemory(rgpIRadioInstance, sizeof(rgpIRadioInstance[0]) * cInstance); + DWORD dwIndex = 0; + + for (POSITION p = _listRadioInstances.GetHeadPosition(); nullptr != p; _listRadioInstances.GetNext(p)) + { + hr = (_listRadioInstances.GetAt(p))->spRadioInstance.QueryInterface(&(rgpIRadioInstance[dwIndex])); + if (FAILED(hr)) + { + break; + } + else + { + dwIndex++; + } + } + } + } + + if (SUCCEEDED(hr)) + { + hr = CRadioInstanceCollection_CreateInstance(cInstance, rgpIRadioInstance, ppCollection); + } + + for (DWORD dwIndex = 0; dwIndex < cInstance; dwIndex++) + { + if (nullptr != rgpIRadioInstance[dwIndex]) + { + rgpIRadioInstance[dwIndex]->Release(); + } + } + + return hr; +} + +IFACEMETHODIMP CSampleRadioManager::OnSystemRadioStateChange( + _In_ SYSTEM_RADIO_STATE sysRadioState, + _In_ UINT32 uTimeoutSec) +{ + HRESULT hr = S_OK; + CAutoPtr spSetSysRadioJob; + bool fRefAdded = false; + + spSetSysRadioJob.Attach(new SET_SYS_RADIO_JOB); + if (nullptr == spSetSysRadioJob) + { + hr = E_OUTOFMEMORY; + } + + if (SUCCEEDED(hr)) + { + spSetSysRadioJob->hr = E_FAIL; + spSetSysRadioJob->srsTarget = sysRadioState; + spSetSysRadioJob->pSampleRM = this; + + // Add ref to object to avoid object release before working thread return + this->AddRef(); + fRefAdded = true; + + HANDLE hEvent = ::CreateEvent(nullptr, TRUE, FALSE, nullptr); + if (nullptr == hEvent) + { + hr = HRESULT_FROM_WIN32(GetLastError()); + } + else + { + spSetSysRadioJob->hEvent.Attach(hEvent); + } + } + + if (SUCCEEDED(hr)) + { + if (!QueueUserWorkItem(CSampleRadioManager::s_ThreadSetSysRadio, spSetSysRadioJob, WT_EXECUTEDEFAULT)) + { + hr = HRESULT_FROM_WIN32(GetLastError()); + } + } + + if (SUCCEEDED(hr)) + { + DWORD dwIgnore; + hr = CoWaitForMultipleHandles(0, + uTimeoutSec * 1000, + 1, + reinterpret_cast(&(spSetSysRadioJob->hEvent)), + &dwIgnore); + if (RPC_S_CALLPENDING == hr) + { + spSetSysRadioJob.Detach(); + } + else + { + hr = spSetSysRadioJob->hr; + } + } + + if (fRefAdded) + { + this->Release(); + } + + return hr; +} + +IFACEMETHODIMP CSampleRadioManager::OnInstanceRadioChange( + _In_ BSTR bstrRadioInstanceID, + _In_ DEVICE_RADIO_STATE radioState) +{ + return _FireEventOnInstanceRadioChange(bstrRadioInstanceID, radioState); +} + +HRESULT CSampleRadioManager::_FireEventOnInstanceAdd(_In_ IRadioInstance *pRadioInstance) +{ + HRESULT hr; + + Lock(); + for (IUnknown** ppUnkSrc = m_vec.begin(); ppUnkSrc < m_vec.end(); ppUnkSrc++) + { + if ((nullptr != ppUnkSrc) && (nullptr != *ppUnkSrc)) + { + CComPtr spSink; + + hr = (*ppUnkSrc)->QueryInterface(IID_PPV_ARGS(&spSink)); + if (SUCCEEDED(hr)) + { + spSink->OnInstanceAdd(pRadioInstance); + } + } + } + Unlock(); + + return S_OK; +} + +HRESULT CSampleRadioManager::_FireEventOnInstanceRemove(_In_ BSTR bstrRadioInstanceID) +{ + HRESULT hr; + + Lock(); + for (IUnknown** ppUnkSrc = m_vec.begin(); ppUnkSrc < m_vec.end(); ppUnkSrc++) + { + if ((nullptr != ppUnkSrc) && (nullptr != *ppUnkSrc)) + { + CComPtr spSink; + + hr = (*ppUnkSrc)->QueryInterface(IID_PPV_ARGS(&spSink)); + if (SUCCEEDED(hr)) + { + spSink->OnInstanceRemove(bstrRadioInstanceID); + } + } + } + Unlock(); + + return S_OK; +} + +HRESULT CSampleRadioManager::_FireEventOnInstanceRadioChange( + _In_ BSTR bstrRadioInstanceID, + _In_ DEVICE_RADIO_STATE radioState + ) +{ + HRESULT hr; + + Lock(); + for (IUnknown** ppUnkSrc = m_vec.begin(); ppUnkSrc < m_vec.end(); ppUnkSrc++) + { + if ((nullptr != ppUnkSrc) && (nullptr != *ppUnkSrc)) + { + CComPtr spSink; + + hr = (*ppUnkSrc)->QueryInterface(IID_PPV_ARGS(&spSink)); + if (SUCCEEDED(hr)) + { + spSink->OnInstanceRadioChange(bstrRadioInstanceID, radioState); + } + } + } + Unlock(); + + return S_OK; +} + + +HRESULT CSampleRadioManager::_AddInstance(_In_ PCWSTR pszKeyName, _Out_opt_ IRadioInstance **ppRadioInstance) +{ + HRESULT hr = S_OK; + CComPtr spRadioInstance; + CAutoPtr spInstanceObj; + + CComCritSecLock lock(_criticalSection); + + spInstanceObj.Attach(new INSTANCE_LIST_OBJ); + if (nullptr == spInstanceObj) + { + hr = E_OUTOFMEMORY; + } + + if (SUCCEEDED(hr)) + { + CComPtr spRMInternal = this; + hr = CSampleRadioInstance_CreateInstance(pszKeyName, spRMInternal, &spRadioInstance); + } + + if (SUCCEEDED(hr)) + { + spInstanceObj->fExisting = true; + spInstanceObj->spRadioInstance = spRadioInstance; + + _ATLTRY + { + spInstanceObj->strRadioInstanceID = pszKeyName; + _listRadioInstances.AddTail(spInstanceObj); + spInstanceObj.Detach(); + } + _ATLCATCH(e) + { + hr = e; + } + + if (SUCCEEDED(hr)) + { + if (ppRadioInstance != nullptr) + { + hr = spRadioInstance->QueryInterface(IID_PPV_ARGS(ppRadioInstance)); + } + } + } + + return hr; +} + +void CSampleRadioManager::_OnInstanceAddRemove() +{ + DWORD dwError; + HRESULT hr= S_OK; + WCHAR szSubKeyName[128]; + DWORD cchSubKeyName; + POSITION p; + + // Set all instances as invalid + for (p = _listRadioInstances.GetHeadPosition(); p != nullptr; _listRadioInstances.GetNext(p)) + { + INSTANCE_LIST_OBJ *pRadioInstanceObj = _listRadioInstances.GetAt(p); + pRadioInstanceObj->fExisting = false; + } + + DWORD dwCount = 0; + while (true) + { + cchSubKeyName = ARRAYSIZE(szSubKeyName); + dwError = _hKeyRoot.EnumKey(dwCount, szSubKeyName, &cchSubKeyName, NULL); + + if (ERROR_SUCCESS == dwError) + { + CString strKeyName; + _ATLTRY + { + strKeyName.Format(L"%s\\%s",s_pszRootKey,szSubKeyName); + } + _ATLCATCH(e) + { + hr = e; + } + + if (SUCCEEDED(hr)) + { + for (p = _listRadioInstances.GetHeadPosition(); p != nullptr; _listRadioInstances.GetNext(p)) + { + INSTANCE_LIST_OBJ *pRadioInstanceObj = _listRadioInstances.GetAt(p); + if (pRadioInstanceObj->strRadioInstanceID == strKeyName) + { + break; + } + } + + // find new instance + if (nullptr == p) + { + CComPtr spRadioInstance; + hr = _AddInstance(strKeyName, &spRadioInstance); + if(SUCCEEDED(hr)) + { + _FireEventOnInstanceAdd(spRadioInstance); + } + } + else + { + // The instance still valid. + INSTANCE_LIST_OBJ *pRadioInstanceObj = _listRadioInstances.GetAt(p); + pRadioInstanceObj->fExisting = true; + } + } + + dwCount++; + } + else + { + dwError = ERROR_SUCCESS; + break; + } + } + + // Remove deleted instance from list + p = _listRadioInstances.GetHeadPosition(); + while (nullptr != p) + { + INSTANCE_LIST_OBJ *pRadioInstanceObj = _listRadioInstances.GetAt(p); + if ((pRadioInstanceObj != nullptr) && !pRadioInstanceObj->fExisting) + { + POSITION pTmp = p; + _listRadioInstances.GetPrev(pTmp); + + _listRadioInstances.RemoveAt(p); + CComBSTR bstrTmp = pRadioInstanceObj->strRadioInstanceID.AllocSysString(); + if (nullptr != bstrTmp) + { + _FireEventOnInstanceRemove(bstrTmp); + } + delete pRadioInstanceObj; + p = pTmp; + } + + if (nullptr != p) + { + _listRadioInstances.GetNext(p); + } + else + { + p = _listRadioInstances.GetHeadPosition(); + } + } +} + +HRESULT CSampleRadioManager::_SetSysRadioState(_In_ SYSTEM_RADIO_STATE sysRadioState) +{ + // Since set regkey is fast enough, this implemtation is to set instance radio sequentially. + // If set instance radio takes long time and there are multiple instance within one RM, + // it is better to do it parallelly. + HRESULT hr = S_OK; + CComCritSecLock lock(_criticalSection); + for (POSITION p = _listRadioInstances.GetHeadPosition(); nullptr != p; _listRadioInstances.GetNext(p)) + { + INSTANCE_LIST_OBJ *pInstanceObj = _listRadioInstances.GetAt(p); + hr = pInstanceObj->spRadioInstance->OnSysRadioChange(sysRadioState); + if (FAILED(hr)) + { + break; + } + } + return hr; +} + +DWORD WINAPI CSampleRadioManager::s_ThreadRegChange(LPVOID pThis) +{ + CSampleRadioManager *pRadioMgr = reinterpret_cast(pThis); + DWORD dwError = ERROR_SUCCESS; + + { + CComCritSecLock lock(pRadioMgr->_criticalSection); + if (pRadioMgr->_fClosing) + { + dwError = ERROR_APP_INIT_FAILURE; + } + else + { + dwError = pRadioMgr->_hKeyRoot.NotifyChangeKeyValue(FALSE, + REG_NOTIFY_CHANGE_NAME, + pRadioMgr->_hRegChangeEvent, + TRUE); + } + } + + if (ERROR_SUCCESS != dwError) + { + return dwError; + } + + while (ERROR_SUCCESS == dwError) + { + if (WaitForSingleObject(pRadioMgr->_hRegChangeEvent, INFINITE) == WAIT_FAILED) + { + break; + } + + { + CComCritSecLock lock(pRadioMgr->_criticalSection); + if (pRadioMgr->_fClosing) // main thread is leaving + { + break; + } + + ResetEvent(pRadioMgr->_hRegChangeEvent); + + dwError = pRadioMgr->_hKeyRoot.NotifyChangeKeyValue(FALSE, + REG_NOTIFY_CHANGE_NAME, + pRadioMgr->_hRegChangeEvent, + TRUE); + } + // Receive reg subkey add/remove event. update list + pRadioMgr->_OnInstanceAddRemove(); + } + + return dwError; +} + +DWORD WINAPI CSampleRadioManager::s_ThreadSetSysRadio(LPVOID pThis) +{ + SET_SYS_RADIO_JOB *pJob = reinterpret_cast(pThis); + + pJob->hr = pJob->pSampleRM->_SetSysRadioState(pJob->srsTarget); + + SetEvent(pJob->hEvent); + return ERROR_SUCCESS; +} + diff --git a/network/radio/RadioManagerSample/cpp/SampleRadioManager.h b/network/radio/RadioManagerSample/cpp/SampleRadioManager.h new file mode 100644 index 00000000..a39673ed --- /dev/null +++ b/network/radio/RadioManagerSample/cpp/SampleRadioManager.h @@ -0,0 +1,79 @@ +#pragma once + +typedef struct { + CString strRadioInstanceID; + bool fExisting; + CComPtr spRadioInstance; +} INSTANCE_LIST_OBJ; + +EXTERN_C const IID IID_IMediaRadioManagerNotifySink; + +class ATL_NO_VTABLE CSampleRadioManager : + public CComObjectRootEx, + public CComCoClass, + public IConnectionPointContainerImpl, + public IConnectionPointImpl, + public IMediaRadioManager, + public ISampleRadioManagerInternal +{ +public: + + DECLARE_CLASSFACTORY() + DECLARE_NOT_AGGREGATABLE(CSampleRadioManager) + + DECLARE_NO_REGISTRY() + + BEGIN_COM_MAP(CSampleRadioManager) + COM_INTERFACE_ENTRY(IMediaRadioManager) + COM_INTERFACE_ENTRY(ISampleRadioManagerInternal) + COM_INTERFACE_ENTRY_IMPL(IConnectionPointContainer) + END_COM_MAP() + + BEGIN_CONNECTION_POINT_MAP(CSampleRadioManager) + CONNECTION_POINT_ENTRY(IID_IMediaRadioManagerNotifySink) + END_CONNECTION_POINT_MAP() + + DECLARE_PROTECT_FINAL_CONSTRUCT() + + CSampleRadioManager(); + + HRESULT FinalConstruct(); + void FinalRelease(); + + // IMediaRadioManager interface + IFACEMETHOD(GetRadioInstances)(_Out_ IRadioInstanceCollection **ppCollection); + IFACEMETHOD(OnSystemRadioStateChange)(_In_ SYSTEM_RADIO_STATE sysRadioState, _In_ UINT32 uTimeoutSec); + + // ISampleRadioManagerInternal interface + IFACEMETHOD(OnInstanceRadioChange)(_In_ BSTR bstrRadioInstanceID, _In_ DEVICE_RADIO_STATE radioState); + +private: + HRESULT _FireEventOnInstanceAdd(_In_ IRadioInstance *pRadioInstance); + HRESULT _FireEventOnInstanceRemove(_In_ BSTR bstrRadioInstanceID); + HRESULT _FireEventOnInstanceRadioChange(_In_ BSTR bstrRadioInstanceID, _In_ DEVICE_RADIO_STATE radioState); + + void _Cleanup(); + HRESULT _AddInstance(_In_ PCWSTR pszKeyName, _Out_opt_ IRadioInstance **ppRadioInstance); + void _OnInstanceAddRemove(); + HRESULT _SetSysRadioState(_In_ SYSTEM_RADIO_STATE sysRadioState); + static DWORD WINAPI s_ThreadRegChange(LPVOID pThis); + static DWORD WINAPI s_ThreadSetSysRadio(LPVOID pThis); + + CComAutoCriticalSection _criticalSection; + CAtlList _listRadioInstances; + + CRegKey _hKeyRoot; + CHandle _hRegChangeEvent; + CHandle _hEventThread; + bool _fClosing; // object is closing + + static PCWSTR s_pszRootKey; +}; + +typedef struct _SET_SYS_RADIO_JOB{ + HRESULT hr; + CHandle hEvent; + CSampleRadioManager *pSampleRM; + SYSTEM_RADIO_STATE srsTarget; +} SET_SYS_RADIO_JOB; + diff --git a/network/radio/RadioManagerSample/cpp/dllmain.cpp b/network/radio/RadioManagerSample/cpp/dllmain.cpp new file mode 100644 index 00000000..61d6898b --- /dev/null +++ b/network/radio/RadioManagerSample/cpp/dllmain.cpp @@ -0,0 +1,57 @@ +#include "precomp.h" +#pragma hdrstop + +OBJECT_ENTRY_AUTO(__uuidof(SampleRadioManager), CSampleRadioManager); + +class CSampleRadioModule : public CAtlDllModuleT +{ +public: +}; + +static CSampleRadioModule s_AtlModule; + +//+--------------------------------------------------------------------------- +// DLL Entry Point +// + +EXTERN_C BOOL WINAPI DllMain +( + HINSTANCE /*hInstance*/, + DWORD dwReason, + LPVOID pvReserved +) +{ + return s_AtlModule.DllMain(dwReason, pvReserved); +} + +STDAPI DllCanUnloadNow(void) +{ + return s_AtlModule.DllCanUnloadNow(); +} + +STDAPI DllGetClassObject( + _In_ REFCLSID rclsid, + _In_ REFIID riid, + _Outptr_ LPVOID* ppv + ) +{ + return s_AtlModule.DllGetClassObject(rclsid, riid, ppv); +} + + +//+--------------------------------------------------------------------------- +// Adds entries to the system registry. Needed because the binary need copy to test machine. +// If binary is deployed by manifest, these functions are not needed. +STDAPI +DllRegisterServer () +{ + s_AtlModule.DllRegisterServer(FALSE); + return S_OK; +} + +STDAPI +DllUnregisterServer () +{ + HRESULT hr = s_AtlModule.DllUnregisterServer(); + return hr; +} diff --git a/network/radio/RadioManagerSample/cpp/precomp.h b/network/radio/RadioManagerSample/cpp/precomp.h new file mode 100644 index 00000000..346a3fe6 --- /dev/null +++ b/network/radio/RadioManagerSample/cpp/precomp.h @@ -0,0 +1,17 @@ +#include +#include + +// ATL includes +#include +#include +#include +#include + + +// radio mamanager includes +#include "RadioMgr.h" +#include "SampleRM.h" +#include "internalInterfaces.h" +#include "SampleRadioInstance.h" +#include "SampleInstanceCollection.h" +#include "SampleRadioManager.h" diff --git a/network/radio/RadioManagerSample/cpp/precompsrc.cpp b/network/radio/RadioManagerSample/cpp/precompsrc.cpp new file mode 100644 index 00000000..5944cf51 --- /dev/null +++ b/network/radio/RadioManagerSample/cpp/precompsrc.cpp @@ -0,0 +1 @@ +#include "precomp.h" \ No newline at end of file diff --git a/network/radio/RadioManagerSample/cpp/sampleRM.idl b/network/radio/RadioManagerSample/cpp/sampleRM.idl new file mode 100644 index 00000000..64ec3fc5 --- /dev/null +++ b/network/radio/RadioManagerSample/cpp/sampleRM.idl @@ -0,0 +1,21 @@ +import "oaidl.idl"; +import "RadioMgr.idl"; + +[ + uuid(4BE52AA0-EF10-420F-9341-681FBCCD772C), + version(1.0), + helpstring("Sample Radio Manager library") +] +library SampleRadioManagerLib +{ + importlib("stdole2.tlb"); + + [ + uuid(41DC5063-AFAF-47DF-86B3-4B2ED82A82CF), + helpstring("Sample Media Radio Manager") + ] + coclass SampleRadioManager + { + [default] interface IMediaRadioManager; + } +} diff --git a/network/radio/RadioManagerSample/install.cmd b/network/radio/RadioManagerSample/install.cmd new file mode 100644 index 00000000..59b84572 --- /dev/null +++ b/network/radio/RadioManagerSample/install.cmd @@ -0,0 +1,3 @@ +copy SampleRM.dll %windir%\system32\ +regsvr32 SampleRM.dll +SampleRM.reg diff --git a/network/radio/RadioManagerSample/readme.txt b/network/radio/RadioManagerSample/readme.txt new file mode 100644 index 00000000..2bdd69bd --- /dev/null +++ b/network/radio/RadioManagerSample/readme.txt @@ -0,0 +1,192 @@ +Sample Radio Manager +==================== +Demonstrates how to structure a Radio Manager for use with the Windows 8 Radio Management APIs. + +On Windows 8 and later, the operating system contains a set of APIs which are used as a software mechanism +to control the various radios found on the machine. The APIs work by communicating with a Radio Manager, +which is a COM object that relays commands from the APIs to turn the radio on or off, and reports back +radio information to the APIs. This feature is designed in such a way that a separate Radio Manager is +required for each radio media type. For example, a WLAN radio will be controlled by a different Radio +Manager than a GPS radio. If there are 2 WLAN radios and a GPS radio, the 2 WLAN radios will be controlled +by one Radio Manager, and the GPS radio will be controlled by a different Radio Manager. The Radio Manager +must be able to run correctly within Local Service Account context. Under this context, the Radio Manager +will have the minimum privilege on the local computer. + +When the user turns the radio off (either by using the specific radio software switch or the airplane mode switch), +radio transmission must be turned off. The device can be powered off as long as the radio switch does not disappear +from the UI. It is very important that the radio manager developer ensures that when the device is powered off, the +radio switch does not disappear from the UI. If the radio switch disappears from the UI when the radio is turned off +by the user, then user has no way to turn the radio back on! If it is desired to conserve power by cutting power to +the device when the radio is turned off, but the device cannot be completely powered off because it disappears from +the UI, then the solution would be to put the device in a low power state (e.g. D3). + +IMPORTANT! The radio manager must be given a name – this is the name of the radio switch that is displayed to the +user in the Wireless page of PC Settings. The name must be simple, yet descriptive of what the radio is. For example, +for NFC radios, the value of the name field should be "NFC", and for GPS radios, the value of the name field should +be "GPS" or "GNSS", whichever is more appropriate. The name must not include the word "radio" or the manufacturer's +name or some other word related to the functionality of the radio (e.g. "Location" OR "port"). + + + +Sample Language Implementations +=============================== +This sample is available in the following language implementations: + C++ + + +Installation Files +================== +install.cmd +- Installation script. Copies and registers the dll and executes SampleRM.reg + +SampleRM.reg +- script to install the Sample Radio Manager into the registry, along with 2 radio instances + + +Source Files +============ +SampleRM.sln +- The Visual Studio 2010 solution file for building the Sample Radio Manager dll + +sampleRM.idl +- The interface definition for the Sample Radio Manager + +RadioMgr.idl +- The interface definition for a Windows Radio Manager + +SampleRadioManager.h +- Header file for the functions required for a Radio Manager + +SampleRadioInstance.h +- Header file for the functions required for a Radio Instance + +SampleInstanceCollection.h +- Header file for the functions required for a Collection of Radio Instances + +precomp.h +- Common header file + +InternalInterfaces.h +- Header file for internal interface used for this sample + +dllmain.cpp +- Standard dllmain + +SampleRadioManager.cpp +- Implementation details for the Sample Radio Manager. Important concepts include: + - Utilizing IMediaRadioManagerNotifySink for radio instance events + - Adding/Removing radio instances + - Queuing and deploying worker jobs for system events + +SampleRadioInstance.cpp +- Implementation details for the Sample Radio Instance. Important concepts include: + - Accessors & Modifiers for radio information + - Instance change functions + +SampleInstanceCollection.cpp +- Implementation details for the Sample Instance Collection. Important concepts include: + - Radio Instance discovery and retrieval + +RadioMgr_interface.cpp +- Helper source file to include the MIDL-generated files. + + +How the sample works +==================== +This sample Radio Manager does not operate on an actual radio. Instead, it uses registry keys to act as +virtual radios. Each "radio" instance can have the following values: + -Name + -RadioState + -PreviousRadioState + -IsMultiComm + -IsAssociatingDevice + +***It is required that the registry key has AT LEAST a Name value, otherwise the Sample Radio Manager will +fail to initialize*** + +IMPORTANT! The radio manager must be given a name – this is the name of the radio switch that is displayed to the +user in the Wireless page of PC Settings. The name must be simple, yet descriptive of what the radio is. For example, +for NFC radios, the value of the name field should be "NFC", and for GPS radios, the value of the name field should +be "GPS" or "GNSS", whichever is more appropriate. The name must not include the word "radio" or the manufacturer's +name or some other word related to the functionality of the radio (e.g. "Location" OR "port"). + + +When the Radio Manager is initialized, it uses these registry keys to retrieve the "radio" information. +The radio state values can be any of the following enum values: + + typedef enum _DEVICE_RADIO_STATE + { + DRS_RADIO_ON = 0, + DRS_SW_RADIO_OFF = 1, + DRS_HW_RADIO_OFF = 2, + DRS_SW_HW_RADIO_OFF = 3, + DRS_HW_RADIO_ON_UNCONTROLLABLE = 4, + DRS_RADIO_INVALID = 5, + DRS_HW_RADIO_OFF_UNCONTROLLABLE = 6, + DRS_RADIO_MAX = DRS_HW_RADIO_OFF_UNCONTROLLABLE + } DEVICE_RADIO_STATE; + +For IsMultiComm and IsAssociatingDevice, a value of 0 means 'no' and 1 means 'yes. + + +To Add a Radio Instance +======================= +Add a new item to the registry: +[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\RadioManagement\Misc\SampleRadioManager\SampleRadioX] +"RadioState"=dword:00000000 +"Name"="SampleRadioX" +"IsMultiComm"=dword:00000000 + +To Edit a Radio Instance +======================== +Simply change the values in the registry. For example, change the radio state from DRS_RADIO_ON to DRS_SW_RADIO_OFF +by changing the 'RadioState' value from 0 to 1. + + +To Remove a Radio Instance +========================== +Delete the corresponding registry key. + + +Prerequisites for viewing and building solution +=============================================== +1. Windows 7 +2. Visual Studio 2010 + + +To build the sample using Visual Studio 2010 (preferred method): +=============================================================== +1. Open File Explorer and navigate to the directory. +2. Double-click the icon for the SampleRM.sln (solution) file to open the file in Visual Studio. +3. In the Build menu, select Build Solution. The dll will be built in the default \Debug or \Release directory + + +Prerequisites for installing Radio Manager +========================================== +1. Windows 8 +2. The VC++ 2010 Redistributable package must be installed for this dll to load. + + +Installing Radio Manager +======================== +1. Copy the install.cmd, SampleRM.reg and SampleRM.dll files to a directory +2. Run install.cmd + + + + + + + + + + + + + + + + + + + diff --git a/network/trans/ddproxy/ddproxy.sln b/network/trans/ddproxy/ddproxy.sln index 9115b369..b420611e 100644 --- a/network/trans/ddproxy/ddproxy.sln +++ b/network/trans/ddproxy/ddproxy.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ddproxy", "sys\ddproxy.vcxproj", "{F5ED1745-0947-474A-924D-CB5D3D2D6C5E}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ddproxy", "sys\ddproxy.vcxproj", "{CBE3E4FB-B5D5-46F1-B97E-B8400FC372C8}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +13,14 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {F5ED1745-0947-474A-924D-CB5D3D2D6C5E}.Debug|Win32.ActiveCfg = Debug|Win32 - {F5ED1745-0947-474A-924D-CB5D3D2D6C5E}.Debug|Win32.Build.0 = Debug|Win32 - {F5ED1745-0947-474A-924D-CB5D3D2D6C5E}.Release|Win32.ActiveCfg = Release|Win32 - {F5ED1745-0947-474A-924D-CB5D3D2D6C5E}.Release|Win32.Build.0 = Release|Win32 - {F5ED1745-0947-474A-924D-CB5D3D2D6C5E}.Debug|x64.ActiveCfg = Debug|x64 - {F5ED1745-0947-474A-924D-CB5D3D2D6C5E}.Debug|x64.Build.0 = Debug|x64 - {F5ED1745-0947-474A-924D-CB5D3D2D6C5E}.Release|x64.ActiveCfg = Release|x64 - {F5ED1745-0947-474A-924D-CB5D3D2D6C5E}.Release|x64.Build.0 = Release|x64 + {CBE3E4FB-B5D5-46F1-B97E-B8400FC372C8}.Debug|Win32.ActiveCfg = Debug|Win32 + {CBE3E4FB-B5D5-46F1-B97E-B8400FC372C8}.Debug|Win32.Build.0 = Debug|Win32 + {CBE3E4FB-B5D5-46F1-B97E-B8400FC372C8}.Release|Win32.ActiveCfg = Release|Win32 + {CBE3E4FB-B5D5-46F1-B97E-B8400FC372C8}.Release|Win32.Build.0 = Release|Win32 + {CBE3E4FB-B5D5-46F1-B97E-B8400FC372C8}.Debug|x64.ActiveCfg = Debug|x64 + {CBE3E4FB-B5D5-46F1-B97E-B8400FC372C8}.Debug|x64.Build.0 = Debug|x64 + {CBE3E4FB-B5D5-46F1-B97E-B8400FC372C8}.Release|x64.ActiveCfg = Release|x64 + {CBE3E4FB-B5D5-46F1-B97E-B8400FC372C8}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/network/trans/ddproxy/sys/ddproxy.vcxproj b/network/trans/ddproxy/sys/ddproxy.vcxproj index 9fd6e6af..516c68a3 100644 --- a/network/trans/ddproxy/sys/ddproxy.vcxproj +++ b/network/trans/ddproxy/sys/ddproxy.vcxproj @@ -19,12 +19,12 @@
- {F5ED1745-0947-474A-924D-CB5D3D2D6C5E} + {CBE3E4FB-B5D5-46F1-B97E-B8400FC372C8} $(MSBuildProjectName) 1 Debug Win32 - {91B8C3EC-EC68-40D0-BDAE-FECDC2A5A69E} + {4805FA90-5926-46C2-845B-2FC0F749B960} diff --git a/network/trans/ddproxy/sys/ddproxy.vcxproj.Filters b/network/trans/ddproxy/sys/ddproxy.vcxproj.Filters index 9728a6bb..6d7db8de 100644 --- a/network/trans/ddproxy/sys/ddproxy.vcxproj.Filters +++ b/network/trans/ddproxy/sys/ddproxy.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {667070D4-ABD3-4134-83D9-C2E8E3B4D990} + {58F05CCD-742F-44E4-8DCB-61983C2AAC0C} h;hpp;hxx;hm;inl;inc;xsd - {55D8461C-9BC4-4CBA-8364-1C9E8628AD2E} + {6FA03C9B-94CF-45F5-ADA3-F23B54700362} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {89C687B6-C04D-48DD-BFC4-36AB091E7E94} + {6D410DAF-C0BC-40CF-8D06-F53EA77C7354} inf;inv;inx;mof;mc; - {3E15A537-E520-445D-AFC4-4CFCEF6234E6} + {6F97EAF5-00A6-4E35-9A51-AF4244397FF6} diff --git a/network/trans/inspect/inspect.sln b/network/trans/inspect/inspect.sln index 79901c54..eb1f632d 100644 --- a/network/trans/inspect/inspect.sln +++ b/network/trans/inspect/inspect.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "inspect", "sys\inspect.vcxproj", "{43AC1739-03F1-4465-8A16-F5FCD06BC2E9}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "inspect", "sys\inspect.vcxproj", "{F850B54F-985A-485A-A99A-E787184F31D8}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +13,14 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {43AC1739-03F1-4465-8A16-F5FCD06BC2E9}.Debug|Win32.ActiveCfg = Debug|Win32 - {43AC1739-03F1-4465-8A16-F5FCD06BC2E9}.Debug|Win32.Build.0 = Debug|Win32 - {43AC1739-03F1-4465-8A16-F5FCD06BC2E9}.Release|Win32.ActiveCfg = Release|Win32 - {43AC1739-03F1-4465-8A16-F5FCD06BC2E9}.Release|Win32.Build.0 = Release|Win32 - {43AC1739-03F1-4465-8A16-F5FCD06BC2E9}.Debug|x64.ActiveCfg = Debug|x64 - {43AC1739-03F1-4465-8A16-F5FCD06BC2E9}.Debug|x64.Build.0 = Debug|x64 - {43AC1739-03F1-4465-8A16-F5FCD06BC2E9}.Release|x64.ActiveCfg = Release|x64 - {43AC1739-03F1-4465-8A16-F5FCD06BC2E9}.Release|x64.Build.0 = Release|x64 + {F850B54F-985A-485A-A99A-E787184F31D8}.Debug|Win32.ActiveCfg = Debug|Win32 + {F850B54F-985A-485A-A99A-E787184F31D8}.Debug|Win32.Build.0 = Debug|Win32 + {F850B54F-985A-485A-A99A-E787184F31D8}.Release|Win32.ActiveCfg = Release|Win32 + {F850B54F-985A-485A-A99A-E787184F31D8}.Release|Win32.Build.0 = Release|Win32 + {F850B54F-985A-485A-A99A-E787184F31D8}.Debug|x64.ActiveCfg = Debug|x64 + {F850B54F-985A-485A-A99A-E787184F31D8}.Debug|x64.Build.0 = Debug|x64 + {F850B54F-985A-485A-A99A-E787184F31D8}.Release|x64.ActiveCfg = Release|x64 + {F850B54F-985A-485A-A99A-E787184F31D8}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/network/trans/inspect/sys/inspect.vcxproj b/network/trans/inspect/sys/inspect.vcxproj index d403b025..cf5d67cb 100644 --- a/network/trans/inspect/sys/inspect.vcxproj +++ b/network/trans/inspect/sys/inspect.vcxproj @@ -19,12 +19,12 @@ - {43AC1739-03F1-4465-8A16-F5FCD06BC2E9} + {F850B54F-985A-485A-A99A-E787184F31D8} $(MSBuildProjectName) 1 Debug Win32 - {CA2EEED8-4078-42F4-947A-29D46ACCC30F} + {1BE47893-DEA2-451D-B25B-B9485B05A13E} diff --git a/network/trans/inspect/sys/inspect.vcxproj.Filters b/network/trans/inspect/sys/inspect.vcxproj.Filters index 7fbd1b25..b8b1fd4b 100644 --- a/network/trans/inspect/sys/inspect.vcxproj.Filters +++ b/network/trans/inspect/sys/inspect.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {89A4FDF7-7B2B-42A3-A13C-4855905159BF} + {090AD1B0-632B-470E-A4F5-19B122F18E4A} h;hpp;hxx;hm;inl;inc;xsd - {893A15B9-96A4-4181-9353-D9C59D6D343C} + {1F438D75-BA91-40B8-A34B-21A50AB1DB2D} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {174E13A1-2D15-477C-9E80-060424681A41} + {C99C7FAB-3055-4C61-98EC-42F2C637694C} inf;inv;inx;mof;mc; - {3D55D549-7A89-4DEB-9C7B-149E8332DD7C} + {6EEC81C3-277F-4A14-831C-A84E74534082} diff --git a/network/trans/msnmntr/exe/monitor.vcxproj b/network/trans/msnmntr/exe/monitor.vcxproj index 06902c7c..47135984 100644 --- a/network/trans/msnmntr/exe/monitor.vcxproj +++ b/network/trans/msnmntr/exe/monitor.vcxproj @@ -19,11 +19,11 @@ - {BF8F75F9-23E9-4925-96A1-76FD729EBA93} + {FCC67889-AD0A-4C2F-A826-7D2AD714FC6A} $(MSBuildProjectName) Debug Win32 - {DED4B73F-AFBE-4142-AD53-004F9F079AA7} + {BC6143C7-DF6C-4466-8AF0-FBE869102EEC} diff --git a/network/trans/msnmntr/exe/monitor.vcxproj.Filters b/network/trans/msnmntr/exe/monitor.vcxproj.Filters index 2838b33f..88c9cd7f 100644 --- a/network/trans/msnmntr/exe/monitor.vcxproj.Filters +++ b/network/trans/msnmntr/exe/monitor.vcxproj.Filters @@ -3,15 +3,15 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {AB53852E-BB5F-49F9-8184-98DAFA476C33} + {E70DDE2C-E112-4C1D-AFC4-39EA907AE848} h;hpp;hxx;hm;inl;inc;xsd - {253A5086-E26E-4352-B8E1-BBBEB6A81F31} + {16A331F5-433A-4195-BA31-CB3D082B7F8A} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {714E88E3-7CAD-4F49-8A28-32DD65C6691E} + {ECFC1BCD-5BF5-4402-B1D2-3C2CDE9E5291} diff --git a/network/trans/msnmntr/msnmntr.sln b/network/trans/msnmntr/msnmntr.sln index ac6d8e3e..5a24d0b5 100644 --- a/network/trans/msnmntr/msnmntr.sln +++ b/network/trans/msnmntr/msnmntr.sln @@ -3,13 +3,13 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Exe", "Exe", "{18ABBE0C-EBB5-4181-AB5D-AD526B2CB283}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Exe", "Exe", "{14AC7312-9D93-4A70-896D-97D9FDB48125}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Sys", "Sys", "{B9075E40-A5B9-42B8-A185-CB3290C4EC12}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Sys", "Sys", "{04F57F95-9237-4AE9-908B-41F30AA8BB1E}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "monitor", "exe\monitor.vcxproj", "{BF8F75F9-23E9-4925-96A1-76FD729EBA93}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "monitor", "exe\monitor.vcxproj", "{FCC67889-AD0A-4C2F-A826-7D2AD714FC6A}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "msnmntr", "sys\msnmntr.vcxproj", "{A0314F39-C7C2-463C-B2BE-DF387AB755F5}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "msnmntr", "sys\msnmntr.vcxproj", "{FB90ED51-1865-4ADC-B3A7-827EFE7302EA}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -19,28 +19,28 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {BF8F75F9-23E9-4925-96A1-76FD729EBA93}.Debug|Win32.ActiveCfg = Debug|Win32 - {BF8F75F9-23E9-4925-96A1-76FD729EBA93}.Debug|Win32.Build.0 = Debug|Win32 - {BF8F75F9-23E9-4925-96A1-76FD729EBA93}.Release|Win32.ActiveCfg = Release|Win32 - {BF8F75F9-23E9-4925-96A1-76FD729EBA93}.Release|Win32.Build.0 = Release|Win32 - {BF8F75F9-23E9-4925-96A1-76FD729EBA93}.Debug|x64.ActiveCfg = Debug|x64 - {BF8F75F9-23E9-4925-96A1-76FD729EBA93}.Debug|x64.Build.0 = Debug|x64 - {BF8F75F9-23E9-4925-96A1-76FD729EBA93}.Release|x64.ActiveCfg = Release|x64 - {BF8F75F9-23E9-4925-96A1-76FD729EBA93}.Release|x64.Build.0 = Release|x64 - {A0314F39-C7C2-463C-B2BE-DF387AB755F5}.Debug|Win32.ActiveCfg = Debug|Win32 - {A0314F39-C7C2-463C-B2BE-DF387AB755F5}.Debug|Win32.Build.0 = Debug|Win32 - {A0314F39-C7C2-463C-B2BE-DF387AB755F5}.Release|Win32.ActiveCfg = Release|Win32 - {A0314F39-C7C2-463C-B2BE-DF387AB755F5}.Release|Win32.Build.0 = Release|Win32 - {A0314F39-C7C2-463C-B2BE-DF387AB755F5}.Debug|x64.ActiveCfg = Debug|x64 - {A0314F39-C7C2-463C-B2BE-DF387AB755F5}.Debug|x64.Build.0 = Debug|x64 - {A0314F39-C7C2-463C-B2BE-DF387AB755F5}.Release|x64.ActiveCfg = Release|x64 - {A0314F39-C7C2-463C-B2BE-DF387AB755F5}.Release|x64.Build.0 = Release|x64 + {FCC67889-AD0A-4C2F-A826-7D2AD714FC6A}.Debug|Win32.ActiveCfg = Debug|Win32 + {FCC67889-AD0A-4C2F-A826-7D2AD714FC6A}.Debug|Win32.Build.0 = Debug|Win32 + {FCC67889-AD0A-4C2F-A826-7D2AD714FC6A}.Release|Win32.ActiveCfg = Release|Win32 + {FCC67889-AD0A-4C2F-A826-7D2AD714FC6A}.Release|Win32.Build.0 = Release|Win32 + {FCC67889-AD0A-4C2F-A826-7D2AD714FC6A}.Debug|x64.ActiveCfg = Debug|x64 + {FCC67889-AD0A-4C2F-A826-7D2AD714FC6A}.Debug|x64.Build.0 = Debug|x64 + {FCC67889-AD0A-4C2F-A826-7D2AD714FC6A}.Release|x64.ActiveCfg = Release|x64 + {FCC67889-AD0A-4C2F-A826-7D2AD714FC6A}.Release|x64.Build.0 = Release|x64 + {FB90ED51-1865-4ADC-B3A7-827EFE7302EA}.Debug|Win32.ActiveCfg = Debug|Win32 + {FB90ED51-1865-4ADC-B3A7-827EFE7302EA}.Debug|Win32.Build.0 = Debug|Win32 + {FB90ED51-1865-4ADC-B3A7-827EFE7302EA}.Release|Win32.ActiveCfg = Release|Win32 + {FB90ED51-1865-4ADC-B3A7-827EFE7302EA}.Release|Win32.Build.0 = Release|Win32 + {FB90ED51-1865-4ADC-B3A7-827EFE7302EA}.Debug|x64.ActiveCfg = Debug|x64 + {FB90ED51-1865-4ADC-B3A7-827EFE7302EA}.Debug|x64.Build.0 = Debug|x64 + {FB90ED51-1865-4ADC-B3A7-827EFE7302EA}.Release|x64.ActiveCfg = Release|x64 + {FB90ED51-1865-4ADC-B3A7-827EFE7302EA}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {BF8F75F9-23E9-4925-96A1-76FD729EBA93} = {18ABBE0C-EBB5-4181-AB5D-AD526B2CB283} - {A0314F39-C7C2-463C-B2BE-DF387AB755F5} = {B9075E40-A5B9-42B8-A185-CB3290C4EC12} + {FCC67889-AD0A-4C2F-A826-7D2AD714FC6A} = {14AC7312-9D93-4A70-896D-97D9FDB48125} + {FB90ED51-1865-4ADC-B3A7-827EFE7302EA} = {04F57F95-9237-4AE9-908B-41F30AA8BB1E} EndGlobalSection EndGlobal diff --git a/network/trans/msnmntr/sys/msnmntr.vcxproj b/network/trans/msnmntr/sys/msnmntr.vcxproj index 19d05a61..fd2ee8a8 100644 --- a/network/trans/msnmntr/sys/msnmntr.vcxproj +++ b/network/trans/msnmntr/sys/msnmntr.vcxproj @@ -19,12 +19,12 @@ - {A0314F39-C7C2-463C-B2BE-DF387AB755F5} + {FB90ED51-1865-4ADC-B3A7-827EFE7302EA} $(MSBuildProjectName) 1 Debug Win32 - {2235E7F5-485C-4A50-AC6E-7D5127C63D50} + {37A322AB-C708-4912-A65E-32CF743F1620} diff --git a/network/trans/msnmntr/sys/msnmntr.vcxproj.Filters b/network/trans/msnmntr/sys/msnmntr.vcxproj.Filters index 7a507ae9..7c24c232 100644 --- a/network/trans/msnmntr/sys/msnmntr.vcxproj.Filters +++ b/network/trans/msnmntr/sys/msnmntr.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {061ABC02-158F-4210-A282-D00E6E173776} + {C234D0E2-4C06-4AD3-911B-E5B20C7AA72D} h;hpp;hxx;hm;inl;inc;xsd - {EAF55685-C4D1-47E0-A3A8-B3E417170A02} + {65D341DD-B365-45C9-9EDE-816F5EE76E72} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {7449D543-948C-4CDB-AB03-EE885873121D} + {023B8D22-079E-43B6-8C96-623C9ED0B1F1} inf;inv;inx;mof;mc; - {E3258914-96DA-44CC-9DB9-3F58E7232911} + {D2F25005-E168-4EEF-8F96-23805D06AAAE} diff --git a/network/trans/stmedit/stmedit.sln b/network/trans/stmedit/stmedit.sln index 7f1cb436..b626c402 100644 --- a/network/trans/stmedit/stmedit.sln +++ b/network/trans/stmedit/stmedit.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "stmedit", "sys\stmedit.vcxproj", "{98513F1C-C28D-4F03-99A8-88FD4BD707C7}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "stmedit", "sys\stmedit.vcxproj", "{047B99BF-F490-4938-BFDA-3697680EE8AB}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +13,14 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {98513F1C-C28D-4F03-99A8-88FD4BD707C7}.Debug|Win32.ActiveCfg = Debug|Win32 - {98513F1C-C28D-4F03-99A8-88FD4BD707C7}.Debug|Win32.Build.0 = Debug|Win32 - {98513F1C-C28D-4F03-99A8-88FD4BD707C7}.Release|Win32.ActiveCfg = Release|Win32 - {98513F1C-C28D-4F03-99A8-88FD4BD707C7}.Release|Win32.Build.0 = Release|Win32 - {98513F1C-C28D-4F03-99A8-88FD4BD707C7}.Debug|x64.ActiveCfg = Debug|x64 - {98513F1C-C28D-4F03-99A8-88FD4BD707C7}.Debug|x64.Build.0 = Debug|x64 - {98513F1C-C28D-4F03-99A8-88FD4BD707C7}.Release|x64.ActiveCfg = Release|x64 - {98513F1C-C28D-4F03-99A8-88FD4BD707C7}.Release|x64.Build.0 = Release|x64 + {047B99BF-F490-4938-BFDA-3697680EE8AB}.Debug|Win32.ActiveCfg = Debug|Win32 + {047B99BF-F490-4938-BFDA-3697680EE8AB}.Debug|Win32.Build.0 = Debug|Win32 + {047B99BF-F490-4938-BFDA-3697680EE8AB}.Release|Win32.ActiveCfg = Release|Win32 + {047B99BF-F490-4938-BFDA-3697680EE8AB}.Release|Win32.Build.0 = Release|Win32 + {047B99BF-F490-4938-BFDA-3697680EE8AB}.Debug|x64.ActiveCfg = Debug|x64 + {047B99BF-F490-4938-BFDA-3697680EE8AB}.Debug|x64.Build.0 = Debug|x64 + {047B99BF-F490-4938-BFDA-3697680EE8AB}.Release|x64.ActiveCfg = Release|x64 + {047B99BF-F490-4938-BFDA-3697680EE8AB}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/network/trans/stmedit/sys/stmedit.vcxproj b/network/trans/stmedit/sys/stmedit.vcxproj index bc3ef00b..0a3e35b0 100644 --- a/network/trans/stmedit/sys/stmedit.vcxproj +++ b/network/trans/stmedit/sys/stmedit.vcxproj @@ -19,12 +19,12 @@ - {98513F1C-C28D-4F03-99A8-88FD4BD707C7} + {047B99BF-F490-4938-BFDA-3697680EE8AB} $(MSBuildProjectName) 1 Debug Win32 - {72C54687-6A7C-47CA-9E90-E2D689DC07FF} + {E10325C3-F867-4F5D-BD53-F06AA0782EB0} diff --git a/network/trans/stmedit/sys/stmedit.vcxproj.Filters b/network/trans/stmedit/sys/stmedit.vcxproj.Filters index 54528237..474bda82 100644 --- a/network/trans/stmedit/sys/stmedit.vcxproj.Filters +++ b/network/trans/stmedit/sys/stmedit.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {C9744BA5-8ED9-44CA-83D6-EFDEDA84812B} + {3D06BA82-AC80-46D1-B13E-F01845AF9A9C} h;hpp;hxx;hm;inl;inc;xsd - {2B1C683F-EF24-453C-B303-9CAE8061F7C3} + {2D8AF9DE-2497-4917-9CCF-7C147BB503A4} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {FF447D8A-41FE-4980-B0AE-27782414E0C0} + {B9C19587-10DE-473E-AF48-2BDC5E84B3D7} inf;inv;inx;mof;mc; - {A061D6F2-D701-4D44-9CAB-055FBD8E95A9} + {02D242A6-B147-4BA5-BCAA-8086413C2C7E} diff --git a/network/wlan/ihvsample/ihvsample.vcxproj b/network/wlan/ihvsample/ihvsample.vcxproj index 8b0dde8a..8222ef43 100644 --- a/network/wlan/ihvsample/ihvsample.vcxproj +++ b/network/wlan/ihvsample/ihvsample.vcxproj @@ -19,11 +19,11 @@ - {C2DB15CB-342E-4E84-BFD0-5E839DE380DE} + {098D97D4-8A9D-4AEA-8BBB-B5330EC55613} $(MSBuildProjectName) Debug Win32 - {D58AEDC0-211B-4E2E-B92B-D297D272865F} + {DD05EC52-7706-4D38-9EB6-596FBE935277} diff --git a/network/wlan/ihvsample/ihvsample.vcxproj.Filters b/network/wlan/ihvsample/ihvsample.vcxproj.Filters index 7a93e51c..41235fc2 100644 --- a/network/wlan/ihvsample/ihvsample.vcxproj.Filters +++ b/network/wlan/ihvsample/ihvsample.vcxproj.Filters @@ -3,15 +3,15 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {C3AD44B7-58F4-43D6-8928-4E57B6E0C023} + {2BFA3B7C-5457-42F0-AD10-BCFC2B55D74E} h;hpp;hxx;hm;inl;inc;xsd - {76ABC86D-F7B4-4BB5-8600-84AEDE01171B} + {3558D843-4C29-406E-87A5-E654CFF05FC4} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {25477ACB-EF62-4C7A-9AAC-8DF8119A6070} + {87382B19-B7AA-4E7F-AB03-0AE307E2059E} diff --git a/network/wlan/ihvsampleui/IHVSampleUI.vcxproj b/network/wlan/ihvsampleui/IHVSampleUI.vcxproj index c4fe2319..cccce063 100644 --- a/network/wlan/ihvsampleui/IHVSampleUI.vcxproj +++ b/network/wlan/ihvsampleui/IHVSampleUI.vcxproj @@ -19,11 +19,11 @@ - {A6B24475-C40B-4105-9896-6076AB284D92} + {5576312E-999E-4699-8F35-62D86C7E24B7} $(MSBuildProjectName) Debug Win32 - {BFF15FF4-CA6C-4126-AE5C-43FEAC2373DA} + {CC668046-DE22-495D-BF12-86B0754ADBA4} diff --git a/network/wlan/ihvsampleui/IHVSampleUI.vcxproj.Filters b/network/wlan/ihvsampleui/IHVSampleUI.vcxproj.Filters index 35f3326f..cd389088 100644 --- a/network/wlan/ihvsampleui/IHVSampleUI.vcxproj.Filters +++ b/network/wlan/ihvsampleui/IHVSampleUI.vcxproj.Filters @@ -3,15 +3,15 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {94F31788-CC51-4779-82A7-949AF23515AB} + {7A398CC0-086B-4682-9345-45CFA3130E1A} h;hpp;hxx;hm;inl;inc;xsd - {2AFE8613-F5FD-4251-B520-F5354B519860} + {FC7DD856-4C33-419F-B10E-5BF283171077} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {4C783C36-ECB3-435F-B739-9B522EEF773A} + {260AC1C3-C7B5-451F-B4BB-FA1C77706860} diff --git a/network/wlan/wlan.sln b/network/wlan/wlan.sln index 4d92aa78..45081799 100644 --- a/network/wlan/wlan.sln +++ b/network/wlan/wlan.sln @@ -3,13 +3,13 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Ihvsample", "Ihvsample", "{7ECA32F1-551B-4AF3-9726-A319C35A19D3}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Ihvsample", "Ihvsample", "{4F0C336F-C969-4455-9DC3-5AC3E4321343}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Ihvsampleui", "Ihvsampleui", "{42757992-DA8D-4434-9B9C-ED549C43BA83}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Ihvsampleui", "Ihvsampleui", "{A185AFB8-6C0D-42D1-AF6A-7790F0CFA38C}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ihvsample", "ihvsample\ihvsample.vcxproj", "{C2DB15CB-342E-4E84-BFD0-5E839DE380DE}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ihvsample", "ihvsample\ihvsample.vcxproj", "{098D97D4-8A9D-4AEA-8BBB-B5330EC55613}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "IHVSampleUI", "ihvsampleui\IHVSampleUI.vcxproj", "{A6B24475-C40B-4105-9896-6076AB284D92}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "IHVSampleUI", "ihvsampleui\IHVSampleUI.vcxproj", "{5576312E-999E-4699-8F35-62D86C7E24B7}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -19,28 +19,28 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {C2DB15CB-342E-4E84-BFD0-5E839DE380DE}.Debug|Win32.ActiveCfg = Debug|Win32 - {C2DB15CB-342E-4E84-BFD0-5E839DE380DE}.Debug|Win32.Build.0 = Debug|Win32 - {C2DB15CB-342E-4E84-BFD0-5E839DE380DE}.Release|Win32.ActiveCfg = Release|Win32 - {C2DB15CB-342E-4E84-BFD0-5E839DE380DE}.Release|Win32.Build.0 = Release|Win32 - {C2DB15CB-342E-4E84-BFD0-5E839DE380DE}.Debug|x64.ActiveCfg = Debug|x64 - {C2DB15CB-342E-4E84-BFD0-5E839DE380DE}.Debug|x64.Build.0 = Debug|x64 - {C2DB15CB-342E-4E84-BFD0-5E839DE380DE}.Release|x64.ActiveCfg = Release|x64 - {C2DB15CB-342E-4E84-BFD0-5E839DE380DE}.Release|x64.Build.0 = Release|x64 - {A6B24475-C40B-4105-9896-6076AB284D92}.Debug|Win32.ActiveCfg = Debug|Win32 - {A6B24475-C40B-4105-9896-6076AB284D92}.Debug|Win32.Build.0 = Debug|Win32 - {A6B24475-C40B-4105-9896-6076AB284D92}.Release|Win32.ActiveCfg = Release|Win32 - {A6B24475-C40B-4105-9896-6076AB284D92}.Release|Win32.Build.0 = Release|Win32 - {A6B24475-C40B-4105-9896-6076AB284D92}.Debug|x64.ActiveCfg = Debug|x64 - {A6B24475-C40B-4105-9896-6076AB284D92}.Debug|x64.Build.0 = Debug|x64 - {A6B24475-C40B-4105-9896-6076AB284D92}.Release|x64.ActiveCfg = Release|x64 - {A6B24475-C40B-4105-9896-6076AB284D92}.Release|x64.Build.0 = Release|x64 + {098D97D4-8A9D-4AEA-8BBB-B5330EC55613}.Debug|Win32.ActiveCfg = Debug|Win32 + {098D97D4-8A9D-4AEA-8BBB-B5330EC55613}.Debug|Win32.Build.0 = Debug|Win32 + {098D97D4-8A9D-4AEA-8BBB-B5330EC55613}.Release|Win32.ActiveCfg = Release|Win32 + {098D97D4-8A9D-4AEA-8BBB-B5330EC55613}.Release|Win32.Build.0 = Release|Win32 + {098D97D4-8A9D-4AEA-8BBB-B5330EC55613}.Debug|x64.ActiveCfg = Debug|x64 + {098D97D4-8A9D-4AEA-8BBB-B5330EC55613}.Debug|x64.Build.0 = Debug|x64 + {098D97D4-8A9D-4AEA-8BBB-B5330EC55613}.Release|x64.ActiveCfg = Release|x64 + {098D97D4-8A9D-4AEA-8BBB-B5330EC55613}.Release|x64.Build.0 = Release|x64 + {5576312E-999E-4699-8F35-62D86C7E24B7}.Debug|Win32.ActiveCfg = Debug|Win32 + {5576312E-999E-4699-8F35-62D86C7E24B7}.Debug|Win32.Build.0 = Debug|Win32 + {5576312E-999E-4699-8F35-62D86C7E24B7}.Release|Win32.ActiveCfg = Release|Win32 + {5576312E-999E-4699-8F35-62D86C7E24B7}.Release|Win32.Build.0 = Release|Win32 + {5576312E-999E-4699-8F35-62D86C7E24B7}.Debug|x64.ActiveCfg = Debug|x64 + {5576312E-999E-4699-8F35-62D86C7E24B7}.Debug|x64.Build.0 = Debug|x64 + {5576312E-999E-4699-8F35-62D86C7E24B7}.Release|x64.ActiveCfg = Release|x64 + {5576312E-999E-4699-8F35-62D86C7E24B7}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {C2DB15CB-342E-4E84-BFD0-5E839DE380DE} = {7ECA32F1-551B-4AF3-9726-A319C35A19D3} - {A6B24475-C40B-4105-9896-6076AB284D92} = {42757992-DA8D-4434-9B9C-ED549C43BA83} + {098D97D4-8A9D-4AEA-8BBB-B5330EC55613} = {4F0C336F-C969-4455-9DC3-5AC3E4321343} + {5576312E-999E-4699-8F35-62D86C7E24B7} = {A185AFB8-6C0D-42D1-AF6A-7790F0CFA38C} EndGlobalSection EndGlobal diff --git a/network/wsk/echosrv/echosrv.sln b/network/wsk/echosrv/echosrv.sln index ce0d54fc..c21b2bf1 100644 --- a/network/wsk/echosrv/echosrv.sln +++ b/network/wsk/echosrv/echosrv.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "echosrv", "echosrv.vcxproj", "{FFEE1E8D-35BB-4B3B-A59E-CC8D6DE39B5D}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "echosrv", "echosrv.vcxproj", "{8E78BC0A-849D-4702-9E81-6F042E9390D6}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +13,14 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {FFEE1E8D-35BB-4B3B-A59E-CC8D6DE39B5D}.Debug|Win32.ActiveCfg = Debug|Win32 - {FFEE1E8D-35BB-4B3B-A59E-CC8D6DE39B5D}.Debug|Win32.Build.0 = Debug|Win32 - {FFEE1E8D-35BB-4B3B-A59E-CC8D6DE39B5D}.Release|Win32.ActiveCfg = Release|Win32 - {FFEE1E8D-35BB-4B3B-A59E-CC8D6DE39B5D}.Release|Win32.Build.0 = Release|Win32 - {FFEE1E8D-35BB-4B3B-A59E-CC8D6DE39B5D}.Debug|x64.ActiveCfg = Debug|x64 - {FFEE1E8D-35BB-4B3B-A59E-CC8D6DE39B5D}.Debug|x64.Build.0 = Debug|x64 - {FFEE1E8D-35BB-4B3B-A59E-CC8D6DE39B5D}.Release|x64.ActiveCfg = Release|x64 - {FFEE1E8D-35BB-4B3B-A59E-CC8D6DE39B5D}.Release|x64.Build.0 = Release|x64 + {8E78BC0A-849D-4702-9E81-6F042E9390D6}.Debug|Win32.ActiveCfg = Debug|Win32 + {8E78BC0A-849D-4702-9E81-6F042E9390D6}.Debug|Win32.Build.0 = Debug|Win32 + {8E78BC0A-849D-4702-9E81-6F042E9390D6}.Release|Win32.ActiveCfg = Release|Win32 + {8E78BC0A-849D-4702-9E81-6F042E9390D6}.Release|Win32.Build.0 = Release|Win32 + {8E78BC0A-849D-4702-9E81-6F042E9390D6}.Debug|x64.ActiveCfg = Debug|x64 + {8E78BC0A-849D-4702-9E81-6F042E9390D6}.Debug|x64.Build.0 = Debug|x64 + {8E78BC0A-849D-4702-9E81-6F042E9390D6}.Release|x64.ActiveCfg = Release|x64 + {8E78BC0A-849D-4702-9E81-6F042E9390D6}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/network/wsk/echosrv/echosrv.vcxproj b/network/wsk/echosrv/echosrv.vcxproj index 670bbe52..7ccd0d41 100644 --- a/network/wsk/echosrv/echosrv.vcxproj +++ b/network/wsk/echosrv/echosrv.vcxproj @@ -19,11 +19,11 @@ - {FFEE1E8D-35BB-4B3B-A59E-CC8D6DE39B5D} + {8E78BC0A-849D-4702-9E81-6F042E9390D6} $(MSBuildProjectName) Debug Win32 - {356832D6-4003-4E04-991A-8885A867DFF1} + {0B7202D2-759C-425C-B5C5-FAE073649589} diff --git a/network/wsk/echosrv/echosrv.vcxproj.Filters b/network/wsk/echosrv/echosrv.vcxproj.Filters index f0757e26..22d8f67f 100644 --- a/network/wsk/echosrv/echosrv.vcxproj.Filters +++ b/network/wsk/echosrv/echosrv.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {7A5FF825-82E8-4B8C-A384-AFE5DDF0241F} + {F13DC512-BF50-42A6-A954-1C591BDB2EF6} h;hpp;hxx;hm;inl;inc;xsd - {7BD60EFA-8AB3-4BA8-8624-F096458DF6FD} + {239F589A-028C-461F-B097-D81EBE166FDF} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {02D631B3-0A60-43EF-A6F1-92F34CD3105C} + {724E389F-B1ED-4B03-A345-5153DC92B75C} inf;inv;inx;mof;mc; - {81350963-697B-4F08-9AEA-8A5426D14C60} + {B9E8C901-FCC9-4990-990F-3D7CBBA234FC} diff --git a/nfp/net/NetNfpProvider.htm b/nfp/net/NetNfpProvider.htm new file mode 100644 index 00000000..0c3efbef --- /dev/null +++ b/nfp/net/NetNfpProvider.htm @@ -0,0 +1,1240 @@ + + + + + + + + + + + + + + + + + + +
+ +

NetNfpProvider

+ +

SUMMARY

+ +

This +sample demonstrates how to use the User-Mode Driver Framework to write a Near +Field Proximity driver and demonstrates best practices. Typically, a Near Field +Proximity driver would use Near Field technologies like “NFC”, “TransferJet”, or “Bump”. However, this sample uses a +TCP/IPv6 network connection and a static configuration between two machines to +allow simulation of Near Field interaction.

+ +

BUILDING THE SAMPLE

+ +

Load the NetNfpProvider Visual Studio project file in to Visual +Studio. Use Visual Studio to build the sample. If the build succeeds, you will +find the driver, NetNfpProvider.dll in the binary output directory specified +for the build environment.

+ +

INSTALLATION

+ +

To install the NetNfpProvider driver:

+ +
+ +
    +
  1. First + copy the driver binary and the NetNfpProvider.inf file to a directory on + your test machine (for example c:\NetNfpProvider.)
  2. +
  3. Change + to the directory containing the inf and binaries + (for example cd /d c:\NetNfpProvider.)
  4. +
  5. Next + run devcon.exe as follows:
  6. +
+ +
+ +

devcon.exe install +NetNfpProvider.inf WUDF\NetNfpProvider

+ +

DevCon can be found in +the tools directory of your WDK enlistment (for example: +c:\winddk\<bld>\tools\devcon\i386\devcon.exe.)

+ +
+ +
    +
  1. Create a Windows Firewall rule to allow the NetNfpProvider to receive proximity simulation + requests over the network:
    + Run WF.msc
    + Create a new inbound rule that opens port 9299
  2. +
+ +
+ +

To update +the NetNfpProvider driver after making any changes:

+ +
+ +
    +
  1. Increment + the version number found in the INF.  While this is not strictly + necessary, it will help ensure PnP selects your new driver as a better + match for the device.
  2. +
  3. Copy + the updated driver binary and the NetNfpProvider.inf file to a directory + on your test machine (for example c:\ NetNfpProvider.)
  4. +
  5. Change + to the directory containing the inf and binaries + (for example cd /d c:\ NetNfpProvider.)
  6. +
  7. Next + run devcon.exe as follows:
  8. +
+ +
+ +

devcon.exe update +NetNfpProvider.inf WUDF\NetNfpProvider

+ +
+ +
+ +

TESTING

+ +

To test +the NetNfpProvider driver, you can run +NetNfpControl.exe which is built from the src\nfp\net\exe.

+ +

First +install the device as described above. Then run NetNfpControl.exe from one +command window.

+ +

NetNfpControl console app allows +control of the NetNfpProvider test driver. Both the +local and remote machine must have the NetNfpProvider +driver installed.

+ +

USAGE:

+ +

Windows Near-field +Proximity Test tool. Designed for simulating proximity hardware.

+ +

NetNfpControl.exe +[<remoteMachine>] [/k]

+ +

Example: NetNfpControl.exe John-PC1
+The first operating mode allows the user to specify a remote machine name (or +IPv6 address) that the local machine should connect to and simulate proximity +with. After it's connected, a simple key-press ends the simulated proximity +link. The console app then exits.

+ +

Example: NetNfpControl.exe John-PC1 +/k
+A second operating mode keeps the console app running with a Ctrl-F1 hotkey +registered (even when running in the background). When the hot key is +intercepted, a near-field proximity event is simulated directly with the +specified remote machine.
+Note: The console app needs to be running (only on one machine) to intercept +the system hot key.

+ +

Example: NetNfpControl.exe /k
+A third operating mode also keeps the console app running with a Ctrl-F1 hotkey +registered. However, you'll have to run this on two or more machines at the +same time. Pressing Ctrl-F1 on any two machines at the same time causes the +machines to exchange their network name via a file on a private share with a +special file name.

+ +

·         +The +server share used is hard coded to: \\scratch2\scratch\travm\proxrendezvous\

+ +

o    +Either +create a file server with these folders shared, or change this to match yours.

+ +

·         +The +file has an effective lifetime of 2 seconds.

+ +

·         +In +the event of a collision (two clients posting an event during the same +interval), only one client 'wins'.

+ +

CODE TOUR

+ +

File Manifest

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

File

+
+

Description

+
+

NetNfpProvider.htm

+
+

Documentation for this sample + (this file).

+
+

dllsup.cpp

+
+

DLL + Support code - provides the DLL's entry point as well as the single required + export (DllGetClassObject).

+
+

Exports.def

+
+

This file lists the functions that + the driver DLL exports.

+
+

Internal.h

+
+

This is the main header file for + this driver.

+
+

Driver.cpp & Driver.h

+
+

DriverEntry and events on the Driver Object.

+
+

Device.cpp & Device.h

+
+

Events on the Device Object.

+
+

Queue.cpp & Queue.h

+
+

Contains events on the I/O Queue + Objects. IOCTL handlers and filename parsing.

+
+

connection.cpp & connection.h

+
+

Contains events on the connection + object created per simulated proximity link. This contains the code for + socket client.

+
+

Socketlistener.cpp &

+

Socketlistener.h

+
+

Contains + a socket listener for accepting inbound proximity simulation requests.

+
+

FileContext.cpp and FileContext.h

+
+

Defines the context associated with the file object. Per file context + stores per connection information, publications, and subscriptions.

+
+

NetNfpProvider.rc

+
+

Resource file for the driver.

+
+

NetNfpProvider.inx

+
+

File that describes the + installation of this driver. The build process converts this into an INF + file.

+
+

WppDefs.h

+
+

A header used to generate WPP + Macros for this project. Note, with WPP, some comments are actually compiled + by the pre-processor. Thread Local Storage is used to properly indent logs.

+
+ +

Top +of Page

+ +

© 2012 Microsoft +Corporation

+ +
+ + + + diff --git a/nfp/net/driver/NetNfpProvider.vcxproj b/nfp/net/driver/NetNfpProvider.vcxproj index da21fa09..76f4232d 100644 --- a/nfp/net/driver/NetNfpProvider.vcxproj +++ b/nfp/net/driver/NetNfpProvider.vcxproj @@ -19,12 +19,12 @@
- {756016BF-4187-4482-A0BE-CEE1698BD129} + {6765F4B0-264E-4EA6-9EAE-CE43C3BE04DF} $(MSBuildProjectName) 1 Debug Win32 - {9E5FA410-9825-4FD4-845A-FFEDEE9AF94B} + {0884BE29-DDC3-4627-8B57-3997978EE1F4} diff --git a/nfp/net/driver/NetNfpProvider.vcxproj.Filters b/nfp/net/driver/NetNfpProvider.vcxproj.Filters index cfe106d2..e24f17e8 100644 --- a/nfp/net/driver/NetNfpProvider.vcxproj.Filters +++ b/nfp/net/driver/NetNfpProvider.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {1A46FC37-1F58-4A1C-AD58-4C8F0BFF8004} + {42E23DE8-32D3-4399-8E2F-4287E410E541} h;hpp;hxx;hm;inl;inc;xsd - {558A638D-8A37-44D7-BB58-296F1AEE8066} + {A4E94E74-991C-42D2-9F4D-67AD587F6D11} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {06C2D74D-F153-45FD-9B8F-09D1A0CD979F} + {AE74648C-BE93-41BD-B6F8-BCE184684B75} inf;inv;inx;mof;mc; - {D6F88F8A-6CD0-44DA-BC07-EEFF2E791D12} + {873765C6-CA93-4C7A-87AF-E0B883B4EBB2} diff --git a/nfp/net/exe/NetNfpControl.vcxproj b/nfp/net/exe/NetNfpControl.vcxproj index b2eb94ff..404f1b5a 100644 --- a/nfp/net/exe/NetNfpControl.vcxproj +++ b/nfp/net/exe/NetNfpControl.vcxproj @@ -19,11 +19,11 @@ - {4ABF1B83-9726-45DE-B705-A8458BCB0915} + {D40F7042-2180-40DF-A634-104BFB614097} $(MSBuildProjectName) Debug Win32 - {B57AFB72-58B6-45CF-8E49-3D56D66A2842} + {9F1521A4-16AA-4263-84BB-5026569D1020} diff --git a/nfp/net/exe/NetNfpControl.vcxproj.Filters b/nfp/net/exe/NetNfpControl.vcxproj.Filters index c01e6141..c75f7dcf 100644 --- a/nfp/net/exe/NetNfpControl.vcxproj.Filters +++ b/nfp/net/exe/NetNfpControl.vcxproj.Filters @@ -3,15 +3,15 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {1C29E1A2-5E3D-4A88-A8C5-2DBBA704EF00} + {9C04ED10-5BA4-42E5-B5D5-4BD50217EBAE} h;hpp;hxx;hm;inl;inc;xsd - {5535C5B0-0DF3-4CF2-ACA9-2F899FA6CE1C} + {53BD2E40-1C93-498E-8D59-323CB3D066BA} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {534D73C8-CECE-4D3E-9B06-469E2C777F49} + {E9074112-F156-4968-A49A-5C281DDB3F60} diff --git a/nfp/net/netnfp.sln b/nfp/net/netnfp.sln index f8b5f6b2..aabb3bbf 100644 --- a/nfp/net/netnfp.sln +++ b/nfp/net/netnfp.sln @@ -3,13 +3,13 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Driver", "Driver", "{6133A073-0A35-45D3-BC68-BA16B0F829D8}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Driver", "Driver", "{D2BA67B7-002A-468C-A45C-ABC347AB834D}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Exe", "Exe", "{4FD03920-D970-4A51-A2A1-A394DF683A03}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Exe", "Exe", "{439733D7-5A78-4FF7-9985-FFB40E84BAC2}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NetNfpProvider", "driver\NetNfpProvider.vcxproj", "{756016BF-4187-4482-A0BE-CEE1698BD129}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NetNfpProvider", "driver\NetNfpProvider.vcxproj", "{6765F4B0-264E-4EA6-9EAE-CE43C3BE04DF}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NetNfpControl", "exe\NetNfpControl.vcxproj", "{4ABF1B83-9726-45DE-B705-A8458BCB0915}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NetNfpControl", "exe\NetNfpControl.vcxproj", "{D40F7042-2180-40DF-A634-104BFB614097}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -19,28 +19,28 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {756016BF-4187-4482-A0BE-CEE1698BD129}.Debug|Win32.ActiveCfg = Debug|Win32 - {756016BF-4187-4482-A0BE-CEE1698BD129}.Debug|Win32.Build.0 = Debug|Win32 - {756016BF-4187-4482-A0BE-CEE1698BD129}.Release|Win32.ActiveCfg = Release|Win32 - {756016BF-4187-4482-A0BE-CEE1698BD129}.Release|Win32.Build.0 = Release|Win32 - {756016BF-4187-4482-A0BE-CEE1698BD129}.Debug|x64.ActiveCfg = Debug|x64 - {756016BF-4187-4482-A0BE-CEE1698BD129}.Debug|x64.Build.0 = Debug|x64 - {756016BF-4187-4482-A0BE-CEE1698BD129}.Release|x64.ActiveCfg = Release|x64 - {756016BF-4187-4482-A0BE-CEE1698BD129}.Release|x64.Build.0 = Release|x64 - {4ABF1B83-9726-45DE-B705-A8458BCB0915}.Debug|Win32.ActiveCfg = Debug|Win32 - {4ABF1B83-9726-45DE-B705-A8458BCB0915}.Debug|Win32.Build.0 = Debug|Win32 - {4ABF1B83-9726-45DE-B705-A8458BCB0915}.Release|Win32.ActiveCfg = Release|Win32 - {4ABF1B83-9726-45DE-B705-A8458BCB0915}.Release|Win32.Build.0 = Release|Win32 - {4ABF1B83-9726-45DE-B705-A8458BCB0915}.Debug|x64.ActiveCfg = Debug|x64 - {4ABF1B83-9726-45DE-B705-A8458BCB0915}.Debug|x64.Build.0 = Debug|x64 - {4ABF1B83-9726-45DE-B705-A8458BCB0915}.Release|x64.ActiveCfg = Release|x64 - {4ABF1B83-9726-45DE-B705-A8458BCB0915}.Release|x64.Build.0 = Release|x64 + {6765F4B0-264E-4EA6-9EAE-CE43C3BE04DF}.Debug|Win32.ActiveCfg = Debug|Win32 + {6765F4B0-264E-4EA6-9EAE-CE43C3BE04DF}.Debug|Win32.Build.0 = Debug|Win32 + {6765F4B0-264E-4EA6-9EAE-CE43C3BE04DF}.Release|Win32.ActiveCfg = Release|Win32 + {6765F4B0-264E-4EA6-9EAE-CE43C3BE04DF}.Release|Win32.Build.0 = Release|Win32 + {6765F4B0-264E-4EA6-9EAE-CE43C3BE04DF}.Debug|x64.ActiveCfg = Debug|x64 + {6765F4B0-264E-4EA6-9EAE-CE43C3BE04DF}.Debug|x64.Build.0 = Debug|x64 + {6765F4B0-264E-4EA6-9EAE-CE43C3BE04DF}.Release|x64.ActiveCfg = Release|x64 + {6765F4B0-264E-4EA6-9EAE-CE43C3BE04DF}.Release|x64.Build.0 = Release|x64 + {D40F7042-2180-40DF-A634-104BFB614097}.Debug|Win32.ActiveCfg = Debug|Win32 + {D40F7042-2180-40DF-A634-104BFB614097}.Debug|Win32.Build.0 = Debug|Win32 + {D40F7042-2180-40DF-A634-104BFB614097}.Release|Win32.ActiveCfg = Release|Win32 + {D40F7042-2180-40DF-A634-104BFB614097}.Release|Win32.Build.0 = Release|Win32 + {D40F7042-2180-40DF-A634-104BFB614097}.Debug|x64.ActiveCfg = Debug|x64 + {D40F7042-2180-40DF-A634-104BFB614097}.Debug|x64.Build.0 = Debug|x64 + {D40F7042-2180-40DF-A634-104BFB614097}.Release|x64.ActiveCfg = Release|x64 + {D40F7042-2180-40DF-A634-104BFB614097}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {756016BF-4187-4482-A0BE-CEE1698BD129} = {6133A073-0A35-45D3-BC68-BA16B0F829D8} - {4ABF1B83-9726-45DE-B705-A8458BCB0915} = {4FD03920-D970-4A51-A2A1-A394DF683A03} + {6765F4B0-264E-4EA6-9EAE-CE43C3BE04DF} = {D2BA67B7-002A-468C-A45C-ABC347AB834D} + {D40F7042-2180-40DF-A634-104BFB614097} = {439733D7-5A78-4FF7-9985-FFB40E84BAC2} EndGlobalSection EndGlobal diff --git a/pofx/UMDF2/App/PowerFxApp.cpp b/pofx/UMDF2/App/PowerFxApp.cpp index c628d366..2ea29a33 100644 --- a/pofx/UMDF2/App/PowerFxApp.cpp +++ b/pofx/UMDF2/App/PowerFxApp.cpp @@ -478,115 +478,70 @@ GetDevicePath( _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; + CONFIGRET cr = CR_SUCCESS; + PWSTR deviceInterfaceList = NULL; + ULONG deviceInterfaceListLength = 0; + PWSTR nextInterface; + HRESULT hr = E_FAIL; + BOOL bRet = TRUE; + + cr = CM_Get_Device_Interface_List_Size( + &deviceInterfaceListLength, + InterfaceGuid, + NULL, + CM_GET_DEVICE_INTERFACE_LIST_PRESENT); + if (cr != CR_SUCCESS) { + printf("Error 0x%x retrieving device interface list size.\n", cr); + goto clean0; } - 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); - } + if (deviceInterfaceListLength <= 1) { + bRet = FALSE; + printf("Error: No active device interfaces found.\n" + " Is the sample driver loaded?"); + goto clean0; + } - printf("SetupDiEnumDeviceInterfaces failed.\n"); - SetupDiDestroyDeviceInfoList(HardwareDeviceInfo); - return FALSE; + deviceInterfaceList = (PWSTR)malloc(deviceInterfaceListLength * sizeof(WCHAR)); + if (deviceInterfaceList == NULL) { + printf("Error allocating memory for device interface list.\n"); + goto clean0; } + ZeroMemory(deviceInterfaceList, deviceInterfaceListLength * sizeof(WCHAR)); - SetupDiGetDeviceInterfaceDetail( - HardwareDeviceInfo, - &DeviceInterfaceData, + cr = CM_Get_Device_Interface_List( + InterfaceGuid, 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; + deviceInterfaceList, + deviceInterfaceListLength, + CM_GET_DEVICE_INTERFACE_LIST_PRESENT); + if (cr != CR_SUCCESS) { + printf("Error 0x%x retrieving device interface list.\n", cr); + goto clean0; } - 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; + nextInterface = deviceInterfaceList + wcslen(deviceInterfaceList) + 1; + if (*nextInterface != UNICODE_NULL) { + printf("Warning: More than one device interface instance found. \n" + "Selecting first matching device.\n\n"); } - hr = StringCchCopy(DevicePath, - BufLen, - DeviceInterfaceDetailData->DevicePath) ; + hr = StringCchCopy(DevicePath, BufLen, deviceInterfaceList); + if (FAILED(hr)) { + bRet = FALSE; + printf("Error: StringCchCopy failed with HRESULT 0x%x", hr); + goto clean0; + } - SetupDiDestroyDeviceInfoList(HardwareDeviceInfo); // It must be executed in both success and failure traces - LocalFree(DeviceInterfaceDetailData); +clean0: + if (deviceInterfaceList != NULL) { + free(deviceInterfaceList); + } + if (CR_SUCCESS != cr) { + bRet = FALSE; + } - return ( !FAILED(hr) ); // Result depends on StringCchCopy() + return bRet; } diff --git a/pofx/UMDF2/App/PowerFxApp.vcxproj b/pofx/UMDF2/App/PowerFxApp.vcxproj index 6201baec..eb59260d 100644 --- a/pofx/UMDF2/App/PowerFxApp.vcxproj +++ b/pofx/UMDF2/App/PowerFxApp.vcxproj @@ -19,17 +19,17 @@ - {DA8D50B3-7692-4E79-9181-21576805D3E5} + {14E1832B-DF5A-4B4C-A079-A9446881E742} $(MSBuildProjectName) Debug Win32 - {86082276-A94B-42CE-B3D2-1AF13BE34A92} + {9DB58C83-24AF-4AFE-B48E-AD1449C17B9E} Windows10 False - Desktop + Universal WindowsApplicationForDrivers10.0 Application @@ -37,7 +37,7 @@ Windows10 True - Desktop + Universal WindowsApplicationForDrivers10.0 Application @@ -45,7 +45,7 @@ Windows10 False - Desktop + Universal WindowsApplicationForDrivers10.0 Application @@ -53,7 +53,7 @@ Windows10 True - Desktop + Universal WindowsApplicationForDrivers10.0 Application @@ -105,7 +105,7 @@ %(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc - %(AdditionalDependencies);setupapi.lib;user32.lib + %(AdditionalDependencies);mincore.lib @@ -126,7 +126,7 @@ %(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc - %(AdditionalDependencies);setupapi.lib;user32.lib + %(AdditionalDependencies);mincore.lib @@ -147,7 +147,7 @@ %(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc - %(AdditionalDependencies);setupapi.lib;user32.lib + %(AdditionalDependencies);mincore.lib @@ -168,7 +168,7 @@ %(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc - %(AdditionalDependencies);setupapi.lib;user32.lib + %(AdditionalDependencies);mincore.lib diff --git a/pofx/UMDF2/App/PowerFxApp.vcxproj.Filters b/pofx/UMDF2/App/PowerFxApp.vcxproj.Filters index 73e699bc..9a2f1269 100644 --- a/pofx/UMDF2/App/PowerFxApp.vcxproj.Filters +++ b/pofx/UMDF2/App/PowerFxApp.vcxproj.Filters @@ -3,15 +3,15 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {B5C219BE-1582-4433-8AEB-794DA8983AB0} + {20A2E7AD-88FC-4506-B935-ECBEEE1ADBA4} h;hpp;hxx;hm;inl;inc;xsd - {86E06376-FA08-4058-A118-F8CB221B0462} + {B9BF62AC-CE9A-4203-BEF5-D3532A0B4D2F} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {0F043EAF-993B-4742-95AE-C40C10DD5D19} + {019B37E5-DD40-4E7A-8889-3F4D51462380} diff --git a/pofx/UMDF2/App/include.h b/pofx/UMDF2/App/include.h index 29f0cb5e..50d7160b 100644 --- a/pofx/UMDF2/App/include.h +++ b/pofx/UMDF2/App/include.h @@ -9,7 +9,7 @@ #include #include -#include +#include #include #include #include diff --git a/pofx/UMDF2/Driver/SingleComp/SingleComponentSingleStateUm.inx b/pofx/UMDF2/Driver/SingleComp/SingleComponentSingleStateUm.inx index b5e35b21..ef4eed6f 100644 --- a/pofx/UMDF2/Driver/SingleComp/SingleComponentSingleStateUm.inx +++ b/pofx/UMDF2/Driver/SingleComp/SingleComponentSingleStateUm.inx @@ -55,7 +55,7 @@ SingleComponentSingleStateUm.dll = 1,, CopyFiles=UMDriverCopy [UMDriverCopy] -SingleComponentSingleStateUm.dll +SingleComponentSingleStateUm.dll,,,0x00004000 ; COPYFLG_IN_USE_RENAME [DestinationDirs] UMDriverCopy=12,UMDF ; copy to drivers\umdf diff --git a/pofx/UMDF2/Driver/SingleComp/SingleComponentSingleStateUm.vcxproj b/pofx/UMDF2/Driver/SingleComp/SingleComponentSingleStateUm.vcxproj index f74a6321..fd73ebc0 100644 --- a/pofx/UMDF2/Driver/SingleComp/SingleComponentSingleStateUm.vcxproj +++ b/pofx/UMDF2/Driver/SingleComp/SingleComponentSingleStateUm.vcxproj @@ -19,12 +19,12 @@ - {C2742046-68D5-46C4-8974-1523D6E81E44} + {54734149-462F-4F08-8921-8657E8244D5D} $(MSBuildProjectName) 2 Debug Win32 - {2F2C473D-EF60-4754-A765-016CE7E59AF5} + {0595E788-E11C-4E8F-9E6A-BDA9CD38B976} diff --git a/pofx/UMDF2/Driver/SingleComp/SingleComponentSingleStateUm.vcxproj.Filters b/pofx/UMDF2/Driver/SingleComp/SingleComponentSingleStateUm.vcxproj.Filters index 1acbb43d..1d74c304 100644 --- a/pofx/UMDF2/Driver/SingleComp/SingleComponentSingleStateUm.vcxproj.Filters +++ b/pofx/UMDF2/Driver/SingleComp/SingleComponentSingleStateUm.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {827A6CD7-9B1B-48EA-B00F-776EAD83C5D5} + {7C049D51-D629-4AF2-8583-A455CA3F6C83} h;hpp;hxx;hm;inl;inc;xsd - {A90EB6DF-7C46-439E-83E4-284A2D766EA8} + {D157BB47-2A77-4F69-B485-150DF7755B16} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {9C2DE4D9-2409-4940-AF45-0F2E072F10A3} + {0D9C7FEA-F5BC-44BC-82E3-86171939BAE4} inf;inv;inx;mof;mc; - {62D85CBA-F225-41CA-BF89-4C98DB9363E5} + {4B52E5EA-1DD3-41C5-B7B3-6530888DA16A} diff --git a/pofx/UMDF2/ReadMe.md b/pofx/UMDF2/ReadMe.md index 7272604e..cca46fdf 100644 --- a/pofx/UMDF2/ReadMe.md +++ b/pofx/UMDF2/ReadMe.md @@ -6,6 +6,9 @@ This solution demonstrates how a User-Mode Driver Framework (UMDF) version 2 dri ## Universal Compliant This sample builds a Windows Universal driver. It uses only APIs and DDIs that are included in Windows Core. +**Note** +Due to a known bug in the current Windows Driver Kit tools, when building this sample in Debug mode, the exe project may report some ApiValidator warnings. These can be safely ignored. + Related technologies -------------------- For related information, see the [KMDF Power Framework (PoFx) Sample](http://code.msdn.microsoft.com/windowshardware/PoFx-1974b51c). diff --git a/pofx/UMDF2/pofx.sln b/pofx/UMDF2/pofx.sln index 627cffb2..ea920a24 100644 --- a/pofx/UMDF2/pofx.sln +++ b/pofx/UMDF2/pofx.sln @@ -3,15 +3,15 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "App", "App", "{83BD6E56-4CF0-40D7-8D4B-AB8FBA52B0C6}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "App", "App", "{EE8B0086-FE51-41C2-BC68-73296D84902B}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SingleComp", "SingleComp", "{35021FFA-A126-4138-8574-9D62921627EB}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SingleComp", "SingleComp", "{86B4235E-0C5C-4A44-ABD0-C43595C7B39B}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Driver", "Driver", "{72A7C89C-0E64-4C4E-BF27-BD8187423B39}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Driver", "Driver", "{B554B2DD-3D1D-4665-850B-BB3D3E655C69}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PowerFxApp", "App\PowerFxApp.vcxproj", "{DA8D50B3-7692-4E79-9181-21576805D3E5}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PowerFxApp", "App\PowerFxApp.vcxproj", "{14E1832B-DF5A-4B4C-A079-A9446881E742}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SingleComponentSingleStateUm", "Driver\SingleComp\SingleComponentSingleStateUm.vcxproj", "{C2742046-68D5-46C4-8974-1523D6E81E44}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SingleComponentSingleStateUm", "Driver\SingleComp\SingleComponentSingleStateUm.vcxproj", "{54734149-462F-4F08-8921-8657E8244D5D}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -21,29 +21,29 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {DA8D50B3-7692-4E79-9181-21576805D3E5}.Debug|Win32.ActiveCfg = Debug|Win32 - {DA8D50B3-7692-4E79-9181-21576805D3E5}.Debug|Win32.Build.0 = Debug|Win32 - {DA8D50B3-7692-4E79-9181-21576805D3E5}.Release|Win32.ActiveCfg = Release|Win32 - {DA8D50B3-7692-4E79-9181-21576805D3E5}.Release|Win32.Build.0 = Release|Win32 - {DA8D50B3-7692-4E79-9181-21576805D3E5}.Debug|x64.ActiveCfg = Debug|x64 - {DA8D50B3-7692-4E79-9181-21576805D3E5}.Debug|x64.Build.0 = Debug|x64 - {DA8D50B3-7692-4E79-9181-21576805D3E5}.Release|x64.ActiveCfg = Release|x64 - {DA8D50B3-7692-4E79-9181-21576805D3E5}.Release|x64.Build.0 = Release|x64 - {C2742046-68D5-46C4-8974-1523D6E81E44}.Debug|Win32.ActiveCfg = Debug|Win32 - {C2742046-68D5-46C4-8974-1523D6E81E44}.Debug|Win32.Build.0 = Debug|Win32 - {C2742046-68D5-46C4-8974-1523D6E81E44}.Release|Win32.ActiveCfg = Release|Win32 - {C2742046-68D5-46C4-8974-1523D6E81E44}.Release|Win32.Build.0 = Release|Win32 - {C2742046-68D5-46C4-8974-1523D6E81E44}.Debug|x64.ActiveCfg = Debug|x64 - {C2742046-68D5-46C4-8974-1523D6E81E44}.Debug|x64.Build.0 = Debug|x64 - {C2742046-68D5-46C4-8974-1523D6E81E44}.Release|x64.ActiveCfg = Release|x64 - {C2742046-68D5-46C4-8974-1523D6E81E44}.Release|x64.Build.0 = Release|x64 + {14E1832B-DF5A-4B4C-A079-A9446881E742}.Debug|Win32.ActiveCfg = Debug|Win32 + {14E1832B-DF5A-4B4C-A079-A9446881E742}.Debug|Win32.Build.0 = Debug|Win32 + {14E1832B-DF5A-4B4C-A079-A9446881E742}.Release|Win32.ActiveCfg = Release|Win32 + {14E1832B-DF5A-4B4C-A079-A9446881E742}.Release|Win32.Build.0 = Release|Win32 + {14E1832B-DF5A-4B4C-A079-A9446881E742}.Debug|x64.ActiveCfg = Debug|x64 + {14E1832B-DF5A-4B4C-A079-A9446881E742}.Debug|x64.Build.0 = Debug|x64 + {14E1832B-DF5A-4B4C-A079-A9446881E742}.Release|x64.ActiveCfg = Release|x64 + {14E1832B-DF5A-4B4C-A079-A9446881E742}.Release|x64.Build.0 = Release|x64 + {54734149-462F-4F08-8921-8657E8244D5D}.Debug|Win32.ActiveCfg = Debug|Win32 + {54734149-462F-4F08-8921-8657E8244D5D}.Debug|Win32.Build.0 = Debug|Win32 + {54734149-462F-4F08-8921-8657E8244D5D}.Release|Win32.ActiveCfg = Release|Win32 + {54734149-462F-4F08-8921-8657E8244D5D}.Release|Win32.Build.0 = Release|Win32 + {54734149-462F-4F08-8921-8657E8244D5D}.Debug|x64.ActiveCfg = Debug|x64 + {54734149-462F-4F08-8921-8657E8244D5D}.Debug|x64.Build.0 = Debug|x64 + {54734149-462F-4F08-8921-8657E8244D5D}.Release|x64.ActiveCfg = Release|x64 + {54734149-462F-4F08-8921-8657E8244D5D}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {DA8D50B3-7692-4E79-9181-21576805D3E5} = {83BD6E56-4CF0-40D7-8D4B-AB8FBA52B0C6} - {C2742046-68D5-46C4-8974-1523D6E81E44} = {35021FFA-A126-4138-8574-9D62921627EB} - {35021FFA-A126-4138-8574-9D62921627EB} = {72A7C89C-0E64-4C4E-BF27-BD8187423B39} + {14E1832B-DF5A-4B4C-A079-A9446881E742} = {EE8B0086-FE51-41C2-BC68-73296D84902B} + {54734149-462F-4F08-8921-8657E8244D5D} = {86B4235E-0C5C-4A44-ABD0-C43595C7B39B} + {86B4235E-0C5C-4A44-ABD0-C43595C7B39B} = {B554B2DD-3D1D-4665-850B-BB3D3E655C69} EndGlobalSection EndGlobal diff --git a/pofx/WDF/App/PowerFxApp.cpp b/pofx/WDF/App/PowerFxApp.cpp index c628d366..2ea29a33 100644 --- a/pofx/WDF/App/PowerFxApp.cpp +++ b/pofx/WDF/App/PowerFxApp.cpp @@ -478,115 +478,70 @@ GetDevicePath( _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; + CONFIGRET cr = CR_SUCCESS; + PWSTR deviceInterfaceList = NULL; + ULONG deviceInterfaceListLength = 0; + PWSTR nextInterface; + HRESULT hr = E_FAIL; + BOOL bRet = TRUE; + + cr = CM_Get_Device_Interface_List_Size( + &deviceInterfaceListLength, + InterfaceGuid, + NULL, + CM_GET_DEVICE_INTERFACE_LIST_PRESENT); + if (cr != CR_SUCCESS) { + printf("Error 0x%x retrieving device interface list size.\n", cr); + goto clean0; } - 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); - } + if (deviceInterfaceListLength <= 1) { + bRet = FALSE; + printf("Error: No active device interfaces found.\n" + " Is the sample driver loaded?"); + goto clean0; + } - printf("SetupDiEnumDeviceInterfaces failed.\n"); - SetupDiDestroyDeviceInfoList(HardwareDeviceInfo); - return FALSE; + deviceInterfaceList = (PWSTR)malloc(deviceInterfaceListLength * sizeof(WCHAR)); + if (deviceInterfaceList == NULL) { + printf("Error allocating memory for device interface list.\n"); + goto clean0; } + ZeroMemory(deviceInterfaceList, deviceInterfaceListLength * sizeof(WCHAR)); - SetupDiGetDeviceInterfaceDetail( - HardwareDeviceInfo, - &DeviceInterfaceData, + cr = CM_Get_Device_Interface_List( + InterfaceGuid, 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; + deviceInterfaceList, + deviceInterfaceListLength, + CM_GET_DEVICE_INTERFACE_LIST_PRESENT); + if (cr != CR_SUCCESS) { + printf("Error 0x%x retrieving device interface list.\n", cr); + goto clean0; } - 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; + nextInterface = deviceInterfaceList + wcslen(deviceInterfaceList) + 1; + if (*nextInterface != UNICODE_NULL) { + printf("Warning: More than one device interface instance found. \n" + "Selecting first matching device.\n\n"); } - hr = StringCchCopy(DevicePath, - BufLen, - DeviceInterfaceDetailData->DevicePath) ; + hr = StringCchCopy(DevicePath, BufLen, deviceInterfaceList); + if (FAILED(hr)) { + bRet = FALSE; + printf("Error: StringCchCopy failed with HRESULT 0x%x", hr); + goto clean0; + } - SetupDiDestroyDeviceInfoList(HardwareDeviceInfo); // It must be executed in both success and failure traces - LocalFree(DeviceInterfaceDetailData); +clean0: + if (deviceInterfaceList != NULL) { + free(deviceInterfaceList); + } + if (CR_SUCCESS != cr) { + bRet = FALSE; + } - return ( !FAILED(hr) ); // Result depends on StringCchCopy() + return bRet; } diff --git a/pofx/WDF/App/PowerFxApp.vcxproj b/pofx/WDF/App/PowerFxApp.vcxproj index 32b104c3..6bab5de8 100644 --- a/pofx/WDF/App/PowerFxApp.vcxproj +++ b/pofx/WDF/App/PowerFxApp.vcxproj @@ -19,17 +19,17 @@ - {3E233D0A-F988-4C9D-B15A-49B54025E11F} + {1A459D79-27B4-4E77-A42D-CC2F498A5822} $(MSBuildProjectName) Debug Win32 - {11455AB9-264E-4853-AE1E-615C1C5CA620} + {346F7370-1A09-4402-8CD3-22F8DAEEA624} Windows10 False - Desktop + Universal WindowsApplicationForDrivers10.0 Application @@ -37,7 +37,7 @@ Windows10 True - Desktop + Universal WindowsApplicationForDrivers10.0 Application @@ -45,7 +45,7 @@ Windows10 False - Desktop + Universal WindowsApplicationForDrivers10.0 Application @@ -53,7 +53,7 @@ Windows10 True - Desktop + Universal WindowsApplicationForDrivers10.0 Application @@ -105,7 +105,7 @@ %(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc - %(AdditionalDependencies);setupapi.lib;user32.lib + %(AdditionalDependencies);mincore.lib @@ -126,7 +126,7 @@ %(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc - %(AdditionalDependencies);setupapi.lib;user32.lib + %(AdditionalDependencies);mincore.lib @@ -147,7 +147,7 @@ %(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc - %(AdditionalDependencies);setupapi.lib;user32.lib + %(AdditionalDependencies);mincore.lib @@ -168,7 +168,7 @@ %(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc - %(AdditionalDependencies);setupapi.lib;user32.lib + %(AdditionalDependencies);mincore.lib diff --git a/pofx/WDF/App/PowerFxApp.vcxproj.Filters b/pofx/WDF/App/PowerFxApp.vcxproj.Filters index 8d16d12b..48b861b9 100644 --- a/pofx/WDF/App/PowerFxApp.vcxproj.Filters +++ b/pofx/WDF/App/PowerFxApp.vcxproj.Filters @@ -3,15 +3,15 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {C8B06C0E-8C3C-4875-8327-4C592F8FD738} + {DBFF1BEC-1FF0-4FC6-A3FB-36AB6A323683} h;hpp;hxx;hm;inl;inc;xsd - {8091FCE2-2451-4561-B199-CB021902EA1B} + {8DEA6B64-1CF1-4A28-B5D3-BFCA577AE595} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {CC2C62EE-9135-480E-9DF9-5DB6BEB61DE8} + {F09BE8A3-EFB1-48A4-B813-6AE290BFBD71} diff --git a/pofx/WDF/App/include.h b/pofx/WDF/App/include.h index 29f0cb5e..50d7160b 100644 --- a/pofx/WDF/App/include.h +++ b/pofx/WDF/App/include.h @@ -9,7 +9,7 @@ #include #include -#include +#include #include #include #include diff --git a/pofx/WDF/Driver/MultiComp/driver/WdfMultiComp.vcxproj b/pofx/WDF/Driver/MultiComp/driver/WdfMultiComp.vcxproj index c0905b5a..4253010f 100644 --- a/pofx/WDF/Driver/MultiComp/driver/WdfMultiComp.vcxproj +++ b/pofx/WDF/Driver/MultiComp/driver/WdfMultiComp.vcxproj @@ -19,12 +19,12 @@ - {45DBDC5F-2109-432B-8149-29D3693D57E1} + {E47411F4-AAEA-4766-B62B-A5171ED47CCF} $(MSBuildProjectName) 1 Debug Win32 - {5F84F53D-DFA0-47A1-9759-FC7CFFC9599C} + {499A6FF7-57CD-4962-9500-BCF78D83750D} diff --git a/pofx/WDF/Driver/MultiComp/driver/WdfMultiComp.vcxproj.Filters b/pofx/WDF/Driver/MultiComp/driver/WdfMultiComp.vcxproj.Filters index dfe3aac9..deab83ee 100644 --- a/pofx/WDF/Driver/MultiComp/driver/WdfMultiComp.vcxproj.Filters +++ b/pofx/WDF/Driver/MultiComp/driver/WdfMultiComp.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {A5B06A84-D70F-4D83-B76D-FEA4F09EE4FC} + {0A9BD918-2221-4EB8-ADEE-BBD2CDD7492D} h;hpp;hxx;hm;inl;inc;xsd - {B738D047-A23C-43C1-9D52-3E0AC54B5C3D} + {919CB3FE-5154-4606-A075-B786F5FFFE57} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {9A02D86B-B4BE-4C57-BD3E-ADD87EE33EE9} + {425BB5CA-635C-4170-8213-7A71C5055DC8} inf;inv;inx;mof;mc; - {000E9CB4-5A60-438C-8F77-72AE7E890BB8} + {3CF8A5B4-951A-49C5-ADD3-0B82C94AD6CA} diff --git a/pofx/WDF/Driver/MultiComp/lib/WdfPoFx.vcxproj b/pofx/WDF/Driver/MultiComp/lib/WdfPoFx.vcxproj index ec187a39..5e6d09e7 100644 --- a/pofx/WDF/Driver/MultiComp/lib/WdfPoFx.vcxproj +++ b/pofx/WDF/Driver/MultiComp/lib/WdfPoFx.vcxproj @@ -19,12 +19,12 @@ - {21F832DD-6A4C-4E5F-941E-15BF98CE4137} + {30087DFC-5BF1-4BF6-A3C2-EB767B04A346} $(MSBuildProjectName) 1 Debug Win32 - {568CF874-EF69-46EF-AAE1-E59FAE847FBA} + {0BE1315A-9E67-4D52-9B4A-7C3D83D80492} diff --git a/pofx/WDF/Driver/MultiComp/lib/WdfPoFx.vcxproj.Filters b/pofx/WDF/Driver/MultiComp/lib/WdfPoFx.vcxproj.Filters index 50376050..6aa5f910 100644 --- a/pofx/WDF/Driver/MultiComp/lib/WdfPoFx.vcxproj.Filters +++ b/pofx/WDF/Driver/MultiComp/lib/WdfPoFx.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {A155D773-8FFA-4E28-9C42-A363BDD03866} + {3D1EA9F6-249A-4E28-B709-6DF1A0364A1D} h;hpp;hxx;hm;inl;inc;xsd - {7CBF3FE5-FDC1-4483-B02B-EDCEEAF60743} + {F52C45CC-11FD-4B95-ACC4-8A9F96EE4C70} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {D4BDD463-7BCE-4779-856D-4D42D6FBB5E1} + {DF786B9D-15CF-4A15-A833-C326C1B42E70} inf;inv;inx;mof;mc; - {29D299CC-0D9F-4BB4-8E92-8A1E35E7A85E} + {478A4E92-8150-4A53-8756-5B211AA8FF2F} diff --git a/pofx/WDF/Driver/MultiComp/lib/init.c b/pofx/WDF/Driver/MultiComp/lib/init.c index 780434b5..57ad7744 100644 --- a/pofx/WDF/Driver/MultiComp/lib/init.c +++ b/pofx/WDF/Driver/MultiComp/lib/init.c @@ -385,7 +385,12 @@ Return value: WDF_OBJECT_ATTRIBUTES_INIT(&objectAttributes); objectAttributes.ParentObject = Initializer; // auto-delete when parent // deleted - #pragma prefast(suppress:28160, "memorySize > 0") + + + // + // Suppress the warning that memorySize must be greater than zero + // + #pragma warning(suppress:28160) status = WdfMemoryCreate(&objectAttributes, NonPagedPool, 0, // PoolTag @@ -424,7 +429,11 @@ Return value: status); goto exit; } - #pragma prefast(suppress:28160, "minorFunctionsSize > 0") + + // + // Suppress the warning that minorFunctionsSize must be greater than zero + // + #pragma warning(suppress:28160) status = WdfMemoryCopyFromBuffer(memory, minorFunctionsOffset, memoryBuffer->MinorFunctions, diff --git a/pofx/WDF/Driver/SingleComp/SingleComponentFStateDriver.vcxproj b/pofx/WDF/Driver/SingleComp/SingleComponentFStateDriver.vcxproj index 3f0b05c0..2e912d51 100644 --- a/pofx/WDF/Driver/SingleComp/SingleComponentFStateDriver.vcxproj +++ b/pofx/WDF/Driver/SingleComp/SingleComponentFStateDriver.vcxproj @@ -19,12 +19,12 @@ - {17F25816-A09C-44DF-99A3-16D0FF5FCD66} + {288FFC86-69F2-41A0-A08B-CD42CFF51401} $(MSBuildProjectName) 1 Debug Win32 - {D3CED862-FD94-4428-9E76-0D63654856A3} + {BA711105-13CB-4276-BD41-6D3CCAA448F7} diff --git a/pofx/WDF/Driver/SingleComp/SingleComponentFStateDriver.vcxproj.Filters b/pofx/WDF/Driver/SingleComp/SingleComponentFStateDriver.vcxproj.Filters index a8eba88d..01241dd7 100644 --- a/pofx/WDF/Driver/SingleComp/SingleComponentFStateDriver.vcxproj.Filters +++ b/pofx/WDF/Driver/SingleComp/SingleComponentFStateDriver.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {C09CD711-AD25-4CEA-8535-7051049866B9} + {06F67341-2370-4DB8-B281-2E622D2C8146} h;hpp;hxx;hm;inl;inc;xsd - {8C669253-AA2C-4BA8-970C-BE8E4A5BEB6C} + {81CB8FD0-9854-41A8-8288-C99CBEED8E9A} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {2086162C-ED1C-4446-9A17-03967584AA37} + {00576151-6245-4316-B0D6-A9C1DEAD6E26} inf;inv;inx;mof;mc; - {ACF33661-8D77-4D77-ACD7-ABC80DD52BE0} + {919E6D2D-111D-421B-9634-371A59B22921} diff --git a/pofx/WDF/ReadMe.md b/pofx/WDF/ReadMe.md index 41a5a620..74cec6e0 100644 --- a/pofx/WDF/ReadMe.md +++ b/pofx/WDF/ReadMe.md @@ -6,6 +6,9 @@ This solution consists of two samples that demonstrate how a KMDF driver can imp ## Universal Compliant This sample builds a Windows Universal driver. It uses only APIs and DDIs that are included in Windows Core. +**Note** +Due to a known bug in the current Windows Driver Kit tools, when building this sample in Debug mode, the exe project may report some ApiValidator warnings. These can be safely ignored. + Related technologies -------------------- [Supporting Functional Power States](http://msdn.microsoft.com/en-us/library/windows/hardware/hh451017) diff --git a/pofx/WDF/pofx.sln b/pofx/WDF/pofx.sln index 16edf7d3..64ddbc7c 100644 --- a/pofx/WDF/pofx.sln +++ b/pofx/WDF/pofx.sln @@ -3,28 +3,28 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "App", "App", "{F0B333C5-FFAD-425B-8064-EB950E9718B8}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "App", "App", "{3EAA5179-3DB5-4480-98C6-5B5EA1965C68}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Lib", "Lib", "{24B27C7D-03C0-4286-8250-57110C794853}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Lib", "Lib", "{262CC7E2-0008-43E9-90AA-8031F479A615}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "MultiComp", "MultiComp", "{36BE1DCF-A58E-45E4-B458-3640AA1FBCC1}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "MultiComp", "MultiComp", "{A8DB64B7-4C39-4D20-85C2-1181FA6BBD36}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Driver", "Driver", "{2F266524-ED06-4654-BCFB-DBB9FE440BD7}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Driver", "Driver", "{6F6084BB-35B3-48A8-BAAC-D67835D818A2}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Driver", "Driver", "{8CA441A3-D099-4853-9D9D-3AE4DCBEC7E8}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Driver", "Driver", "{24335DF0-0022-4BAA-8DDF-02DB6E1D6BC4}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SingleComp", "SingleComp", "{18E8D511-CACD-410E-8791-41511E36F2D5}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SingleComp", "SingleComp", "{3D40DC7D-ECA2-4581-A5DE-676F30DF32C0}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PowerFxApp", "App\PowerFxApp.vcxproj", "{3E233D0A-F988-4C9D-B15A-49B54025E11F}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PowerFxApp", "App\PowerFxApp.vcxproj", "{1A459D79-27B4-4E77-A42D-CC2F498A5822}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WdfPoFx", "Driver\MultiComp\lib\WdfPoFx.vcxproj", "{21F832DD-6A4C-4E5F-941E-15BF98CE4137}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WdfPoFx", "Driver\MultiComp\lib\WdfPoFx.vcxproj", "{30087DFC-5BF1-4BF6-A3C2-EB767B04A346}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WdfMultiComp", "Driver\MultiComp\driver\WdfMultiComp.vcxproj", "{45DBDC5F-2109-432B-8149-29D3693D57E1}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WdfMultiComp", "Driver\MultiComp\driver\WdfMultiComp.vcxproj", "{E47411F4-AAEA-4766-B62B-A5171ED47CCF}" ProjectSection(ProjectDependencies) = postProject - {21F832DD-6A4C-4E5F-941E-15BF98CE4137} = {21F832DD-6A4C-4E5F-941E-15BF98CE4137} + {30087DFC-5BF1-4BF6-A3C2-EB767B04A346} = {30087DFC-5BF1-4BF6-A3C2-EB767B04A346} EndProjectSection EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SingleComponentFStateDriver", "Driver\SingleComp\SingleComponentFStateDriver.vcxproj", "{17F25816-A09C-44DF-99A3-16D0FF5FCD66}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SingleComponentFStateDriver", "Driver\SingleComp\SingleComponentFStateDriver.vcxproj", "{288FFC86-69F2-41A0-A08B-CD42CFF51401}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -34,50 +34,50 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {3E233D0A-F988-4C9D-B15A-49B54025E11F}.Debug|Win32.ActiveCfg = Debug|Win32 - {3E233D0A-F988-4C9D-B15A-49B54025E11F}.Debug|Win32.Build.0 = Debug|Win32 - {3E233D0A-F988-4C9D-B15A-49B54025E11F}.Release|Win32.ActiveCfg = Release|Win32 - {3E233D0A-F988-4C9D-B15A-49B54025E11F}.Release|Win32.Build.0 = Release|Win32 - {3E233D0A-F988-4C9D-B15A-49B54025E11F}.Debug|x64.ActiveCfg = Debug|x64 - {3E233D0A-F988-4C9D-B15A-49B54025E11F}.Debug|x64.Build.0 = Debug|x64 - {3E233D0A-F988-4C9D-B15A-49B54025E11F}.Release|x64.ActiveCfg = Release|x64 - {3E233D0A-F988-4C9D-B15A-49B54025E11F}.Release|x64.Build.0 = Release|x64 - {21F832DD-6A4C-4E5F-941E-15BF98CE4137}.Debug|Win32.ActiveCfg = Debug|Win32 - {21F832DD-6A4C-4E5F-941E-15BF98CE4137}.Debug|Win32.Build.0 = Debug|Win32 - {21F832DD-6A4C-4E5F-941E-15BF98CE4137}.Release|Win32.ActiveCfg = Release|Win32 - {21F832DD-6A4C-4E5F-941E-15BF98CE4137}.Release|Win32.Build.0 = Release|Win32 - {21F832DD-6A4C-4E5F-941E-15BF98CE4137}.Debug|x64.ActiveCfg = Debug|x64 - {21F832DD-6A4C-4E5F-941E-15BF98CE4137}.Debug|x64.Build.0 = Debug|x64 - {21F832DD-6A4C-4E5F-941E-15BF98CE4137}.Release|x64.ActiveCfg = Release|x64 - {21F832DD-6A4C-4E5F-941E-15BF98CE4137}.Release|x64.Build.0 = Release|x64 - {45DBDC5F-2109-432B-8149-29D3693D57E1}.Debug|Win32.ActiveCfg = Debug|Win32 - {45DBDC5F-2109-432B-8149-29D3693D57E1}.Debug|Win32.Build.0 = Debug|Win32 - {45DBDC5F-2109-432B-8149-29D3693D57E1}.Release|Win32.ActiveCfg = Release|Win32 - {45DBDC5F-2109-432B-8149-29D3693D57E1}.Release|Win32.Build.0 = Release|Win32 - {45DBDC5F-2109-432B-8149-29D3693D57E1}.Debug|x64.ActiveCfg = Debug|x64 - {45DBDC5F-2109-432B-8149-29D3693D57E1}.Debug|x64.Build.0 = Debug|x64 - {45DBDC5F-2109-432B-8149-29D3693D57E1}.Release|x64.ActiveCfg = Release|x64 - {45DBDC5F-2109-432B-8149-29D3693D57E1}.Release|x64.Build.0 = Release|x64 - {17F25816-A09C-44DF-99A3-16D0FF5FCD66}.Debug|Win32.ActiveCfg = Debug|Win32 - {17F25816-A09C-44DF-99A3-16D0FF5FCD66}.Debug|Win32.Build.0 = Debug|Win32 - {17F25816-A09C-44DF-99A3-16D0FF5FCD66}.Release|Win32.ActiveCfg = Release|Win32 - {17F25816-A09C-44DF-99A3-16D0FF5FCD66}.Release|Win32.Build.0 = Release|Win32 - {17F25816-A09C-44DF-99A3-16D0FF5FCD66}.Debug|x64.ActiveCfg = Debug|x64 - {17F25816-A09C-44DF-99A3-16D0FF5FCD66}.Debug|x64.Build.0 = Debug|x64 - {17F25816-A09C-44DF-99A3-16D0FF5FCD66}.Release|x64.ActiveCfg = Release|x64 - {17F25816-A09C-44DF-99A3-16D0FF5FCD66}.Release|x64.Build.0 = Release|x64 + {1A459D79-27B4-4E77-A42D-CC2F498A5822}.Debug|Win32.ActiveCfg = Debug|Win32 + {1A459D79-27B4-4E77-A42D-CC2F498A5822}.Debug|Win32.Build.0 = Debug|Win32 + {1A459D79-27B4-4E77-A42D-CC2F498A5822}.Release|Win32.ActiveCfg = Release|Win32 + {1A459D79-27B4-4E77-A42D-CC2F498A5822}.Release|Win32.Build.0 = Release|Win32 + {1A459D79-27B4-4E77-A42D-CC2F498A5822}.Debug|x64.ActiveCfg = Debug|x64 + {1A459D79-27B4-4E77-A42D-CC2F498A5822}.Debug|x64.Build.0 = Debug|x64 + {1A459D79-27B4-4E77-A42D-CC2F498A5822}.Release|x64.ActiveCfg = Release|x64 + {1A459D79-27B4-4E77-A42D-CC2F498A5822}.Release|x64.Build.0 = Release|x64 + {30087DFC-5BF1-4BF6-A3C2-EB767B04A346}.Debug|Win32.ActiveCfg = Debug|Win32 + {30087DFC-5BF1-4BF6-A3C2-EB767B04A346}.Debug|Win32.Build.0 = Debug|Win32 + {30087DFC-5BF1-4BF6-A3C2-EB767B04A346}.Release|Win32.ActiveCfg = Release|Win32 + {30087DFC-5BF1-4BF6-A3C2-EB767B04A346}.Release|Win32.Build.0 = Release|Win32 + {30087DFC-5BF1-4BF6-A3C2-EB767B04A346}.Debug|x64.ActiveCfg = Debug|x64 + {30087DFC-5BF1-4BF6-A3C2-EB767B04A346}.Debug|x64.Build.0 = Debug|x64 + {30087DFC-5BF1-4BF6-A3C2-EB767B04A346}.Release|x64.ActiveCfg = Release|x64 + {30087DFC-5BF1-4BF6-A3C2-EB767B04A346}.Release|x64.Build.0 = Release|x64 + {E47411F4-AAEA-4766-B62B-A5171ED47CCF}.Debug|Win32.ActiveCfg = Debug|Win32 + {E47411F4-AAEA-4766-B62B-A5171ED47CCF}.Debug|Win32.Build.0 = Debug|Win32 + {E47411F4-AAEA-4766-B62B-A5171ED47CCF}.Release|Win32.ActiveCfg = Release|Win32 + {E47411F4-AAEA-4766-B62B-A5171ED47CCF}.Release|Win32.Build.0 = Release|Win32 + {E47411F4-AAEA-4766-B62B-A5171ED47CCF}.Debug|x64.ActiveCfg = Debug|x64 + {E47411F4-AAEA-4766-B62B-A5171ED47CCF}.Debug|x64.Build.0 = Debug|x64 + {E47411F4-AAEA-4766-B62B-A5171ED47CCF}.Release|x64.ActiveCfg = Release|x64 + {E47411F4-AAEA-4766-B62B-A5171ED47CCF}.Release|x64.Build.0 = Release|x64 + {288FFC86-69F2-41A0-A08B-CD42CFF51401}.Debug|Win32.ActiveCfg = Debug|Win32 + {288FFC86-69F2-41A0-A08B-CD42CFF51401}.Debug|Win32.Build.0 = Debug|Win32 + {288FFC86-69F2-41A0-A08B-CD42CFF51401}.Release|Win32.ActiveCfg = Release|Win32 + {288FFC86-69F2-41A0-A08B-CD42CFF51401}.Release|Win32.Build.0 = Release|Win32 + {288FFC86-69F2-41A0-A08B-CD42CFF51401}.Debug|x64.ActiveCfg = Debug|x64 + {288FFC86-69F2-41A0-A08B-CD42CFF51401}.Debug|x64.Build.0 = Debug|x64 + {288FFC86-69F2-41A0-A08B-CD42CFF51401}.Release|x64.ActiveCfg = Release|x64 + {288FFC86-69F2-41A0-A08B-CD42CFF51401}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {3E233D0A-F988-4C9D-B15A-49B54025E11F} = {F0B333C5-FFAD-425B-8064-EB950E9718B8} - {21F832DD-6A4C-4E5F-941E-15BF98CE4137} = {24B27C7D-03C0-4286-8250-57110C794853} - {45DBDC5F-2109-432B-8149-29D3693D57E1} = {8CA441A3-D099-4853-9D9D-3AE4DCBEC7E8} - {17F25816-A09C-44DF-99A3-16D0FF5FCD66} = {18E8D511-CACD-410E-8791-41511E36F2D5} - {24B27C7D-03C0-4286-8250-57110C794853} = {36BE1DCF-A58E-45E4-B458-3640AA1FBCC1} - {36BE1DCF-A58E-45E4-B458-3640AA1FBCC1} = {2F266524-ED06-4654-BCFB-DBB9FE440BD7} - {8CA441A3-D099-4853-9D9D-3AE4DCBEC7E8} = {36BE1DCF-A58E-45E4-B458-3640AA1FBCC1} - {18E8D511-CACD-410E-8791-41511E36F2D5} = {2F266524-ED06-4654-BCFB-DBB9FE440BD7} + {1A459D79-27B4-4E77-A42D-CC2F498A5822} = {3EAA5179-3DB5-4480-98C6-5B5EA1965C68} + {30087DFC-5BF1-4BF6-A3C2-EB767B04A346} = {262CC7E2-0008-43E9-90AA-8031F479A615} + {E47411F4-AAEA-4766-B62B-A5171ED47CCF} = {24335DF0-0022-4BAA-8DDF-02DB6E1D6BC4} + {288FFC86-69F2-41A0-A08B-CD42CFF51401} = {3D40DC7D-ECA2-4581-A5DE-676F30DF32C0} + {262CC7E2-0008-43E9-90AA-8031F479A615} = {A8DB64B7-4C39-4D20-85C2-1181FA6BBD36} + {A8DB64B7-4C39-4D20-85C2-1181FA6BBD36} = {6F6084BB-35B3-48A8-BAAC-D67835D818A2} + {24335DF0-0022-4BAA-8DDF-02DB6E1D6BC4} = {A8DB64B7-4C39-4D20-85C2-1181FA6BBD36} + {3D40DC7D-ECA2-4581-A5DE-676F30DF32C0} = {6F6084BB-35B3-48A8-BAAC-D67835D818A2} EndGlobalSection EndGlobal diff --git a/print/SampleOpenXPS/BlankProjSrc/BlankProject.vcxproj b/print/SampleOpenXPS/BlankProjSrc/BlankProject.vcxproj index 544fe0e2..179b5e40 100644 --- a/print/SampleOpenXPS/BlankProjSrc/BlankProject.vcxproj +++ b/print/SampleOpenXPS/BlankProjSrc/BlankProject.vcxproj @@ -19,12 +19,12 @@ - {8DD661EC-C827-40E9-8894-C81041AC4324} + {51F80EDA-1959-4685-91F9-C820EB0F9550} $(MSBuildProjectName) false Debug Win32 - {AF94EE33-40D5-4CD7-9F09-5A1CC16F2EF0} + {3411A7DF-973F-40B3-A8C5-80134DE29E92} diff --git a/print/SampleOpenXPS/BlankProjSrc/BlankProject.vcxproj.Filters b/print/SampleOpenXPS/BlankProjSrc/BlankProject.vcxproj.Filters index fee230a4..91b3d644 100644 --- a/print/SampleOpenXPS/BlankProjSrc/BlankProject.vcxproj.Filters +++ b/print/SampleOpenXPS/BlankProjSrc/BlankProject.vcxproj.Filters @@ -3,15 +3,15 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {B2CC4F75-22F6-4939-B93F-DAFE36BFD9D6} + {6352E8DC-DB14-463B-8201-DBB7F41937D7} h;hpp;hxx;hm;inl;inc;xsd - {0A89D084-FD85-4B63-B752-7C0852CD9001} + {6CBD6890-5328-4EFE-B850-7A28B1683741} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {74429B5A-7FD5-4707-BEED-E41681C9E5B0} + {6F8E2B21-C7AA-4015-931A-B23BB2400C33} \ No newline at end of file diff --git a/print/SampleOpenXPS/SampleOpenXPS.sln b/print/SampleOpenXPS/SampleOpenXPS.sln index 19ed775e..a11afc00 100644 --- a/print/SampleOpenXPS/SampleOpenXPS.sln +++ b/print/SampleOpenXPS/SampleOpenXPS.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BlankProject", "BlankProjSrc\BlankProject.vcxproj", "{8DD661EC-C827-40E9-8894-C81041AC4324}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BlankProject", "BlankProjSrc\BlankProject.vcxproj", "{51F80EDA-1959-4685-91F9-C820EB0F9550}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +13,14 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {8DD661EC-C827-40E9-8894-C81041AC4324}.Debug|Win32.ActiveCfg = Debug|Win32 - {8DD661EC-C827-40E9-8894-C81041AC4324}.Debug|Win32.Build.0 = Debug|Win32 - {8DD661EC-C827-40E9-8894-C81041AC4324}.Release|Win32.ActiveCfg = Release|Win32 - {8DD661EC-C827-40E9-8894-C81041AC4324}.Release|Win32.Build.0 = Release|Win32 - {8DD661EC-C827-40E9-8894-C81041AC4324}.Debug|x64.ActiveCfg = Debug|x64 - {8DD661EC-C827-40E9-8894-C81041AC4324}.Debug|x64.Build.0 = Debug|x64 - {8DD661EC-C827-40E9-8894-C81041AC4324}.Release|x64.ActiveCfg = Release|x64 - {8DD661EC-C827-40E9-8894-C81041AC4324}.Release|x64.Build.0 = Release|x64 + {51F80EDA-1959-4685-91F9-C820EB0F9550}.Debug|Win32.ActiveCfg = Debug|Win32 + {51F80EDA-1959-4685-91F9-C820EB0F9550}.Debug|Win32.Build.0 = Debug|Win32 + {51F80EDA-1959-4685-91F9-C820EB0F9550}.Release|Win32.ActiveCfg = Release|Win32 + {51F80EDA-1959-4685-91F9-C820EB0F9550}.Release|Win32.Build.0 = Release|Win32 + {51F80EDA-1959-4685-91F9-C820EB0F9550}.Debug|x64.ActiveCfg = Debug|x64 + {51F80EDA-1959-4685-91F9-C820EB0F9550}.Debug|x64.Build.0 = Debug|x64 + {51F80EDA-1959-4685-91F9-C820EB0F9550}.Release|x64.ActiveCfg = Release|x64 + {51F80EDA-1959-4685-91F9-C820EB0F9550}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/print/SampleXPS/BlankProjSrc/BlankProject.vcxproj b/print/SampleXPS/BlankProjSrc/BlankProject.vcxproj index b7b96fa8..6e631d9e 100644 --- a/print/SampleXPS/BlankProjSrc/BlankProject.vcxproj +++ b/print/SampleXPS/BlankProjSrc/BlankProject.vcxproj @@ -19,12 +19,12 @@ - {D2B639CE-AC86-49E5-82A5-0754C41CE7C2} + {374C5441-19FB-43F0-9F91-70B2255B56F9} $(MSBuildProjectName) false Debug Win32 - {940BB686-F68A-4FA7-B9AC-441E0AA3E7D6} + {BFA1B08D-DEAD-42D3-905F-2DF39E5AE1D1} diff --git a/print/SampleXPS/BlankProjSrc/BlankProject.vcxproj.Filters b/print/SampleXPS/BlankProjSrc/BlankProject.vcxproj.Filters index fd3edb1a..42201c91 100644 --- a/print/SampleXPS/BlankProjSrc/BlankProject.vcxproj.Filters +++ b/print/SampleXPS/BlankProjSrc/BlankProject.vcxproj.Filters @@ -3,15 +3,15 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {4B942DCE-1A35-4E9F-A667-4A78801DCCB2} + {857EAB9E-D7F0-451B-ABA4-71DFA74756A3} h;hpp;hxx;hm;inl;inc;xsd - {F50DDDBE-9690-4E91-B1BC-32FA17D99E70} + {D187F73D-A17E-4192-9F70-A8B25DB85600} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {9F0418C7-D852-4109-8654-6A18AD8318D1} + {42B46C1A-D46A-4720-9CB2-7C73C57409B2} \ No newline at end of file diff --git a/print/SampleXPS/SampleXPS.sln b/print/SampleXPS/SampleXPS.sln index 7653b4c4..536becc7 100644 --- a/print/SampleXPS/SampleXPS.sln +++ b/print/SampleXPS/SampleXPS.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BlankProject", "BlankProjSrc\BlankProject.vcxproj", "{D2B639CE-AC86-49E5-82A5-0754C41CE7C2}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BlankProject", "BlankProjSrc\BlankProject.vcxproj", "{374C5441-19FB-43F0-9F91-70B2255B56F9}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +13,14 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {D2B639CE-AC86-49E5-82A5-0754C41CE7C2}.Debug|Win32.ActiveCfg = Debug|Win32 - {D2B639CE-AC86-49E5-82A5-0754C41CE7C2}.Debug|Win32.Build.0 = Debug|Win32 - {D2B639CE-AC86-49E5-82A5-0754C41CE7C2}.Release|Win32.ActiveCfg = Release|Win32 - {D2B639CE-AC86-49E5-82A5-0754C41CE7C2}.Release|Win32.Build.0 = Release|Win32 - {D2B639CE-AC86-49E5-82A5-0754C41CE7C2}.Debug|x64.ActiveCfg = Debug|x64 - {D2B639CE-AC86-49E5-82A5-0754C41CE7C2}.Debug|x64.Build.0 = Debug|x64 - {D2B639CE-AC86-49E5-82A5-0754C41CE7C2}.Release|x64.ActiveCfg = Release|x64 - {D2B639CE-AC86-49E5-82A5-0754C41CE7C2}.Release|x64.Build.0 = Release|x64 + {374C5441-19FB-43F0-9F91-70B2255B56F9}.Debug|Win32.ActiveCfg = Debug|Win32 + {374C5441-19FB-43F0-9F91-70B2255B56F9}.Debug|Win32.Build.0 = Debug|Win32 + {374C5441-19FB-43F0-9F91-70B2255B56F9}.Release|Win32.ActiveCfg = Release|Win32 + {374C5441-19FB-43F0-9F91-70B2255B56F9}.Release|Win32.Build.0 = Release|Win32 + {374C5441-19FB-43F0-9F91-70B2255B56F9}.Debug|x64.ActiveCfg = Debug|x64 + {374C5441-19FB-43F0-9F91-70B2255B56F9}.Debug|x64.Build.0 = Debug|x64 + {374C5441-19FB-43F0-9F91-70B2255B56F9}.Release|x64.ActiveCfg = Release|x64 + {374C5441-19FB-43F0-9F91-70B2255B56F9}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/print/SimplePipelineFilter/SimplePipelineFilter.sln b/print/SimplePipelineFilter/SimplePipelineFilter.sln index c7863beb..f7d259a1 100644 --- a/print/SimplePipelineFilter/SimplePipelineFilter.sln +++ b/print/SimplePipelineFilter/SimplePipelineFilter.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WdkPipelineFilter", "WdkPipelineFilter.vcxproj", "{D3CE825A-F33C-4DF0-AA6D-F7BC0463164D}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WdkPipelineFilter", "WdkPipelineFilter.vcxproj", "{73744205-4B30-4AA3-9C04-DA4826B3E07C}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +13,14 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {D3CE825A-F33C-4DF0-AA6D-F7BC0463164D}.Debug|Win32.ActiveCfg = Debug|Win32 - {D3CE825A-F33C-4DF0-AA6D-F7BC0463164D}.Debug|Win32.Build.0 = Debug|Win32 - {D3CE825A-F33C-4DF0-AA6D-F7BC0463164D}.Release|Win32.ActiveCfg = Release|Win32 - {D3CE825A-F33C-4DF0-AA6D-F7BC0463164D}.Release|Win32.Build.0 = Release|Win32 - {D3CE825A-F33C-4DF0-AA6D-F7BC0463164D}.Debug|x64.ActiveCfg = Debug|x64 - {D3CE825A-F33C-4DF0-AA6D-F7BC0463164D}.Debug|x64.Build.0 = Debug|x64 - {D3CE825A-F33C-4DF0-AA6D-F7BC0463164D}.Release|x64.ActiveCfg = Release|x64 - {D3CE825A-F33C-4DF0-AA6D-F7BC0463164D}.Release|x64.Build.0 = Release|x64 + {73744205-4B30-4AA3-9C04-DA4826B3E07C}.Debug|Win32.ActiveCfg = Debug|Win32 + {73744205-4B30-4AA3-9C04-DA4826B3E07C}.Debug|Win32.Build.0 = Debug|Win32 + {73744205-4B30-4AA3-9C04-DA4826B3E07C}.Release|Win32.ActiveCfg = Release|Win32 + {73744205-4B30-4AA3-9C04-DA4826B3E07C}.Release|Win32.Build.0 = Release|Win32 + {73744205-4B30-4AA3-9C04-DA4826B3E07C}.Debug|x64.ActiveCfg = Debug|x64 + {73744205-4B30-4AA3-9C04-DA4826B3E07C}.Debug|x64.Build.0 = Debug|x64 + {73744205-4B30-4AA3-9C04-DA4826B3E07C}.Release|x64.ActiveCfg = Release|x64 + {73744205-4B30-4AA3-9C04-DA4826B3E07C}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/print/SimplePipelineFilter/WdkPipelineFilter.vcxproj b/print/SimplePipelineFilter/WdkPipelineFilter.vcxproj index 3af320ac..d319d2d4 100644 --- a/print/SimplePipelineFilter/WdkPipelineFilter.vcxproj +++ b/print/SimplePipelineFilter/WdkPipelineFilter.vcxproj @@ -19,11 +19,11 @@ - {D3CE825A-F33C-4DF0-AA6D-F7BC0463164D} + {73744205-4B30-4AA3-9C04-DA4826B3E07C} $(MSBuildProjectName) Debug Win32 - {5BC5D9DA-A9ED-4BE2-8DD9-33853EFC148A} + {762535A9-A614-4687-AB86-D73CBAAA409F} diff --git a/print/SimplePipelineFilter/WdkPipelineFilter.vcxproj.Filters b/print/SimplePipelineFilter/WdkPipelineFilter.vcxproj.Filters index 65c4c551..e411e036 100644 --- a/print/SimplePipelineFilter/WdkPipelineFilter.vcxproj.Filters +++ b/print/SimplePipelineFilter/WdkPipelineFilter.vcxproj.Filters @@ -3,15 +3,15 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {9E97BFB7-9C77-4223-A684-83194A1A1C59} + {11B1E8EE-5ECF-4526-81C3-DD599D206041} h;hpp;hxx;hm;inl;inc;xsd - {ED009CED-C036-41C0-96C7-B993C7F42ECD} + {950D7CF8-7A8C-4160-8862-253FA4766F3F} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {F44E5BC1-1970-4C43-A39A-30A1F28A6E42} + {24D44278-1B4F-454E-8344-E9A8C98D75EF} diff --git a/print/XPSDrvSmpl/Package/package.VcxProj b/print/XPSDrvSmpl/Package/package.VcxProj new file mode 100644 index 00000000..c33ab5d8 --- /dev/null +++ b/print/XPSDrvSmpl/Package/package.VcxProj @@ -0,0 +1,115 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + WindowsKernelModeDriver10.0 + Utility + Package + true + Debug + + + + {419B0310-99CD-4866-A8E6-B6F43E6B8513} + {9C2ED56D-6953-498B-9DC6-826F1AEE4F15} + $(MSBuildProjectName) + + + Windows10 + true + + + Windows10 + false + + + Windows10 + true + + + Windows10 + false + + + + + + + + + + + DbgengRemoteDebugger + False + None + + + + + + %PathToInf% + False + False + True + + 133563 + + + + + + + + + + {AF94DFED-1979-486B-A16E-7BBB14711EA0} + + + {B0A0CBB7-DC33-4FE1-B356-C4978A035097} + + + {49DD5381-63D8-41FB-B641-AFE52BFBBC32} + + + {AE18BFE5-EA00-477B-A051-F28DD3078679} + + + {DDC3CDA6-A188-4A21-A321-37E8A044EC22} + + + {06548B4B-6104-4F36-8BAA-127D23F73CD4} + + + {268439B8-E924-47E4-BFE9-01DED439AFFE} + + + {89DE916B-9E07-4E1F-BFF9-3FC16328B0DD} + + + {BCB6A109-EB2A-4D55-908E-22EE132F75AD} + + + {20DDD6AA-CA85-46F3-8446-EDA619839273} + + + + + + \ No newline at end of file diff --git a/print/XPSDrvSmpl/Package/package.VcxProj.Filters b/print/XPSDrvSmpl/Package/package.VcxProj.Filters new file mode 100644 index 00000000..1ff2a8df --- /dev/null +++ b/print/XPSDrvSmpl/Package/package.VcxProj.Filters @@ -0,0 +1,21 @@ + + + + + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* + {7620518A-2F71-40A2-BDB7-BCE6E48AB046} + + + h;hpp;hxx;hm;inl;inc;xsd + {C711D8E7-2B9C-4F45-8379-E6A59904E3B7} + + + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml + {A7890E75-2E06-42D1-B99F-2664864649B8} + + + inf;inv;inx;mof;mc; + {540AC39A-B8D9-430D-BAC0-44BACAB69C1E} + + + \ No newline at end of file diff --git a/print/XPSDrvSmpl/ReadMe.md b/print/XPSDrvSmpl/ReadMe.md new file mode 100644 index 00000000..659f442a --- /dev/null +++ b/print/XPSDrvSmpl/ReadMe.md @@ -0,0 +1,268 @@ +XPSDrv Driver and Filter Sample +=============================== + +This sample is intended to provide a starting point for developing XPSDrv printer drivers and to illustrate the facility and potential of an XPSDrv print driver. This goal is accomplished by implementing a number of real-world features within a set of XPS print pipeline filters that are configured through a configuration plug-in that supports custom UI content and PrintTicket handling. + +Windows Vista introduced a new print architecture and a new document format known as XPS (XML Paper Specification). Part of the new architecture is the XPSDrv print driver, which is designed to provide a flexible, extensible path to manipulate and print an XPS spool file through a series of filters. + +This sample is intended to provide a starting point for developing XPSDrv printer drivers and to illustrate the facility and potential of an XPSDrv print driver. This goal is accomplished by implementing a number of real-world features within a set of XPS print pipeline filters that are configured through a configuration plug-in that supports custom UI content and PrintTicket handling. + +The sample broadly consists of three components: a set of filters, a configuration plug-in for handling custom UI content, and a configuration plug-in for handling more advanced PrintTicket features. For more information, see [XPS Printing Features](http://msdn.microsoft.com/en-us/library/windows/hardware/ff564299(v=vs.85).aspx). + + +Build the sample +---------------- + +To build a driver solution using Windows 8.1 driver kit (WDK 8.1) and Visual Studio 2013, perform the following steps. + +1. Open the solution file in Visual Studio 2013 + +2. Add all non-binary files (usually located in the \\install directory of the sample) to the Package project + +a. In the **Solution Explorer**, right click **Driver Files** + +b. Select **Add**, then click **Existing Item** + +c. Navigate to the location to which you downloaded the sample, and select all the files in the install directory, or the equivalent set of non-binary files such as INFs, INIs, GPD, PPD files, etc. + +d. Click **Add** + +3. Configure these files to be added into the driver package + +a. In the **Solution Explorer**, right click the Package project and select **Properties** + +b. In the left pane, click **Configuration Properties** \> **Driver Install** \> **Package Files**. + +c. In the right pane, use the ellipsis button (...) to browse to the set of files that needs to be added to the driver package. All the data files that you added in **Step 2-c**, except the INF file, should be added. + +**Note**  This configuration is per-architecture, so this configuration must be repeated for each architecture that will be built. + +d. Click **OK** + +4. Open the INF file and edit it to match the built output + +a. Open the INF file + +b. In the Version section, add a reference to a catalog file like this: CatalogFile=XpsDrvSmpl.cat + +c. In the SourceDisksFiles section, change the location of the DLL files you are building, to =1. This indicates that there is no architecture specific directory in this driver. If you ship multiple architectures simultaneously, you will need to collate the driver INF manually. + +At this point, Visual Studio 2013 will be able to build a driver package and output the files to disk. In order to configure driver signing and deployment, see [Developing, Testing, and Deploying Drivers](http://msdn.microsoft.com/en-us/library/windows/hardware/ff554651(v=vs.85).aspx). + +**Note**  If you compile your sample driver with Microsoft Visual Studio version 10, or 11 with the \_DEBUG flag set, then you should not use CComVariant on the following two XPS Print Filter Pipeline properties: + +- XPS\_FP\_USER\_TOKEN +- XPS\_FP\_PRINTER\_HANDLE + +There is a known issue with the current implementation of the Print Filter Pipeline, where the variant type for these two properties is set to VT\_BYREF. And as a result of this known issue, any filter binary that is compiled with the \_DEBUG flag set will experience the ATLASSERT() failure. This is because when you use the CComVariant, its destructor checks the returned value from the Clear() function, as shown: + + +++ + + + + + + + + + + +
C++
~CComVariant() throw()
+{
+   HRESULT hr = Clear();
+   ATLASSERT(SUCCEEDED(hr));
+   (hr);
+}
+ +When you compile this sample driver with Visual Studio version 9, you don't experience this problem because the destructor for CComVariant doesn't perform this check on the returned value from the Clear() function. + +Run the sample +-------------- + +Installation +------------ + +The sample has the following prerequisites: + +- Microsoft XPS Document Writer print driver and the XPS filter-pipeline infrastructure. +- Microsoft MSXML 6.0 + +Install the driver through the **Add Printer Wizard** by selecting \\\install as the source for the driver install. + +Design and Operation +-------------------- + +### Overview + +This sample can be used as a basis for implementing a driver based on the new XPS pipeline infrastructure. + +The Page Scaling filter is written by using the stream interface to attempt to demonstrate how to use the stream interface. It thus depends on a ZIP library to handle the PK archive structure. The sample does not include the code for the PK archive handling. + +Two interfaces are defined in *ipkarch.h* and *ipkfile.h* that need support from an additional PK archive handling module called pkarch.dll. Pkarch.dll is a file that is included in the [PKWare SDK](http://www.pkware.com/software/developer-tools/sdk/pkzip-standard-toolkit). If this module is not present, the page scaling filter sample will revert to merely copying the data from the read stream to the write stream. Developers who are using this sample can choose one of the following options: + +- Simplify the scaling filter to use the XPS interfaces (like the other four filters) +- License the third-party zip library that is used in the sample +- Modify the sample to use another ZIP library. For example, you can modify the sample to use the [Packaging API Reference](http://msdn.microsoft.com/en-us/library/windows/desktop/dd371643(v=vs.85).aspx) + +IPKArch defines an interface for initializing, controlling, and accessing the PK archive. IPKFile defines an interface that abstracts the details of a PK archive file header record from the XPS container handling. Access to the files within the archive is provided through a map between the file name and file objects that support the IPKFile interface. This allows the XPS processing code to retrieve file data by name (a convenience as the interaction between parts and relationships between parts is defined using the part name). + +### Print Pipeline Filters + +There are five filters that are split into two types: four use the XPS filter interface and one uses the stream filter interface. The XPS interface provides the filter writer with a logical view on an XPS document by presenting logical XPS document parts (XPS Document, Fixed Document Sequences, Fixed Documents, and Fixed Pages) to the filter in a known and defined order. The stream interface simply provides a stream that contains the XPS document--a zip archive. The filter writer is in this case required to handle the PK archive structure, decompression of the parts within the container, and the XPS Open Packaging conventions. + +The four filters that use the XPS interface provide support for the following: + +- The Watermark Filter is responsible for adding mark-up to Fixed Page content to express textual, bitmap, and vector-based watermarks. +- The Booklet Filter is responsible for page re-ordering and padding page insertion to create booklets from the XPS document. Note that this filter re-uses the NUp filter to provide appropriate page transformation. +- The NUp Filter is responsible for transforming and combining logical pages onto physical pages to provide multiple page per sheet support. +- The Color Management Filter is responsible for constructing and applying color transforms to Fixed Page content. + +The stream interface filter provides Page Scaling support (that is, wrapping content with the appropriate transforms to scale from a source Fixed Page to the destination). + +### UI Plug-in + +The UI plug-in provides support for controlling features that are not supported by the Unidrv core UI. Three additional printer property pages are implemented that provide color management, watermarking, and general features. The UI plug-in also provides custom Devmode support for options that are not easily expressed in a GPD file (for example, the numeric values required to define custom page scaling options). + +### Print Ticket Provider Plug-in + +Unidrv provides support for mapping simple features and options from a GPD file to a Print Ticket by a "PrintSchemaKeywordMap" keyword in the GPD file. Many of the features that are supported by the sample filters require a more sophisticated mapping between the GPD description and the Print Schema definition. These features include features that are nested within features and control of numeric values. The Print Ticket provider plug-in provides this support by converting a number of GPD feature options to a single more complicated Print Ticket feature. For example, the Print Schema definition of PageScaling requires numeric values for custom page scaling options (offset and scale values) as well as a sub-feature defining the scaling offset option. This plug-in can take settings from a "flat" description of the scaling and offset alignment features in the GPD combined with custom DevMode values configured by the UI plug-in to generate an appropriate PrintTicket construct that conforms to the PrintSchema definition of PageScaling. + +The components of the XPSDrv sample enable a user or application to configure the filter pipeline to process an XPS container according to the supported filters. The XPS spool file that is passed to the filter pipeline broadly comprises two components: the document structure and page content as well as one or more Print Tickets that configure the print job at various levels. Job content will be defined either as output directly from a Windows Presentation Foundation (WPF) application or through a conversion from legacy GDI to XPS through the Microsoft XPS Document Writer (MXDW). PrintTicket settings can be controlled directly through the UI or through application settings in either DevMode or PrintTicket. + +To enable configuration of the driver, the sample uses a set of GPD files and a configuration plug-in. The configuration plug-in provides custom DevMode and custom UI support. This support enables the driver to store and configure driver specific settings that can be used as a source for configuring PrintTicket features. In order to provide the appropriate PrintTicket support, the driver makes use of a combination of the core Unidrv PrintTicket support and a PrintTicket provider plug-in to enable the generation of more sophisticated PrintTicket settings. In combination these allow an application or user to setup a PrintTicket ready for inclusion in an XPS document. + +With the PrintTicket in place and the document content supplied by either an application using WPF or a legacy application through MXDW, the filters that make up the filter pipeline for the sample driver act on the XPS document according to the settings specified in the PrintTicket. Each filter checks whether its functionality has been enabled and extracts any settings relevant to its function before processing the container appropriately. The order in which filters are applied is important to the eventual output; for example, a filter adding page content (like the watermark filter) can be placed anywhere in the pipeline, but its placement determines where the content is added. Configured to run before an NUp filter ensures page content is confined to the logical page; whereas, if it is run after an NUp filter, the watermark will be applied to the transformed pages. The filter ordering is controlled by the filter configuration file; this file is an XML document that details the order and interface type for each filter. + +### Common Filter Functionality + +Regardless of the type of interface that a filter uses to process the XPS document content, there are common requirements for all filters. These include filter initialization and shutdown and are provided as a base class from which either an XPS or stream interface filter can derive. + +### XPS Interface + +Four of the five filters make use of the XPS interface that is provided by the filter pipeline manager as XPS provider and consumer interfaces. The XPS provider interface supplies XPS parts to the filter on demand. When a part is requested from the provider, a generic interface pointer is returned. This interface is queried to identify its type: an XPS document, a Fixed Document Sequence, a Fixed Document or a Fixed Page. This functionality is common between filters that use the XPS interface and a base class XPS interface implementation (that derives from the common filter class described earlier) is provided that retrieves, identifies, and dispatches the part to the appropriate handler. When all parts have been processed, the base class calls a method to finalize the filter. To supply the filter-specific functionality, a filter derives from the base class and implements handlers for any of the part types it requires and/or the finalize method to complete its function. Additionally, the base class provides default implementations for the XPS part handlers (using these exclusively merely passes the document on through the XPS consumer interface) and a method for initializing the XPS interface. + +### Stream Interface + +One of the filters (page scaling) makes use of the stream interface that is provided by the filter pipeline manager as a read and write stream. This interface is a very basic interface that merely supplies the filter with a stream that contains the XPS document as a PK archive. To be able to use the stream interface to modify document content, the filter needs to be able to process the PK archive to retrieve all of the files contained within, decompress the data associated with these files, process the open packaging conventions (taking into account potentially interleaved data), and compress and send the data in a structure appropriate to both the open package and PK archive conventions. A class is provided that uses an XPS document processor for accessing the logical structure of the package and reporting the Fixed Page content to the filter. This class supports the necessary interfaces to initialize the IO streams, start the process of handling the data, and a default handler for processing Fixed Page content. The page scaling filter derives from this class and implements its own Fixed Page handler that is called by the XPS processor. + +### Watermark Filter + +The Watermark filter is intended to demonstrate adding presentation content to the Fixed Pages within an existing XPS container by using the XPS interface as the source of the XPS document. This added content acts as a watermark and is configured by the PrintTicket. The filter takes as input the PageWatermark public Print Schema feature with custom support for vector and bitmap watermark types and the Fixed Pages in an XPS document. This custom content is expressed as Private options to the existing PageWatermark definition. The output is the sequence of Fixed Pages and accompanying resources required for the watermark. + +The filter is configured by parsing an input PrintTicket by using DOM to extract the relevant features and options. If the functionality is enabled, the filter processes the document as required. The PrintTicket is constructed through the following algorithm to provide settings at the appropriate scope (Fixed Document Sequence, Fixed Document and Fixed Page): + +1. Validate and merge the print ticket from the FDS with the default PrintTicket converted from the default DevMode in the property bag. The resultant ticket will be the Job level ticket. +2. Validate and merge the print ticket from the current FD with the Job level ticket from step 1. The resultant ticket will be the document level ticket. +3. Validate and merge the print ticket from the current FP with the Doc level ticket from step 2. The resultant ticket will be the page level ticket. + +When a watermark is enabled in the PrintTicket, the filter creates a watermark of the appropriate type (text, raster, or vector). This is returned as a generic watermark interface that abstracts the watermark type from the filter. The filter then calls the watermark object to send any resources that it may require to the filter pipeline (the font for text, the bitmap for raster, and none for vector). All resources are added through a resource cache that enables the watermark object to ignore any problems with sending repeated resources (the cache checks if the resource is present and only sends it if it has not seen the resource before). With the resource in place, the filter instantiates a SAX handler passing the watermark object. The SAX handler is used to parse the Fixed Page, allowing the filter to control when it inserts the watermark into the Fixed Page; when underlay is required, the mark-up is inserted when the FixedPage start element is encountered and when overlay is required the mark-up is inserted when FixedPage end element is encountered. By passing the abstracted watermark object, the SAX handler can be re-used for any watermark as it merely requests appropriate mark-up from the watermark object and inserts it into the Fixed Page mark-up as appropriate. + +### Vector Mark-up + +XPS documents can contain a range of vector elements that contain color data that describes how the elements should be rendered on a specific device. The following elements support color data: + +- Color +- Fill +- Stroke + +When any of these elements are found in a fixed page, the SAX handler passes the associated color data to a color conversion object. This uses the following algorithm to convert the color: + +1. The XML mark-up is broken down into color channel values, color channel value types, color format, and any other color details contained in the color mark-up string. +2. The resulting values are color transformed in conjunction with preferences defined in the PrintTicket. The result is a new set of color values. +3. These new values are used to reconstructs a color reference containing the new color values. +4. The newly constructed color reference is used in place of the original color reference, resulting in the transformed color output. + +### Bitmap Resources + +When a bitmap is referred to in a fixed page, the SAX handler passes the bitmap URI to a bitmap conversion method in the color converter object. + +The conversion process starts by creating a new color managed bitmap object that represents the bitmap along with a color profile manager. The color profile manager is initialized by the PrintTicket settings and is used to supply a suitable color transform based on those settings. + +After the color managed bitmap object is created, the object is passed to a resource caching class that manages which bitmaps are written out and ensures bitmaps are only written out once. A single bitmap can be referred to many times in an XPS container but the bitmap itself should have a color transformation applied only once and should be written out only once to avoid unnecessary processing overhead. The caching manager ensures this by creating a unique key generated from the bitmap URI and color profile that is then recorded against the URI. If the caching manager receives bitmap objects with an existing key, those bitmaps do not need re-processing and the stored URI is used merely to identify the color transformed bitmap. + +If a bitmap has not been handled yet, the caching manager calls a write data method in the color bitmap object to indicate that the bitmap should write itself out to the filter pipeline. The write process also includes the application of a color transform to the bitmap. The following steps occur to apply the transform: + +1. A stream is created to the bitmap itself and the bitmap is loaded into memory. +2. A bitmap codec object is created that takes the bitmap and uses an appropriate codec to decompress the bitmap and present the bitmap data and values. +3. The bitmap data is then converted by using a color transform supplied by the color profile management class. +4. The bitmap codec object re-encodes the bitmap by using a matching codec to that used to decode the bitmap. +5. The encoded bitmap is streamed back out to the container. + +### Booklet Filter + +The Booklet filter is intended to demonstrate how a filter can re-order the pages and add additional pages to a document to enable booklet binding using the XPS interface as the source of the XPS document. Page transformation is not applied by the filter but deferred to the NUp filter demonstrating filter re-use. The filter takes as input the JobBinding and DocumentBinding public Print Schema features (defined in the PrintTicket), and the sequence of pages in the fixed documents or fixed document sequence within the XPS document and outputs the fixed pages in an appropriate order to be printed as a booklet. Page content is not modified; however, an additional fixed page might be required to ensure the appropriate fixed page flow. + +The filter is configured by parsing an input PrintTicket by using DOM to extract the relevant features and options. If the functionality is enabled, the filter processes the document as required. Again the PrintTicket is constructed according to the algorithm that is documented in the watermark filter notes. + +The booklet filter maintains a list of references to the fixed page parts within an XPS document as they are presented to the filter. This list is used to output the correct page order and is reset and repopulated according to whether JobBinding or DocumentBinding is set. If JobBinding is enabled, all pages within the Fixed Documents that make up the Fixed Document Sequence are cached and the list is not flushed until the document has completed. If DocumentBinding is enabled, the filter caches all pages in a Fixed Document and flushes the list at the end of the Fixed Document. When the list is flushed, the pages are re-ordered and a padding page is added if the total page count is odd before being sent on to the filter pipeline. + +### NUp Filter + +The NUp filter is intended to demonstrate how a filter can transform vector mark-up within an XPS container by using the XPS interface as the source of the XPS document. The PrintTicket might contain preferences that the filter uses to apply a multi-up transformation to the containers fixed pages, resulting in a new set of pages that contain the original pages as child canvases. The filter takes as input the JobNUp, DocumentNUp, JobBinding, DocumentBinding, PageMediaSize, and PageOrientation public Print Schema features (defined in the PrintTicket) and the Fixed Pages that define the Fixed Document and Fixed Document Sequence. The output is a new sequence of Fixed Pages that contain the render-transformed source pages sent through the XPS interface to the filter pipeline. + +The filter is configured by parsing an input PrintTicket using DOM to extract the relevant features and options. If the functionality is enabled, the filter processes the document as required. Again the PrintTicket is constructed according to the algorithm that is documented in the watermark filter notes. + +Within the filter, SAX is used to parse the XPS container with each fixed page being read, amended, and inserted into a new fixed page as a canvas. The amendment of the source fixed page involves removing any wrapping mark-up that defines a fixed page and in place adding suitable mark-up to define a new canvas. The new canvas mark-up includes a transformation matrix that positions, rotates, and scales the canvas on the new fixed page. The transformation is provided by a supporting object that generates the transform according to the PrintTicket settings. Settings in the print ticket that are used include how many source pages should be stored as canvases in a single new fixed page (NUp count), the ordering of canvases on the new fixed page, and the target page size and orientation. + +New canvases are added to the new fixed page mark-up until the document contains the number of source fixed pages that are required in a single new fixed page or until there are no source pages left. When the new fixed page is full, it is written out to the pipeline and another fixed page is started ready for population with source pages. + +In addition to the NUp feature processing, the NUp filter is re-used to apply the 2-Up processing required for booklet printing. This is achieved by looking for a valid binding option in the PrintTicket and applying 2-Up as appropriate. + +Page Scaling Filter +------------------- + +The page scaling filter is intended to demonstrate how a filter can transform vector mark-up within a XPS container by using the stream interface as the source of the XPS document. The PrintTicket can contain page scaling preferences that the filter uses to amend page dimension values in each fixed page processed. + +Within the filter, SAX is used to parse the XPS container with each fixed page being read, amended, and written back out. The modification of the fixed page mark-up begins by modifying the fixed page dimensions to match the target page size specified in the print ticket for the current fixed page. Subsequently, the fixed page content is scaled to correctly fit the target scale by applying a canvas around the source content that includes a transformation matrix. The SAX handler is supported by a page scale class which manages the creation of a transformation matrix and the presentation of the matrix correctly formatted for use in the fixed page. + +XPS Container Handling +---------------------- + +The stream filter is required to handle the Open Packaging conventions that are used by an XPS document. These conventions can be thought of as the document structure above that of the PK archive itself. Sources for a set of classes are provided that support processing of the XPS document in terms of the constituent files in the PK archive. This includes: + +- Initiating the document processing based on the root relationships part defined in the package. +- Validation of the parts within the package against their content type and usage. +- Processing of Fixed Document Sequence and all resources associated with it. +- Processing of the Fixed Documents within the Fixed Document Sequence and all resources associated with them. +- Processing of the Fixed Page parts with the Fixed Documents and all resources associated with them. +- Passing Fixed Page content processing to a registered FP handler for modification. +- Passing all parts on to a PK archive handling module with valid ordering. + +The XPS processor is not responsible for extracting or decompressing part data from the PK archive. This task is the responsibility of an additional module that implements an interface known to the XPS container handling code. + +UI Plug-in +---------- + +The UI Plug-in is intended to demonstrate how to extend the standard Unidrv UI to add additional property sheets and controls and to provide support for custom features that are not supported by the core Unidrv UI. Three new pages have been added that allow control of the sample filters: + +- Color--enables configuration of the color conversion filter. +- Watermarks--enables a watermark to be selected and enable configuration of its properties for use in the watermark filter. +- Features--includes controls to configure the page scaling, booklet, and NUp filters. In addition, the standard driver settings--duplex, intent, and page borders--can also be modified. + +Various UI control types have been implemented on these property pages to enable a user to modify settings in the driver. The UI supports the following control types: + +- Check-box +- Combo-box +- List-Box +- Edit-Box +- Edit number (with buddy up/down control) + +The settings that associated with each of these controls are stored as one the following types: + +- GPD options. These settings are defined in the sample driver GPD configuration file and are handled by the Unidrv core via the CPSUI interface. All GPD options that are managed from the UI plug-in are hidden from the standard Unidrv Treeview dialog box. +- OEM private DevMode. These settings are settings that cannot be represented in the GPD file format (for example, numerical values and strings). They are instead added to the DevMode at a private offset. + +The Unidrv UI Plug-in interface includes methods that allow additional property pages to be inserted into the drivers property sheet. In the sample, only additional document property pages are implemented because there are no device property pages required. A collection of property page objects are stored at the plug-in interface level, each of which is responsible for the three property pages (Color, Watermarks, and Features). Each property page object creates a Microsoft Windows property page from a dialog resource and handles all Windows Messages that are received through a common dialog procedure. A collection of UI control objects are stored in the property page, one for each Windows control on the page. + +When a property page receives a message for a control, it looks up the relevant control in the collection (by using the resource identifier) and calls the appropriate method in the control interface, given the Windows message. Each control object is responsible for handling its own initialization and any user input through the appropriate get and set functions. The sample get and set functions provide an interface to read and update the GPD options and OEM private DevMode. + +PrintTicket Provider Plug-in +---------------------------- + +The sample Print Ticket Provider plug-in is intended to demonstrate how to validate and map driver settings from a DevMode description to a Print Ticket description and back again. The driver allows configuration of custom settings through a custom user interface. These custom settings are represented as either GPD options or in the OEM private DevMode and are mapped to and from the Print Ticket using an XML schema. + +To support Print Ticket handling, the Unidrv UI Plug-in Print Ticket Provider Interface is utilized. The Unidrv UI Plug-in interface includes methods that allow mapping of DevMode to and from a Print Ticket Schema. A collection of feature conversion objects are stored at the plug-in interface level, each of which is responsible for the conversion of a specific feature (Color, Watermark, Booklet, Scaling, and NUp). Whenever the Unidrv core calls through the external interface of the plug-in to convert from DevMode to Print Ticket or Print Ticket to DevMode, the collection is iterated through calling each conversion object in turn; each then perform its own DevMode/Print Ticket mapping via the appropriate get and set functions. The sample get and set functions provide an interface to read and write the GPD options, OEM private DevMode, and Print Ticket keyword value pairs. + diff --git a/print/XPSDrvSmpl/XPSDrvSmpl.sln b/print/XPSDrvSmpl/XPSDrvSmpl.sln new file mode 100644 index 00000000..f2525eae --- /dev/null +++ b/print/XPSDrvSmpl/XPSDrvSmpl.sln @@ -0,0 +1,217 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0 +MinimumVisualStudioVersion = 12.0 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Package", "Package", "{15E89F3C-10FD-40C7-A13E-707394EAE0C0}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Debug", "Debug", "{A249B218-7739-42E2-BCAF-46500B971F83}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Src", "Src", "{D67EEBCA-A813-4CD8-8F93-CA40013A6EAF}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Common", "Common", "{A088C774-8AD8-4256-A851-10528BEE6E7F}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Ui", "Ui", "{93EE619A-8EA7-4755-A6FD-1F2DF51B628C}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Common", "Common", "{EDE58C09-846E-4B4D-A4C7-20D713FC48B6}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Filters", "Filters", "{22B3AF3E-2F29-41FF-800D-C482843900CA}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Xdcont", "Xdcont", "{CF0E3C90-89E7-4D5A-9EFE-319152E67DB0}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Watermark", "Watermark", "{11B663E8-C2A1-460E-A03E-2E11744CDC07}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Scaling", "Scaling", "{9FC13A6C-6504-47D6-B543-AB5B80FC29ED}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Nup", "Nup", "{F5F774EA-448F-47CA-B541-38577DE88B73}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Color", "Color", "{0E961C80-9F70-4327-80B0-FF1C5A0BF6F0}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Booklet", "Booklet", "{A340E86D-0D37-482B-9EE7-153DBA7B72F2}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "package", "Package\package.VcxProj", "{419B0310-99CD-4866-A8E6-B6F43E6B8513}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xdsdbg", "src\debug\xdsdbg.vcxproj", "{B0A0CBB7-DC33-4FE1-B356-C4978A035097}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xdsmplcmn", "src\common\xdsmplcmn.vcxproj", "{AF94DFED-1979-486B-A16E-7BBB14711EA0}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xdsmplui", "src\ui\xdsmplui.vcxproj", "{20DDD6AA-CA85-46F3-8446-EDA619839273}" + ProjectSection(ProjectDependencies) = postProject + {B0A0CBB7-DC33-4FE1-B356-C4978A035097} = {B0A0CBB7-DC33-4FE1-B356-C4978A035097} + {AF94DFED-1979-486B-A16E-7BBB14711EA0} = {AF94DFED-1979-486B-A16E-7BBB14711EA0} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xdfltcmn", "src\filters\common\xdfltcmn.vcxproj", "{DDC3CDA6-A188-4A21-A321-37E8A044EC22}" + ProjectSection(ProjectDependencies) = postProject + {B0A0CBB7-DC33-4FE1-B356-C4978A035097} = {B0A0CBB7-DC33-4FE1-B356-C4978A035097} + {AF94DFED-1979-486B-A16E-7BBB14711EA0} = {AF94DFED-1979-486B-A16E-7BBB14711EA0} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xdcont", "src\filters\xdcont\xdcont.vcxproj", "{BCB6A109-EB2A-4D55-908E-22EE132F75AD}" + ProjectSection(ProjectDependencies) = postProject + {B0A0CBB7-DC33-4FE1-B356-C4978A035097} = {B0A0CBB7-DC33-4FE1-B356-C4978A035097} + {AF94DFED-1979-486B-A16E-7BBB14711EA0} = {AF94DFED-1979-486B-A16E-7BBB14711EA0} + {DDC3CDA6-A188-4A21-A321-37E8A044EC22} = {DDC3CDA6-A188-4A21-A321-37E8A044EC22} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xdwmark", "src\filters\watermark\xdwmark.vcxproj", "{89DE916B-9E07-4E1F-BFF9-3FC16328B0DD}" + ProjectSection(ProjectDependencies) = postProject + {B0A0CBB7-DC33-4FE1-B356-C4978A035097} = {B0A0CBB7-DC33-4FE1-B356-C4978A035097} + {AF94DFED-1979-486B-A16E-7BBB14711EA0} = {AF94DFED-1979-486B-A16E-7BBB14711EA0} + {DDC3CDA6-A188-4A21-A321-37E8A044EC22} = {DDC3CDA6-A188-4A21-A321-37E8A044EC22} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xdscale", "src\filters\scaling\xdscale.vcxproj", "{268439B8-E924-47E4-BFE9-01DED439AFFE}" + ProjectSection(ProjectDependencies) = postProject + {BCB6A109-EB2A-4D55-908E-22EE132F75AD} = {BCB6A109-EB2A-4D55-908E-22EE132F75AD} + {B0A0CBB7-DC33-4FE1-B356-C4978A035097} = {B0A0CBB7-DC33-4FE1-B356-C4978A035097} + {AF94DFED-1979-486B-A16E-7BBB14711EA0} = {AF94DFED-1979-486B-A16E-7BBB14711EA0} + {DDC3CDA6-A188-4A21-A321-37E8A044EC22} = {DDC3CDA6-A188-4A21-A321-37E8A044EC22} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xdnup", "src\filters\nup\xdnup.vcxproj", "{06548B4B-6104-4F36-8BAA-127D23F73CD4}" + ProjectSection(ProjectDependencies) = postProject + {B0A0CBB7-DC33-4FE1-B356-C4978A035097} = {B0A0CBB7-DC33-4FE1-B356-C4978A035097} + {AF94DFED-1979-486B-A16E-7BBB14711EA0} = {AF94DFED-1979-486B-A16E-7BBB14711EA0} + {DDC3CDA6-A188-4A21-A321-37E8A044EC22} = {DDC3CDA6-A188-4A21-A321-37E8A044EC22} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "XDColMan", "src\filters\color\XDColMan.vcxproj", "{AE18BFE5-EA00-477B-A051-F28DD3078679}" + ProjectSection(ProjectDependencies) = postProject + {B0A0CBB7-DC33-4FE1-B356-C4978A035097} = {B0A0CBB7-DC33-4FE1-B356-C4978A035097} + {AF94DFED-1979-486B-A16E-7BBB14711EA0} = {AF94DFED-1979-486B-A16E-7BBB14711EA0} + {DDC3CDA6-A188-4A21-A321-37E8A044EC22} = {DDC3CDA6-A188-4A21-A321-37E8A044EC22} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xdbook", "src\filters\booklet\xdbook.vcxproj", "{49DD5381-63D8-41FB-B641-AFE52BFBBC32}" + ProjectSection(ProjectDependencies) = postProject + {B0A0CBB7-DC33-4FE1-B356-C4978A035097} = {B0A0CBB7-DC33-4FE1-B356-C4978A035097} + {AF94DFED-1979-486B-A16E-7BBB14711EA0} = {AF94DFED-1979-486B-A16E-7BBB14711EA0} + {DDC3CDA6-A188-4A21-A321-37E8A044EC22} = {DDC3CDA6-A188-4A21-A321-37E8A044EC22} + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {419B0310-99CD-4866-A8E6-B6F43E6B8513}.Debug|Win32.ActiveCfg = Debug|Win32 + {419B0310-99CD-4866-A8E6-B6F43E6B8513}.Debug|Win32.Build.0 = Debug|Win32 + {419B0310-99CD-4866-A8E6-B6F43E6B8513}.Release|Win32.ActiveCfg = Release|Win32 + {419B0310-99CD-4866-A8E6-B6F43E6B8513}.Release|Win32.Build.0 = Release|Win32 + {419B0310-99CD-4866-A8E6-B6F43E6B8513}.Debug|x64.ActiveCfg = Debug|x64 + {419B0310-99CD-4866-A8E6-B6F43E6B8513}.Debug|x64.Build.0 = Debug|x64 + {419B0310-99CD-4866-A8E6-B6F43E6B8513}.Release|x64.ActiveCfg = Release|x64 + {419B0310-99CD-4866-A8E6-B6F43E6B8513}.Release|x64.Build.0 = Release|x64 + {B0A0CBB7-DC33-4FE1-B356-C4978A035097}.Debug|Win32.ActiveCfg = Debug|Win32 + {B0A0CBB7-DC33-4FE1-B356-C4978A035097}.Debug|Win32.Build.0 = Debug|Win32 + {B0A0CBB7-DC33-4FE1-B356-C4978A035097}.Release|Win32.ActiveCfg = Release|Win32 + {B0A0CBB7-DC33-4FE1-B356-C4978A035097}.Release|Win32.Build.0 = Release|Win32 + {B0A0CBB7-DC33-4FE1-B356-C4978A035097}.Debug|x64.ActiveCfg = Debug|x64 + {B0A0CBB7-DC33-4FE1-B356-C4978A035097}.Debug|x64.Build.0 = Debug|x64 + {B0A0CBB7-DC33-4FE1-B356-C4978A035097}.Release|x64.ActiveCfg = Release|x64 + {B0A0CBB7-DC33-4FE1-B356-C4978A035097}.Release|x64.Build.0 = Release|x64 + {AF94DFED-1979-486B-A16E-7BBB14711EA0}.Debug|Win32.ActiveCfg = Debug|Win32 + {AF94DFED-1979-486B-A16E-7BBB14711EA0}.Debug|Win32.Build.0 = Debug|Win32 + {AF94DFED-1979-486B-A16E-7BBB14711EA0}.Release|Win32.ActiveCfg = Release|Win32 + {AF94DFED-1979-486B-A16E-7BBB14711EA0}.Release|Win32.Build.0 = Release|Win32 + {AF94DFED-1979-486B-A16E-7BBB14711EA0}.Debug|x64.ActiveCfg = Debug|x64 + {AF94DFED-1979-486B-A16E-7BBB14711EA0}.Debug|x64.Build.0 = Debug|x64 + {AF94DFED-1979-486B-A16E-7BBB14711EA0}.Release|x64.ActiveCfg = Release|x64 + {AF94DFED-1979-486B-A16E-7BBB14711EA0}.Release|x64.Build.0 = Release|x64 + {20DDD6AA-CA85-46F3-8446-EDA619839273}.Debug|Win32.ActiveCfg = Debug|Win32 + {20DDD6AA-CA85-46F3-8446-EDA619839273}.Debug|Win32.Build.0 = Debug|Win32 + {20DDD6AA-CA85-46F3-8446-EDA619839273}.Release|Win32.ActiveCfg = Release|Win32 + {20DDD6AA-CA85-46F3-8446-EDA619839273}.Release|Win32.Build.0 = Release|Win32 + {20DDD6AA-CA85-46F3-8446-EDA619839273}.Debug|x64.ActiveCfg = Debug|x64 + {20DDD6AA-CA85-46F3-8446-EDA619839273}.Debug|x64.Build.0 = Debug|x64 + {20DDD6AA-CA85-46F3-8446-EDA619839273}.Release|x64.ActiveCfg = Release|x64 + {20DDD6AA-CA85-46F3-8446-EDA619839273}.Release|x64.Build.0 = Release|x64 + {DDC3CDA6-A188-4A21-A321-37E8A044EC22}.Debug|Win32.ActiveCfg = Debug|Win32 + {DDC3CDA6-A188-4A21-A321-37E8A044EC22}.Debug|Win32.Build.0 = Debug|Win32 + {DDC3CDA6-A188-4A21-A321-37E8A044EC22}.Release|Win32.ActiveCfg = Release|Win32 + {DDC3CDA6-A188-4A21-A321-37E8A044EC22}.Release|Win32.Build.0 = Release|Win32 + {DDC3CDA6-A188-4A21-A321-37E8A044EC22}.Debug|x64.ActiveCfg = Debug|x64 + {DDC3CDA6-A188-4A21-A321-37E8A044EC22}.Debug|x64.Build.0 = Debug|x64 + {DDC3CDA6-A188-4A21-A321-37E8A044EC22}.Release|x64.ActiveCfg = Release|x64 + {DDC3CDA6-A188-4A21-A321-37E8A044EC22}.Release|x64.Build.0 = Release|x64 + {BCB6A109-EB2A-4D55-908E-22EE132F75AD}.Debug|Win32.ActiveCfg = Debug|Win32 + {BCB6A109-EB2A-4D55-908E-22EE132F75AD}.Debug|Win32.Build.0 = Debug|Win32 + {BCB6A109-EB2A-4D55-908E-22EE132F75AD}.Release|Win32.ActiveCfg = Release|Win32 + {BCB6A109-EB2A-4D55-908E-22EE132F75AD}.Release|Win32.Build.0 = Release|Win32 + {BCB6A109-EB2A-4D55-908E-22EE132F75AD}.Debug|x64.ActiveCfg = Debug|x64 + {BCB6A109-EB2A-4D55-908E-22EE132F75AD}.Debug|x64.Build.0 = Debug|x64 + {BCB6A109-EB2A-4D55-908E-22EE132F75AD}.Release|x64.ActiveCfg = Release|x64 + {BCB6A109-EB2A-4D55-908E-22EE132F75AD}.Release|x64.Build.0 = Release|x64 + {89DE916B-9E07-4E1F-BFF9-3FC16328B0DD}.Debug|Win32.ActiveCfg = Debug|Win32 + {89DE916B-9E07-4E1F-BFF9-3FC16328B0DD}.Debug|Win32.Build.0 = Debug|Win32 + {89DE916B-9E07-4E1F-BFF9-3FC16328B0DD}.Release|Win32.ActiveCfg = Release|Win32 + {89DE916B-9E07-4E1F-BFF9-3FC16328B0DD}.Release|Win32.Build.0 = Release|Win32 + {89DE916B-9E07-4E1F-BFF9-3FC16328B0DD}.Debug|x64.ActiveCfg = Debug|x64 + {89DE916B-9E07-4E1F-BFF9-3FC16328B0DD}.Debug|x64.Build.0 = Debug|x64 + {89DE916B-9E07-4E1F-BFF9-3FC16328B0DD}.Release|x64.ActiveCfg = Release|x64 + {89DE916B-9E07-4E1F-BFF9-3FC16328B0DD}.Release|x64.Build.0 = Release|x64 + {268439B8-E924-47E4-BFE9-01DED439AFFE}.Debug|Win32.ActiveCfg = Debug|Win32 + {268439B8-E924-47E4-BFE9-01DED439AFFE}.Debug|Win32.Build.0 = Debug|Win32 + {268439B8-E924-47E4-BFE9-01DED439AFFE}.Release|Win32.ActiveCfg = Release|Win32 + {268439B8-E924-47E4-BFE9-01DED439AFFE}.Release|Win32.Build.0 = Release|Win32 + {268439B8-E924-47E4-BFE9-01DED439AFFE}.Debug|x64.ActiveCfg = Debug|x64 + {268439B8-E924-47E4-BFE9-01DED439AFFE}.Debug|x64.Build.0 = Debug|x64 + {268439B8-E924-47E4-BFE9-01DED439AFFE}.Release|x64.ActiveCfg = Release|x64 + {268439B8-E924-47E4-BFE9-01DED439AFFE}.Release|x64.Build.0 = Release|x64 + {06548B4B-6104-4F36-8BAA-127D23F73CD4}.Debug|Win32.ActiveCfg = Debug|Win32 + {06548B4B-6104-4F36-8BAA-127D23F73CD4}.Debug|Win32.Build.0 = Debug|Win32 + {06548B4B-6104-4F36-8BAA-127D23F73CD4}.Release|Win32.ActiveCfg = Release|Win32 + {06548B4B-6104-4F36-8BAA-127D23F73CD4}.Release|Win32.Build.0 = Release|Win32 + {06548B4B-6104-4F36-8BAA-127D23F73CD4}.Debug|x64.ActiveCfg = Debug|x64 + {06548B4B-6104-4F36-8BAA-127D23F73CD4}.Debug|x64.Build.0 = Debug|x64 + {06548B4B-6104-4F36-8BAA-127D23F73CD4}.Release|x64.ActiveCfg = Release|x64 + {06548B4B-6104-4F36-8BAA-127D23F73CD4}.Release|x64.Build.0 = Release|x64 + {AE18BFE5-EA00-477B-A051-F28DD3078679}.Debug|Win32.ActiveCfg = Debug|Win32 + {AE18BFE5-EA00-477B-A051-F28DD3078679}.Debug|Win32.Build.0 = Debug|Win32 + {AE18BFE5-EA00-477B-A051-F28DD3078679}.Release|Win32.ActiveCfg = Release|Win32 + {AE18BFE5-EA00-477B-A051-F28DD3078679}.Release|Win32.Build.0 = Release|Win32 + {AE18BFE5-EA00-477B-A051-F28DD3078679}.Debug|x64.ActiveCfg = Debug|x64 + {AE18BFE5-EA00-477B-A051-F28DD3078679}.Debug|x64.Build.0 = Debug|x64 + {AE18BFE5-EA00-477B-A051-F28DD3078679}.Release|x64.ActiveCfg = Release|x64 + {AE18BFE5-EA00-477B-A051-F28DD3078679}.Release|x64.Build.0 = Release|x64 + {49DD5381-63D8-41FB-B641-AFE52BFBBC32}.Debug|Win32.ActiveCfg = Debug|Win32 + {49DD5381-63D8-41FB-B641-AFE52BFBBC32}.Debug|Win32.Build.0 = Debug|Win32 + {49DD5381-63D8-41FB-B641-AFE52BFBBC32}.Release|Win32.ActiveCfg = Release|Win32 + {49DD5381-63D8-41FB-B641-AFE52BFBBC32}.Release|Win32.Build.0 = Release|Win32 + {49DD5381-63D8-41FB-B641-AFE52BFBBC32}.Debug|x64.ActiveCfg = Debug|x64 + {49DD5381-63D8-41FB-B641-AFE52BFBBC32}.Debug|x64.Build.0 = Debug|x64 + {49DD5381-63D8-41FB-B641-AFE52BFBBC32}.Release|x64.ActiveCfg = Release|x64 + {49DD5381-63D8-41FB-B641-AFE52BFBBC32}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {419B0310-99CD-4866-A8E6-B6F43E6B8513} = {15E89F3C-10FD-40C7-A13E-707394EAE0C0} + {B0A0CBB7-DC33-4FE1-B356-C4978A035097} = {A249B218-7739-42E2-BCAF-46500B971F83} + {AF94DFED-1979-486B-A16E-7BBB14711EA0} = {A088C774-8AD8-4256-A851-10528BEE6E7F} + {20DDD6AA-CA85-46F3-8446-EDA619839273} = {93EE619A-8EA7-4755-A6FD-1F2DF51B628C} + {DDC3CDA6-A188-4A21-A321-37E8A044EC22} = {EDE58C09-846E-4B4D-A4C7-20D713FC48B6} + {BCB6A109-EB2A-4D55-908E-22EE132F75AD} = {CF0E3C90-89E7-4D5A-9EFE-319152E67DB0} + {89DE916B-9E07-4E1F-BFF9-3FC16328B0DD} = {11B663E8-C2A1-460E-A03E-2E11744CDC07} + {268439B8-E924-47E4-BFE9-01DED439AFFE} = {9FC13A6C-6504-47D6-B543-AB5B80FC29ED} + {06548B4B-6104-4F36-8BAA-127D23F73CD4} = {F5F774EA-448F-47CA-B541-38577DE88B73} + {AE18BFE5-EA00-477B-A051-F28DD3078679} = {0E961C80-9F70-4327-80B0-FF1C5A0BF6F0} + {49DD5381-63D8-41FB-B641-AFE52BFBBC32} = {A340E86D-0D37-482B-9EE7-153DBA7B72F2} + {A249B218-7739-42E2-BCAF-46500B971F83} = {D67EEBCA-A813-4CD8-8F93-CA40013A6EAF} + {A088C774-8AD8-4256-A851-10528BEE6E7F} = {D67EEBCA-A813-4CD8-8F93-CA40013A6EAF} + {93EE619A-8EA7-4755-A6FD-1F2DF51B628C} = {D67EEBCA-A813-4CD8-8F93-CA40013A6EAF} + {EDE58C09-846E-4B4D-A4C7-20D713FC48B6} = {22B3AF3E-2F29-41FF-800D-C482843900CA} + {22B3AF3E-2F29-41FF-800D-C482843900CA} = {D67EEBCA-A813-4CD8-8F93-CA40013A6EAF} + {CF0E3C90-89E7-4D5A-9EFE-319152E67DB0} = {22B3AF3E-2F29-41FF-800D-C482843900CA} + {11B663E8-C2A1-460E-A03E-2E11744CDC07} = {22B3AF3E-2F29-41FF-800D-C482843900CA} + {9FC13A6C-6504-47D6-B543-AB5B80FC29ED} = {22B3AF3E-2F29-41FF-800D-C482843900CA} + {F5F774EA-448F-47CA-B541-38577DE88B73} = {22B3AF3E-2F29-41FF-800D-C482843900CA} + {0E961C80-9F70-4327-80B0-FF1C5A0BF6F0} = {22B3AF3E-2F29-41FF-800D-C482843900CA} + {A340E86D-0D37-482B-9EE7-153DBA7B72F2} = {22B3AF3E-2F29-41FF-800D-C482843900CA} + EndGlobalSection +EndGlobal diff --git a/print/XPSDrvSmpl/install/xdCMYKPrinter.icc b/print/XPSDrvSmpl/install/xdCMYKPrinter.icc new file mode 100644 index 00000000..59c55ae6 Binary files /dev/null and b/print/XPSDrvSmpl/install/xdCMYKPrinter.icc differ diff --git a/print/XPSDrvSmpl/install/xdbook.gpd b/print/XPSDrvSmpl/install/xdbook.gpd new file mode 100644 index 00000000..8083ec45 --- /dev/null +++ b/print/XPSDrvSmpl/install/xdbook.gpd @@ -0,0 +1,87 @@ +*% +*% Copyright (c) 2005 Microsoft Corporation +*% +*% All rights reserved. +*% +*% THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +*% ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +*% THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +*% PARTICULAR PURPOSE. +*% +*% File Name: +*% +*% xdbook.gpd +*% +*% Abstract: +*% +*% XPSDrv filter feature sample driver Booklet specific GPD settings. +*% + +*%****************************************************************************** +*% JobBindAllDocuments +*%****************************************************************************** +*Feature: JobBindAllDocuments +{ + *rcNameID: =IDS_GPD_JOBBINDING + *DefaultOption: None + + *Option: None + { + *rcNameID: =IDS_GPD_NONE + } + + *Option: BindLeft + { + *rcNameID: =IDS_GPD_LTOR + } + + *Option: BindRight + { + *rcNameID: =IDS_GPD_RTOL + } + + *Option: BindTop + { + *rcNameID: =IDS_GPD_TTOB + } + + *Option: BindBottom + { + *rcNameID: =IDS_GPD_BTOT + } +} + +*%****************************************************************************** +*% DocumentBinding +*%****************************************************************************** +*Feature: DocumentBinding +{ + *rcNameID: =IDS_GPD_DOCBIND + *DefaultOption: None + + *Option: None + { + *rcNameID: =IDS_GPD_NONE + } + + *Option: BindLeft + { + *rcNameID: =IDS_GPD_LTOR + } + + *Option: BindRight + { + *rcNameID: =IDS_GPD_RTOL + } + + *Option: BindTop + { + *rcNameID: =IDS_GPD_TTOB + } + + *Option: BindBottom + { + *rcNameID: =IDS_GPD_BTOT + } +} + diff --git a/print/XPSDrvSmpl/install/xdcolman.gpd b/print/XPSDrvSmpl/install/xdcolman.gpd new file mode 100644 index 00000000..ea84c964 --- /dev/null +++ b/print/XPSDrvSmpl/install/xdcolman.gpd @@ -0,0 +1,106 @@ +*% +*% Copyright (c) 2005 Microsoft Corporation +*% +*% All rights reserved. +*% +*% THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +*% ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +*% THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +*% PARTICULAR PURPOSE. +*% +*% File Name: +*% +*% xdcolman.gpd +*% +*% Abstract: +*% +*% XPSDrv filter feature sample driver Color Management specific GPD settings. +*% + +*%****************************************************************************** +*% PageColorManagement +*%****************************************************************************** +*Feature: PageColorManagement +{ + *rcNameID: =IDS_GPD_PAGECOLMAN + *DefaultOption: None + *PrintSchemaKeywordMap: "PageColorManagement" + + *Option: None + { + *rcNameID: =IDS_GPD_NONE + *PrintSchemaKeywordMap: "None" + } + + *Option: Device + { + *rcNameID: =IDS_GPD_DEVICE + *PrintSchemaKeywordMap: "Device" + } + + *Option: Driver + { + *rcNameID: =IDS_GPD_DRIVER + *PrintSchemaKeywordMap: "Driver" + } + + *Option: System + { + *rcNameID: =IDS_GPD_SYSTEM + *PrintSchemaKeywordMap: "System" + } +} + +*%****************************************************************************** +*% PageSourceColorProfile +*%****************************************************************************** +*Feature: PageSourceColorProfile +{ + *rcNameID: =IDS_GPD_SRCCOLPROF + *DefaultOption: CMYK + + *Option: CMYK + { + *rcNameID: =IDS_GPD_CMYK + } + + *Option: scRGB + { + *rcNameID: =IDS_GPD_SCRGB + } +} + +*%****************************************************************************** +*% PageICMRenderingIntent +*%****************************************************************************** +*Feature: PageICMRenderingIntent +{ + *rcNameID: =IDS_GPD_PAGEICMINTENT + *DefaultOption: AbsoluteColorimetric + *PrintSchemaKeywordMap: "PageICMRenderingIntent" + + *Option: AbsoluteColorimetric + { + *rcNameID: =IDS_GPD_ABSCOLINTENT + *PrintSchemaKeywordMap: "AbsoluteColorimetric" + } + + *Option: RelativeColorimetric + { + *rcNameID: =IDS_GPD_RELCOLINTENT + *PrintSchemaKeywordMap: "RelativeColorimetric" + } + + *Option: Photographs + { + *rcNameID: =IDS_GPD_PHOTOINTENT + *PrintSchemaKeywordMap: "Photographs" + } + + *Option: BusinessGraphics + { + *rcNameID: =IDS_GPD_BIZINTENT + *PrintSchemaKeywordMap: "BusinessGraphics" + } +} + diff --git a/print/XPSDrvSmpl/install/xdnames.gpd b/print/XPSDrvSmpl/install/xdnames.gpd new file mode 100644 index 00000000..0a45a313 --- /dev/null +++ b/print/XPSDrvSmpl/install/xdnames.gpd @@ -0,0 +1,151 @@ +*% +*% Copyright (c) 2005 Microsoft Corporation +*% +*% All rights reserved. +*% +*% THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +*% ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +*% THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +*% PARTICULAR PURPOSE. +*% +*% File Name: +*% +*% xdnames.gpd +*% +*% Abstract: +*% +*% XPSDrv filter feature sample driver GPD resource names. +*% + +*CodePage: 1252 *% Windows 3.1 US (ANSI) code page + +*Feature: RESDLL +{ + *Name: "resource dll files" + *ConcealFromUI?: TRUE + + *Option: UniresDLL + { + *Name: "unires.dll" + } + *Option: xdsmplui + { + *Name: "xdsmplui.dll" + } +} + +*Macros: StdFeatureNames +{ + IDS_GPD_1PPS: RESDLL.xdsmplui.2000 + IDS_GPD_2PPS: RESDLL.xdsmplui.2001 + IDS_GPD_4PPS: RESDLL.xdsmplui.2002 + IDS_GPD_6PPS: RESDLL.xdsmplui.2003 + IDS_GPD_8PPS: RESDLL.xdsmplui.2004 + IDS_GPD_9PPS: RESDLL.xdsmplui.2005 + IDS_GPD_16PPS: RESDLL.xdsmplui.2006 + IDS_GPD_RES1200: RESDLL.xdsmplui.2007 + IDS_GPD_RES600: RESDLL.xdsmplui.2008 + IDS_GPD_AUTOMATIC: RESDLL.xdsmplui.2009 + IDS_GPD_BORDERED: RESDLL.xdsmplui.2010 + IDS_GPD_BORDERLESS: RESDLL.xdsmplui.2011 + IDS_GPD_BTOT: RESDLL.xdsmplui.2012 + IDS_GPD_BTOTLTOR: RESDLL.xdsmplui.2013 + IDS_GPD_BTOTRTOL: RESDLL.xdsmplui.2014 + IDS_GPD_CMYK: RESDLL.xdsmplui.2015 + IDS_GPD_COLOR: RESDLL.xdsmplui.2016 + IDS_GPD_CONFIDENTIAL: RESDLL.xdsmplui.2017 + IDS_GPD_CUSTSQUARE: RESDLL.xdsmplui.2018 + IDS_GPD_CUSTOM: RESDLL.xdsmplui.2019 + IDS_GPD_SRCCOLPROF: RESDLL.xdsmplui.2020 + IDS_GPD_DEVICE: RESDLL.xdsmplui.2021 + IDS_GPD_DOCBIND: RESDLL.xdsmplui.2022 + IDS_GPD_PAGECOLMAN: RESDLL.xdsmplui.2023 + IDS_GPD_PAGEPHOTINTENT: RESDLL.xdsmplui.2024 + IDS_GPD_DOCDUPLEX: RESDLL.xdsmplui.2025 + IDS_GPD_DOCNUP: RESDLL.xdsmplui.2026 + IDS_GPD_DOCNUPPRESENTORDER: RESDLL.xdsmplui.2027 + IDS_GPD_DRAFT: RESDLL.xdsmplui.2028 + IDS_GPD_DRIVER: RESDLL.xdsmplui.2029 + IDS_GPD_DUPLEX: RESDLL.xdsmplui.2030 + IDS_GPD_FAX: RESDLL.xdsmplui.2031 + IDS_GPD_FITBLEED: RESDLL.xdsmplui.2032 + IDS_GPD_FITCONTENT: RESDLL.xdsmplui.2033 + IDS_GPD_FITPAGE: RESDLL.xdsmplui.2034 + IDS_GPD_GLOSSY: RESDLL.xdsmplui.2035 + IDS_GPD_GRAYSCALE: RESDLL.xdsmplui.2036 + IDS_GPD_HIGH: RESDLL.xdsmplui.2037 + IDS_GPD_HORIZONTAL: RESDLL.xdsmplui.2038 + IDS_GPD_JOBBINDING: RESDLL.xdsmplui.2039 + IDS_GPD_JOBNUPPRESENTORDER: RESDLL.xdsmplui.2040 + IDS_GPD_JOBNUP: RESDLL.xdsmplui.2041 + IDS_GPD_JOBPAGEORDER: RESDLL.xdsmplui.2042 + IDS_GPD_LANDSCAPE: RESDLL.xdsmplui.2043 + IDS_GPD_LTOR: RESDLL.xdsmplui.2044 + IDS_GPD_LTORBTOT: RESDLL.xdsmplui.2045 + IDS_GPD_LTORTTOB: RESDLL.xdsmplui.2046 + IDS_GPD_MEDIATYPE: RESDLL.xdsmplui.2047 + IDS_GPD_MONO: RESDLL.xdsmplui.2048 + IDS_GPD_NONE: RESDLL.xdsmplui.2049 + IDS_GPD_NORMAL: RESDLL.xdsmplui.2050 + IDS_GPD_OFF: RESDLL.xdsmplui.2051 + IDS_GPD_ON: RESDLL.xdsmplui.2052 + IDS_GPD_ORIENATION: RESDLL.xdsmplui.2053 + IDS_GPD_OVERLAYED: RESDLL.xdsmplui.2054 + IDS_GPD_PAGEBORDER: RESDLL.xdsmplui.2055 + IDS_GPD_PAGEQUALITY: RESDLL.xdsmplui.2056 + IDS_GPD_PAGESCALING: RESDLL.xdsmplui.2057 + IDS_GPD_PAPERSOURCE: RESDLL.xdsmplui.2058 + IDS_GPD_PHOTOGRAPHIC: RESDLL.xdsmplui.2059 + IDS_GPD_PORTRAIT: RESDLL.xdsmplui.2060 + IDS_GPD_RASTERIMAGE: RESDLL.xdsmplui.2061 + IDS_GPD_RESOLUTION: RESDLL.xdsmplui.2062 + IDS_GPD_REVERSELANDSCAPE: RESDLL.xdsmplui.2063 + IDS_GPD_REVERSE: RESDLL.xdsmplui.2064 + IDS_GPD_RTOL: RESDLL.xdsmplui.2065 + IDS_GPD_RTOLBTOT: RESDLL.xdsmplui.2066 + IDS_GPD_RTOLTTOB: RESDLL.xdsmplui.2067 + IDS_GPD_SCALEPAGETOPAGE: RESDLL.xdsmplui.2068 + IDS_GPD_SCRGB: RESDLL.xdsmplui.2069 + IDS_GPD_STANDARD: RESDLL.xdsmplui.2070 + IDS_GPD_TEXT: RESDLL.xdsmplui.2071 + IDS_GPD_TTOB: RESDLL.xdsmplui.2072 + IDS_GPD_TTOBLTOR: RESDLL.xdsmplui.2073 + IDS_GPD_TTOBRTOL: RESDLL.xdsmplui.2074 + IDS_GPD_TRANSPARENCY: RESDLL.xdsmplui.2075 + IDS_GPD_TRANSPARENT: RESDLL.xdsmplui.2076 + IDS_GPD_UNDERLAYED: RESDLL.xdsmplui.2077 + IDS_GPD_UPPER: RESDLL.xdsmplui.2078 + IDS_GPD_VECTORIMAGE: RESDLL.xdsmplui.2079 + IDS_GPD_VERTICAL: RESDLL.xdsmplui.2080 + IDS_GPD_WATERMARKLAYERING: RESDLL.xdsmplui.2081 + IDS_GPD_WATERMARKTEXT: RESDLL.xdsmplui.2082 + IDS_GPD_WATERMARKTYPE: RESDLL.xdsmplui.2083 + IDS_GPD_WATERMARKBITMAP: RESDLL.xdsmplui.2084 + IDS_GPD_WATERMARKGRAPHIC: RESDLL.xdsmplui.2087 + IDS_GPD_BEST: RESDLL.xdsmplui.2090 + IDS_GPD_PAGEICMINTENT: RESDLL.xdsmplui.2091 + IDS_GPD_ABSCOLINTENT: RESDLL.xdsmplui.2092 + IDS_GPD_RELCOLINTENT: RESDLL.xdsmplui.2093 + IDS_GPD_PHOTOINTENT: RESDLL.xdsmplui.2094 + IDS_GPD_BIZINTENT: RESDLL.xdsmplui.2095 + IDS_GPD_SYSTEM: RESDLL.xdsmplui.2096 + IDS_GPD_WATERMARKTEXTCOLOR: RESDLL.xdsmplui.2097 + IDS_GPD_RED: RESDLL.xdsmplui.2098 + IDS_GPD_GREEN: RESDLL.xdsmplui.2099 + IDS_GPD_BLUE: RESDLL.xdsmplui.2100 + IDS_GPD_MAGENTA: RESDLL.xdsmplui.2101 + IDS_GPD_CYAN: RESDLL.xdsmplui.2102 + IDS_GPD_YELLOW: RESDLL.xdsmplui.2103 + IDS_GPD_BLACK: RESDLL.xdsmplui.2104 + IDS_GPD_SCALE_ALIGN: RESDLL.xdsmplui.2105 + IDS_GPD_SCALE_ALIGN_BC: RESDLL.xdsmplui.2106 + IDS_GPD_SCALE_ALIGN_BL: RESDLL.xdsmplui.2107 + IDS_GPD_SCALE_ALIGN_BR: RESDLL.xdsmplui.2108 + IDS_GPD_SCALE_ALIGN_CC: RESDLL.xdsmplui.2109 + IDS_GPD_SCALE_ALIGN_LC: RESDLL.xdsmplui.2110 + IDS_GPD_SCALE_ALIGN_CR: RESDLL.xdsmplui.2111 + IDS_GPD_SCALE_ALIGN_CT: RESDLL.xdsmplui.2112 + IDS_GPD_SCALE_ALIGN_TL: RESDLL.xdsmplui.2113 + IDS_GPD_SCALE_ALIGN_TR: RESDLL.xdsmplui.2114 +} + diff --git a/print/XPSDrvSmpl/install/xdnup.gpd b/print/XPSDrvSmpl/install/xdnup.gpd new file mode 100644 index 00000000..2f846dae --- /dev/null +++ b/print/XPSDrvSmpl/install/xdnup.gpd @@ -0,0 +1,207 @@ +*% +*% Copyright (c) 2005 Microsoft Corporation +*% +*% All rights reserved. +*% +*% THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +*% ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +*% THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +*% PARTICULAR PURPOSE. +*% +*% File Name: +*% +*% xdnup.gpd +*% +*% Abstract: +*% +*% XPSDrv filter feature sample driver NUp specific GPD settings. +*% + +*%****************************************************************************** +*% JobNUpAllDocumentsContiguously +*%****************************************************************************** +*Feature: JobNUpAllDocumentsContiguously +{ + *rcNameID: =IDS_GPD_JOBNUP + *DefaultOption: 1 + *PrintSchemaKeywordMap: "JobNUpAllDocumentsContiguously" + + *Option: 1 + { + *rcNameID: =IDS_GPD_1PPS + } + + *Option: 2 + { + *rcNameID: =IDS_GPD_2PPS + } + + *Option: 4 + { + *rcNameID: =IDS_GPD_4PPS + } + + *Option: 6 + { + *rcNameID: =IDS_GPD_6PPS + } + + *Option: 8 + { + *rcNameID: =IDS_GPD_8PPS + } + + *Option: 9 + { + *rcNameID: =IDS_GPD_9PPS + } + + *Option: 16 + { + *rcNameID: =IDS_GPD_16PPS + } +} + +*%****************************************************************************** +*% JobNUpContiguouslyPresentationOrder +*%****************************************************************************** +*Feature: JobNUpContiguouslyPresentationOrder +{ + *rcNameID: =IDS_GPD_JOBNUPPRESENTORDER + *DefaultOption: RightBottom + + *Option: RightBottom + { + *rcNameID: =IDS_GPD_LTORTTOB + } + + *Option: BottomRight + { + *rcNameID: =IDS_GPD_TTOBLTOR + } + + *Option: LeftBottom + { + *rcNameID: =IDS_GPD_RTOLTTOB + } + + *Option: BottomLeft + { + *rcNameID: =IDS_GPD_TTOBRTOL + } + + *Option: RightTop + { + *rcNameID: =IDS_GPD_LTORBTOT + } + + *Option: TopRight + { + *rcNameID: =IDS_GPD_BTOTLTOR + } + + *Option: LeftTop + { + *rcNameID: =IDS_GPD_RTOLBTOT + } + + *Option: TopLeft + { + *rcNameID: =IDS_GPD_BTOTRTOL + } +} + +*%****************************************************************************** +*% DocumentNUp +*%****************************************************************************** +*Feature: DocumentNUp +{ + *rcNameID: =IDS_GPD_DOCNUP + *DefaultOption: 1 + *PrintSchemaKeywordMap: "DocumentNUp" + + *Option: 1 + { + *rcNameID: =IDS_GPD_1PPS + } + + *Option: 2 + { + *rcNameID: =IDS_GPD_2PPS + } + + *Option: 4 + { + *rcNameID: =IDS_GPD_4PPS + } + + *Option: 6 + { + *rcNameID: =IDS_GPD_6PPS + } + + *Option: 8 + { + *rcNameID: =IDS_GPD_8PPS + } + + *Option: 9 + { + *rcNameID: =IDS_GPD_9PPS + } + + *Option: 16 + { + *rcNameID: =IDS_GPD_16PPS + } +} + +*%****************************************************************************** +*% DocumentNUpPresentationOrder +*%****************************************************************************** +*Feature: DocumentNUpPresentationOrder +{ + *rcNameID: =IDS_GPD_DOCNUPPRESENTORDER + *DefaultOption: RightBottom + + *Option: RightBottom + { + *rcNameID: =IDS_GPD_LTORTTOB + } + + *Option: BottomRight + { + *rcNameID: =IDS_GPD_TTOBLTOR + } + + *Option: LeftBottom + { + *rcNameID: =IDS_GPD_RTOLTTOB + } + + *Option: BottomLeft + { + *rcNameID: =IDS_GPD_TTOBRTOL + } + + *Option: RightTop + { + *rcNameID: =IDS_GPD_LTORBTOT + } + + *Option: TopRight + { + *rcNameID: =IDS_GPD_BTOTLTOR + } + + *Option: LeftTop + { + *rcNameID: =IDS_GPD_RTOLBTOT + } + + *Option: TopLeft + { + *rcNameID: =IDS_GPD_BTOTRTOL + } +} + diff --git a/print/XPSDrvSmpl/install/xdpgscl.gpd b/print/XPSDrvSmpl/install/xdpgscl.gpd new file mode 100644 index 00000000..bacef11c --- /dev/null +++ b/print/XPSDrvSmpl/install/xdpgscl.gpd @@ -0,0 +1,117 @@ +*% +*% Copyright (c) 2005 Microsoft Corporation +*% +*% All rights reserved. +*% +*% THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +*% ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +*% THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +*% PARTICULAR PURPOSE. +*% +*% File Name: +*% +*% xdpgscl.gpd +*% +*% Abstract: +*% +*% XPSDrv filter feature sample driver page scaling specific GPD settings. +*% + +*%****************************************************************************** +*% PageScaling +*%****************************************************************************** +*Feature: PageScaling +{ + *rcNameID: =IDS_GPD_PAGESCALING + *DefaultOption: None + + *Option: None + { + *rcNameID: =IDS_GPD_NONE + } + + *Option: Custom + { + *rcNameID: =IDS_GPD_CUSTOM + } + + *Option: CustomSquare + { + *rcNameID: =IDS_GPD_CUSTSQUARE + } + + *Option: FitApplicationBleedSizeToPageImageableSize + { + *rcNameID: =IDS_GPD_FITBLEED + } + + *Option: FitApplicationContentSizeToPageImageableSize + { + *rcNameID: =IDS_GPD_FITCONTENT + } + + *Option: FitApplicationMediaSizeToPageImageableSize + { + *rcNameID: =IDS_GPD_FITPAGE + } + + *Option: FitApplicationMediaSizeToPageMediaSize + { + *rcNameID: =IDS_GPD_SCALEPAGETOPAGE + } +} + +*%****************************************************************************** +*% ScaleOffsetAlignment +*%****************************************************************************** +*Feature: ScaleOffsetAlignment +{ + *rcNameID: =IDS_GPD_SCALE_ALIGN + *DefaultOption: Center + + *Option: BottomCenter + { + *rcNameID: =IDS_GPD_SCALE_ALIGN_BC + } + + *Option: BottomLeft + { + *rcNameID: =IDS_GPD_SCALE_ALIGN_BL + } + + *Option: BottomRight + { + *rcNameID: =IDS_GPD_SCALE_ALIGN_BR + } + + *Option: Center + { + *rcNameID: =IDS_GPD_SCALE_ALIGN_CC + } + + *Option: LeftCenter + { + *rcNameID: =IDS_GPD_SCALE_ALIGN_LC + } + + *Option: RightCenter + { + *rcNameID: =IDS_GPD_SCALE_ALIGN_CR + } + + *Option: TopCenter + { + *rcNameID: =IDS_GPD_SCALE_ALIGN_CT + } + + *Option: TopLeft + { + *rcNameID: =IDS_GPD_SCALE_ALIGN_TL + } + + *Option: TopRight + { + *rcNameID: =IDS_GPD_SCALE_ALIGN_TR + } +} + diff --git a/print/XPSDrvSmpl/install/xdsmpl-PipelineConfig.xml b/print/XPSDrvSmpl/install/xdsmpl-PipelineConfig.xml new file mode 100644 index 00000000..b649032a --- /dev/null +++ b/print/XPSDrvSmpl/install/xdsmpl-PipelineConfig.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/print/XPSDrvSmpl/install/xdsmpl.gpd b/print/XPSDrvSmpl/install/xdsmpl.gpd new file mode 100644 index 00000000..2ad72e6a --- /dev/null +++ b/print/XPSDrvSmpl/install/xdsmpl.gpd @@ -0,0 +1,467 @@ +*% +*% Copyright (c) 2005 Microsoft Corporation +*% +*% All rights reserved. +*% +*% THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +*% ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +*% THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +*% PARTICULAR PURPOSE. +*% +*% File Name: +*% +*% xdsmpl.gpd +*% +*% Abstract: +*% +*% XPSDrv filter feature sample driver main GPD file. +*% + +*GPDFileVersion: "1.0" +*GPDSpecVersion: "1.0" +*GPDFileName: "XDSmpl.gpd" +*Include: "msxpsinc.gpd" +*Include: "StdNames.gpd" +*Include: "xdnames.gpd" +*Include: "xdwmark.gpd" +*Include: "xdbook.gpd" +*Include: "xdcolman.gpd" +*Include: "xdnup.gpd" +*Include: "xdpgscl.gpd" +*ModelName: "XPSDrv Sample Driver" +*MasterUnits: PAIR(1200, 1200) +*ResourceDLL: "unires.dll" +*PrinterType: PAGE +*MaxCopies: 1 + +*%****************************************************************************** +*% PageMediaSize - Paper Size +*%****************************************************************************** +*Feature: PaperSize +{ + *rcNameID: =PAPER_SIZE_DISPLAY + *DefaultOption: LETTER + + *Option: A3 + { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *PageProtectMem: 9667 + *switch: Orientation + { + *case: PORTRAIT + { + *PrintableArea: PAIR(13460, 19440) + *PrintableOrigin: PAIR(284, 200) + *CursorOrigin: PAIR(284, 200) + } + *case: LANDSCAPE_CC270 + { + *PrintableArea: PAIR(13628, 19368) + *PrintableOrigin: PAIR(200, 236) + *CursorOrigin: PAIR(200, 19604) + } + } + } + + *Option: A4 + { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *PageProtectMem: 4249 + *switch: Orientation + { + *case: PORTRAIT + { + *PrintableArea: PAIR(9352, 13628) + *PrintableOrigin: PAIR(284, 200) + *CursorOrigin: PAIR(284, 200) + } + *case: LANDSCAPE_CC270 + { + *PrintableArea: PAIR(9520, 13556) + *PrintableOrigin: PAIR(200, 236) + *CursorOrigin: PAIR(200, 13792) + } + } + } + + *Option: B4 + { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *PageProtectMem: 6391 + *switch: Orientation + { + *case: PORTRAIT + { + *PrintableArea: PAIR(11572, 16796) + *PrintableOrigin: PAIR(284, 200) + *CursorOrigin: PAIR(284, 200) + } + *case: LANDSCAPE_CC270 + { + *PrintableArea: PAIR(11740, 16724) + *PrintableOrigin: PAIR(200, 236) + *CursorOrigin: PAIR(200, 16960) + } + } + } + + *Option: B5 + { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *PageProtectMem: 3198 + *switch: Orientation + { + *case: PORTRAIT + { + *PrintableArea: PAIR(7900, 11140) + *PrintableOrigin: PAIR(352, 300) + *CursorOrigin: PAIR(300, 100) + } + *case: LANDSCAPE_CC270 + { + *PrintableArea: PAIR(7760, 11140) + *PrintableOrigin: PAIR(300, 400) + *CursorOrigin: PAIR(100, 11940) + } + } + } + + *Option: EXECUTIVE + { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *PageProtectMem: 4109 + *switch: Orientation + { + *case: PORTRAIT + { + *PrintableArea: PAIR(8100, 11500) + *PrintableOrigin: PAIR(300, 300) + *CursorOrigin: PAIR(300, 200) + } + *case: LANDSCAPE_CC270 + { + *PrintableArea: PAIR(8300, 11500) + *PrintableOrigin: PAIR(200, 300) + *CursorOrigin: PAIR(200, 12300) + } + } + } + + *Option: ENV_10 + { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *PageProtectMem: 4109 + *switch: Orientation + { + *case: PORTRAIT + { + *PrintableArea: PAIR(4348, 11000) + *PrintableOrigin: PAIR(300, 200) + *CursorOrigin: PAIR(300, 200) + } + *case: LANDSCAPE_CC270 + { + *PrintableArea: PAIR(4548, 10920) + *PrintableOrigin: PAIR(200, 240) + *CursorOrigin: PAIR(200, 11160) + } + } + } + + *Option: LEGAL + { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *PageProtectMem: 1692 + *switch: Orientation + { + *case: PORTRAIT + { + *PrintableArea: PAIR(9000, 15500) + *PrintableOrigin: PAIR(400, 600) + *CursorOrigin: PAIR(180, 300) + } + *case: LANDSCAPE_CC270 + { + *PrintableArea: PAIR(9000, 15500) + *PrintableOrigin: PAIR(400, 900) + *CursorOrigin: PAIR(180, 16500) + } + } + } + + *Option: LETTER + { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *PageProtectMem: 1028 + *switch: Orientation + { + *case: PORTRAIT + { + *PrintableArea: PAIR(9500, 12500) + *PrintableOrigin: PAIR(400, 400) + *CursorOrigin: PAIR(300, 300) + } + *case: LANDSCAPE_CC270 + { + *PrintableArea: PAIR(9500, 12200) + *PrintableOrigin: PAIR(450, 300) + *CursorOrigin: PAIR(200, 12900) + } + } + } + + *Option: ENV_MONARCH + { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *PageProtectMem: 4109 + *switch: Orientation + { + *case: PORTRAIT + { + *PrintableArea: PAIR(4048, 8600) + *PrintableOrigin: PAIR(300, 200) + *CursorOrigin: PAIR(300, 200) + } + *case: LANDSCAPE_CC270 + { + *PrintableArea: PAIR(4248, 8520) + *PrintableOrigin: PAIR(200, 240) + *CursorOrigin: PAIR(200, 8760) + } + } + } + + *Option: TABLOID + { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *PageProtectMem: 4109 + *switch: Orientation + { + *case: PORTRAIT + { + *PrintableArea: PAIR(12000, 19200) + *PrintableOrigin: PAIR(400, 400) + *CursorOrigin: PAIR(400, 400) + } + *case: LANDSCAPE_CC270 + { + *PrintableArea: PAIR(12000, 19200) + *PrintableOrigin: PAIR(400, 600) + *CursorOrigin: PAIR(400, 18000) + } + } + } +} + +*%****************************************************************************** +*% PageOrientation +*%****************************************************************************** +*Feature: Orientation +{ + *rcNameID: =ORIENTATION_DISPLAY + *DefaultOption: PORTRAIT + + *Option: PORTRAIT + { + *rcNameID: =PORTRAIT_DISPLAY + } + + *Option: LANDSCAPE_CC270 + { + *rcNameID: =LANDSCAPE_DISPLAY + } +} + +*%****************************************************************************** +*% PageOutputColor +*%****************************************************************************** +*Feature: ColorMode +{ + *rcNameID: =COLOR_PRINTING_MODE_DISPLAY + *DefaultOption: Color + + *Option: Mono + { + *rcNameID: =MONO_DISPLAY + *DevNumOfPlanes: 1 + *DevBPP: 1 + *Color?: FALSE + } + + *Option: Grayscale + { + *rcNameID: =8BPP_DISPLAY + *DevNumOfPlanes: 1 + *DevBPP: 8 + *DrvBPP: 8 + *PaletteSize: 256 + *Color?: FALSE + } + + *Option: Color + { + *rcNameID: =24BPP_DISPLAY + *DevNumOfPlanes: 1 + *DevBPP: 24 + *DrvBPP: 24 + *PaletteSize: 1 + } +} + +*%****************************************************************************** +*% Resolution +*%****************************************************************************** +*Feature: Resolution +{ + *rcNameID: =RESOLUTION_DISPLAY + *DefaultOption: DPI600 + + *Option: DPI600 + { + *Name: "600 x 600 " =DOTS_PER_INCH + *DPI: PAIR(600, 600) + *TextDPI: PAIR(600, 600) + *SpotDiameter: 100 + *Command: CmdBeginRaster { *Cmd : "<1B>*v7S<1B>*r1A" } + *Command: CmdEndRaster { *Cmd : "<1B>*rC" } + *Command: CmdSendBlockData { *Cmd : "<1B>*b" %d{NumOfDataBytes}"W" } + } + + *Option: DPI1200 + { + *Name: "1200 x 1200 " =DOTS_PER_INCH + *DPI: PAIR(1200, 1200) + *TextDPI: PAIR(1200, 1200) + *SpotDiameter: 100 + *Command: CmdBeginRaster { *Cmd : "<1B>*v7S<1B>*r1A" } + *Command: CmdEndRaster { *Cmd : "<1B>*rC" } + *Command: CmdSendBlockData { *Cmd : "<1B>*b" %d{NumOfDataBytes}"W" } + } +} + +*%****************************************************************************** +*% Input Bin +*%****************************************************************************** +*Feature: InputBin +{ + *rcNameID: =PAPER_SOURCE_DISPLAY + *DefaultOption: UPPER + *ConcealFromUI?: TRUE + + *Option: UPPER + { + *rcNameID: =UPPER_TRAY_DISPLAY + } +} + +*%****************************************************************************** +*% DocumentDuplex +*%****************************************************************************** +*Feature: DocumentDuplex +{ + *rcNameID: =IDS_GPD_DOCDUPLEX + *DefaultOption: None + *PrintSchemaKeywordMap: "DocumentDuplex" + + *Option: None + { + *rcNameID: =IDS_GPD_NONE + *PrintSchemaKeywordMap: "OneSided" + } + + *Option: Horizontal + { + *rcNameID: =IDS_GPD_HORIZONTAL + *PrintSchemaKeywordMap: "TwoSidedLongEdge" + } + + *Option: Vertical + { + *rcNameID: =IDS_GPD_VERTICAL + *PrintSchemaKeywordMap: "TwoSidedShortEdge" + } +} + +*%****************************************************************************** +*% PagePhotoPrintingIntent +*%****************************************************************************** +*Feature: PagePhotoPrintingIntent +{ + *rcNameID: =IDS_GPD_PAGEPHOTINTENT + *DefaultOption: None + *PrintSchemaKeywordMap: "PagePhotoPrintingIntent" + + *Option: None + { + *rcNameID: =IDS_GPD_NONE + *PrintSchemaKeywordMap: "None" + } + + *Option: PhotoBest + { + *rcNameID: =IDS_GPD_BEST + *PrintSchemaKeywordMap: "PhotoBest" + } + + *Option: PhotoDraft + { + *rcNameID: =IDS_GPD_DRAFT + *PrintSchemaKeywordMap: "PhotoDraft" + } + + *Option: PhotoStandard + { + *rcNameID: =IDS_GPD_STANDARD + *PrintSchemaKeywordMap: "PhotoStandard" + } +} + +*%****************************************************************************** +*% PageBorderless +*%****************************************************************************** +*Feature: PageBorderless +{ + *rcNameID: =IDS_GPD_PAGEBORDER + *DefaultOption: Borderless + *PrintSchemaKeywordMap: "PageBorderless" + + *Option: None + { + *rcNameID: =IDS_GPD_BORDERED + *PrintSchemaKeywordMap: "None" + } + + *Option: Borderless + { + *rcNameID: =IDS_GPD_BORDERLESS + *PrintSchemaKeywordMap: "Borderless" + } +} + + +*%****************************************************************************** +*% Printer Memory +*%****************************************************************************** +*Feature: Memory +{ + *rcNameID: =PRINTER_MEMORY_DISPLAY + *DefaultOption: 32768KB + *Option: 16384KB + { + *Name: "16MB" + *MemoryConfigKB: PAIR(16384, 13950) + } + *Option: 32768KB + { + *Name: "32MB" + *MemoryConfigKB: PAIR(32768, 28350) + } +} + +*%****************************************************************************** +*% Cursor Commands +*%****************************************************************************** +*Command: CmdCR { *Cmd : "<0D>" } +*Command: CmdLF { *Cmd : "<0A>" } +*Command: CmdFF { *Cmd : "<0C>" } + diff --git a/print/XPSDrvSmpl/install/xdsmpl.inf b/print/XPSDrvSmpl/install/xdsmpl.inf new file mode 100644 index 00000000..762e4bc9 --- /dev/null +++ b/print/XPSDrvSmpl/install/xdsmpl.inf @@ -0,0 +1,139 @@ +; +; Copyright (c) 2005 Microsoft Corporation +; +; All rights reserved. +; +; THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +; ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +; THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +; PARTICULAR PURPOSE. +; +; File Name: +; +; xdsmpl.inf +; +; Abstract: +; +; XPSDrv sample driver install file +; +[Version] +Signature="$Windows NT$" +Provider=%MS% +ClassGUID={4D36E979-E325-11CE-BFC1-08002BE10318} +Class=Printer +DriverVer=10/17/2008,6.1.6930.0 + +[Manufacturer] +%Microsoft%=Microsoft,NTx86,NTia64,NTamd64,NTx86.6.0,NTia64.6.0,NTamd64.6.0 + +[Microsoft.NTx86] +"XPSDrv Sample Driver" = INSTALL_XDSMPL_FILTERS_PRE_VISTA + +[Microsoft.NTia64] +"XPSDrv Sample Driver" = INSTALL_XDSMPL_FILTERS_PRE_VISTA + +[Microsoft.NTamd64] +"XPSDrv Sample Driver" = INSTALL_XDSMPL_FILTERS_PRE_VISTA + +[Microsoft.NTx86.6.0] +"XPSDrv Sample Driver" = INSTALL_XDSMPL_FILTERS_VISTA + +[Microsoft.NTia64.6.0] +"XPSDrv Sample Driver" = INSTALL_XDSMPL_FILTERS_VISTA + +[Microsoft.NTamd64.6.0] +"XPSDrv Sample Driver" = INSTALL_XDSMPL_FILTERS_VISTA + +[INSTALL_XDSMPL_FILTERS_PRE_VISTA] +CopyFiles=XPSDrvSample,ConfigPlugin,COLORPROFILES +DriverFile=mxdwdrv.dll +PrintProcessor="MS_XPS,filterpipelineprintproc.dll" +ConfigFile=UniDrvUI.dll +HelpFile=UniDrv.HLP +DataFile=XDSmpl.GPD +Include=NTPRINT.INF, MSXPSDRV.INF +Needs=UNIDRV.OEM, XPSGPD.OEM, XPSDRV.OEM + +[INSTALL_XDSMPL_FILTERS_VISTA] +CopyFiles=XPSDrvSample,ConfigPlugin,COLORPROFILES +DriverFile=mxdwdrv.dll +ConfigFile=UniDrvUI.dll +HelpFile=UniDrv.HLP +DataFile=XDSmpl.GPD +ICMProfiles=xdwscRGB.icc +CoreDriverSections="{D20EA372-DD35-4950-9ED8-A6335AFE79F0},UNIDRV.OEM", "{D20EA372-DD35-4950-9ED8-A6335AFE79F5},XPSDRV.OEM,XPSGPD.OEM" + +[PrinterPackageInstallation.x86] +PackageAware=TRUE +CoreDriverDependencies={D20EA372-DD35-4950-9ED8-A6335AFE79F0}, {D20EA372-DD35-4950-9ED8-A6335AFE79F5} + +[PrinterPackageInstallation.amd64] +PackageAware=TRUE +CoreDriverDependencies={D20EA372-DD35-4950-9ED8-A6335AFE79F0}, {D20EA372-DD35-4950-9ED8-A6335AFE79F5} + +[PrinterPackageInstallation.ia64] +PackageAware=TRUE +CoreDriverDependencies={D20EA372-DD35-4950-9ED8-A6335AFE79F0}, {D20EA372-DD35-4950-9ED8-A6335AFE79F5} + +[DestinationDirs] +DefaultDestDir=66000 +COLORPROFILES=66003 + +[COLORPROFILES] +xdwscRGB.icc +xdCMYKPrinter.icc + +[ConfigPlugin] +XDSmpl.ini +XDSmplUI.dll + +[XPSDrvSample] +xdsmpl.gpd +xdnames.gpd +xdwmark.gpd +xdbook.gpd +xdcolman.gpd +xdnup.gpd +xdpgscl.gpd +xdwmark.dll +xdcolman.dll +xdbook.dll +xdnup.dll +xdscale.dll +xdsmpl-pipelineconfig.xml + +[SourceDisksNames.x86] +1 = %Location%,, +2 = %Location%,,,x86 + +[SourceDisksNames.ia64] +1 = %Location%,, +2 = %Location%,,,ia64 + +[SourceDisksNames.amd64] +1 = %Location%,, +2 = %Location%,,,amd64 + +[SourceDisksFiles] +xdsmpl.gpd = 1 +xdnames.gpd = 1 +xdwmark.gpd = 1 +xdbook.gpd = 1 +xdcolman.gpd = 1 +xdnup.gpd = 1 +xdpgscl.gpd = 1 +xdsmpl-pipelineconfig.xml = 1 +xdsmpl.ini = 1 +xdwscRGB.icc = 1 +xdCMYKPrinter.icc = 1 +xdwmark.dll = 2 +xdcolman.dll = 2 +xdbook.dll = 2 +xdnup.dll = 2 +xdsmplui.dll = 2 +xdscale.dll = 2 + +[Strings] +Location="XPSDrv Sample Driver Location" +MS="Microsoft" +Microsoft="Microsoft" \ No newline at end of file diff --git a/print/XPSDrvSmpl/install/xdsmpl.ini b/print/XPSDrvSmpl/install/xdsmpl.ini new file mode 100644 index 00000000..d9e17f2c --- /dev/null +++ b/print/XPSDrvSmpl/install/xdsmpl.ini @@ -0,0 +1,22 @@ +; +; Copyright (c) 2005 Microsoft Corporation +; +; All rights reserved. +; +; THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +; ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +; THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +; PARTICULAR PURPOSE. +; +; File Name: +; +; xdsmpl.ini +; +; Abstract: +; +; XPSDrv sample driver configuration file for UI plug-in. +; + +[OEMFiles] +OEMConfigFile1=xdsmplui.DLL + diff --git a/print/XPSDrvSmpl/install/xdwmark.gpd b/print/XPSDrvSmpl/install/xdwmark.gpd new file mode 100644 index 00000000..cf1802d8 --- /dev/null +++ b/print/XPSDrvSmpl/install/xdwmark.gpd @@ -0,0 +1,67 @@ +*% +*% Copyright (c) 2005 Microsoft Corporation +*% +*% All rights reserved. +*% +*% THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +*% ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +*% THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +*% PARTICULAR PURPOSE. +*% +*% File Name: +*% +*% xdwmark.gpd +*% +*% Abstract: +*% +*% XPSDrv filter feature sample driver watermark specific GPD settings. +*% + +*%****************************************************************************** +*% PageWatermark +*%****************************************************************************** +*Feature: PageWatermarkType +{ + *rcNameID: =IDS_GPD_WATERMARKTYPE + *DefaultOption: None + + *Option: None + { + *rcNameID: =IDS_GPD_NONE + } + + *Option: Text + { + *rcNameID: =IDS_GPD_TEXT + } + + *Option: Raster + { + *rcNameID: =IDS_GPD_RASTERIMAGE + } + + *Option: Vector + { + *rcNameID: =IDS_GPD_VECTORIMAGE + } +} + +*%****************************************************************************** +*% PageWatermarkLayering +*%****************************************************************************** +*Feature: PageWatermarkLayering +{ + *rcNameID: =IDS_GPD_WATERMARKLAYERING + *DefaultOption: Overlay + + *Option: Overlay + { + *rcNameID: =IDS_GPD_OVERLAYED + } + + *Option: Underlay + { + *rcNameID: =IDS_GPD_UNDERLAYED + } +} + diff --git a/print/XPSDrvSmpl/install/xdwscRGB.icc b/print/XPSDrvSmpl/install/xdwscRGB.icc new file mode 100644 index 00000000..b1e6845d Binary files /dev/null and b/print/XPSDrvSmpl/install/xdwscRGB.icc differ diff --git a/print/XPSDrvSmpl/readme.txt b/print/XPSDrvSmpl/readme.txt new file mode 100644 index 00000000..fee929fe --- /dev/null +++ b/print/XPSDrvSmpl/readme.txt @@ -0,0 +1,63 @@ +Print Features Filter Sample Driver +=================================== + +Sample History: +=============== + +Windows 7: +The sample has been changed such that the DllGetClassObject() function for each filter +returns an instance of IClassFactory instead of an instance of IPrintPipelineFilter. This +is in agreement with the updated MSDN documentation surrounding XpsDrv filters. + +Note: As reflected in the MSDN documentation, DllGetClassObject() functions that return + IPrintPipelineFilter will still be compatible with the Print Pipeline in order to + maintain compatibility with existing XpsDrv filters. + +Also, the sample now uses the PrintSchema keyword PageSourceColorProfile to store the +color matching profile in the PrintTicket. + + +Contents: +========= + +install + Install directory. Contains driver gpd and install files and is where driver DLLs are published. + +src\common + Code common to both the filter and config modules. This is mostly common print ticket handling code. + +src\debug + Common debug code. + +src\filters + Precompiled header and common sources information. + +src\filters\booklet + Booklet filter specific code. + +src\filters\color + Color filter specific code. + +src\filters\common + Code common to all filters. + +src\filters\nup + NUp filter specific code. + +src\filters\scaling + Scaling filter specific code. + +src\filters\watermark + Watermark filter specific code. + +src\filters\xdcont + Sources for XPS container handling. This code is used with the stream interface to process the XPS container. + +src\inc + Common include files. + +src\ui + Config plug-in code. This provides the custom UI and PrintTicket provider support. + + + diff --git a/print/XPSDrvSmpl/src/common/bkdata.h b/print/XPSDrvSmpl/src/common/bkdata.h new file mode 100644 index 00000000..dae29cf2 --- /dev/null +++ b/print/XPSDrvSmpl/src/common/bkdata.h @@ -0,0 +1,46 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + bkdata.h + +Abstract: + + Booklet data structure definition. This provides a convenient description + of the PrintSchema JobBindAllDocuments and DcoumentBinding features. + +--*/ + +#pragma once + +#include "bkschema.h" + +namespace XDPrintSchema +{ + namespace Binding + { + struct BindingData + { + BindingData() : + bindFeature(JobBindAllDocuments), + bindOption(None), + bindGutter(0) + { + } + + EBinding bindFeature; + EBindingOption bindOption; + INT bindGutter; + }; + } +} + diff --git a/print/XPSDrvSmpl/src/common/bkpchndlr.cpp b/print/XPSDrvSmpl/src/common/bkpchndlr.cpp new file mode 100644 index 00000000..1ce57acf --- /dev/null +++ b/print/XPSDrvSmpl/src/common/bkpchndlr.cpp @@ -0,0 +1,201 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + bkpchndlr.cpp + +Abstract: + + Booklet PrintCapabilities handling implementation. The booklet PC handler + is used to set booklet settings in a PrintCapabilities document. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "xdexcept.h" +#include "bkpchndlr.h" +#include "globals.h" +#include "privatedefs.h" + +using XDPrintSchema::PRINTCAPABILITIES_NAME; + +using XDPrintSchema::Binding::EBinding; +using XDPrintSchema::Binding::EBindingMin; +using XDPrintSchema::Binding::EBindingMax; +using XDPrintSchema::Binding::EBindingOption; +using XDPrintSchema::Binding::EBindingOptionMin; +using XDPrintSchema::Binding::EBindingOptionMax; +using XDPrintSchema::Binding::BIND_FEATURES; +using XDPrintSchema::Binding::BIND_OPTIONS; + +/*++ + +Routine Name: + + CBookPCHandler::CBookPCHandler + +Routine Description: + + CBookPCHandler class constructor + +Arguments: + + pPrintCapabilities - Pointer to the DOM document representation of the PrintCapabilities + +Return Value: + + None + +--*/ +CBookPCHandler::CBookPCHandler( + _In_ IXMLDOMDocument2* pPrintCapabilities + ) : + CPCHandler(pPrintCapabilities) +{ +} + +/*++ + +Routine Name: + + CBookPCHandler::~CBookPCHandler + +Routine Description: + + CBookPCHandler class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CBookPCHandler::~CBookPCHandler() +{ +} + +/*++ + +Routine Name: + + CBookPCHandler::SetCapabilities + +Routine Description: + + This routine sets booklet capabilities in the PrintCapabilities passed to the + class constructor. + +Arguments: + + None + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CBookPCHandler::SetCapabilities( + VOID + ) +{ + HRESULT hr = S_OK; + + try + { + // + // Retrieve the PrintTicket root + // + CComPtr pPTRoot(NULL); + + CComBSTR bstrPTQuery(m_bstrFrameworkPrefix); + bstrPTQuery += PRINTCAPABILITIES_NAME; + + if (SUCCEEDED(hr = GetNode(bstrPTQuery, &pPTRoot))) + { + for (EBinding bindFeatures = EBindingMin; + bindFeatures < EBindingMax && SUCCEEDED(hr); + bindFeatures = static_cast(bindFeatures + 1)) + { + CComPtr pFeatureElement(NULL); + + if (SUCCEEDED(hr = CreateFeatureSelection(CComBSTR(BIND_FEATURES[bindFeatures]), NULL, &pFeatureElement))) + { + PTDOMElementVector optionList; + + for (EBindingOption bindOption = EBindingOptionMin; + bindOption < EBindingOptionMax && SUCCEEDED(hr); + bindOption = static_cast(bindOption + 1)) + { + // + // Create the booklet options + // + CComPtr pOptionProperty(NULL); + + if (SUCCEEDED(hr = CreateOption(CComBSTR(BIND_OPTIONS[bindOption]), NULL, &pOptionProperty))) + { + optionList.push_back(pOptionProperty); + } + } + + // + // Add the options into the booklet feature + // + PTDOMElementVector::iterator iterOptionList = optionList.begin(); + + for (;iterOptionList != optionList.end() && SUCCEEDED(hr); iterOptionList++) + { + hr = pFeatureElement->appendChild(*iterOptionList, NULL); + } + } + + if (SUCCEEDED(hr)) + { + hr = pPTRoot->appendChild(pFeatureElement, NULL); + } + } + + for (UINT cIndex = 0; cIndex < numof(bkParamDefIntegers); cIndex++) + { + CComPtr pParameterDef(NULL); + + if (SUCCEEDED(hr = CreateIntParameterDef(CComBSTR(bkParamDefIntegers[cIndex].property_name), // Paramater Name + bkParamDefIntegers[cIndex].is_public, // Is Print Schema keyword? + CComBSTR(bkParamDefIntegers[cIndex].display_name), // Display Text + bkParamDefIntegers[cIndex].default_value, // Default + bkParamDefIntegers[cIndex].min_length, // Min Length + bkParamDefIntegers[cIndex].max_length, // Max Length + bkParamDefIntegers[cIndex].multiple, // Multiple + CComBSTR(bkParamDefIntegers[cIndex].unit_type), // Unit Type + &pParameterDef))) // Parameter Def + { + hr = pPTRoot->appendChild(pParameterDef, NULL); + } + } + } + } + catch (exception& DBG_ONLY(e)) + { + ERR(e.what()); + hr = E_FAIL; + } + + ERR_ON_HR(hr); + return hr; +} + diff --git a/print/XPSDrvSmpl/src/common/bkpchndlr.h b/print/XPSDrvSmpl/src/common/bkpchndlr.h new file mode 100644 index 00000000..46d65138 --- /dev/null +++ b/print/XPSDrvSmpl/src/common/bkpchndlr.h @@ -0,0 +1,41 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + bkpchndlr.h + +Abstract: + + Booklet PrintCapabilities handling definition. The booklet PC handler + is used to set booklet settings in a PrintCapabilities. + +--*/ + +#pragma once + +#include "pchndlr.h" +#include "bkdata.h" + +class CBookPCHandler : public CPCHandler +{ +public: + CBookPCHandler( + _In_ IXMLDOMDocument2* pPrintCapabilities + ); + + virtual ~CBookPCHandler(); + + HRESULT + SetCapabilities( + VOID + ); +}; diff --git a/print/XPSDrvSmpl/src/common/bkpthndlr.cpp b/print/XPSDrvSmpl/src/common/bkpthndlr.cpp new file mode 100644 index 00000000..46fb54b6 --- /dev/null +++ b/print/XPSDrvSmpl/src/common/bkpthndlr.cpp @@ -0,0 +1,318 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + bkpthndlr.cpp + +Abstract: + + Booklet PrintTicket handling implementation. The booklet PT handler + is used to extract booklet settings from a PrintTicket and populate + the booklet data structure with the retrieved settings. The class also + defines a method for setting the feature in the PrintTicket given the + data structure. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "bkpthndlr.h" + +using XDPrintSchema::PRINTTICKET_NAME; + +using XDPrintSchema::Binding::BindingData; +using XDPrintSchema::Binding::EBinding; +using XDPrintSchema::Binding::EBindingMin; +using XDPrintSchema::Binding::EBindingMax; +using XDPrintSchema::Binding::EBindingOption; +using XDPrintSchema::Binding::EBindingOptionMin; +using XDPrintSchema::Binding::EBindingOptionMax; +using XDPrintSchema::Binding::BIND_FEATURES; +using XDPrintSchema::Binding::BIND_OPTIONS; +using XDPrintSchema::Binding::BIND_PROP; +using XDPrintSchema::Binding::BIND_PROP_REF_SUFFIX; + +/*++ + +Routine Name: + + CBookPTHandler::CBookPTHandler + +Routine Description: + + CBookPTHandler class constructor + +Arguments: + + pPrintTicket - Pointer to the DOM document representation of the PrintTicket + +Return Value: + + None + +--*/ +CBookPTHandler::CBookPTHandler( + _In_ IXMLDOMDocument2* pPrintTicket + ) : + CPTHandler(pPrintTicket) +{ +} + +/*++ + +Routine Name: + + CBookPTHandler::~CBookPTHandler + +Routine Description: + + CBookPTHandler class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CBookPTHandler::~CBookPTHandler() +{ +} + +/*++ + +Routine Name: + + CBookPTHandler::GetData + +Routine Description: + + The routine fills the data structure passed in with binding data retrieved from + the PrintTicket passed to the class constructor. + +Arguments: + + pBindData - Pointer to the binding data structure to be filled in + +Return Value: + + HRESULT + S_OK - On success + E_ELEMENT_NOT_FOUND - Feature not present in PrintTicket + E_* - On error + +--*/ +HRESULT +CBookPTHandler::GetData( + _Out_ BindingData* pBindData + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pBindData, E_POINTER))) + { + for (EBinding bindFeature = EBindingMin; + bindFeature < EBindingMax; + bindFeature = static_cast(bindFeature + 1)) + { + CComBSTR bstrBindOption; + CComBSTR bstrFeature(BIND_FEATURES[bindFeature]); + + if (SUCCEEDED(hr = GetFeatureOption(bstrFeature, &bstrBindOption))) + { + pBindData->bindFeature = bindFeature; + + // + // Identify the option + // + for (EBindingOption bindOption = EBindingOptionMin; + bindOption < EBindingOptionMax; + bindOption = static_cast(bindOption + 1)) + { + if (bstrBindOption == BIND_OPTIONS[bindOption]) + { + pBindData->bindOption = bindOption; + break; + } + } + + // + // Get the gutter value if one exists otherwise use a default + // + if (FAILED(GetScoredPropertyValue(bstrFeature, CComBSTR(BIND_PROP), &pBindData->bindGutter))) + { + pBindData->bindGutter = 0; + } + + break; + } + else if (hr != E_ELEMENT_NOT_FOUND) + { + // + // We have an error other than the element is not present + // so we break and let the result return + // + break; + } + } + } + + // + // Validate the data + // + if (SUCCEEDED(hr)) + { + if (pBindData->bindFeature < EBindingMin || + pBindData->bindFeature >= EBindingMax || + pBindData->bindOption < EBindingOptionMin || + pBindData->bindOption >= EBindingOptionMax) + { + hr = E_FAIL; + } + } + + ERR_ON_HR_EXC(hr, E_ELEMENT_NOT_FOUND); + return hr; +} + +/*++ + +Routine Name: + + CBookPTHandler::SetData + +Routine Description: + + This routine sets the binding data in the PrintTicket passed to the + class constructor. + +Arguments: + + pBindData - Pointer to the binding data to be set in the PrintTicket + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CBookPTHandler::SetData( + _In_ CONST BindingData* pBindData + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pBindData, E_POINTER))) + { + if (pBindData->bindFeature < EBindingMin || + pBindData->bindFeature >= EBindingMax || + pBindData->bindOption < EBindingOptionMin || + pBindData->bindOption >= EBindingOptionMax) + { + hr = E_INVALIDARG; + } + } + + // + // Delete any exsting NUp settings as JobNUpAllDocumentsContiguously and DocumentNUp are mutually exclusive + // + if (SUCCEEDED(hr) && + pBindData->bindOption != XDPrintSchema::Binding::None) + { + // + // Create the following elements + // Feature and Option + // Parameter Ref and Parameter Init + // ScoredProperty + // + // Then append the scored property to the option node and the feature + // and parameter init nodes to the root PrintTicket node. Note: the + // scored poperty is created passing the parameter ref so it is already + // appended + // + CComPtr pFeature(NULL); + CComPtr pOption(NULL); + CComPtr pParamRef(NULL); + CComPtr pParamInit(NULL); + CComPtr pScoredProp(NULL); + + CComBSTR bstrFeature(BIND_FEATURES[pBindData->bindFeature]); + + if (SUCCEEDED(DeleteFeature(bstrFeature))) + { + CComBSTR bstrPropName(BIND_PROP_REF_SUFFIX); + CComBSTR bstrParamRefName(bstrFeature); + bstrParamRefName += bstrPropName; + + if (SUCCEEDED(hr = CreateFeatureOptionPair(bstrFeature, + CComBSTR(BIND_OPTIONS[pBindData->bindOption]), + &pFeature, + &pOption)) && + SUCCEEDED(hr = CreateParamRefInitPair(bstrParamRefName, pBindData->bindGutter, &pParamRef, &pParamInit)) && + SUCCEEDED(hr = CreateScoredProperty(CComBSTR(BIND_PROP), pParamRef, &pScoredProp)) && + SUCCEEDED(hr = pOption->appendChild(pScoredProp, NULL)) && + SUCCEEDED(hr = AppendToElement(CComBSTR(PRINTTICKET_NAME), pFeature))) + { + hr = AppendToElement(CComBSTR(PRINTTICKET_NAME), pParamInit); + } + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CBookPTHandler::Delete + +Routine Description: + + This routine deletes the binding feature from the PrintTicket passed to the + class constructor + +Arguments: + + None + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CBookPTHandler::Delete( + VOID + ) +{ + HRESULT hr = S_OK; + + for (EBinding bindFeature = EBindingMin; + bindFeature < EBindingMax && SUCCEEDED(hr); + bindFeature = static_cast(bindFeature + 1)) + { + hr = DeleteFeature(CComBSTR(BIND_FEATURES[bindFeature])); + } + + ERR_ON_HR(hr); + return hr; +} + diff --git a/print/XPSDrvSmpl/src/common/bkpthndlr.h b/print/XPSDrvSmpl/src/common/bkpthndlr.h new file mode 100644 index 00000000..abd5ef9d --- /dev/null +++ b/print/XPSDrvSmpl/src/common/bkpthndlr.h @@ -0,0 +1,55 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + bkpthndlr.h + +Abstract: + + Booklet PrintTicket handling definition. The booklet PT handler + is used to extract booklet settings from a PrintTicket and populate + the booklet data structure with the retrieved settings. The class also + defines a method for setting the feature in the PrintTicket given the + data structure. + +--*/ + +#pragma once + +#include "pthndlr.h" +#include "bkdata.h" + +class CBookPTHandler : public CPTHandler +{ +public: + CBookPTHandler( + _In_ IXMLDOMDocument2* pPrintTicket + ); + + virtual ~CBookPTHandler(); + + HRESULT + GetData( + _Out_ XDPrintSchema::Binding::BindingData* pBindData + ); + + HRESULT + SetData( + _In_ CONST XDPrintSchema::Binding::BindingData* pBindData + ); + + HRESULT + Delete( + VOID + ); +}; + diff --git a/print/XPSDrvSmpl/src/common/bkschema.cpp b/print/XPSDrvSmpl/src/common/bkschema.cpp new file mode 100644 index 00000000..daa26254 --- /dev/null +++ b/print/XPSDrvSmpl/src/common/bkschema.cpp @@ -0,0 +1,51 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + bkschema.cpp + +Abstract: + + Binding (booklet) PrintSchema implementation. This implements the features, + options and enumerations that describe the PrintSchema JobBindAllDocuments and + DocumentBinding features. + +--*/ + +#include "precomp.h" +#include "bkschema.h" + +LPCWSTR XDPrintSchema::Binding::BIND_FEATURES[] = { + L"JobBindAllDocuments", + L"DocumentBinding" +}; + +LPCWSTR XDPrintSchema::Binding::BIND_OPTIONS[] = { + L"Bale", + L"BindBottom", + L"BindLeft", + L"BindRight", + L"BindTop", + L"Booklet", + L"EdgeStitchBottom", + L"EdgeStitchLeft", + L"EdgeStitchRight", + L"EdgeStitchTop", + L"Fold", + L"JogOffset", + L"Trim", + L"None" +}; + +LPCWSTR XDPrintSchema::Binding::BIND_PROP = L"BindingGutter"; +LPCWSTR XDPrintSchema::Binding::BIND_PROP_REF_SUFFIX = L"Gutter"; + diff --git a/print/XPSDrvSmpl/src/common/bkschema.h b/print/XPSDrvSmpl/src/common/bkschema.h new file mode 100644 index 00000000..bcf68df2 --- /dev/null +++ b/print/XPSDrvSmpl/src/common/bkschema.h @@ -0,0 +1,77 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + bkschema.h + +Abstract: + + Binding (booklet) PrintSchema definition. This defines the features, + options and enumerations that describe the PrintSchema JobBindAllDocuments and + DocumentBinding features within a XDPrintSchema::Binding namespace. + +--*/ + +#pragma once + +#include "schema.h" + +namespace XDPrintSchema +{ + // + // Binding elements described as Printschema keywords + // + namespace Binding + { + // + // Job and Document share identical options so we define two + // features within the Binding namespace. + // + enum EBinding + { + JobBindAllDocuments = 0, EBindingMin = 0, + DocumentBinding, + EBindingMax + }; + + extern LPCWSTR BIND_FEATURES[EBindingMax]; + + // + // Option names + // + enum EBindingOption + { + Bale = 0, EBindingOptionMin = 0, + BindBottom, + BindLeft, + BindRight, + BindTop, + Booklet, + EdgeStitchBottom, + EdgeStitchLeft, + EdgeStitchRight, + EdgeStitchTop, + Fold, + JogOffset, + Trim, + None, + EBindingOptionMax + }; + + extern LPCWSTR BIND_OPTIONS[EBindingOptionMax]; + + extern LPCWSTR BIND_PROP; + + extern LPCWSTR BIND_PROP_REF_SUFFIX; + } +} + diff --git a/print/XPSDrvSmpl/src/common/cmdata.h b/print/XPSDrvSmpl/src/common/cmdata.h new file mode 100644 index 00000000..7b2dcb7f --- /dev/null +++ b/print/XPSDrvSmpl/src/common/cmdata.h @@ -0,0 +1,42 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + cmdata.h + +Abstract: + + PageColorManagement data structure definition. This provides a convenient + description of the PrintSchema PageColorManagement feature. + +--*/ + +#pragma once + +#include "cmschema.h" + +namespace XDPrintSchema +{ + namespace PageColorManagement + { + struct ColorManagementData + { + ColorManagementData() : + cmOption(None) + { + } + + EPCMOption cmOption; + }; + } +} + diff --git a/print/XPSDrvSmpl/src/common/cmintentsdata.h b/print/XPSDrvSmpl/src/common/cmintentsdata.h new file mode 100644 index 00000000..f9fa2c20 --- /dev/null +++ b/print/XPSDrvSmpl/src/common/cmintentsdata.h @@ -0,0 +1,42 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + cmintentsdata.h + +Abstract: + + PageICMRenderingIntent data structure definition. This provides a more + convenient description of the PrintSchema PageICMRenderingIntent feature. + +--*/ + +#pragma once + +#include "cmintentsschema.h" + +namespace XDPrintSchema +{ + namespace PageICMRenderingIntent + { + struct PageICMRenderingIntentData + { + PageICMRenderingIntentData() : + cmOption(AbsoluteColorimetric) + { + } + + EICMIntentOption cmOption; + }; + } +} + diff --git a/print/XPSDrvSmpl/src/common/cmintentsschema.cpp b/print/XPSDrvSmpl/src/common/cmintentsschema.cpp new file mode 100644 index 00000000..1b68de7b --- /dev/null +++ b/print/XPSDrvSmpl/src/common/cmintentsschema.cpp @@ -0,0 +1,34 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + cmintentsschema.cpp + +Abstract: + + PageICMRenderingIntent PrintSchema implementation. This implements the features, + options and enumerations that describe the PrintSchema PageICMRenderingIntent feature. + +--*/ + +#include "precomp.h" +#include "cmintentsschema.h" + +LPCWSTR XDPrintSchema::PageICMRenderingIntent::ICMINTENT_FEATURE = L"PageICMRenderingIntent"; + +LPCWSTR XDPrintSchema::PageICMRenderingIntent::ICMINTENT_OPTIONS[] = { + L"AbsoluteColorimetric", + L"RelativeColorimetric", + L"Photographs", + L"BusinessGraphics" +}; + diff --git a/print/XPSDrvSmpl/src/common/cmintentsschema.h b/print/XPSDrvSmpl/src/common/cmintentsschema.h new file mode 100644 index 00000000..73203876 --- /dev/null +++ b/print/XPSDrvSmpl/src/common/cmintentsschema.h @@ -0,0 +1,55 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + cmintentsschema.h + +Abstract: + + PageICMRenderingIntent PrintSchema definition. This defines the features, + options and enumerations that describe the PrintSchema PageICMRenderingIntent feature + within a XDPrintSchema::PageICMRenderingIntent namespace. + +--*/ + +#pragma once + +#include "schema.h" + +namespace XDPrintSchema +{ + // + // PageColorManagementIntents elements described as Printschema keywords + // + namespace PageICMRenderingIntent + { + // + // Feature name + // + extern LPCWSTR ICMINTENT_FEATURE; + + // + // Who specified the profile to use + // + enum EICMIntentOption + { + AbsoluteColorimetric = 0, EICMIntentOptionMin = 0, + RelativeColorimetric, + Photographs, + BusinessGraphics, + EICMIntentOptionMax + }; + + extern LPCWSTR ICMINTENT_OPTIONS[EICMIntentOptionMax]; + } +} + diff --git a/print/XPSDrvSmpl/src/common/cmintpthndlr.cpp b/print/XPSDrvSmpl/src/common/cmintpthndlr.cpp new file mode 100644 index 00000000..d23fffb6 --- /dev/null +++ b/print/XPSDrvSmpl/src/common/cmintpthndlr.cpp @@ -0,0 +1,156 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + cmintpthndlr.cpp + +Abstract: + + PageICMRenderingIntent PrintTicket handler implementation. Derived from + CPTHandler, this provides PageICMRenderingIntent specific Get and Set methods + acting on the PrintTicket (as a DOM document) passed. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdexcept.h" +#include "cmintpthndlr.h" + +using XDPrintSchema::PageICMRenderingIntent::PageICMRenderingIntentData; +using XDPrintSchema::PageICMRenderingIntent::EICMIntentOption; +using XDPrintSchema::PageICMRenderingIntent::EICMIntentOptionMin; +using XDPrintSchema::PageICMRenderingIntent::BusinessGraphics; +using XDPrintSchema::PageICMRenderingIntent::EICMIntentOptionMax; +using XDPrintSchema::PageICMRenderingIntent::ICMINTENT_FEATURE; +using XDPrintSchema::PageICMRenderingIntent::ICMINTENT_OPTIONS; + +/*++ + +Routine Name: + + CColorManageIntentsPTHandler::CColorManageIntentsPTHandler + +Routine Description: + + CColorManageIntentsPTHandler class constructor + +Arguments: + + pPrintTicket - Pointer to the DOM document representation of the PrintTicket + +Return Value: + + None + +--*/ +CColorManageIntentsPTHandler::CColorManageIntentsPTHandler( + _In_ IXMLDOMDocument2* pPrintTicket + ) : + CPTHandler(pPrintTicket) +{ +} + +/*++ + +Routine Name: + + CColorManageIntentsPTHandler::~CColorManageIntentsPTHandler + +Routine Description: + + CColorManageIntentsPTHandler class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CColorManageIntentsPTHandler::~CColorManageIntentsPTHandler() +{ +} + +/*++ + +Routine Name: + + CColorManageIntentsPTHandler::GetData + +Routine Description: + + The routine fills the data structure passed in with color intent data retrieved + from the PrintTicket passed to the class constructor. + +Arguments: + + pCmData - Pointer to the color intent data structure to be filled in + +Return Value: + + HRESULT + S_OK - On success + E_ELEMENT_NOT_FOUND - Feature not present in PrintTicket + E_* - On error + +--*/ +HRESULT +CColorManageIntentsPTHandler::GetData( + _Inout_ PageICMRenderingIntentData* pCmData + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pCmData, E_POINTER))) + { + CComBSTR bstrCMOption; + + if (SUCCEEDED(hr = GetFeatureOption(CComBSTR(ICMINTENT_FEATURE), &bstrCMOption))) + { + // + // Get the profile type + // + for (EICMIntentOption cmOption = EICMIntentOptionMin; + cmOption < EICMIntentOptionMax; + cmOption = static_cast(cmOption + 1)) + { + if (bstrCMOption == ICMINTENT_OPTIONS[cmOption]) + { + pCmData->cmOption = cmOption; + break; + } + } + + if (SUCCEEDED(hr)) + { + if (pCmData->cmOption < EICMIntentOptionMin || + pCmData->cmOption >= EICMIntentOptionMax) + { + hr = E_FAIL; + } + } + } + else + { + pCmData->cmOption = BusinessGraphics; + hr = S_OK; + } + } + + ERR_ON_HR_EXC(hr, E_ELEMENT_NOT_FOUND); + return hr; +} + diff --git a/print/XPSDrvSmpl/src/common/cmintpthndlr.h b/print/XPSDrvSmpl/src/common/cmintpthndlr.h new file mode 100644 index 00000000..19e5b4bc --- /dev/null +++ b/print/XPSDrvSmpl/src/common/cmintpthndlr.h @@ -0,0 +1,43 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + cmintpthndlr.h + +Abstract: + + PageICMRenderingIntent PrintTicket handler definition. Derived from + CPTHandler, this provides PageICMRenderingIntent specific Get and Set methods + acting on the PrintTicket (as a DOM document) passed. + +--*/ + +#pragma once + +#include "pthndlr.h" +#include "cmintentsdata.h" + +class CColorManageIntentsPTHandler : public CPTHandler +{ +public: + CColorManageIntentsPTHandler( + _In_ IXMLDOMDocument2* pPrintTicket + ); + + virtual ~CColorManageIntentsPTHandler(); + + HRESULT + GetData( + _Inout_ XDPrintSchema::PageICMRenderingIntent::PageICMRenderingIntentData* pCmData + ); +}; + diff --git a/print/XPSDrvSmpl/src/common/cmprofiledata.h b/print/XPSDrvSmpl/src/common/cmprofiledata.h new file mode 100644 index 00000000..29048ea3 --- /dev/null +++ b/print/XPSDrvSmpl/src/common/cmprofiledata.h @@ -0,0 +1,44 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + cmprofiledata.h + +Abstract: + + PageSourceColorProfileData data structure definition. This provides + a convenient description of the PrintSchema PageSourceColorProfileData + feature. + +--*/ + +#pragma once + +#include "cmprofileschema.h" + +namespace XDPrintSchema +{ + namespace PageSourceColorProfile + { + struct PageSourceColorProfileData + { + PageSourceColorProfileData() : + cmProfile(RGB) + { + } + + EProfileOption cmProfile; + CComBSTR cmProfileName; + }; + } +} + diff --git a/print/XPSDrvSmpl/src/common/cmprofileschema.cpp b/print/XPSDrvSmpl/src/common/cmprofileschema.cpp new file mode 100644 index 00000000..5f74fa51 --- /dev/null +++ b/print/XPSDrvSmpl/src/common/cmprofileschema.cpp @@ -0,0 +1,49 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + cmprofileschema.cpp + +Abstract: + + PageSourceColorProfile PrintSchema implementation. This implements the + features, options and enumerations that describe the PrintSchema + PageSourceColorProfile feature. + +--*/ + +#include "precomp.h" +#include "globals.h" +#include "privatedefs.h" +#include "cmprofileschema.h" + +LPCWSTR XDPrintSchema::PageSourceColorProfile::PROFILE_FEATURE = L"PageSourceColorProfile"; + +LPCWSTR XDPrintSchema::PageSourceColorProfile::PROFILE_OPTIONS[] = { + L"RGB", + L"CMYK" +}; + +LPCWSTR XDPrintSchema::PageSourceColorProfile::PROFILE_URI_PROP = L"SourceColorProfileURI"; +LPCWSTR XDPrintSchema::PageSourceColorProfile::PROFILE_URI_REF = L"PageSourceColorProfileURI"; + +PRIVATE_DEF_STRINGS XDPrintSchema::PageSourceColorProfile::PROFILE_PARAM_DEF = { + "PageSourceColorProfileURI", + NULL, + "xdCMYKPrinter.icc", + 0, + 65536, + "characters" +}; + + + diff --git a/print/XPSDrvSmpl/src/common/cmprofileschema.h b/print/XPSDrvSmpl/src/common/cmprofileschema.h new file mode 100644 index 00000000..659d42c5 --- /dev/null +++ b/print/XPSDrvSmpl/src/common/cmprofileschema.h @@ -0,0 +1,60 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + cmintentsschema.h + +Abstract: + + PageSourceColorProfile PrintSchema definition. This defines the features, + options and enumerations that describe the PrintSchema PageSourceColorProfile + feature within a XDPrintSchema::PageSourceColorProfile namespace. + + +--*/ + +#pragma once + +#include "schema.h" +#include "globals.h" +#include "privatedefs.h" + +namespace XDPrintSchema +{ + // + // PageColorManagement elements described as Printschema keywords + // + namespace PageSourceColorProfile + { + // + // Feature name + // + extern LPCWSTR PROFILE_FEATURE; + + // + // Who specified the profile to use + // + enum EProfileOption + { + RGB = 0, EProfileOptionMin = 0, + CMYK, + EProfileOptionMax + }; + + extern LPCWSTR PROFILE_OPTIONS[EProfileOptionMax]; + + extern LPCWSTR PROFILE_URI_PROP; + extern LPCWSTR PROFILE_URI_REF; + extern PRIVATE_DEF_STRINGS PROFILE_PARAM_DEF; + } +} + diff --git a/print/XPSDrvSmpl/src/common/cmprofpchndlr.cpp b/print/XPSDrvSmpl/src/common/cmprofpchndlr.cpp new file mode 100644 index 00000000..a8f5bb9c --- /dev/null +++ b/print/XPSDrvSmpl/src/common/cmprofpchndlr.cpp @@ -0,0 +1,179 @@ +/*++ + +Copyright (c) 2008 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + cmprofpchndlr.cpp + +Abstract: + + PageSourceColorProfile PrintCapabilities handling implementation. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdexcept.h" +#include "ptquerybld.h" +#include "cmprofpchndlr.h" + +using XDPrintSchema::PRINTCAPABILITIES_NAME; + +using XDPrintSchema::PageSourceColorProfile::PROFILE_FEATURE; +using XDPrintSchema::PageSourceColorProfile::PROFILE_OPTIONS; +using XDPrintSchema::PageSourceColorProfile::PROFILE_URI_PROP; +using XDPrintSchema::PageSourceColorProfile::PROFILE_URI_REF; +using XDPrintSchema::PageSourceColorProfile::PROFILE_PARAM_DEF; +using XDPrintSchema::PageSourceColorProfile::EProfileOption; +using XDPrintSchema::PageSourceColorProfile::EProfileOptionMax; +using XDPrintSchema::PageSourceColorProfile::EProfileOptionMin; +using XDPrintSchema::PageSourceColorProfile::RGB; +using XDPrintSchema::PageSourceColorProfile::CMYK; + +/*++ + +Routine Name: + + CColorManageProfilePCHandler::CColorManageProfilePCHandler + +Routine Description: + + CColorManageProfilePCHandler class constructor + +Arguments: + + pPrintCapabilities - Pointer to the DOM document representation of the PrintCapabilities + +Return Value: + + None + +--*/ +CColorManageProfilePCHandler::CColorManageProfilePCHandler( + _In_ IXMLDOMDocument2* pPrintCapabilities + ) : + CPCHandler(pPrintCapabilities) +{ +} + +/*++ + +Routine Name: + + CColorManageProfilePCHandler::~CColorManageProfilePCHandler + +Routine Description: + + CColorManageProfilePCHandler class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CColorManageProfilePCHandler::~CColorManageProfilePCHandler() +{ +} + +/*++ + +Routine Name: + + CColorManageProfilePCHandler::SetCapabilities + +Routine Description: + + This routine sets color profile capabilities in the PrintCapabilities passed to the + class constructor. + +Arguments: + + None + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CColorManageProfilePCHandler::SetCapabilities( + VOID + ) +{ + HRESULT hr = S_OK; + + try + { + // + // Retrieve the PrintTicket root + // + CComPtr pPCRoot(NULL); + CComPtr pFeatureElement(NULL); + + CComBSTR bstrPTQuery(m_bstrFrameworkPrefix); + bstrPTQuery += PRINTCAPABILITIES_NAME; + + if (SUCCEEDED(hr = GetNode(bstrPTQuery, &pPCRoot)) && + SUCCEEDED(hr = CreateFeatureSelection(CComBSTR(PROFILE_FEATURE), NULL, &pFeatureElement))) + { + for ( EProfileOption option = EProfileOptionMin; + option < EProfileOptionMax && SUCCEEDED(hr); + option = static_cast(option + 1)) + { + CComPtr pOptionElement(NULL); + CComPtr pScoredPropElement(NULL); + CComPtr pPropRefElement(NULL); + + if (SUCCEEDED(hr = CreateOption(CComBSTR(PROFILE_OPTIONS[option]), NULL, &pOptionElement)) && + SUCCEEDED(hr = CreateScoredProperty(CComBSTR(PROFILE_URI_PROP), &pScoredPropElement)) && + SUCCEEDED(hr = CreateParameterRef(CComBSTR(PROFILE_URI_REF), &pPropRefElement)) && + SUCCEEDED(hr = pScoredPropElement->appendChild(pPropRefElement, NULL)) && + SUCCEEDED(hr = pOptionElement->appendChild(pScoredPropElement, NULL))) + { + hr = pFeatureElement->appendChild(pOptionElement, NULL); + } + } + + CComPtr pParameterDef(NULL); + + if (SUCCEEDED(hr = pPCRoot->appendChild(pFeatureElement, NULL)) && + SUCCEEDED(hr = CreateStringParameterDef( CComBSTR(PROFILE_PARAM_DEF.property_name), // Paramater Name + TRUE, // Is Print Schema Keyword? + CComBSTR(PROFILE_PARAM_DEF.display_name), // Display Text + CComBSTR(PROFILE_PARAM_DEF.default_value), // Default + PROFILE_PARAM_DEF.min_length, // Min Length + PROFILE_PARAM_DEF.max_length, // Max Length + CComBSTR(PROFILE_PARAM_DEF.unit_type), // Unit Type + &pParameterDef))) // Parameter Def + { + hr = pPCRoot->appendChild(pParameterDef, NULL); + } + } + + + } + catch (exception& DBG_ONLY(e)) + { + ERR(e.what()); + hr = E_FAIL; + } + + ERR_ON_HR(hr); + + return S_OK; +} diff --git a/print/XPSDrvSmpl/src/common/cmprofpchndlr.h b/print/XPSDrvSmpl/src/common/cmprofpchndlr.h new file mode 100644 index 00000000..059ca831 --- /dev/null +++ b/print/XPSDrvSmpl/src/common/cmprofpchndlr.h @@ -0,0 +1,42 @@ +/*++ + +Copyright (c) 2008 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + cmprofpthndlr.h + +Abstract: + + PageSourceColorProfile PrintCapabilities handling definition. + +--*/ + +#pragma once + +#include "pchndlr.h" +#include "cmprofiledata.h" + +class CColorManageProfilePCHandler : public CPCHandler +{ +public: + + CColorManageProfilePCHandler( + _In_ IXMLDOMDocument2* pPrintCapabilities + ); + + virtual ~CColorManageProfilePCHandler(); + + HRESULT + SetCapabilities( + VOID + ); +}; + diff --git a/print/XPSDrvSmpl/src/common/cmprofpthndlr.cpp b/print/XPSDrvSmpl/src/common/cmprofpthndlr.cpp new file mode 100644 index 00000000..ee074fdb --- /dev/null +++ b/print/XPSDrvSmpl/src/common/cmprofpthndlr.cpp @@ -0,0 +1,206 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + cmprofpthndlr.cpp + +Abstract: + + PageSourceColorProfile PrintTicket handling implementation. + The PageSourceColorProfile PT handler is used to extract + PageSourceColorProfile settings from a PrintTicket and populate + the PageSourceColorProfile data structure with the retrieved + settings. The class also defines a method for setting the feature in + the PrintTicket given the data structure. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdexcept.h" +#include "ptquerybld.h" +#include "cmprofpthndlr.h" + +using XDPrintSchema::SCHEMA_STRING; +using XDPrintSchema::PRINTTICKET_NAME; + +using XDPrintSchema::PageSourceColorProfile::PageSourceColorProfileData; +using XDPrintSchema::PageSourceColorProfile::EProfileOption; +using XDPrintSchema::PageSourceColorProfile::EProfileOptionMin; +using XDPrintSchema::PageSourceColorProfile::EProfileOptionMax; +using XDPrintSchema::PageSourceColorProfile::PROFILE_FEATURE; +using XDPrintSchema::PageSourceColorProfile::PROFILE_OPTIONS; +using XDPrintSchema::PageSourceColorProfile::PROFILE_URI_PROP; +using XDPrintSchema::PageSourceColorProfile::PROFILE_URI_REF; +using XDPrintSchema::PageSourceColorProfile::RGB; +using XDPrintSchema::PageSourceColorProfile::CMYK; + +/*++ + +Routine Name: + + CColorManageProfilePTHandler::CColorManageProfilePTHandler + +Routine Description: + + CColorManageProfilePTHandler class constructor + +Arguments: + + pPrintTicket - Pointer to the DOM document representation of the PrintTicket + +Return Value: + + None + +--*/ +CColorManageProfilePTHandler::CColorManageProfilePTHandler( + _In_ IXMLDOMDocument2* pPrintTicket + ) : + CPTHandler(pPrintTicket) +{ +} + +/*++ + +Routine Name: + + CColorManageProfilePTHandler::~CColorManageProfilePTHandler + +Routine Description: + + CColorManageProfilePTHandler class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CColorManageProfilePTHandler::~CColorManageProfilePTHandler() +{ +} + +/*++ + +Routine Name: + + CColorManageProfilePTHandler::GetData + +Routine Description: + + The routine fills the data structure passed in with color profile data + retrieved from the PrintTicket passed to the class constructor. + +Arguments: + + pCmData - Pointer to the color profile data structure to be filled in + +Return Value: + + HRESULT + S_OK - On success + E_ELEMENT_NOT_FOUND - Feature not present in PrintTicket + E_* - On error + +--*/ +HRESULT +CColorManageProfilePTHandler::GetData( + _Inout_ PageSourceColorProfileData* pCmData + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pCmData, E_POINTER))) + { + CComBSTR option; + if (SUCCEEDED(hr = GetFeatureOption(CComBSTR(PROFILE_FEATURE), &option)) && + SUCCEEDED(GetScoredPropertyValue(CComBSTR(PROFILE_FEATURE), CComBSTR(PROFILE_URI_PROP), &pCmData->cmProfileName)) + ) + { + pCmData->cmProfile = CMYK; // default to CMYK + + for (EProfileOption cmOption = EProfileOptionMin; + cmOption < EProfileOptionMax; + cmOption = static_cast(cmOption + 1)) + { + if (option == CComBSTR(PROFILE_OPTIONS[cmOption])) + { + pCmData->cmProfile = cmOption; + } + } + } + } + + ERR_ON_HR_EXC(hr, E_ELEMENT_NOT_FOUND); + return hr; +} + +/*++ + +Routine Name: + + CColorManageProfilePTHandler::SetData + +Routine Description: + + This routine sets the color profile data in the PrintTicket + passed to the class constructor. + +Arguments: + + pCmData - Pointer to the color profile data to be set in the PrintTicket + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CColorManageProfilePTHandler::SetData( + _In_ CONST PageSourceColorProfileData* pCmData + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pCmData, E_POINTER))) + { + CComPtr pFeature(NULL); + CComPtr pOption(NULL); + CComPtr pUriProperty(NULL); + CComPtr pRef(NULL); + CComPtr pInit(NULL); + + + CComBSTR bstrFeature(PROFILE_FEATURE); + + if (SUCCEEDED(hr = DeleteFeature(bstrFeature)) && + SUCCEEDED(hr = CreateFeatureOptionPair(bstrFeature, CComBSTR(PROFILE_OPTIONS[pCmData->cmProfile]), &pFeature, &pOption)) && + SUCCEEDED(hr = CreateParamRefInitPair(CComBSTR(PROFILE_URI_REF), CComBSTR(SCHEMA_STRING), pCmData->cmProfileName, &pRef, &pInit)) && + SUCCEEDED(hr = CreateScoredProperty(CComBSTR(PROFILE_URI_PROP), pRef, &pUriProperty)) && + SUCCEEDED(hr = pOption->appendChild(pUriProperty, NULL)) && + SUCCEEDED(hr = AppendToElement(CComBSTR(PRINTTICKET_NAME), pInit))) + { + SUCCEEDED(hr = AppendToElement(CComBSTR(PRINTTICKET_NAME), pFeature)); + } + } + + ERR_ON_HR(hr); + return hr; +} + diff --git a/print/XPSDrvSmpl/src/common/cmprofpthndlr.h b/print/XPSDrvSmpl/src/common/cmprofpthndlr.h new file mode 100644 index 00000000..fb002a45 --- /dev/null +++ b/print/XPSDrvSmpl/src/common/cmprofpthndlr.h @@ -0,0 +1,51 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + cmprofpthndlr.h + +Abstract: + + PageSourceColorProfile PrintTicket handling definition. + The PageSourceColorProfile PT handler is used to extract + PageSourceColorProfile settings from a PrintTicket and populate + the PageSourceColorProfile data structure with the retrieved + settings. The class also defines a method for setting the feature in + the PrintTicket given the data structure. + +--*/ + +#pragma once + +#include "pthndlr.h" +#include "cmprofiledata.h" + +class CColorManageProfilePTHandler : public CPTHandler +{ +public: + CColorManageProfilePTHandler( + _In_ IXMLDOMDocument2* pPrintTicket + ); + + virtual ~CColorManageProfilePTHandler(); + + HRESULT + GetData( + _Inout_ XDPrintSchema::PageSourceColorProfile::PageSourceColorProfileData* pCmData + ); + + HRESULT + SetData( + _In_ CONST XDPrintSchema::PageSourceColorProfile::PageSourceColorProfileData* pCmData + ); +}; + diff --git a/print/XPSDrvSmpl/src/common/cmpthndlr.cpp b/print/XPSDrvSmpl/src/common/cmpthndlr.cpp new file mode 100644 index 00000000..cdd20311 --- /dev/null +++ b/print/XPSDrvSmpl/src/common/cmpthndlr.cpp @@ -0,0 +1,154 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + cmpthndlr.cpp + +Abstract: + + PageColorManagement PrintTicket handling implementation. The + PageColorManagement PT handler is used to extract booklet settings + from a PrintTicket and populate the PageColorManagement data + structure with the retrieved settings. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdexcept.h" +#include "cmpthndlr.h" + +using XDPrintSchema::PageColorManagement::ColorManagementData; +using XDPrintSchema::PageColorManagement::EPCMOption; +using XDPrintSchema::PageColorManagement::EPCMOptionMin; +using XDPrintSchema::PageColorManagement::EPCMOptionMax; +using XDPrintSchema::PageColorManagement::PCM_FEATURE; +using XDPrintSchema::PageColorManagement::PCM_OPTIONS; + +/*++ + +Routine Name: + + CColorManagePTHandler::CColorManagePTHandler + +Routine Description: + + CColorManagePTHandler class constructor + +Arguments: + + pPrintTicket - Pointer to the DOM document representation of the PrintTicket + +Return Value: + + None + +--*/ +CColorManagePTHandler::CColorManagePTHandler( + _In_ IXMLDOMDocument2* pPrintTicket + ) : + CPTHandler(pPrintTicket) +{ +} + +/*++ + +Routine Name: + + CColorManagePTHandler::~CColorManagePTHandler + +Routine Description: + + CColorManagePTHandler class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CColorManagePTHandler::~CColorManagePTHandler() +{ +} + +/*++ + +Routine Name: + + CColorManagePTHandler::GetData + +Routine Description: + + The routine fills the data structure passed in with color management data + retrieved from the PrintTicket passed to the class constructor. + +Arguments: + + pCmData - Pointer to the color management data structure to be filled in + +Return Value: + + HRESULT + S_OK - On success + E_ELEMENT_NOT_FOUND - Feature not present in PrintTicket + E_* - On error + +--*/ +HRESULT +CColorManagePTHandler::GetData( + _Inout_ ColorManagementData* pCmData + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pCmData, E_POINTER))) + { + CComBSTR bstrCMOption; + + // + // Check whether to use driver or device color matching + // + if (SUCCEEDED(hr = GetFeatureOption(CComBSTR(PCM_FEATURE), &bstrCMOption))) + { + for (EPCMOption cmOpt = EPCMOptionMin; + cmOpt < EPCMOptionMax; + cmOpt = static_cast(cmOpt + 1)) + { + if (bstrCMOption == PCM_OPTIONS[cmOpt]) + { + pCmData->cmOption = cmOpt; + break; + } + } + } + + // + // Validate the data + // + if (SUCCEEDED(hr)) + { + if (pCmData->cmOption < EPCMOptionMin || + pCmData->cmOption >= EPCMOptionMax) + { + hr = E_FAIL; + } + } + } + + ERR_ON_HR_EXC(hr, E_ELEMENT_NOT_FOUND); + return hr; +} + diff --git a/print/XPSDrvSmpl/src/common/cmpthndlr.h b/print/XPSDrvSmpl/src/common/cmpthndlr.h new file mode 100644 index 00000000..17faf30e --- /dev/null +++ b/print/XPSDrvSmpl/src/common/cmpthndlr.h @@ -0,0 +1,46 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + cmpthndlr.h + +Abstract: + + PageColorManagement PrintTicket handling definition. The + PageColorManagement PT handler is used to extract booklet settings + from a PrintTicket and populate the PageColorManagement data + structure with the retrieved settings. The class also + defines a method for setting the feature in the PrintTicket given the + data structure. + +--*/ + +#pragma once + +#include "pthndlr.h" +#include "cmdata.h" + +class CColorManagePTHandler : public CPTHandler +{ +public: + CColorManagePTHandler( + _In_ IXMLDOMDocument2* pPrintTicket + ); + + virtual ~CColorManagePTHandler(); + + HRESULT + GetData( + _Inout_ XDPrintSchema::PageColorManagement::ColorManagementData* pCmData + ); +}; + diff --git a/print/XPSDrvSmpl/src/common/cmschema.cpp b/print/XPSDrvSmpl/src/common/cmschema.cpp new file mode 100644 index 00000000..f047f8fa --- /dev/null +++ b/print/XPSDrvSmpl/src/common/cmschema.cpp @@ -0,0 +1,34 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + cmschema.cpp + +Abstract: + + PageColorManagement PrintSchema implementation. This implements the features, + options and enumerations that describe the PrintSchema PageColorManagement feature. + +--*/ + +#include "precomp.h" +#include "cmschema.h" + +LPCWSTR XDPrintSchema::PageColorManagement::PCM_FEATURE = L"PageColorManagement"; + +LPCWSTR XDPrintSchema::PageColorManagement::PCM_OPTIONS[] = { + L"None", + L"Device", + L"Driver", + L"System" +}; + diff --git a/print/XPSDrvSmpl/src/common/cmschema.h b/print/XPSDrvSmpl/src/common/cmschema.h new file mode 100644 index 00000000..6f4a30a6 --- /dev/null +++ b/print/XPSDrvSmpl/src/common/cmschema.h @@ -0,0 +1,55 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + cmschema.h + +Abstract: + + PageColorManagement PrintSchema definition. This defines the features, options + and enumerations that describe the PrintSchema PageColorManagement feature + within a XDPrintSchema::PageColorManagement namespace. + +--*/ + +#pragma once + +#include "schema.h" + +namespace XDPrintSchema +{ + // + // PageColorManagement elements described as Printschema keywords + // + namespace PageColorManagement + { + // + // Feature name + // + extern LPCWSTR PCM_FEATURE; + + // + // Option names + // + enum EPCMOption + { + None = 0, EPCMOptionMin = 0, + Device, + Driver, + System, + EPCMOptionMax + }; + + extern LPCWSTR PCM_OPTIONS[EPCMOptionMax]; + } +} + diff --git a/print/XPSDrvSmpl/src/common/globals.cpp b/print/XPSDrvSmpl/src/common/globals.cpp new file mode 100644 index 00000000..28cf17a5 --- /dev/null +++ b/print/XPSDrvSmpl/src/common/globals.cpp @@ -0,0 +1,237 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + globals.cpp + +Abstract: + + Stores function implementations and variable instances global to the filter + module. This is shared between all filters. + +--*/ + +#include "precomp.h" +#include + +// +// Module's Instance handle from DLLEntry of process. +// +HINSTANCE g_hInstance = NULL; + +// +// Server lock count +// +LONG g_cServerLocks = 0; + +/*++ + +Routine Name: + + GetLastErrorAsHResult + +Routine Description: + + Converts the Win32 last error to an HRESULT + +Arguments: + + None + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +GetLastErrorAsHResult( + void + ) +{ + DWORD error = GetLastError(); + + return HRESULT_FROM_WIN32(error); +} + +/*++ + +Routine Name: + + GetLastErrorAsHResult + +Routine Description: + + Converts a GDI status error to an HRESULT + +Arguments: + + gdiPStatus - The GDI plus status value to be converted to an HRESULT + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +GetGDIStatusErrorAsHResult( + _In_ Status gdiPStatus + ) +{ + HRESULT hr = E_FAIL; + + switch (gdiPStatus) + { + case Ok: + { + hr = S_OK; + } + break; + + case GenericError: + { + hr = E_FAIL; + } + break; + + case InvalidParameter: + { + hr = E_INVALIDARG; + } + break; + + case OutOfMemory: + { + hr = E_OUTOFMEMORY; + } + break; + + case ObjectBusy: + { + hr = E_PENDING; + } + break; + + case InsufficientBuffer: + { + hr = E_OUTOFMEMORY; + } + break; + + case NotImplemented: + { + hr = E_NOTIMPL; + } + break; + + case Win32Error: + { + hr = GetLastErrorAsHResult(); + } + break; + + case FileNotFound: + { + hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); + } + break; + + case AccessDenied: + { + hr = HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED); + } + break; + + // + // Default to E_FAIL + // + case UnknownImageFormat: + case FontFamilyNotFound: + case FontStyleNotFound: + case NotTrueTypeFont: + case UnsupportedGdiplusVersion: + case GdiplusNotInitialized: + case PropertyNotFound: + case PropertyNotSupported: + case ValueOverflow: + case Aborted: + case WrongState: + default: + break; + }; + + return hr; +} + +/*++ + +Routine Name: + + IsVista + +Routine Description: + + Checks if we are running under Vista + +Arguments: + + None + +Return Value: + + TRUE if we are under Vista + FALSE otherwise + +--*/ + +BOOL +IsVista( + VOID + ) +{ + BOOL bIsVista = FALSE; + bIsVista = IsWindowsVistaOrGreater(); + return bIsVista; +} + +/*++ + +Routine Name: + + GetUniqueNumber + +Routine Description: + + Returns a unique number. + +Arguments: + + None + +Return Value: + + A unique DWORD. + +--*/ + +DWORD +GetUniqueNumber( + VOID + ) +{ + static volatile DWORD number = 0; + + return InterlockedIncrement(&number); +} diff --git a/print/XPSDrvSmpl/src/common/globals.h b/print/XPSDrvSmpl/src/common/globals.h new file mode 100644 index 00000000..e4992c03 --- /dev/null +++ b/print/XPSDrvSmpl/src/common/globals.h @@ -0,0 +1,102 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + globals.cpp + +Abstract: + + Stores function definitions, variable declerations and pre-processor macros + global to the filter module. This is shared between all filters. + +--*/ + +#pragma once + +// +// Module's Instance handle from DLLEntry of process. +// +extern HINSTANCE g_hInstance; + +// +// Server lock count +// +extern LONG g_cServerLocks; + +// +// Global defines +// +#define CB_COPY_BUFFER 0x10000 +#define MAX_UISTRING_LEN 256 +#define OEM_SIGNATURE 'XDSM' +#define OEM_VERSION 0x00000001L + +// +// Conversion functions for Microns to 1/100th of Inch (and visa versa) +// +#define HUNDREDTH_OFINCH_TO_MICRON(x) MulDiv(x, 25400, 100) +#define MICRON_TO_HUNDREDTH_OFINCH(x) MulDiv(x, 100, 25400) + +// +// Macros for checking pointers and handles. +// +#define CHECK_POINTER(p, hr) ((p) == NULL ? hr : S_OK) +#define CHECK_HANDLE(h, hr) ((h) == NULL ? hr : S_OK) + +static const FLOAT kMaxByteAsFloat = 255.0f; +static const FLOAT kMaxWordAsFloat = 65535.0f; + +static const WORD kS2Dot13Neg = 0x8000; +static const WORD kS2Dot13One = 0x2000; +static const WORD kS2Dot13Min = 0xFFFF; +static const WORD kS2Dot13Max = 0x7FFF; + +static const FLOAT k96thInchAsMicrons = 264.58f; + +// +// countof macro +// +#ifndef countof +#define countof(ary) (sizeof(ary) / sizeof((ary)[0])) +#endif + +// +// Converts the Win32 last error to an HRESULT +// +HRESULT +GetLastErrorAsHResult( + void + ); + +// +// Converts a GDI status error to an HRESULT +// +HRESULT +GetGDIStatusErrorAsHResult( + _In_ Status gdiPStatus + ); + +// +// Check if we are running under Vista +// +BOOL +IsVista( + VOID + ); + +// +// Returns a unique number +// +DWORD +GetUniqueNumber( + VOID + ); diff --git a/print/XPSDrvSmpl/src/common/nupchndlr.cpp b/print/XPSDrvSmpl/src/common/nupchndlr.cpp new file mode 100644 index 00000000..e2374eb9 --- /dev/null +++ b/print/XPSDrvSmpl/src/common/nupchndlr.cpp @@ -0,0 +1,196 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + nuppchndlr.cpp + +Abstract: + + NUp PrintCapabilities handling implementation. The NUp PC handler + is used to set NUp settings in a PrintCapabilities. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "xdexcept.h" +#include "nupchndlr.h" +#include "ptquerybld.h" + +using XDPrintSchema::NUp::NUpData; +using XDPrintSchema::NUp::ENUpFeature; +using XDPrintSchema::NUp::ENUpFeatureMin; +using XDPrintSchema::NUp::DocumentNUp; +using XDPrintSchema::NUp::JobNUpAllDocumentsContiguously; +using XDPrintSchema::NUp::ENUpFeatureMax; +using XDPrintSchema::NUp::NUP_FEATURES; +using XDPrintSchema::NUp::NUP_PROP; + +using XDPrintSchema::NUp::PresentationDirection::ENUpDirectionOption; +using XDPrintSchema::NUp::PresentationDirection::ENUpDirectionOptionMin; +using XDPrintSchema::NUp::PresentationDirection::ENUpDirectionOptionMax; +using XDPrintSchema::NUp::PresentationDirection::NUP_DIRECTION_FEATURE; +using XDPrintSchema::NUp::PresentationDirection::NUP_DIRECTION_OPTIONS; + +/*++ + +Routine Name: + + CNUpPCHandler::CNUpPCHandler + +Routine Description: + + CNUpPCHandler class constructor + +Arguments: + + pPrintCapabilities - Pointer to the DOM document representation of the PrintCapabilities + +Return Value: + + None + +--*/ +CNUpPCHandler::CNUpPCHandler( + _In_ IXMLDOMDocument2* pPrintCapabilities + ) : + CPCHandler(pPrintCapabilities) +{ +} + +/*++ + +Routine Name: + + CNUpPCHandler::~CNUpPCHandler + +Routine Description: + + CNUpPCHandler class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CNUpPCHandler::~CNUpPCHandler() +{ +} + +/*++ + +Routine Name: + + CNUpPCHandler::SetCapabilities + +Routine Description: + + This routine sets NUp capabilities in the PrintCapabilities passed to the + class constructor. + +Arguments: + + None + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CNUpPCHandler::SetCapabilities( + VOID + ) +{ + HRESULT hr = S_OK; + + try + { + for (ENUpFeature nupFeatures = ENUpFeatureMin; + nupFeatures < ENUpFeatureMax && SUCCEEDED(hr); + nupFeatures = static_cast(nupFeatures + 1)) + { + // + // Find the existing NUp feature node + // + CPTQueryBuilder propertyQuery(m_bstrFrameworkPrefix); + CComPtr pFeatureNode(NULL); + CComBSTR bstrFeatureQuery; + + if (SUCCEEDED(hr = propertyQuery.AddFeature(m_bstrKeywordsPrefix, CComBSTR(NUP_FEATURES[nupFeatures]))) && + SUCCEEDED(hr = propertyQuery.GetQuery(&bstrFeatureQuery)) && + SUCCEEDED(hr = GetNode(bstrFeatureQuery, &pFeatureNode)) && + hr != S_FALSE) + { + CComPtr pPresentationFeature(NULL); + + // + // Create the presentation feature options + // + if (SUCCEEDED(hr = CreateFeature(CComBSTR(NUP_DIRECTION_FEATURE), + NULL, + &pPresentationFeature))) + { + PTDOMElementVector optionList; + + for (ENUpDirectionOption presentationOption = ENUpDirectionOptionMin; + presentationOption < ENUpDirectionOptionMax && SUCCEEDED(hr); + presentationOption = static_cast(presentationOption + 1)) + { + // + // Create the presentation options property element + // + CComPtr pOptionProperty(NULL); + + if (SUCCEEDED(hr = CreateOption(CComBSTR(NUP_DIRECTION_OPTIONS[presentationOption]), NULL, &pOptionProperty))) + { + optionList.push_back(pOptionProperty); + } + } + + // + // Add the options into the presentation feature + // + PTDOMElementVector::iterator iterOptionList = optionList.begin(); + + for (;iterOptionList != optionList.end() && SUCCEEDED(hr); iterOptionList++) + { + hr = pPresentationFeature->appendChild(*iterOptionList, NULL); + } + + // + // Add the presentation feature into the existing NUp feature + // + if (SUCCEEDED(hr)) + { + hr = pFeatureNode->appendChild(pPresentationFeature, NULL); + } + } + } + } + } + catch (exception& DBG_ONLY(e)) + { + ERR(e.what()); + hr = E_FAIL; + } + + ERR_ON_HR(hr); + return hr; +} + diff --git a/print/XPSDrvSmpl/src/common/nupchndlr.h b/print/XPSDrvSmpl/src/common/nupchndlr.h new file mode 100644 index 00000000..f829d739 --- /dev/null +++ b/print/XPSDrvSmpl/src/common/nupchndlr.h @@ -0,0 +1,41 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + nupchndlr.h + +Abstract: + + NUp PrintCapabilities handling definition. The NUp PC handler + is used to set NUp settings in a PrintCapabilities. + +--*/ + +#pragma once + +#include "pchndlr.h" +#include "nupdata.h" + +class CNUpPCHandler : public CPCHandler +{ +public: + CNUpPCHandler( + _In_ IXMLDOMDocument2* pPrintCapabilities + ); + + virtual ~CNUpPCHandler(); + + HRESULT + SetCapabilities( + VOID + ); +}; diff --git a/print/XPSDrvSmpl/src/common/nupdata.h b/print/XPSDrvSmpl/src/common/nupdata.h new file mode 100644 index 00000000..bf76500a --- /dev/null +++ b/print/XPSDrvSmpl/src/common/nupdata.h @@ -0,0 +1,46 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + nupdata.h + +Abstract: + + NUp data structure definition. This provides a convenient description + of the PrintSchema JobNUpAllDocumentsContiguously and DocumentNUp features. + +--*/ + +#pragma once + +#include "nupschema.h" + +namespace XDPrintSchema +{ + namespace NUp + { + struct NUpData + { + NUpData() : + nUpFeature(JobNUpAllDocumentsContiguously), + cNUp(1), + nUpPresentDir(PresentationDirection::RightBottom) + { + } + + ENUpFeature nUpFeature; + INT cNUp; + PresentationDirection::ENUpDirectionOption nUpPresentDir; + }; + } +} + diff --git a/print/XPSDrvSmpl/src/common/nupschema.cpp b/print/XPSDrvSmpl/src/common/nupschema.cpp new file mode 100644 index 00000000..7ae67391 --- /dev/null +++ b/print/XPSDrvSmpl/src/common/nupschema.cpp @@ -0,0 +1,46 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + nupschema.cpp + +Abstract: + + NUp PrintSchema implementation. This implements the features, + options and enumerations that describe the PrintSchema JobNUpAllDocumentsContiguously + and DocumentNUp features. + +--*/ + +#include "precomp.h" +#include "nupschema.h" + +LPCWSTR XDPrintSchema::NUp::NUP_FEATURES[] = { + L"JobNUpAllDocumentsContiguously", + L"DocumentNUp" +}; + +LPCWSTR XDPrintSchema::NUp::NUP_PROP = L"PagesPerSheet"; + +LPCWSTR XDPrintSchema::NUp::PresentationDirection::NUP_DIRECTION_FEATURE = L"PresentationDirection"; + +LPCWSTR XDPrintSchema::NUp::PresentationDirection::NUP_DIRECTION_OPTIONS[] = { + L"RightBottom", + L"BottomRight", + L"LeftBottom", + L"BottomLeft", + L"RightTop", + L"TopRight", + L"LeftTop", + L"TopLeft" +}; + diff --git a/print/XPSDrvSmpl/src/common/nupschema.h b/print/XPSDrvSmpl/src/common/nupschema.h new file mode 100644 index 00000000..4c10451d --- /dev/null +++ b/print/XPSDrvSmpl/src/common/nupschema.h @@ -0,0 +1,77 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + nupschema.h + +Abstract: + + NUp PrintSchema definition. This defines the features, options and + enumerations that describe the PrintSchema JobNUpAllDocumentsContiguously and DocumentNUp + features within a XDPrintSchema::NUp namespace. + +--*/ + +#pragma once + +#include "schema.h" + +namespace XDPrintSchema +{ + // + // NUp elements described as Printschema keywords + // + namespace NUp + { + // + // JobNUpAllDocumentsContiguously and DocumentNUp share identical options so we define two + // features within the NUp namespace. + // + enum ENUpFeature + { + JobNUpAllDocumentsContiguously = 0, ENUpFeatureMin = 0, + DocumentNUp, + ENUpFeatureMax + }; + + extern LPCWSTR NUP_FEATURES[ENUpFeatureMax]; + + extern LPCWSTR NUP_PROP; + + namespace PresentationDirection + { + // + // Feature name + // + extern LPCWSTR NUP_DIRECTION_FEATURE; + + // + // Option names + // + enum ENUpDirectionOption + { + RightBottom = 0, ENUpDirectionOptionMin = 0, + BottomRight, + LeftBottom, + BottomLeft, + RightTop, + TopRight, + LeftTop, + TopLeft, + ENUpDirectionOptionMax + }; + + extern LPCWSTR NUP_DIRECTION_OPTIONS[ENUpDirectionOptionMax]; + } + } +} + diff --git a/print/XPSDrvSmpl/src/common/nupthndlr.cpp b/print/XPSDrvSmpl/src/common/nupthndlr.cpp new file mode 100644 index 00000000..be836bcc --- /dev/null +++ b/print/XPSDrvSmpl/src/common/nupthndlr.cpp @@ -0,0 +1,309 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + nupthndlr.cpp + +Abstract: + + NUp PrintTicket handling implementation. The nup PT handler + is used to extract nup settings from a PrintTicket and populate + the nup properties class with the retrieved settings. The class also + defines a method for setting the feature in the PrintTicket given the + data structure. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdexcept.h" +#include "nupthndlr.h" + +using XDPrintSchema::NUp::NUpData; +using XDPrintSchema::NUp::ENUpFeature; +using XDPrintSchema::NUp::ENUpFeatureMin; +using XDPrintSchema::NUp::ENUpFeatureMax; +using XDPrintSchema::NUp::NUP_FEATURES; +using XDPrintSchema::NUp::NUP_PROP; + +using XDPrintSchema::NUp::PresentationDirection::ENUpDirectionOption; +using XDPrintSchema::NUp::PresentationDirection::ENUpDirectionOptionMin; +using XDPrintSchema::NUp::PresentationDirection::ENUpDirectionOptionMax; +using XDPrintSchema::NUp::PresentationDirection::NUP_DIRECTION_FEATURE; +using XDPrintSchema::NUp::PresentationDirection::NUP_DIRECTION_OPTIONS; + +/*++ + +Routine Name: + + CNUpPTHandler::CNUpPTHandler + +Routine Description: + + CNUpPTHandler class constructor + +Arguments: + + pPrintTicket - Pointer to the DOM document representation of the PrintTicket + +Return Value: + + None + +--*/ +CNUpPTHandler::CNUpPTHandler( + _In_ IXMLDOMDocument2* pPrintTicket + ) : + CPTHandler(pPrintTicket) +{ +} + +/*++ + +Routine Name: + + CNUpPTHandler::~CNUpPTHandler + +Routine Description: + + CNUpPTHandler class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CNUpPTHandler::~CNUpPTHandler() +{ +} + +/*++ + +Routine Name: + + CNUpPTHandler::GetData + +Routine Description: + + The routine fills the data structure passed in with NUp data retrieved from + the PrintTicket passed to the class constructor. + +Arguments: + + pNUpData - Pointer to the NUp data structure to be filled in + +Return Value: + + HRESULT + S_OK - On success + E_ELEMENT_NOT_FOUND - Feature not present in PrintTicket + E_* - On error + +--*/ +HRESULT +CNUpPTHandler::GetData( + _Out_ NUpData* pNUpData + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pNUpData, E_POINTER))) + { + for (ENUpFeature nUpFeature = ENUpFeatureMin; + nUpFeature < ENUpFeatureMax; + nUpFeature = static_cast(nUpFeature + 1)) + { + CComBSTR bstrPresentOption; + CComBSTR bstrFeature(NUP_FEATURES[nUpFeature]); + + if (SUCCEEDED(hr = FeaturePresent(bstrFeature, NULL)) && + SUCCEEDED(hr = GetSubFeatureOption(bstrFeature, + CComBSTR(NUP_DIRECTION_FEATURE), + &bstrPresentOption)) && + SUCCEEDED(hr = GetScoredPropertyValue(bstrFeature, CComBSTR(NUP_PROP), &pNUpData->cNUp))) + { + // + // We may be set to 1-up. If so treat as though the feature is not present + // + if (pNUpData->cNUp > 1) + { + pNUpData->nUpFeature = nUpFeature; + + // + // Convert the presentation direction string to our enumeration + // + for (ENUpDirectionOption presDir = ENUpDirectionOptionMin; + presDir < ENUpDirectionOptionMax; + presDir = static_cast(presDir + 1)) + { + if (bstrPresentOption == NUP_DIRECTION_OPTIONS[presDir]) + { + pNUpData->nUpPresentDir = presDir; + break; + } + } + + // + // We have found and initialised the feature - break out the feature loop + // + break; + } + else + { + hr = E_ELEMENT_NOT_FOUND; + } + } + else if (hr != E_ELEMENT_NOT_FOUND) + { + // + // We have an error other than the element is not present + // so we break and let the result return + // + break; + } + } + } + + // + // Validate the data + // + if (SUCCEEDED(hr)) + { + if (pNUpData->nUpFeature < ENUpFeatureMin || + pNUpData->nUpFeature >= ENUpFeatureMax || + pNUpData->nUpPresentDir < ENUpDirectionOptionMin || + pNUpData->nUpPresentDir >= ENUpDirectionOptionMax) + { + hr = E_FAIL; + } + } + + ERR_ON_HR_EXC(hr, E_ELEMENT_NOT_FOUND); + return hr; +} + +/*++ + +Routine Name: + + CNUpPTHandler::SetData + +Routine Description: + + This routine sets the NUp data in the PrintTicket passed to the + class constructor. Note: The GPD handles the NUp count option and + scored properties so we only have to add the presentation direction + sub-feature. + +Arguments: + + pNUpData - Pointer to the NUp data to be set in the PrintTicket + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CNUpPTHandler::SetData( + _In_ CONST NUpData* pNUpData + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pNUpData, E_POINTER))) + { + if (pNUpData->nUpFeature < ENUpFeatureMin || + pNUpData->nUpFeature >= ENUpFeatureMax || + pNUpData->nUpPresentDir < ENUpDirectionOptionMin || + pNUpData->nUpPresentDir >= ENUpDirectionOptionMax) + { + hr = E_INVALIDARG; + } + } + + if (SUCCEEDED(hr)) + { + // + // Check the appropriate NUp option is set in the PT + // + CComPtr pNUpFeature(NULL); + CComBSTR bstrFeature(NUP_FEATURES[pNUpData->nUpFeature]); + + if (SUCCEEDED(hr = FeaturePresent(bstrFeature, &pNUpFeature))) + { + // + // The NUp feature is present. Create the presentation direction sub-feature + // and ensure it is set in the PrintTicket. + // + CComPtr pPresDirFeature(NULL); + CComPtr pPresDirOption(NULL); + + if (SUCCEEDED(hr = DeleteFeature(CComBSTR(NUP_DIRECTION_FEATURE))) && + SUCCEEDED(hr = CreateFeatureOptionPair(CComBSTR(NUP_DIRECTION_FEATURE), + CComBSTR(NUP_DIRECTION_OPTIONS[pNUpData->nUpPresentDir]), + &pPresDirFeature, + &pPresDirOption))) + { + hr = pNUpFeature->appendChild(pPresDirFeature, NULL); + } + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CNUpPTHandler::Delete + +Routine Description: + + This routine deletes the NUp feature from the PrintTicket passed to the + class constructor + +Arguments: + + None + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CNUpPTHandler::Delete() +{ + HRESULT hr = S_OK; + + for (ENUpFeature nUpFeature = ENUpFeatureMin; + nUpFeature < ENUpFeatureMax && SUCCEEDED(hr); + nUpFeature = static_cast(nUpFeature + 1)) + { + hr = DeleteFeature(CComBSTR(NUP_FEATURES[nUpFeature])); + } + + ERR_ON_HR(hr); + return hr; +} diff --git a/print/XPSDrvSmpl/src/common/nupthndlr.h b/print/XPSDrvSmpl/src/common/nupthndlr.h new file mode 100644 index 00000000..eaeb22a6 --- /dev/null +++ b/print/XPSDrvSmpl/src/common/nupthndlr.h @@ -0,0 +1,53 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + nupthndlr.h + +Abstract: + + NUp properties class implementation. The NUp properties class + is responsible for holding and controling NUp properties. + +--*/ + +#pragma once + + +#include "pthndlr.h" +#include "nupdata.h" + +class CNUpPTHandler : public CPTHandler +{ +public: + CNUpPTHandler( + _In_ IXMLDOMDocument2* pPrintTicket + ); + + virtual ~CNUpPTHandler(); + + HRESULT + GetData( + _Out_ XDPrintSchema::NUp::NUpData* pNUpData + ); + + HRESULT + SetData( + _In_ CONST XDPrintSchema::NUp::NUpData* pNUpData + ); + + HRESULT + Delete( + VOID + ); +}; + diff --git a/print/XPSDrvSmpl/src/common/pchndlr.cpp b/print/XPSDrvSmpl/src/common/pchndlr.cpp new file mode 100644 index 00000000..c480ac52 --- /dev/null +++ b/print/XPSDrvSmpl/src/common/pchndlr.cpp @@ -0,0 +1,640 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +File Name: + + pchndlr.cpp + +Abstract: + + Base PrintCapabilities handler class implementation. This class provides common + PrintCapabilities handling functionality for any feature that requires + PrintCapabilities handling. A feature specific handler can derive from + this class to get feature unspecific XML handling functionality. + +--*/ + + +// +// Note on handling missing DOM nodes: +// +// Convert MSXML's S_FALSE to E_ELEMENT_NOT_FOUND. This allows clients to +// use the SUCCEEDED macro more effectively. +// +// E_ELEMENT_NOT_FOUND should not be propogated as an error to the +// filter pipeline or config module - treat as though the requested feature +// has not been enabled. +// + +#include "precomp.h" +#include "debug.h" +#include "xdstring.h" +#include "pchndlr.h" + +using XDPrintSchema::PRINTCAPABILITIES_NAME; +using XDPrintSchema::PARAM_DEF_ELEMENT_NAME; +using XDPrintSchema::NAME_ATTRIBUTE_NAME; +using XDPrintSchema::SCHEMA_CONDITIONAL; +using XDPrintSchema::SCHEMA_INTEGER; +using XDPrintSchema::DATATYPE_VALUE_NAME; +using XDPrintSchema::SCHEMA_QNAME; +using XDPrintSchema::DEFAULTVAL_VALUE_NAME; +using XDPrintSchema::SCHEMA_STRING; +using XDPrintSchema::MAX_VALUE_NAME; +using XDPrintSchema::MIN_VALUE_NAME; +using XDPrintSchema::MAX_LENGTH_NAME; +using XDPrintSchema::MIN_LENGTH_NAME; +using XDPrintSchema::MANDATORY_VALUE_NAME; +using XDPrintSchema::UNITTYPE_VALUE_NAME; +using XDPrintSchema::MULTIPLE_VALUE_NAME; +using XDPrintSchema::DISPLAYNAME_VALUE_NAME; +using XDPrintSchema::SCHEMA_DECIMAL; +using XDPrintSchema::FEATURE_ELEMENT_NAME; +using XDPrintSchema::PICKONE_VALUE_NAME; +using XDPrintSchema::SELECTIONTYPE_VALUE_NAME; +using XDPrintSchema::OPTION_ELEMENT_NAME; +using XDPrintSchema::PARAM_REF_ELEMENT_NAME; +using XDPrintSchema::FRAMEWORK_URI; +using XDPrintSchema::KEYWORDS_URI; + +/*++ + +Routine Name: + + CPCHandler::CPCHandler + +Routine Description: + + CPCHandler class constructor + +Arguments: + + pPrintCapabilities - Pointer to the DOM document representation of the PrintCapabilities + +Return Value: + + None + + Note: Base Class (CPSHandler) - Throws CXDException(HRESULT) on an error + +--*/ +CPCHandler::CPCHandler( + _In_ IXMLDOMDocument2 *pDOMDocument + ) : + CPSHandler(CComBSTR(PRINTCAPABILITIES_NAME), pDOMDocument) +{ +} + +/*++ + +Routine Name: + + CPCHandler::~CPCHandler + +Routine Description: + + CPCHandler class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CPCHandler::~CPCHandler() +{ +} + + +/*++ + +Routine Name: + + CPCHandler::CreateStringParameterDef + +Routine Description: + + Creates a String type ParameterDef Element. + +Arguments: + + bstrParamName - Keyword value name for the parameter + bstrDisplayName - Optional string containing a description of the parameter definition. + defaultValue - Default value of the parameter. + minLength - Minimium valid value. + maxLength - Maximium valid value. + multiple - value can be increased or decreased in multiples of. + bstrUnitType - String containing a description of the unit type of the parameter value. + ppParameterDef - Pointer to an IXMLDOMElement that recieves the new element. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPCHandler::CreateStringParameterDef( + _In_z_ CONST BSTR bstrParamName, + _In_ CONST BOOL bIsPublicKeyword, + _In_opt_z_ CONST BSTR bstrDisplayName, + _In_ CONST BSTR defaultValue, + _In_ CONST INT minLength, + _In_ CONST INT maxLength, + _In_z_ CONST BSTR bstrUnitType, + _Outptr_ IXMLDOMElement** ppParameterDef + ) +{ + HRESULT hr = S_OK; + + // + // Create the parameterDef + // + CComBSTR bstrParameter(m_bstrFrameworkPrefix); + bstrParameter += PARAM_DEF_ELEMENT_NAME; + + // + // PageWatermarkSizeWidth and PageWatermarkSizeHeight are non-standard + // parameter names so need to be accessed using a user defined namespace + // + CComBSTR bstrParameterAttrib; + if (bIsPublicKeyword) + { + hr = bstrParameterAttrib.Append(m_bstrKeywordsPrefix); + } + else + { + hr = bstrParameterAttrib.Append(m_bstrUserKeywordsPrefix); + } + + if (SUCCEEDED(hr)) + { + bstrParameterAttrib += bstrParamName; + } + + if(SUCCEEDED(hr)) + { + hr = CreateXMLElement(bstrParameter, FRAMEWORK_URI, ppParameterDef); + } + + if(SUCCEEDED(hr)) + { + if(SUCCEEDED(hr = CreateXMLAttribute(*ppParameterDef, NAME_ATTRIBUTE_NAME, NULL, bstrParameterAttrib ))) + { + CComPtr pDataTypeProp(NULL); + CComPtr pDefValProp(NULL); + CComPtr pMaxLengthProp(NULL); + CComPtr pMinLengthProp(NULL); + CComPtr pMandatoryProp(NULL); + CComPtr pUnitTypeProp(NULL); + + CComBSTR bstrMandatory(m_bstrKeywordsPrefix); + bstrMandatory += SCHEMA_CONDITIONAL; + + CStringXDW cstrMaxLength; + cstrMaxLength.Format(L"%i", maxLength); + + CStringXDW cstrMinLength; + cstrMinLength.Format(L"%i", minLength); + + CComBSTR bstrStringType(m_bstrSchemaPrefix); + bstrStringType += SCHEMA_STRING; + + if (SUCCEEDED(hr = CreateProperty(CComBSTR(DATATYPE_VALUE_NAME), CComBSTR(SCHEMA_QNAME), bstrStringType, &pDataTypeProp)) && + SUCCEEDED(hr = CreateProperty(CComBSTR(DEFAULTVAL_VALUE_NAME), CComBSTR(SCHEMA_STRING), defaultValue, &pDefValProp)) && + SUCCEEDED(hr = CreateProperty(CComBSTR(MAX_LENGTH_NAME), CComBSTR(SCHEMA_INTEGER), CComBSTR(cstrMaxLength), &pMaxLengthProp)) && + SUCCEEDED(hr = CreateProperty(CComBSTR(MIN_LENGTH_NAME), CComBSTR(SCHEMA_INTEGER), CComBSTR(cstrMinLength), &pMinLengthProp)) && + SUCCEEDED(hr = CreateProperty(CComBSTR(MANDATORY_VALUE_NAME), CComBSTR(SCHEMA_QNAME), bstrMandatory, &pMandatoryProp)) && + SUCCEEDED(hr = CreateProperty(CComBSTR(UNITTYPE_VALUE_NAME), CComBSTR(SCHEMA_STRING), bstrUnitType, &pUnitTypeProp)) && + SUCCEEDED(hr = (*ppParameterDef)->appendChild(pDataTypeProp, NULL)) && + SUCCEEDED(hr = (*ppParameterDef)->appendChild(pDefValProp, NULL)) && + SUCCEEDED(hr = (*ppParameterDef)->appendChild(pMaxLengthProp, NULL)) && + SUCCEEDED(hr = (*ppParameterDef)->appendChild(pMinLengthProp, NULL)) && + SUCCEEDED(hr = (*ppParameterDef)->appendChild(pMandatoryProp, NULL)) && + SUCCEEDED(hr = (*ppParameterDef)->appendChild(pUnitTypeProp, NULL))) + { + if (SUCCEEDED(hr) && + SysStringLen(bstrDisplayName) > 0) + { + CComPtr pDisplayProp(NULL); + + if (SUCCEEDED(hr = CreateProperty(CComBSTR(DISPLAYNAME_VALUE_NAME), CComBSTR(SCHEMA_STRING), bstrDisplayName, &pDisplayProp))) + { + hr = (*ppParameterDef)->appendChild(pDisplayProp, NULL); + } + } + } + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CPCHandler::CreateIntParameterDef + +Routine Description: + + Creates a Integer type ParameterDef Element. + +Arguments: + + bstrParamName - Keyword value name for the parameter + bstrDisplayName - Optional string containing a description of the parameter definition. + defaultValue - Default value of the parameter. + minValue - Minimium valid value. + maxLength - Maximium valid value. + multiple - value can be increased or decreased in multiples of. + bstrUnitType - String containing a description of the unit type of the parameter value. + ppParameterDef - Pointer to an IXMLDOMElement that recieves the new element. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPCHandler::CreateIntParameterDef( + _In_z_ CONST BSTR bstrParamName, + _In_ CONST BOOL bIsPublicKeyword, + _In_opt_z_ CONST BSTR bstrDisplayName, + _In_ CONST INT defaultValue, + _In_ CONST INT minValue, + _In_ CONST INT maxValue, + _In_ CONST INT multiple, + _In_z_ CONST BSTR bstrUnitType, + _Outptr_ IXMLDOMElement** ppParameterDef + ) +{ + HRESULT hr = S_OK; + + // + // Create the parameterDef + // + CComBSTR bstrParameter(m_bstrFrameworkPrefix); + bstrParameter += PARAM_DEF_ELEMENT_NAME; + + CComBSTR bstrParameterAttrib; + if (bIsPublicKeyword) + { + hr = bstrParameterAttrib.Append(m_bstrKeywordsPrefix); + } + else + { + hr = bstrParameterAttrib.Append(m_bstrUserKeywordsPrefix); + } + + if (SUCCEEDED(hr)) + { + bstrParameterAttrib += bstrParamName; + } + + if(SUCCEEDED(hr)) + { + hr = CreateXMLElement(bstrParameter, FRAMEWORK_URI, ppParameterDef); + } + + if(SUCCEEDED(hr)) + { + if(SUCCEEDED(hr = CreateXMLAttribute(*ppParameterDef, NAME_ATTRIBUTE_NAME, NULL, bstrParameterAttrib ))) + { + CComPtr pDataTypeProp(NULL); + CComPtr pDefValProp(NULL); + CComPtr pMaxValueProp(NULL); + CComPtr pMinValueProp(NULL); + CComPtr pMandatoryProp(NULL); + CComPtr pUnitTypeProp(NULL); + CComPtr pMultipleProp(NULL); + + CStringXDW cstrMultiple; + cstrMultiple.Format(L"%i", multiple); + + CComBSTR bstrMandatory(m_bstrKeywordsPrefix); + bstrMandatory += SCHEMA_CONDITIONAL; + + CStringXDW cstrDefaultValue; + cstrDefaultValue.Format(L"%i", defaultValue); + + CStringXDW cstrMaxValue; + cstrMaxValue.Format(L"%i", maxValue); + + CStringXDW cstrMinValue; + cstrMinValue.Format(L"%i", minValue); + + CComBSTR bstrIntegerType(m_bstrSchemaPrefix); + bstrIntegerType += SCHEMA_INTEGER; + + if (SUCCEEDED(hr = CreateProperty(CComBSTR(DATATYPE_VALUE_NAME), CComBSTR(SCHEMA_QNAME), bstrIntegerType, &pDataTypeProp)) && + SUCCEEDED(hr = CreateProperty(CComBSTR(DEFAULTVAL_VALUE_NAME), CComBSTR(SCHEMA_INTEGER), CComBSTR(cstrDefaultValue), &pDefValProp)) && + SUCCEEDED(hr = CreateProperty(CComBSTR(MAX_VALUE_NAME), CComBSTR(SCHEMA_INTEGER), CComBSTR(cstrMaxValue), &pMaxValueProp)) && + SUCCEEDED(hr = CreateProperty(CComBSTR(MIN_VALUE_NAME), CComBSTR(SCHEMA_INTEGER), CComBSTR(cstrMinValue), &pMinValueProp)) && + SUCCEEDED(hr = CreateProperty(CComBSTR(MANDATORY_VALUE_NAME), CComBSTR(SCHEMA_QNAME), bstrMandatory, &pMandatoryProp)) && + SUCCEEDED(hr = CreateProperty(CComBSTR(UNITTYPE_VALUE_NAME), CComBSTR(SCHEMA_STRING), bstrUnitType, &pUnitTypeProp)) && + SUCCEEDED(hr = CreateProperty(CComBSTR(MULTIPLE_VALUE_NAME), CComBSTR(SCHEMA_INTEGER), CComBSTR(cstrMultiple), &pMultipleProp)) && + SUCCEEDED(hr = (*ppParameterDef)->appendChild(pDataTypeProp, NULL)) && + SUCCEEDED(hr = (*ppParameterDef)->appendChild(pDefValProp, NULL)) && + SUCCEEDED(hr = (*ppParameterDef)->appendChild(pMaxValueProp, NULL)) && + SUCCEEDED(hr = (*ppParameterDef)->appendChild(pMinValueProp, NULL)) && + SUCCEEDED(hr = (*ppParameterDef)->appendChild(pMandatoryProp, NULL)) && + SUCCEEDED(hr = (*ppParameterDef)->appendChild(pUnitTypeProp, NULL)) && + SUCCEEDED(hr = (*ppParameterDef)->appendChild(pMultipleProp, NULL))) + { + if (SysStringLen(bstrDisplayName) > 0) + { + CComPtr pDisplayProp(NULL); + + if (SUCCEEDED(hr = CreateProperty(CComBSTR(DISPLAYNAME_VALUE_NAME), CComBSTR(SCHEMA_STRING), bstrDisplayName, &pDisplayProp))) + { + hr = (*ppParameterDef)->appendChild(pDisplayProp, NULL); + } + } + } + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CPCHandler::CreateFeature + +Routine Description: + + Creates a Feature Element. + +Arguments: + + bstrFeatureName - Keyword value name for the feature. + bstrDisplayName - Optional string containing a description of the feature. + ppFeatureElement - Pointer to an IXMLDOMElement that recieves the new element. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPCHandler::CreateFeature( + _In_z_ CONST BSTR bstrFeatureName, + _In_opt_z_ CONST BSTR bstrDisplayName, + _Outptr_ IXMLDOMElement** ppFeatureElement + ) +{ + HRESULT hr = S_OK; + + // + // Create the base feature node + // + CComBSTR bstrFeature(m_bstrFrameworkPrefix); + bstrFeature += FEATURE_ELEMENT_NAME; + + CComBSTR bstrFeatureAttrib(m_bstrKeywordsPrefix); + bstrFeatureAttrib += bstrFeatureName; + + if(SUCCEEDED(hr)) + { + hr = CreateXMLElement(bstrFeature, FRAMEWORK_URI, ppFeatureElement); + } + + if (SUCCEEDED(hr)) + { + hr = CreateXMLAttribute(*ppFeatureElement, NAME_ATTRIBUTE_NAME, NULL, bstrFeatureAttrib ); + } + + // + // Append the Display Name property type + // + if (SUCCEEDED(hr) && + SysStringLen(bstrDisplayName) > 0) + { + CComPtr pDisplayProp(NULL); + + if (SUCCEEDED(hr = CreateProperty(CComBSTR(DISPLAYNAME_VALUE_NAME), CComBSTR(SCHEMA_STRING), bstrDisplayName, &pDisplayProp))) + { + hr = (*ppFeatureElement)->appendChild(pDisplayProp, NULL); + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CPCHandler::CreateFeatureSelection + +Routine Description: + + Creates a Selection Feature Element. + +Arguments: + + bstrFeatureName - Keyword value name for the feature. + bstrDisplayName - Optional string containing a description of the feature. + ppFeatureElement - Pointer to an IXMLDOMElement that recieves the new element. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPCHandler::CreateFeatureSelection( + _In_z_ CONST BSTR bstrFeatureName, + _In_opt_z_ CONST BSTR bstrDisplayName, + _Outptr_ IXMLDOMElement** ppFeatureElement + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CreateFeature(bstrFeatureName, bstrDisplayName, ppFeatureElement))) + { + // + // Append the property type + // + CComPtr pPropertyTypeElement(NULL); + + // + // Create the keyname + // + CComBSTR bstrPickOne(m_bstrKeywordsPrefix); + bstrPickOne += PICKONE_VALUE_NAME; + + if (SUCCEEDED(hr = CreateFWProperty(CComBSTR(SELECTIONTYPE_VALUE_NAME), CComBSTR(SCHEMA_QNAME), bstrPickOne, &pPropertyTypeElement))) + { + hr = (*ppFeatureElement)->appendChild(pPropertyTypeElement, NULL); + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CPCHandler::CreateOption + +Routine Description: + + Creates an Option Type Element. + +Arguments: + + bstrOptionName - Keyword value name for the option. + bstrDisplayName - Optional string containing a description of the feature. + ppOptionElement - Pointer to an IXMLDOMElement that recieves the new element. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPCHandler::CreateOption( + _In_z_ CONST BSTR bstrOptionName, + _In_opt_z_ CONST BSTR bstrDisplayName, + _Outptr_ IXMLDOMElement** ppOptionElement + ) +{ + HRESULT hr = S_OK; + + // + // Create the base feature node + // + CComBSTR bstrOption(m_bstrFrameworkPrefix); + bstrOption += OPTION_ELEMENT_NAME; + + CComBSTR bstrOptionAttrib(m_bstrKeywordsPrefix); + bstrOptionAttrib += bstrOptionName; + + if(SUCCEEDED(hr)) + { + hr = CreateXMLElement(bstrOption, FRAMEWORK_URI, ppOptionElement); + } + + if (SUCCEEDED(hr)) + { + hr = CreateXMLAttribute(*ppOptionElement, NAME_ATTRIBUTE_NAME, NULL, bstrOptionAttrib ); + } + + // + // Append the Display Name property type + // + if (SUCCEEDED(hr) && + SysStringLen(bstrDisplayName) > 0) + { + CComPtr pDisplayProp(NULL); + + if (SUCCEEDED(hr = CreateProperty(CComBSTR(DISPLAYNAME_VALUE_NAME), CComBSTR(SCHEMA_STRING), bstrDisplayName, &pDisplayProp))) + { + hr = (*ppOptionElement)->appendChild(pDisplayProp, NULL); + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CPCHandler::CreateParameterRef + +Routine Description: + + Creates a Reference to a ParameterDef Element. + +Arguments: + + bstrParamRefName - Keyword value name for the parameter reference. + ppParamRefElement - Pointer to an IXMLDOMElement that recieves the new element. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPCHandler::CreateParameterRef( + _In_z_ CONST BSTR bstrParamRefName, + _Outptr_ IXMLDOMElement** ppParamRefElement + ) +{ + HRESULT hr = S_OK; + + // + // Create the base feature node + // + CComBSTR bstrParameterRef(m_bstrFrameworkPrefix); + bstrParameterRef += PARAM_REF_ELEMENT_NAME; + + + // + // PageWatermarkSizeWidth and PageWatermarkSizeHeight are non-standard + // parameter names so need to be accessed using a user defined namespace + // + CComBSTR bstrParamRefAttrib; + if (wcscmp(bstrParamRefName, L"PageWatermarkSizeWidth") == 0 || + wcscmp(bstrParamRefName, L"PageWatermarkSizeHeight") == 0) + { + hr = bstrParamRefAttrib.Append(m_bstrUserKeywordsPrefix); + } + else + { + hr = bstrParamRefAttrib.Append(m_bstrKeywordsPrefix); + } + + if (SUCCEEDED(hr)) + { + bstrParamRefAttrib += bstrParamRefName; + } + + // + //Create the IXMLDOMNode for ParameterRef + // + CComPtr pParameterRefNode(NULL); + + if(SUCCEEDED(hr)) + { + hr = CreateXMLElement(bstrParameterRef, FRAMEWORK_URI, ppParamRefElement); + } + + if (SUCCEEDED(hr)) + { + hr = CreateXMLAttribute(*ppParamRefElement, NAME_ATTRIBUTE_NAME, NULL, bstrParamRefAttrib ); + } + + ERR_ON_HR(hr); + return hr; +} + diff --git a/print/XPSDrvSmpl/src/common/pchndlr.h b/print/XPSDrvSmpl/src/common/pchndlr.h new file mode 100644 index 00000000..df958354 --- /dev/null +++ b/print/XPSDrvSmpl/src/common/pchndlr.h @@ -0,0 +1,91 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +File Name: + + pchndlr.h + +Abstract: + + Base PrintCapabilities handler class definition. This class provides common + PrintCapabilities handling functionality for any feature that requires + PrintCapabilities handling. A feature specific handler can inherit from + this class to get feature unspecific XML handling functionality. + +--*/ + +#pragma once + +#include "schema.h" +#include "pshndlr.h" + +class CPCHandler : public CPSHandler +{ +public: + // + // Constructors and destructors + // + CPCHandler( + _In_ IXMLDOMDocument2 *pPrintCapabilities + ); + + virtual ~CPCHandler(); + +protected: + + HRESULT + CreateStringParameterDef( + _In_z_ CONST BSTR bstrParamName, + _In_ CONST BOOL bIsPublicKeyword, + _In_opt_z_ CONST BSTR bstrDisplayName, + _In_ CONST BSTR bstrDefaultValue, + _In_ CONST INT minLength, + _In_ CONST INT maxLength, + _In_z_ CONST BSTR bstrUnitType, + _Outptr_ IXMLDOMElement** ppParameterDef + ); + + HRESULT + CreateIntParameterDef( + _In_z_ CONST BSTR bstrParamName, + _In_ CONST BOOL bIsPublicKeyword, + _In_opt_z_ CONST BSTR bstrDisplayName, + _In_ CONST INT defaultValue, + _In_ CONST INT minValue, + _In_ CONST INT maxValue, + _In_ CONST INT multiple, + _In_z_ CONST BSTR bstrUnitType, + _Outptr_ IXMLDOMElement** ppParameterDef + ); + + HRESULT + CreateFeature( + _In_z_ CONST BSTR bstrFeatureName, + _In_opt_z_ CONST BSTR bstrDisplayName, + _Outptr_ IXMLDOMElement** ppFeatureElement + ); + + HRESULT + CreateOption( + _In_z_ CONST BSTR bstrOptionName, + _In_opt_z_ CONST BSTR bstrDisplayName, + _Outptr_ IXMLDOMElement** ppOptionElement + ); + + HRESULT + CreateFeatureSelection( + _In_z_ CONST BSTR bstrFeatureName, + _In_opt_z_ CONST BSTR bstrDisplayName, + _Outptr_ IXMLDOMElement** ppFeatureElement + ); + + HRESULT + CreateParameterRef( + _In_z_ CONST BSTR bstrParamRefName, + _Outptr_ IXMLDOMElement** ppParamRefElement + ); +}; + diff --git a/print/XPSDrvSmpl/src/common/pgscdata.h b/print/XPSDrvSmpl/src/common/pgscdata.h new file mode 100644 index 00000000..7a06ce24 --- /dev/null +++ b/print/XPSDrvSmpl/src/common/pgscdata.h @@ -0,0 +1,52 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + pgscdata.h + +Abstract: + + PageScaling data structure definition. This provides a convenient + description of the PrintSchema PageScaling feature. + +--*/ + +#pragma once + +#include "pgscschema.h" + +namespace XDPrintSchema +{ + namespace PageScaling + { + struct PageScalingData + { + PageScalingData() : + pgscOption(None), + offWidth(0), + offHeight(0), + scaleWidth(100), + scaleHeight(100), + offsetOption(OffsetAlignment::Center) + { + } + + EScaleOption pgscOption; + INT offWidth; + INT offHeight; + INT scaleWidth; + INT scaleHeight; + OffsetAlignment::EScaleOffsetOption offsetOption; + }; + } +} + diff --git a/print/XPSDrvSmpl/src/common/pgscpchndlr.cpp b/print/XPSDrvSmpl/src/common/pgscpchndlr.cpp new file mode 100644 index 00000000..12883a69 --- /dev/null +++ b/print/XPSDrvSmpl/src/common/pgscpchndlr.cpp @@ -0,0 +1,349 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + pgscpchndlr.cpp + +Abstract: + + Pagescale PrintCapabilities handling implementation. The pagescale PC handler + is used to set page scaling settings in a PrintCapabilities. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdexcept.h" +#include "pgscpchndlr.h" +#include "privatedefs.h" + +using XDPrintSchema::PRINTCAPABILITIES_NAME; + +using XDPrintSchema::PageScaling::EScaleOption; +using XDPrintSchema::PageScaling::FitBleedToImageable; +using XDPrintSchema::PageScaling::FitMediaToMedia; +using XDPrintSchema::PageScaling::Custom; +using XDPrintSchema::PageScaling::CustomSquare; +using XDPrintSchema::PageScaling::ECustomScaleProps; +using XDPrintSchema::PageScaling::ECustomScalePropsMin; +using XDPrintSchema::PageScaling::ECustomScalePropsMax; +using XDPrintSchema::PageScaling::ECustomSquareScaleProps; +using XDPrintSchema::PageScaling::ECustomSquareScalePropsMin; +using XDPrintSchema::PageScaling::ECustomSquareScalePropsMax; +using XDPrintSchema::PageScaling::SCALE_FEATURE; +using XDPrintSchema::PageScaling::SCALE_OPTIONS; +using XDPrintSchema::PageScaling::CUST_SCALE_PROPS; +using XDPrintSchema::PageScaling::CUST_SQR_SCALE_PROPS; + +using XDPrintSchema::PageScaling::OffsetAlignment::EScaleOffsetOption; +using XDPrintSchema::PageScaling::OffsetAlignment::EScaleOffsetOptionMin; +using XDPrintSchema::PageScaling::OffsetAlignment::EScaleOffsetOptionMax; +using XDPrintSchema::PageScaling::OffsetAlignment::SCALE_OFFSET_FEATURE; +using XDPrintSchema::PageScaling::OffsetAlignment::SCALE_OFFSET_OPTIONS; + +/*++ + +Routine Name: + + CPageScalingPCHandler::CPageScalingPCHandler + +Routine Description: + + CPageScalingPCHandler class constructor + +Arguments: + + pPrintCapabilities - Pointer to the DOM document representation of the PrintCapabilities + +Return Value: + + None + +--*/ +CPageScalingPCHandler::CPageScalingPCHandler( + _In_ IXMLDOMDocument2* pPrintCapabilities + ) : + CPCHandler(pPrintCapabilities) +{ +} + +/*++ + +Routine Name: + + CPageScalingPCHandler::~CPageScalingPCHandler + +Routine Description: + + CPageScalingPCHandler class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CPageScalingPCHandler::~CPageScalingPCHandler() +{ +} + +/*++ + +Routine Name: + + CPageScalingPCHandler::SetCapabilities + +Routine Description: + + This routine sets page scaling capabilities in the PrintCapabilities passed to the + class constructor. + +Arguments: + + None + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPageScalingPCHandler::SetCapabilities( + VOID + ) +{ + HRESULT hr = S_OK; + + try + { + // + // Retrieve the PrintTicket root + // + CComPtr pPTRoot(NULL); + + CComBSTR bstrPTQuery(m_bstrFrameworkPrefix); + bstrPTQuery += PRINTCAPABILITIES_NAME; + + if (SUCCEEDED(hr = GetNode(bstrPTQuery, &pPTRoot))) + { + CComPtr pFeatureElement(NULL); + + if (SUCCEEDED(hr = CreateFeatureSelection(CComBSTR(SCALE_FEATURE), NULL, &pFeatureElement))) + { + CComPtr pCustomOption(NULL); + + // + // Create the Custom Options + // + if (SUCCEEDED(hr = CreateOption(CComBSTR(SCALE_OPTIONS[Custom]), NULL, &pCustomOption))) + { + PTDOMElementVector propertList; + + for (ECustomScaleProps customProps = ECustomScalePropsMin; + customProps < ECustomScalePropsMax && SUCCEEDED(hr); + customProps = static_cast(customProps + 1)) + { + CComPtr pScoredProperty(NULL); + + // + // Create the scored property list + // + if (SUCCEEDED(hr = CreateScoredProperty(CComBSTR(CUST_SCALE_PROPS[customProps]), &pScoredProperty))) + { + CComPtr pParamRef(NULL); + + // + // Construct the parameter reference elements + // + CComBSTR bstrPRefName(SCALE_FEATURE); + bstrPRefName += CUST_SCALE_PROPS[customProps]; + + if (SUCCEEDED(hr = CreateParameterRef(bstrPRefName, &pParamRef))) + { + hr = pScoredProperty->appendChild(pParamRef, NULL); + } + + propertList.push_back(pScoredProperty); + } + } + + // + // Add the properties to the custom option + // + PTDOMElementVector::iterator iterPropertList = propertList.begin(); + + for (;iterPropertList != propertList.end() && SUCCEEDED(hr); iterPropertList++) + { + hr = pCustomOption->appendChild(*iterPropertList, NULL); + } + + if (SUCCEEDED(hr)) + { + hr = pFeatureElement->appendChild(pCustomOption, NULL); + } + } + + CComPtr pCustomSquareOption(NULL); + + // + // Create the Custom Square + // + if (SUCCEEDED(hr) && + SUCCEEDED(hr = CreateOption(CComBSTR(SCALE_OPTIONS[CustomSquare]), NULL, &pCustomSquareOption))) + { + PTDOMElementVector propertList; + + for (ECustomSquareScaleProps customSquareProps = ECustomSquareScalePropsMin; + customSquareProps < ECustomSquareScalePropsMax && SUCCEEDED(hr); + customSquareProps = static_cast(customSquareProps + 1)) + { + CComPtr pScoredProperty(NULL); + + // + // Create the scored property list + // + if (SUCCEEDED(hr = CreateScoredProperty(CComBSTR(CUST_SQR_SCALE_PROPS[customSquareProps]), &pScoredProperty))) + { + CComPtr pParamRef(NULL); + + // + // Construct the parameter reference elements + // + CComBSTR bstrPRefName(SCALE_FEATURE); + bstrPRefName += CUST_SQR_SCALE_PROPS[customSquareProps]; + + if (SUCCEEDED(hr = CreateParameterRef(bstrPRefName, &pParamRef))) + { + hr = pScoredProperty->appendChild(pParamRef, NULL); + } + + propertList.push_back(pScoredProperty); + } + } + + // + // Add the properties to the custom square option + // + PTDOMElementVector::iterator iterPropertList = propertList.begin(); + + for (;iterPropertList != propertList.end() && SUCCEEDED(hr); iterPropertList++) + { + hr = pCustomSquareOption->appendChild(*iterPropertList, NULL); + } + + if (SUCCEEDED(hr)) + { + hr = pFeatureElement->appendChild(pCustomSquareOption, NULL); + } + } + + // + // Create the remaining scaling options: Fit To ... + // + for (EScaleOption fitToOptions = FitBleedToImageable; + fitToOptions <= FitMediaToMedia && SUCCEEDED(hr); + fitToOptions = static_cast(fitToOptions + 1)) + { + CComPtr pFitToOption(NULL); + + // + // Create the fit to page option + // + if (SUCCEEDED(hr = CreateOption(CComBSTR(SCALE_OPTIONS[fitToOptions]), NULL, &pFitToOption))) + { + hr = pFeatureElement->appendChild(pFitToOption, NULL); + } + } + + // + // Create the offset options + // + if (SUCCEEDED(hr)) + { + CComPtr pOffsetFeature(NULL); + if (SUCCEEDED(hr = CreateFeature(CComBSTR(SCALE_OFFSET_FEATURE), + NULL, + &pOffsetFeature))) + { + PTDOMElementVector optionList; + + for (EScaleOffsetOption offsetOption = EScaleOffsetOptionMin; + offsetOption < EScaleOffsetOptionMax && SUCCEEDED(hr); + offsetOption = static_cast(offsetOption + 1)) + { + CComPtr pOptionProperty(NULL); + + if (SUCCEEDED(hr = CreateOption(CComBSTR(SCALE_OFFSET_OPTIONS[offsetOption]), NULL, &pOptionProperty))) + { + optionList.push_back(pOptionProperty); + } + } + + // + // Add the options to the offset feature + // + PTDOMElementVector::iterator iterOptionList = optionList.begin(); + + for (;iterOptionList != optionList.end() && SUCCEEDED(hr); iterOptionList++) + { + hr = pOffsetFeature->appendChild(*iterOptionList, NULL); + } + } + + if (SUCCEEDED(hr)) + { + hr = pFeatureElement->appendChild(pOffsetFeature, NULL); + } + } + + if (SUCCEEDED(hr)) + { + hr = pPTRoot->appendChild(pFeatureElement, NULL); + } + } + + for (UINT cIndex = 0; cIndex < numof(pgscParamDefIntegers); cIndex++) + { + CComPtr pParameterDef(NULL); + + if (SUCCEEDED(hr = CreateIntParameterDef(CComBSTR(pgscParamDefIntegers[cIndex].property_name), // Paramater Name + pgscParamDefIntegers[cIndex].is_public, // Is Print Schema Keyword? + CComBSTR(pgscParamDefIntegers[cIndex].display_name), // Display Text + pgscParamDefIntegers[cIndex].default_value, // Default + pgscParamDefIntegers[cIndex].min_length, // Min Length + pgscParamDefIntegers[cIndex].max_length, // Max Length + pgscParamDefIntegers[cIndex].multiple, // Multiple + CComBSTR(pgscParamDefIntegers[cIndex].unit_type), // Unit Type + &pParameterDef))) // Parameter Def + { + hr = pPTRoot->appendChild(pParameterDef, NULL); + } + } + } + } + catch (exception& DBG_ONLY(e)) + { + ERR(e.what()); + hr = E_FAIL; + } + + ERR_ON_HR(hr); + return hr; +} + + diff --git a/print/XPSDrvSmpl/src/common/pgscpchndlr.h b/print/XPSDrvSmpl/src/common/pgscpchndlr.h new file mode 100644 index 00000000..3d30583f --- /dev/null +++ b/print/XPSDrvSmpl/src/common/pgscpchndlr.h @@ -0,0 +1,41 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + pgscpchndlr.h + +Abstract: + + Page Scaling PrintCapabilities handling definition. The page scaling PC handler + is used to set page scaling settings in a PrintCapabilities. + +--*/ + +#pragma once + +#include "pchndlr.h" +#include "pgscdata.h" + +class CPageScalingPCHandler : public CPCHandler +{ +public: + CPageScalingPCHandler( + _In_ IXMLDOMDocument2* pPrintCapabilities + ); + + virtual ~CPageScalingPCHandler(); + + HRESULT + SetCapabilities( + VOID + ); +}; diff --git a/print/XPSDrvSmpl/src/common/pgscpthndlr.cpp b/print/XPSDrvSmpl/src/common/pgscpthndlr.cpp new file mode 100644 index 00000000..beffe034 --- /dev/null +++ b/print/XPSDrvSmpl/src/common/pgscpthndlr.cpp @@ -0,0 +1,479 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + pgscpthndlr.cpp + +Abstract: + + PageScaling PrintTicket handler implementation. Derived from CPTHandler, + this provides PageScaling specific Get and Set methods acting on the + PrintTicket (as a DOM document) passed. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdexcept.h" +#include "pgscpthndlr.h" + +using XDPrintSchema::PRINTTICKET_NAME; +using XDPrintSchema::NAME_ATTRIBUTE_NAME; + +using XDPrintSchema::PageScaling::PageScalingData; +using XDPrintSchema::PageScaling::EScaleOption; +using XDPrintSchema::PageScaling::EScaleOptionMin; +using XDPrintSchema::PageScaling::Custom; +using XDPrintSchema::PageScaling::CustomSquare; +using XDPrintSchema::PageScaling::FitBleedToImageable; +using XDPrintSchema::PageScaling::FitContentToImageable; +using XDPrintSchema::PageScaling::FitMediaToImageable; +using XDPrintSchema::PageScaling::FitMediaToMedia; +using XDPrintSchema::PageScaling::None; +using XDPrintSchema::PageScaling::EScaleOptionMax; +using XDPrintSchema::PageScaling::ECustomScaleProps; +using XDPrintSchema::PageScaling::ECustomScalePropsMin; +using XDPrintSchema::PageScaling::CstOffsetWidth; +using XDPrintSchema::PageScaling::CstOffsetHeight; +using XDPrintSchema::PageScaling::CstScaleWidth; +using XDPrintSchema::PageScaling::CstScaleHeight; +using XDPrintSchema::PageScaling::ECustomScalePropsMax; +using XDPrintSchema::PageScaling::ECustomSquareScaleProps; +using XDPrintSchema::PageScaling::ECustomSquareScalePropsMin; +using XDPrintSchema::PageScaling::CstSqOffsetWidth; +using XDPrintSchema::PageScaling::CstSqOffsetHeight; +using XDPrintSchema::PageScaling::CstSqScale; +using XDPrintSchema::PageScaling::ECustomSquareScalePropsMax; +using XDPrintSchema::PageScaling::SCALE_FEATURE; +using XDPrintSchema::PageScaling::SCALE_OPTIONS; +using XDPrintSchema::PageScaling::CUST_SCALE_PROPS; +using XDPrintSchema::PageScaling::CUST_SQR_SCALE_PROPS; + +using XDPrintSchema::PageScaling::OffsetAlignment::EScaleOffsetOption; +using XDPrintSchema::PageScaling::OffsetAlignment::EScaleOffsetOptionMin; +using XDPrintSchema::PageScaling::OffsetAlignment::EScaleOffsetOptionMax; +using XDPrintSchema::PageScaling::OffsetAlignment::SCALE_OFFSET_FEATURE; +using XDPrintSchema::PageScaling::OffsetAlignment::SCALE_OFFSET_OPTIONS; + +/*++ + +Routine Name: + + CPageScalingPTHandler::CPageScalingPTHandler + +Routine Description: + + CPageScalingPTHandler class constructor + +Arguments: + + pPrintTicket - Pointer to the DOM document representation of the PrintTicket + +Return Value: + + None + +--*/ +CPageScalingPTHandler::CPageScalingPTHandler( + _In_ IXMLDOMDocument2* pPrintTicket + ) : + CPTHandler(pPrintTicket) +{ +} + +/*++ + +Routine Name: + + CPageScalingPTHandler::~CPageScalingPTHandler + +Routine Description: + + CPageScalingPTHandler class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CPageScalingPTHandler::~CPageScalingPTHandler() +{ +} + +/*++ + +Routine Name: + + CPageScalingPTHandler::GetData + +Routine Description: + + The routine fills the data structure passed in with page scaling data + retrieved from the PrintTicket passed to the class constructor. + +Arguments: + + pPageScaleData - Pointer to the page scaling data structure to be filled in + +Return Value: + + HRESULT + S_OK - On success + E_ELEMENT_NOT_FOUND - Feature not present in PrintTicket + E_* - On error + +--*/ +HRESULT +CPageScalingPTHandler::GetData( + _Out_ PageScalingData* pPageScaleData + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pPageScaleData, E_POINTER))) + { + CComBSTR bstrPgScOption; + + if (SUCCEEDED(hr = GetFeatureOption(CComBSTR(SCALE_FEATURE), &bstrPgScOption))) + { + if (bstrPgScOption == SCALE_OPTIONS[Custom]) + { + pPageScaleData->pgscOption = Custom; + + if (SUCCEEDED(hr = GetScoredPropertyValue(CComBSTR(SCALE_FEATURE), + CComBSTR(CUST_SCALE_PROPS[CstOffsetWidth]), + &pPageScaleData->offWidth)) && + SUCCEEDED(hr = GetScoredPropertyValue(CComBSTR(SCALE_FEATURE), + CComBSTR(CUST_SCALE_PROPS[CstOffsetHeight]), + &pPageScaleData->offHeight)) && + SUCCEEDED(hr = GetScoredPropertyValue(CComBSTR(SCALE_FEATURE), + CComBSTR(CUST_SCALE_PROPS[CstScaleWidth]), + &pPageScaleData->scaleWidth))) + { + hr = GetScoredPropertyValue(CComBSTR(SCALE_FEATURE), + CComBSTR(CUST_SCALE_PROPS[CstScaleHeight]), + &pPageScaleData->scaleHeight); + } + } + else if (bstrPgScOption == SCALE_OPTIONS[CustomSquare]) + { + pPageScaleData->pgscOption = CustomSquare; + + if (SUCCEEDED(hr = GetScoredPropertyValue(CComBSTR(SCALE_FEATURE), + CComBSTR(CUST_SQR_SCALE_PROPS[CstSqOffsetWidth]), + &pPageScaleData->offWidth)) && + SUCCEEDED(hr = GetScoredPropertyValue(CComBSTR(SCALE_FEATURE), + CComBSTR(CUST_SQR_SCALE_PROPS[CstSqOffsetHeight]), + &pPageScaleData->offHeight)) && + SUCCEEDED(hr = GetScoredPropertyValue(CComBSTR(SCALE_FEATURE), + CComBSTR(CUST_SQR_SCALE_PROPS[CstSqScale]), + &pPageScaleData->scaleWidth))) + { + pPageScaleData->scaleHeight = pPageScaleData->scaleWidth; + } + } + else if (bstrPgScOption == SCALE_OPTIONS[None]) + { + // + // No scaling - return as if no element is present + // + hr = E_ELEMENT_NOT_FOUND; + } + else + { + // + // Identify the option + // + for (EScaleOption pgScOption = FitBleedToImageable; + pgScOption < EScaleOptionMax; + pgScOption = static_cast(pgScOption + 1)) + { + if (bstrPgScOption == SCALE_OPTIONS[pgScOption]) + { + pPageScaleData->pgscOption = pgScOption; + + // + // Get the offset alignment + // + CComBSTR bstrOffsetAlignment; + + hr = GetSubFeatureOption(CComBSTR(SCALE_FEATURE), + CComBSTR(SCALE_OFFSET_FEATURE), + &bstrOffsetAlignment); + + // + // Identify the Alignment + // + for (EScaleOffsetOption offOption = EScaleOffsetOptionMin; + offOption < EScaleOffsetOptionMax; + offOption = static_cast(offOption + 1)) + { + if (bstrOffsetAlignment == SCALE_OFFSET_OPTIONS[offOption]) + { + pPageScaleData->offsetOption = offOption; + + break; + } + } + + break; + } + } + } + } + } + + // + // Validate the data + // + if (SUCCEEDED(hr)) + { + if (pPageScaleData->pgscOption < EScaleOptionMin || + pPageScaleData->pgscOption >= EScaleOptionMax) + { + hr = E_FAIL; + } + } + + ERR_ON_HR_EXC(hr, E_ELEMENT_NOT_FOUND); + return hr; +} + +/*++ + +Routine Name: + + CPageScalingPTHandler::SetData + +Routine Description: + + This routine sets the page scaling data in the PrintTicket passed to the + class constructor. + +Arguments: + + pPageScaleData - Pointer to the page scale data to be set in the PrintTicket + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPageScalingPTHandler::SetData( + _In_ CONST PageScalingData* pPageScaleData + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pPageScaleData, E_POINTER))) + { + if (pPageScaleData->pgscOption < EScaleOptionMin || + pPageScaleData->pgscOption >= EScaleOptionMax || + pPageScaleData->offsetOption < EScaleOffsetOptionMin || + pPageScaleData->offsetOption >= EScaleOffsetOptionMax) + { + hr = E_INVALIDARG; + } + } + + if (SUCCEEDED(hr)) + { + // + // Remove any existing page scaling feature node + // + CComPtr pFeature(NULL); + CComPtr pOption(NULL); + + CComBSTR bstrFeature(SCALE_FEATURE); + CComBSTR bstrAttribName(m_bstrKeywordsPrefix); + + if (SUCCEEDED(hr = DeleteFeature(bstrFeature)) && + pPageScaleData->pgscOption != None && + SUCCEEDED(hr = CreateFeatureOptionPair(bstrFeature, &pFeature, &pOption))) + { + // + // Retrieve the PrintTicket root + // + CComPtr pPTRoot(NULL); + + CComBSTR bstrPTQuery(m_bstrFrameworkPrefix); + bstrPTQuery += PRINTTICKET_NAME; + + if (SUCCEEDED(hr = GetNode(bstrPTQuery, &pPTRoot))) + { + // + // Append the feature node to the PrintTicket root element + // + hr = pPTRoot->appendChild(pFeature, NULL); + } + + // + // Set the option value + // + bstrAttribName += SCALE_OPTIONS[pPageScaleData->pgscOption]; + + if (SUCCEEDED(hr) && + SUCCEEDED(hr = CreateXMLAttribute(pOption, NAME_ATTRIBUTE_NAME, NULL, bstrAttribName ))) + { + switch (pPageScaleData->pgscOption) + { + case Custom: + { + // + // Create the width offset, height offset, width scale and height scale + // parameter ref/init pairs. Create the relevant scored properties passing the + // paramater refs. Append the scored properties to the option element and the + // paramter init values to the PrintTicket element + // + CONST INT* pValue = &pPageScaleData->offWidth; + for (ECustomScaleProps props = ECustomScalePropsMin; + props < ECustomScalePropsMax && SUCCEEDED(hr); + props = static_cast(props + 1), pValue++) + { + CComPtr pParamRef(NULL); + CComPtr pParamInit(NULL); + CComPtr pScoredProp(NULL); + + CComBSTR bstrParamRefName(SCALE_FEATURE); + bstrParamRefName += CUST_SCALE_PROPS[props]; + + if (SUCCEEDED(hr = CreateParamRefInitPair(bstrParamRefName, + *pValue, + &pParamRef,&pParamInit)) && + SUCCEEDED(hr = CreateScoredProperty(CComBSTR(CUST_SCALE_PROPS[props]), + pParamRef, + &pScoredProp)) && + SUCCEEDED(hr = pOption->appendChild(pScoredProp, NULL))) + { + hr = pPTRoot->appendChild(pParamInit, NULL); + } + } + } + break; + + case CustomSquare: + { + // + // Create the width offset, height offset and scale parameter ref/init pairs. + // Create the relevant scored properties passing the paramater refs. Append + // the scored properties to the option element and the paramter init values + // to the PrintTicket element. + // + CONST INT* pValue = &pPageScaleData->offWidth; + for (ECustomSquareScaleProps props = ECustomSquareScalePropsMin; + props < ECustomSquareScalePropsMax && SUCCEEDED(hr); + props = static_cast(props + 1), pValue++) + { + CComPtr pParamRef(NULL); + CComPtr pParamInit(NULL); + CComPtr pScoredProp(NULL); + + CComBSTR bstrParamRefName(SCALE_FEATURE); + bstrParamRefName += CUST_SQR_SCALE_PROPS[props]; + + if (SUCCEEDED(hr = CreateParamRefInitPair(bstrParamRefName, + *pValue, + &pParamRef, + &pParamInit)) && + SUCCEEDED(hr = CreateScoredProperty(CComBSTR(CUST_SQR_SCALE_PROPS[props]), + pParamRef, + &pScoredProp)) && + SUCCEEDED(hr = pOption->appendChild(pScoredProp, NULL))) + { + hr = pPTRoot->appendChild(pParamInit, NULL); + } + } + } + break; + + case FitBleedToImageable: + case FitContentToImageable: + case FitMediaToImageable: + case FitMediaToMedia: + { + // + // Create the ScaleOffsetAlignement feature and append to the option node + // + CComPtr pSubFeature(NULL); + CComPtr pSubOption(NULL); + + CComBSTR bstrOffsetFeature(SCALE_OFFSET_FEATURE); + CComBSTR bstrOffsetOption(SCALE_OFFSET_OPTIONS[pPageScaleData->offsetOption]); + + if (SUCCEEDED(hr = CreateFeatureOptionPair(bstrOffsetFeature, + bstrOffsetOption, + &pSubFeature, + &pSubOption))) + { + hr = pFeature->appendChild(pSubFeature, NULL); + } + } + break; + + case None: + default: + { + } + break; + } + } + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CPageScalingPTHandler::Delete + +Routine Description: + + This routine deletes the page scaling feature from the PrintTicket passed to the + class constructor + +Arguments: + + None + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPageScalingPTHandler::Delete( + VOID + ) +{ + // + // Remove any existing page scaling feature node + // + HRESULT hr = DeleteFeature(CComBSTR(SCALE_FEATURE)); + + ERR_ON_HR(hr); + return hr; +} + diff --git a/print/XPSDrvSmpl/src/common/pgscpthndlr.h b/print/XPSDrvSmpl/src/common/pgscpthndlr.h new file mode 100644 index 00000000..08c52e7d --- /dev/null +++ b/print/XPSDrvSmpl/src/common/pgscpthndlr.h @@ -0,0 +1,55 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + pgscpthndlr.h + +Abstract: + + PageScaling PrintTicket handling definition. The PageScaling PT handler + is used to extract PageScaling settings from a PrintTicket and populate + the PageScaling data structure with the retrieved settings. The class also + defines a method for setting the feature in the PrintTicket given the + data structure. + +--*/ + +#pragma once + +#include "pthndlr.h" +#include "pgscdata.h" + +class CPageScalingPTHandler : public CPTHandler +{ +public: + CPageScalingPTHandler( + _In_ IXMLDOMDocument2* pPrintTicket + ); + + virtual ~CPageScalingPTHandler(); + + HRESULT + GetData( + _Out_ XDPrintSchema::PageScaling::PageScalingData* pPageScaleData + ); + + HRESULT + SetData( + _In_ CONST XDPrintSchema::PageScaling::PageScalingData* pPageScaleData + ); + + HRESULT + Delete( + void + ); +}; + diff --git a/print/XPSDrvSmpl/src/common/pgscschema.cpp b/print/XPSDrvSmpl/src/common/pgscschema.cpp new file mode 100644 index 00000000..a8ada487 --- /dev/null +++ b/print/XPSDrvSmpl/src/common/pgscschema.cpp @@ -0,0 +1,64 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + pgscschema.cpp + +Abstract: + + PageScaling PrintSchema implementation. This implements the features, + options and enumerations that describe the PrintSchema PageScaling feature. + +--*/ + +#include "precomp.h" +#include "pgscschema.h" + +LPCWSTR XDPrintSchema::PageScaling::SCALE_FEATURE = L"PageScaling"; + +LPCWSTR XDPrintSchema::PageScaling::SCALE_OPTIONS[EScaleOptionMax] = { + L"Custom", + L"CustomSquare", + L"FitApplicationBleedSizeToPageImageableSize", + L"FitApplicationContentSizeToPageImageableSize", + L"FitApplicationMediaSizeToPageImageableSize", + L"FitApplicationMediaSizeToPageMediaSize", + L"None" +}; + +LPCWSTR XDPrintSchema::PageScaling::CUST_SCALE_PROPS[] = { + L"OffsetWidth", + L"OffsetHeight", + L"ScaleWidth", + L"ScaleHeight" +}; + +LPCWSTR XDPrintSchema::PageScaling::CUST_SQR_SCALE_PROPS[] = { + L"OffsetWidth", + L"OffsetHeight", + L"Scale" +}; + +LPCWSTR XDPrintSchema::PageScaling::OffsetAlignment::SCALE_OFFSET_FEATURE = L"ScaleOffsetAlignment"; + +LPCWSTR XDPrintSchema::PageScaling::OffsetAlignment::SCALE_OFFSET_OPTIONS[] = { + L"BottomCenter", + L"BottomLeft", + L"BottomRight", + L"Center", + L"LeftCenter", + L"RightCenter", + L"TopCenter", + L"TopLeft", + L"TopRight" +}; + diff --git a/print/XPSDrvSmpl/src/common/pgscschema.h b/print/XPSDrvSmpl/src/common/pgscschema.h new file mode 100644 index 00000000..d30c9c92 --- /dev/null +++ b/print/XPSDrvSmpl/src/common/pgscschema.h @@ -0,0 +1,112 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + pgscschema.h + +Abstract: + + PageScaling PrintSchema definition. This defines the features, options + and enumerations that describe the PrintSchema PageScaling feature within + a XDPrintSchema::PageScaling namespace. + +--*/ + +#pragma once + +#include "schema.h" + +namespace XDPrintSchema +{ + // + // PageScaling elements described as Printschema keywords + // + namespace PageScaling + { + // + // The feature name + // + extern LPCWSTR SCALE_FEATURE; + + // + // Option names + // + enum EScaleOption + { + Custom = 0, EScaleOptionMin = 0, + CustomSquare, + FitBleedToImageable, + FitContentToImageable, + FitMediaToImageable, + FitMediaToMedia, + None, + EScaleOptionMax + }; + + extern LPCWSTR SCALE_OPTIONS[EScaleOptionMax]; + + // + // Custom scaling properties + // + enum ECustomScaleProps + { + CstOffsetWidth = 0, ECustomScalePropsMin = 0, + CstOffsetHeight, + CstScaleWidth, + CstScaleHeight, + ECustomScalePropsMax + }; + + extern LPCWSTR CUST_SCALE_PROPS[ECustomScalePropsMax]; + + // + // Custom square scaling properties + // + enum ECustomSquareScaleProps + { + CstSqOffsetWidth = 0, ECustomSquareScalePropsMin = 0, + CstSqOffsetHeight, + CstSqScale, + ECustomSquareScalePropsMax + }; + + extern LPCWSTR CUST_SQR_SCALE_PROPS[ECustomSquareScalePropsMax]; + + namespace OffsetAlignment + { + // + // The feature name + // + extern LPCWSTR SCALE_OFFSET_FEATURE; + + // + // Option names + // + enum EScaleOffsetOption + { + BottomCenter = 0, EScaleOffsetOptionMin = 0, + BottomLeft, + BottomRight, + Center, + LeftCenter, + RightCenter, + TopCenter, + TopLeft, + TopRight, + EScaleOffsetOptionMax + }; + + extern LPCWSTR SCALE_OFFSET_OPTIONS[EScaleOffsetOptionMax]; + } + } +} + diff --git a/print/XPSDrvSmpl/src/common/pimagedata.h b/print/XPSDrvSmpl/src/common/pimagedata.h new file mode 100644 index 00000000..fc9a36c7 --- /dev/null +++ b/print/XPSDrvSmpl/src/common/pimagedata.h @@ -0,0 +1,52 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + pimagedata.h + +Abstract: + + PageImageableSize data structure definition. This provides a convenient + description of the PrintSchema PageImageableSize feature. + +--*/ + +#pragma once + +#include "pimageschema.h" + +namespace XDPrintSchema +{ + namespace PageImageableSize + { + struct PageImageableData + { + PageImageableData() : + imageableSizeWidth(0), + imageableSizeHeight(0), + originWidth(0), + originHeight(0), + extentWidth(0), + extentHeight(0) + { + } + + INT imageableSizeWidth; + INT imageableSizeHeight; + INT originWidth; + INT originHeight; + INT extentWidth; + INT extentHeight; + }; + } +} + diff --git a/print/XPSDrvSmpl/src/common/pimagepthndlr.cpp b/print/XPSDrvSmpl/src/common/pimagepthndlr.cpp new file mode 100644 index 00000000..23013810 --- /dev/null +++ b/print/XPSDrvSmpl/src/common/pimagepthndlr.cpp @@ -0,0 +1,171 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + pimagepthndlr.cpp + +Abstract: + + This class is responsible for retrieving the PageImageableSize properties from a + PrintCapabilities document. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdexcept.h" +#include "ptquerybld.h" +#include "pimagepthndlr.h" + +using XDPrintSchema::PageImageableSize::PageImageableData; +using XDPrintSchema::PageImageableSize::ImageableSizeWidth; +using XDPrintSchema::PageImageableSize::ImageableSizeHeight; +using XDPrintSchema::PageImageableSize::ImageableArea; +using XDPrintSchema::PageImageableSize::EPageImageablePropsMax; +using XDPrintSchema::PageImageableSize::OriginWidth; +using XDPrintSchema::PageImageableSize::OriginHeight; +using XDPrintSchema::PageImageableSize::ExtentWidth; +using XDPrintSchema::PageImageableSize::ExtentHeight; +using XDPrintSchema::PageImageableSize::PAGE_IMAGEABLE_PROPERTY; +using XDPrintSchema::PageImageableSize::PAGE_IMAGEABLE_PROPS; +using XDPrintSchema::PageImageableSize::PAGE_IMAGEABLE_PROPS_AREA; + +/*++ + +Routine Name: + + CPageImageablePCHandler::CPageImageablePCHandler + +Routine Description: + + CPageImageablePCHandler class constructor + +Arguments: + + pPrintCapabilities - Pointer to the DOM document representation of the PrintCapabilities + +Return Value: + + None + +--*/ +CPageImageablePCHandler::CPageImageablePCHandler( + _In_ IXMLDOMDocument2* pPrintCapabilities + ) : + CPCHandler(pPrintCapabilities) +{ +} + +/*++ + +Routine Name: + + CPageImageablePCHandler::~CPageImageablePCHandler + +Routine Description: + + CPageImageablePCHandler class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CPageImageablePCHandler::~CPageImageablePCHandler() +{ +} + +/*++ + +Routine Name: + + CPageImageablePCHandler::GetData + +Routine Description: + + The routine fills the data structure passed in with page imageable size + data retrieved from the PrintCapabilities passed to the class constructor. + +Arguments: + + pPageImageableData - Pointer to the page imageable size data structure to be filled in + +Return Value: + + HRESULT + S_OK - On success + E_ELEMENT_NOT_FOUND - Feature not present in PrintCapabilities + E_* - On error + +--*/ +HRESULT +CPageImageablePCHandler::GetData( + _Inout_ PageImageableData* pPageImageableData + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pPageImageableData, E_POINTER))) + { + CComBSTR bstrQuery; + CPTQueryBuilder queryImageableArea(m_bstrFrameworkPrefix); + + if (SUCCEEDED(hr = queryImageableArea.AddProperty(m_bstrKeywordsPrefix, CComBSTR(PAGE_IMAGEABLE_PROPERTY))) && + SUCCEEDED(hr = queryImageableArea.GetQuery(&bstrQuery)) && + SUCCEEDED(hr = QueryNode(bstrQuery))) + { + CPTQueryBuilder queryImageableSizeWidth(queryImageableArea); + CPTQueryBuilder queryImageableSizeHeight(queryImageableArea); + + if (SUCCEEDED(hr = queryImageableSizeWidth.AddProperty(m_bstrKeywordsPrefix, CComBSTR(PAGE_IMAGEABLE_PROPS[ImageableSizeWidth]))) && + SUCCEEDED(hr = queryImageableSizeHeight.AddProperty(m_bstrKeywordsPrefix, CComBSTR(PAGE_IMAGEABLE_PROPS[ImageableSizeHeight]))) && + SUCCEEDED(hr = queryImageableSizeWidth.GetQuery(&bstrQuery)) && + SUCCEEDED(hr = QueryNodeValue(bstrQuery, &pPageImageableData->imageableSizeWidth)) && + SUCCEEDED(hr = queryImageableSizeHeight.GetQuery(&bstrQuery)) && + SUCCEEDED(hr = QueryNodeValue(bstrQuery, &pPageImageableData->imageableSizeHeight))) + { + CPTQueryBuilder queryOriginWidth(queryImageableArea); + CPTQueryBuilder queryOriginHeight(queryImageableArea); + CPTQueryBuilder queryExtentWidth(queryImageableArea); + CPTQueryBuilder queryExtentHeight(queryImageableArea); + + if (SUCCEEDED(hr = queryOriginWidth.AddProperty(m_bstrKeywordsPrefix, CComBSTR(PAGE_IMAGEABLE_PROPS[ImageableArea]))) && + SUCCEEDED(hr = queryOriginWidth.AddProperty(m_bstrKeywordsPrefix, CComBSTR(PAGE_IMAGEABLE_PROPS_AREA[OriginWidth]))) && + SUCCEEDED(hr = queryOriginHeight.AddProperty(m_bstrKeywordsPrefix, CComBSTR(PAGE_IMAGEABLE_PROPS[ImageableArea]))) && + SUCCEEDED(hr = queryOriginHeight.AddProperty(m_bstrKeywordsPrefix, CComBSTR(PAGE_IMAGEABLE_PROPS_AREA[OriginHeight]))) && + SUCCEEDED(hr = queryExtentWidth.AddProperty(m_bstrKeywordsPrefix, CComBSTR(PAGE_IMAGEABLE_PROPS[ImageableArea]))) && + SUCCEEDED(hr = queryExtentWidth.AddProperty(m_bstrKeywordsPrefix, CComBSTR(PAGE_IMAGEABLE_PROPS_AREA[ExtentWidth]))) && + SUCCEEDED(hr = queryExtentHeight.AddProperty(m_bstrKeywordsPrefix, CComBSTR(PAGE_IMAGEABLE_PROPS[ImageableArea]))) && + SUCCEEDED(hr = queryExtentHeight.AddProperty(m_bstrKeywordsPrefix, CComBSTR(PAGE_IMAGEABLE_PROPS_AREA[ExtentHeight]))) && + SUCCEEDED(hr = queryOriginWidth.GetQuery(&bstrQuery)) && + SUCCEEDED(hr = QueryNodeValue(bstrQuery, &pPageImageableData->originWidth)) && + SUCCEEDED(hr = queryOriginHeight.GetQuery(&bstrQuery)) && + SUCCEEDED(hr = QueryNodeValue(bstrQuery, &pPageImageableData->originHeight)) && + SUCCEEDED(hr = queryExtentWidth.GetQuery(&bstrQuery)) && + SUCCEEDED(hr = QueryNodeValue(bstrQuery, &pPageImageableData->extentWidth)) && + SUCCEEDED(hr = queryExtentHeight.GetQuery(&bstrQuery))) + { + hr = QueryNodeValue(bstrQuery, &pPageImageableData->extentHeight); + } + } + } + } + + ERR_ON_HR_EXC(hr, E_ELEMENT_NOT_FOUND); + return hr; +} + diff --git a/print/XPSDrvSmpl/src/common/pimagepthndlr.h b/print/XPSDrvSmpl/src/common/pimagepthndlr.h new file mode 100644 index 00000000..99d5025e --- /dev/null +++ b/print/XPSDrvSmpl/src/common/pimagepthndlr.h @@ -0,0 +1,42 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + pimagepthndlr.h + +Abstract: + + This class is responsible for retrieving the PageImageableSize properties from a + PrintCapabilities document. + +--*/ + +#pragma once + +#include "pchndlr.h" +#include "pimagedata.h" + +class CPageImageablePCHandler : public CPCHandler +{ +public: + CPageImageablePCHandler( + _In_ IXMLDOMDocument2* pPrintCapabilities + ); + + virtual ~CPageImageablePCHandler(); + + HRESULT + GetData( + _Inout_ XDPrintSchema::PageImageableSize::PageImageableData* pPageImageableData + ); +}; + diff --git a/print/XPSDrvSmpl/src/common/pimageschema.cpp b/print/XPSDrvSmpl/src/common/pimageschema.cpp new file mode 100644 index 00000000..bd9dd484 --- /dev/null +++ b/print/XPSDrvSmpl/src/common/pimageschema.cpp @@ -0,0 +1,40 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + pimageschema.cpp + +Abstract: + + PageImageableSize PrintSchema implementation. This implements the features, + options and enumerations that describe the PrintSchema PageImageableSize feature. + +--*/ + +#include "precomp.h" +#include "pimageschema.h" + +LPCWSTR XDPrintSchema::PageImageableSize::PAGE_IMAGEABLE_PROPERTY = L"PageImageableSize"; + +LPCWSTR XDPrintSchema::PageImageableSize::PAGE_IMAGEABLE_PROPS[] = { + L"ImageableSizeWidth", + L"ImageableSizeHeight", + L"ImageableArea" +}; + +LPCWSTR XDPrintSchema::PageImageableSize::PAGE_IMAGEABLE_PROPS_AREA[] = { + L"OriginWidth", + L"OriginHeight", + L"ExtentWidth", + L"ExtentHeight" +}; + diff --git a/print/XPSDrvSmpl/src/common/pimageschema.h b/print/XPSDrvSmpl/src/common/pimageschema.h new file mode 100644 index 00000000..760b1d2b --- /dev/null +++ b/print/XPSDrvSmpl/src/common/pimageschema.h @@ -0,0 +1,62 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + pimageschema.h + +Abstract: + + PageImageableSize PrintSchema definition. This defines the features, options + and enumerations that describe the PrintSchema PageImageableSize feature within + a XDPrintSchema::PageImageableSize namespace. + +--*/ + +#pragma once + +#include "schema.h" + +namespace XDPrintSchema +{ + // + // PageImageSize elements described as Printschema keywords + // + namespace PageImageableSize + { + // + // The property name + // + extern LPCWSTR PAGE_IMAGEABLE_PROPERTY; + + enum EPageImageableProps + { + ImageableSizeWidth = 0, EPageImageablePropsMin = 0, + ImageableSizeHeight, + ImageableArea, + EPageImageablePropsMax + }; + + extern LPCWSTR PAGE_IMAGEABLE_PROPS[EPageImageablePropsMax]; + + enum EPageImageablePropsArea + { + OriginWidth = 0, EPageImageablePropsAreaMin = 0, + OriginHeight, + ExtentWidth, + ExtentHeight, + EPageImageablePropsAreaMax + }; + + extern LPCWSTR PAGE_IMAGEABLE_PROPS_AREA[EPageImageablePropsAreaMax]; + } +} + diff --git a/print/XPSDrvSmpl/src/common/porientdata.h b/print/XPSDrvSmpl/src/common/porientdata.h new file mode 100644 index 00000000..4e3a181d --- /dev/null +++ b/print/XPSDrvSmpl/src/common/porientdata.h @@ -0,0 +1,42 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + porientdata.h + +Abstract: + + PageOrientation data structure definition. This provides a convenient + description of the PrintSchema PageOrientation feature. + +--*/ + +#pragma once + +#include "porientschema.h" + +namespace XDPrintSchema +{ + namespace PageOrientation + { + struct PageOrientationData + { + PageOrientationData() : + orientation(Landscape) + { + } + + EOrientationOption orientation; + }; + } +} + diff --git a/print/XPSDrvSmpl/src/common/porientpthndlr.cpp b/print/XPSDrvSmpl/src/common/porientpthndlr.cpp new file mode 100644 index 00000000..52e3e7ed --- /dev/null +++ b/print/XPSDrvSmpl/src/common/porientpthndlr.cpp @@ -0,0 +1,150 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + porientpthndlr.cpp + +Abstract: + + PageOrientation PrintTicket handler implementation. Derived from CPTHandler, + this provides a PageOrientation specific Get methods acting on the passed in + PrintTicket (as a DOM document). + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdexcept.h" +#include "porientpthndlr.h" + +using XDPrintSchema::PageOrientation::PageOrientationData; +using XDPrintSchema::PageOrientation::EOrientationOption; +using XDPrintSchema::PageOrientation::EOrientationOptionMin; +using XDPrintSchema::PageOrientation::EOrientationOptionMax; +using XDPrintSchema::PageOrientation::ORIENTATION_FEATURE; +using XDPrintSchema::PageOrientation::ORIENTATION_OPTIONS; + +/*++ + +Routine Name: + + CPageOrientationPTHandler::CPageOrientationPTHandler + +Routine Description: + + CPageOrientationPTHandler class constructor + +Arguments: + + pPrintTicket - Pointer to the DOM document representation of the PrintTicket + +Return Value: + + None + +--*/ +CPageOrientationPTHandler::CPageOrientationPTHandler( + _In_ IXMLDOMDocument2* pPrintTicket + ) : + CPTHandler(pPrintTicket) +{ +} + +/*++ + +Routine Name: + + CPageOrientationPTHandler::~CPageOrientationPTHandler + +Routine Description: + + CPageOrientationPTHandler class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CPageOrientationPTHandler::~CPageOrientationPTHandler() +{ +} + +/*++ + +Routine Name: + + CPageOrientationPTHandler::GetData + +Routine Description: + + The routine fills the data structure passed in with page orientation data retrieved from + the PrintTicket passed to the class constructor. + +Arguments: + + pPageOrientationData - Pointer to the page orientation data structure to be filled in + +Return Value: + + HRESULT + S_OK - On success + E_ELEMENT_NOT_FOUND - Feature not present in PrintTicket + E_* - On error + +--*/ +HRESULT +CPageOrientationPTHandler::GetData( + _Inout_ PageOrientationData* pPageOrientationData + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pPageOrientationData, E_POINTER))) + { + CComBSTR bstrPOOption; + + if (SUCCEEDED(hr = GetFeatureOption(CComBSTR(ORIENTATION_FEATURE), &bstrPOOption))) + { + for (EOrientationOption poOpt = EOrientationOptionMin; + poOpt < EOrientationOptionMax; + poOpt = static_cast(poOpt + 1)) + { + if (bstrPOOption == ORIENTATION_OPTIONS[poOpt]) + { + pPageOrientationData->orientation = poOpt; + break; + } + } + } + } + + // + // Validate the data + // + if (SUCCEEDED(hr)) + { + if (pPageOrientationData->orientation < EOrientationOptionMin || + pPageOrientationData->orientation >= EOrientationOptionMax) + { + hr = E_FAIL; + } + } + + ERR_ON_HR_EXC(hr, E_ELEMENT_NOT_FOUND); + return hr; +} + diff --git a/print/XPSDrvSmpl/src/common/porientpthndlr.h b/print/XPSDrvSmpl/src/common/porientpthndlr.h new file mode 100644 index 00000000..138bbc0c --- /dev/null +++ b/print/XPSDrvSmpl/src/common/porientpthndlr.h @@ -0,0 +1,45 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + porientpthndlr.h + +Abstract: + + PageOrientation PrintTicket handling definition. The PageOrientation PT handler + is used to extract PageOrientation settings from a PrintTicket and populate + the PageOrientation data structure with the retrieved settings. The class also + defines a method for setting the feature in the PrintTicket given the + data structure. + +--*/ + +#pragma once + +#include "pthndlr.h" +#include "porientdata.h" + +class CPageOrientationPTHandler : public CPTHandler +{ +public: + CPageOrientationPTHandler( + _In_ IXMLDOMDocument2* pPrintTicket + ); + + virtual ~CPageOrientationPTHandler(); + + HRESULT + GetData( + _Inout_ XDPrintSchema::PageOrientation::PageOrientationData* pPageOrientationData + ); +}; + diff --git a/print/XPSDrvSmpl/src/common/porientschema.cpp b/print/XPSDrvSmpl/src/common/porientschema.cpp new file mode 100644 index 00000000..524001c1 --- /dev/null +++ b/print/XPSDrvSmpl/src/common/porientschema.cpp @@ -0,0 +1,34 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + porientschema.cpp + +Abstract: + + PageOrientation PrintSchema implementation. This implements the features, + options and enumerations that describe the PrintSchema PageOrientation feature. + +--*/ + +#include "precomp.h" +#include "porientschema.h" + +LPCWSTR XDPrintSchema::PageOrientation::ORIENTATION_FEATURE = L"PageOrientation"; + +LPCWSTR XDPrintSchema::PageOrientation::ORIENTATION_OPTIONS[EOrientationOptionMax] = { + L"Landscape", + L"Portrait", + L"ReverseLandscape", + L"ReversePortrait" +}; + diff --git a/print/XPSDrvSmpl/src/common/porientschema.h b/print/XPSDrvSmpl/src/common/porientschema.h new file mode 100644 index 00000000..2fdca11c --- /dev/null +++ b/print/XPSDrvSmpl/src/common/porientschema.h @@ -0,0 +1,55 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + porientschema.h + +Abstract: + + PageOrientation PrintSchema definition. This defines the features, options + and enumerations that describe the PrintSchema PageOrientation feature within + a XDPrintSchema::PageOrientation namespace. + +--*/ + +#pragma once + +#include "schema.h" + +namespace XDPrintSchema +{ + // + // PageOrientation elements described as Printschema keywords + // + namespace PageOrientation + { + // + // The feature name + // + extern LPCWSTR ORIENTATION_FEATURE; + + // + // Paper orientation options + // + enum EOrientationOption + { + Landscape = 0, EOrientationOptionMin = 0, + Portrait, + ReverseLandscape, + ReversePortrait, + EOrientationOptionMax + }; + + extern LPCWSTR ORIENTATION_OPTIONS[EOrientationOptionMax]; + } +} + diff --git a/print/XPSDrvSmpl/src/common/precomp.h b/print/XPSDrvSmpl/src/common/precomp.h new file mode 100644 index 00000000..808f191b --- /dev/null +++ b/print/XPSDrvSmpl/src/common/precomp.h @@ -0,0 +1,99 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + precomp.h + +Abstract: + + Precompiled header for all filters + +--*/ + +#pragma once + +// +// Annotate this as a usermode driver for static analysis +// +#include +_Analysis_mode_(_Analysis_code_type_user_driver_) + +// +// Standard Annotation Language include +// +#include + +// +// Windows includes +// +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif // WIN32_LEAN_AND_MEAN +#include +#include + +// +// COM includes +// +#include +#include + +// +// ATL Includes +// +#include + + +// +// GDIPlus includes +// +#include + +// +// MSXML includes +// +#include + +// +// WCS Includes +// +#include + +// +// Filter pipeline includes +// +#include +#include +#include +#include + +// +// Standard library includes +// +#include +#include +#include +#include +#include + +// +// Commonly used namespaces +// +using namespace std; +using namespace Gdiplus; + +// +// String safe includes - included last to prevent build warnings +// +#include + +#include "common.ver" diff --git a/print/XPSDrvSmpl/src/common/precompsrc.cpp b/print/XPSDrvSmpl/src/common/precompsrc.cpp new file mode 100644 index 00000000..5944cf51 --- /dev/null +++ b/print/XPSDrvSmpl/src/common/precompsrc.cpp @@ -0,0 +1 @@ +#include "precomp.h" \ No newline at end of file diff --git a/print/XPSDrvSmpl/src/common/privatedefs.h b/print/XPSDrvSmpl/src/common/privatedefs.h new file mode 100644 index 00000000..0c8cb96d --- /dev/null +++ b/print/XPSDrvSmpl/src/common/privatedefs.h @@ -0,0 +1,300 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + privatedefs.h + +Abstract: + + Definitions for private PrintTicket/PrintCapabilities properties for watermark and page scaling features. + +--*/ + +#pragma once + +// +// Macro to return the number of elements in an array +// +#define numof(n) (sizeof(n) / sizeof(n[0])) + +// +// Structure definition for the Private Parameter Defs (Integer Type) +// +typedef struct _PRIVATE_DEF_INTS +{ + PCSTR property_name; + BOOL is_public; + PCSTR display_name; + INT default_value; + INT min_length; + INT max_length; + INT multiple; + PCSTR unit_type; +}PRIVATE_DEF_INTEGERS; + +// +// Structure definition for the Private Parameter Defs (String Type) +// +typedef struct _PRIVATE_DEF_STRS +{ + PCSTR property_name; + PCSTR display_name; + PCSTR default_value; + INT min_length; + INT max_length; + PCSTR unit_type; +}PRIVATE_DEF_STRINGS; + +// +// Structure definition for the Private Parameter Defs (Decimal Type) +// +typedef struct _PRIVATE_DEF_DECS +{ + PCSTR property_name; + PCSTR display_name; + REAL default_value; + REAL min_length; + REAL max_length; + REAL multiple; + PCSTR unit_type; +}PRIVATE_DEF_DECIMALS; + +// +// Table of values for private integer watermark properties. +// +CONST PRIVATE_DEF_INTEGERS wmParamDefIntegers[] = +{ + { + "PageWatermarkTextAngle", + TRUE, + NULL, + 0, + 0, + 360, + 1, + "Degrees" + }, + { + "PageWatermarkOriginWidth", + TRUE, + NULL, + 0, + -INT_MAX, + INT_MAX, + 1, + "Microns" + }, + { + "PageWatermarkOriginHeight", + TRUE, + NULL, + HUNDREDTH_OFINCH_TO_MICRON(100), + -INT_MAX, + INT_MAX, + 1, + "Microns" + }, + { + "PageWatermarkSizeWidth", + FALSE, + NULL, + HUNDREDTH_OFINCH_TO_MICRON(100), + 0, + INT_MAX, + 1, + "Microns" + }, + { + "PageWatermarkSizeHeight", + FALSE, + NULL, + HUNDREDTH_OFINCH_TO_MICRON(100), + 0, + INT_MAX, + 1, + "Microns" + }, + { + "PageWatermarkTextFontSize", + TRUE, + NULL, + 72, + 1, + INT_MAX, + 1, + "Points Per Inch" + }, + { + "PageWatermarkTextColor", + TRUE, + NULL, + (INT) 0xFFFF0000, + 0, + (INT) 0xFFFFFFFF, + 1, + "sRGB" + }, + { + "PageWatermarkTransparency", + TRUE, + NULL, + 50, + 0, + 100, + 1, + "Transparency" + }, +}; + +// +// enum lookup into above table +// +enum eWMParamDefIntegers +{ + ePageWatermarkAngle = 0, + ePageWatermarkOriginWidth, + ePageWatermarkOriginHeight, + ePageWatermarkSizeWidth, + ePageWatermarkSizeHeight, + ePageWatermarkTextFontSize, + ePageWatermarkTextColor, + ePageWatermarkTransparency, +}; + +// +// Table of values for private string watermark properties. +// +CONST PRIVATE_DEF_STRINGS wmParamDefStrings[] = +{ + { + "PageWatermarkTextText", + NULL, + "CONFIDENTIAL", + 0, + 20, + "characters" + } +}; + +// +// enum lookup into above table +// +enum eWMParamDefStrings +{ + ePageWatermarkTextText = 0 +}; + +// +// Table of values for private integer page scaling properties. +// +CONST PRIVATE_DEF_INTEGERS pgscParamDefIntegers[] = +{ + { + "PageScalingScaleWidth", + TRUE, + NULL, + 100, + 1, + 1000, + 1, + "Percent" + }, + { + "PageScalingScaleHeight", + TRUE, + NULL, + 100, + 1, + 1000, + 1, + "Percent" + }, + { + "PageScalingScale", + TRUE, + NULL, + 100, + 1, + 1000, + 1, + "Percent" + }, + { + "PageScalingOffsetWidth", + TRUE, + NULL, + 0, + -INT_MAX, + INT_MAX, + 1, + "Microns" + }, + { + "PageScalingOffsetHeight", + TRUE, + NULL, + 0, + -INT_MAX, + INT_MAX, + 1, + "Microns" + }, +}; + +// +// enum lookup into above table +// +enum ePGSCParamDefIntegers +{ + ePageScalingScaleWidth = 0, + ePageScalingScaleHeight, + ePageScalingScale, + ePageScalingOffsetWidth, + ePageScalingOffsetHeight, +}; + +// +// Table of values for private integer booklet gutter properties. +// +CONST PRIVATE_DEF_INTEGERS bkParamDefIntegers[] = +{ + { + "JobBindAllDocumentsGutter", + TRUE, + NULL, + 0, + -INT_MAX, + INT_MAX, + 0, + "Microns" + }, + { + "DocumentBindingGutter", + TRUE, + NULL, + 0, + -INT_MAX, + INT_MAX, + 0, + "Microns" + } +}; + +// +// enum lookup into above table +// +enum eBindingParamDefIntegers +{ + eJobBindAllDocumentsGutter = 0, + eDocumentBindingGutter, +}; + diff --git a/print/XPSDrvSmpl/src/common/pshndlr.cpp b/print/XPSDrvSmpl/src/common/pshndlr.cpp new file mode 100644 index 00000000..989837be --- /dev/null +++ b/print/XPSDrvSmpl/src/common/pshndlr.cpp @@ -0,0 +1,1836 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +File Name: + + pshndlr.cpp + +Abstract: + + Base PrintSchema Document handler class implementation. + This class provides common PrintTicket / PrintCapabilities handling functionality. + A class can derive from this base class to get PrintTicket/PrintCapabilities + unspecific XML handling functionality. + + Note: The PrintSchema handler code is only intended to work with the sdtandard + public PrintSchema keywords. + +--*/ + + +// +// Note on handling missing DOM nodes: +// +// Convert MSXML's S_FALSE to E_ELEMENT_NOT_FOUND. This allows clients to +// use the SUCCEEDED macro more effectively. +// +// E_ELEMENT_NOT_FOUND should not be propogated as an error to the +// filter pipeline or config module - treat as though the requested feature +// has not been enabled. +// + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdstring.h" +#include "pshndlr.h" + +using XDPrintSchema::FRAMEWORK_URI; +using XDPrintSchema::KEYWORDS_URI; +using XDPrintSchema::SCHEMA_INST_URI; +using XDPrintSchema::SCHEMA_DEF_URI; +using XDPrintSchema::PROPERTY_ELEMENT_NAME; +using XDPrintSchema::NAME_ATTRIBUTE_NAME; +using XDPrintSchema::VALUE_ELEMENT_NAME; +using XDPrintSchema::SCHEMA_TYPE; +using XDPrintSchema::SCORED_PROP_ELEMENT_NAME; +using XDPrintSchema::SCHEMA_STRING; +using XDPrintSchema::SCHEMA_INTEGER; +using XDPrintSchema::SCHEMA_DECIMAL; +using XDPrintSchema::PARAM_REF_ELEMENT_NAME; +using XDPrintSchema::PARAM_INIT_ELEMENT_NAME; +using XDPrintSchema::SCHEMA_INST_URI; + +static LPCWSTR szSelectNS = L"SelectionNamespaces"; +static LPCWSTR szTmpNS = L"psf"; +static LPCWSTR szNSSelection = L"xmlns:%s='%s'"; +static LPCWSTR szSelectLang = L"SelectionLanguage"; +static LPCWSTR szLangSection = L"XPath"; + +static LPCWSTR szPTRootQuery = L"//%s:%s"; + +/*++ + +Routine Name: + + CPSHandler::CPSHandler + +Routine Description: + + CPSHandler class constructor + +Arguments: + + pDOMDocument - Pointer to the DOM document representation of the PrintTicket/PrintCapabilities + +Return Value: + + None + Throws CXDException(HRESULT) on an error + +--*/ +CPSHandler::CPSHandler( + _In_z_ BSTR bstrDocumentType, + _In_ IXMLDOMDocument2 *pPrintDocument + ) : + m_bstrDocumentType(bstrDocumentType), + m_pPrintDocument(pPrintDocument) +{ + ASSERTMSG(m_pPrintDocument != NULL, "NULL PrintDocument passed to PS manager.\n"); + + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(m_pPrintDocument, E_PENDING))) + { + try + { + // + // Make sure XPath selection language is set + // + if (SUCCEEDED(hr = m_pPrintDocument->setProperty(CComBSTR(szSelectLang), CComVariant(szLangSection)))) + { + // + // Construct the alias namespace string + // + CStringXDW cstrNamespaces; + cstrNamespaces.Format(szNSSelection, szTmpNS, FRAMEWORK_URI); + + // + // Specify an alias PrintSchema namespace prefix to allow us to find the real ones + // + if (SUCCEEDED(hr = m_pPrintDocument->setProperty(CComBSTR(szSelectNS), CComVariant(cstrNamespaces)))) + { + if (SUCCEEDED(hr = GetPrefixFromURI(CComBSTR(FRAMEWORK_URI), &m_bstrFrameworkPrefix)) && + SUCCEEDED(hr = GetPrefixFromURI(CComBSTR(KEYWORDS_URI), &m_bstrKeywordsPrefix)) && + SUCCEEDED(hr = GetPrefixFromURI(CComBSTR(SCHEMA_INST_URI), &m_bstrSchemaInstPrefix)) && + SUCCEEDED(hr = GetPrefixFromURI(CComBSTR(SCHEMA_DEF_URI), &m_bstrSchemaPrefix))) + { + CStringXDW cstrNSUserPrefix(L"ns0000:"); + m_bstrUserKeywordsPrefix.Empty(); + m_bstrUserKeywordsPrefix.Attach(cstrNSUserPrefix.AllocSysString()); + + // + // Restore the original namespace prefix for the PrintSchema framework + // + CComBSTR bstrOrgNamespaces; + CStringXDW cstrNSPrefix(m_bstrFrameworkPrefix); + + INT iIndex = cstrNSPrefix.Find(L":"); + if (iIndex != -1 && + cstrNSPrefix.Delete(iIndex, 1) > 0) + { + CStringXDW cstrOrgNamespaces; + cstrOrgNamespaces.Format(szNSSelection, cstrNSPrefix, FRAMEWORK_URI); + + hr = m_pPrintDocument->setProperty(CComBSTR(szSelectNS), CComVariant(cstrOrgNamespaces)); + } + else + { + RIP("Could not create namespace prefix correctly\n"); + hr = E_FAIL; + } + } + } + else + { + ERR("Failed to set SelectionNamespaces.\n"); + } + } + else + { + RIP("Failed to set SelectionLanguage.\n"); + } + } + catch (CXDException& e) + { + hr = e; + } + } + + if (FAILED(hr)) + { + throw CXDException(hr); + } +} + +/*++ + +Routine Name: + + CPSHandler::~CPSHandler + +Routine Description: + + CPSHandler class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CPSHandler::~CPSHandler() +{ +} + +/*++ + +Routine Name: + + CPSHandler::DeleteNode + +Routine Description: + + This routine deletes the given node from the PrintDocument + +Arguments: + + pNode - Pointer to the DOM node to be deleted + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPSHandler::DeleteNode( + _In_ IXMLDOMNode* pNode + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pNode, E_POINTER))) + { + CComPtr pParentNode(NULL); + CComPtr pDeletedNode(NULL); + + if (SUCCEEDED(hr = pNode->get_parentNode(&pParentNode)) && + hr != S_FALSE && + SUCCEEDED(hr = pParentNode->removeChild(pNode, &pDeletedNode)) && + pDeletedNode == NULL) + { + hr = E_FAIL; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CPSHandler::GetNode + +Routine Description: + + This routine retrieves a node given an XPath query + +Arguments: + + bstrNodeQuery - The XPath query for a node + ppNode - Pointer to an IXMLDOMNode pointer that recieves the node retrieved + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPSHandler::GetNode( + _In_z_ BSTR bstrNodeQuery, + _Outptr_ IXMLDOMNode** ppNode + ) +{ + // + // We should have the PrintDocment in place + // + ASSERTMSG(m_pPrintDocument != NULL, "NULL PS detected whilst retrieving node.\n"); + + // + // Method which takes a query string and returns the first node that matches + // + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(ppNode, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(m_pPrintDocument, E_PENDING))) + { + *ppNode = NULL; + if (SysStringLen(bstrNodeQuery) == 0) + { + hr = E_INVALIDARG; + } + } + + if (SUCCEEDED(hr)) + { + // + // Get the node from the PrintDocument + // + hr = m_pPrintDocument->selectSingleNode(bstrNodeQuery, ppNode); + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CPSHandler::DeletePrivateFeatures + +Routine Description: + + This routine finds and deletes features with values defined in the + private namespace passed in + +Arguments: + + bstrPrivateNS - the private namespace + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPSHandler::DeletePrivateFeatures( + _In_z_ BSTR bstrPrivateNS + ) +{ + HRESULT hr = S_OK; + + if (SysStringLen(bstrPrivateNS) > 0) + { + CComBSTR bstrNSPrefix; + if (SUCCEEDED(hr = GetPrefixFromURI(bstrPrivateNS, &bstrNSPrefix))) + { + // + // Find all root feature elements in the namespace + // + CComPtr pNodeList(NULL); + + CComBSTR bstrFeatureQuery(L"//"); + bstrFeatureQuery += m_bstrFrameworkPrefix; + bstrFeatureQuery += L"Feature"; + + if (SUCCEEDED(hr) && + SUCCEEDED(hr = m_pPrintDocument->selectNodes(bstrFeatureQuery, &pNodeList)) && + SUCCEEDED(hr = pNodeList->reset())) + { + // + // Delete all the feature with name attributes using the private namespace + // + CComPtr pDeleteNode(NULL); + + while (SUCCEEDED(hr) && + SUCCEEDED(hr = pNodeList->nextNode(&pDeleteNode)) && + hr != S_FALSE) + { + CComPtr pDeleteNodeAtts(NULL); + CComPtr pNameNode(NULL); + CComVariant varNameValue; + + if (SUCCEEDED(hr = pDeleteNode->get_attributes(&pDeleteNodeAtts)) && + hr != S_FALSE && + SUCCEEDED(hr = pDeleteNodeAtts->getNamedItem(CComBSTR(L"name"), &pNameNode)) && + hr != S_FALSE && + SUCCEEDED(hr = pNameNode->get_nodeValue(&varNameValue)) && + hr != S_FALSE) + { + try + { + CStringXDW cstrNameValue(varNameValue.bstrVal); + + if (cstrNameValue.Find(bstrNSPrefix) == 0) + { + hr = DeleteNode(pDeleteNode); + } + } + catch (CXDException& e) + { + hr = e; + } + } + + pDeleteNode = NULL; + } + } + } + } + else + { + hr = E_INVALIDARG; + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CPSHandler::CreateProperty + +Routine Description: + + This routine creates a property element of the given name. Note: this + method only creates the property element; it is up to the caller to + set the property value + +Arguments: + + bstrPropName - The name of the property + ppPropElement - Pointer to a IXMLDOMElement pointer that recieves the newly created Property element + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPSHandler::CreateProperty( + _In_ CONST BSTR bstrPropName, + _Outptr_ IXMLDOMElement** ppPropElement + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(ppPropElement, E_POINTER))) + { + *ppPropElement = NULL; + + if (SysStringLen(bstrPropName) <= 0) + { + hr = E_INVALIDARG; + } + } + + if (SUCCEEDED(hr)) + { + CComBSTR bstrTagName(m_bstrFrameworkPrefix); + bstrTagName += PROPERTY_ELEMENT_NAME; + + CComBSTR bstrAttribName(szTmpNS); + bstrAttribName += L":"; + bstrAttribName += bstrPropName; + + hr = CreateXMLElement(bstrTagName, FRAMEWORK_URI, ppPropElement); + + if (SUCCEEDED(hr)) + { + if (*ppPropElement != NULL) + { + hr = CreateXMLAttribute(*ppPropElement, NAME_ATTRIBUTE_NAME, NULL, bstrAttribName ); + } + else + { + hr = E_FAIL; + } + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CPSHandler::CreateProperty + +Routine Description: + + This routine creates a property element of the given name. + +Arguments: + + bstrPropName - The name of the property to be created + bstrType - The type of the property value (integer, string etc.) + bstrValue - The value of the property + ppPropElement - Pointer to an IXMLDOMElement pointer that recieves the new element + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPSHandler::CreateProperty( + _In_ CONST BSTR bstrPropName, + _In_ CONST BSTR bstrType, + _In_ CONST BSTR bstrValue, + _Outptr_ IXMLDOMElement** ppPropElement + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(ppPropElement, E_POINTER))) + { + if (SysStringLen(bstrPropName) <= 0 || + SysStringLen(bstrType) <= 0 || + SysStringLen(bstrValue) <= 0) + { + hr = E_INVALIDARG; + } + } + + if (SUCCEEDED(hr)) + { + // + // Create the scored property and value node + // + if (SUCCEEDED(hr = CreateProperty(bstrPropName, ppPropElement))) + { + CComPtr pValue(NULL); + + CComBSTR bstrValueElement(m_bstrFrameworkPrefix); + bstrValueElement += VALUE_ELEMENT_NAME; + + CComBSTR bstrTypeAttribName(m_bstrSchemaInstPrefix); + bstrTypeAttribName += SCHEMA_TYPE; + + CComBSTR bstrTypeAttribValue(m_bstrSchemaPrefix); + bstrTypeAttribValue += bstrType; + + hr = CreateXMLElement(bstrValueElement, FRAMEWORK_URI, &pValue); + + if(SUCCEEDED(hr)) + { + if (SUCCEEDED(hr = CreateXMLAttribute(pValue, bstrTypeAttribName, SCHEMA_INST_URI, bstrTypeAttribValue )) && + SUCCEEDED(hr = pValue->put_text(bstrValue))) + { + hr = (*ppPropElement)->appendChild(pValue, NULL); + } + } + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CPSHandler::CreateFWProperty + +Routine Description: + + This routine creates a property element of the given name. Note: this + method only creates the property element; it is up to the caller to + set the property value + +Arguments: + + bstrPropName - The name of the property + ppPropElement - Pointer to a IXMLDOMElement pointer that recieves the newly created Property element + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPSHandler::CreateFWProperty( + _In_ CONST BSTR bstrPropName, + _Outptr_ IXMLDOMElement** ppPropElement + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(ppPropElement, E_POINTER))) + { + *ppPropElement = NULL; + + if (SysStringLen(bstrPropName) <= 0) + { + hr = E_INVALIDARG; + } + } + + if (SUCCEEDED(hr)) + { + CComBSTR bstrTagName(m_bstrFrameworkPrefix); + bstrTagName += PROPERTY_ELEMENT_NAME; + + CComBSTR bstrAttribName(m_bstrFrameworkPrefix); + bstrAttribName += bstrPropName; + + hr = CreateXMLElement(bstrTagName, FRAMEWORK_URI, ppPropElement); + + if (SUCCEEDED(hr)) + { + if (*ppPropElement != NULL) + { + hr = CreateXMLAttribute(*ppPropElement, NAME_ATTRIBUTE_NAME, NULL, bstrAttribName ); + } + else + { + hr = E_FAIL; + } + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CPSHandler::CreateFWProperty + +Routine Description: + + This routine creates a property element of the given name. + +Arguments: + + bstrPropName - The name of the property to be created + bstrType - The type of the property value (integer, string etc.) + bstrValue - The value of the property + ppPropElement - Pointer to an IXMLDOMElement pointer that recieves the new element + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPSHandler::CreateFWProperty( + _In_ CONST BSTR bstrPropName, + _In_ CONST BSTR bstrType, + _In_ CONST BSTR bstrValue, + _Outptr_ IXMLDOMElement** ppPropElement + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(ppPropElement, E_POINTER))) + { + if (SysStringLen(bstrPropName) <= 0 || + SysStringLen(bstrType) <= 0 || + SysStringLen(bstrValue) <= 0) + { + hr = E_INVALIDARG; + } + } + + if (SUCCEEDED(hr)) + { + // + // Create the scored property and value node + // + if (SUCCEEDED(hr = CreateFWProperty(bstrPropName, ppPropElement))) + { + CComPtr pValue(NULL); + + CComBSTR bstrValueElement(m_bstrFrameworkPrefix); + bstrValueElement += VALUE_ELEMENT_NAME; + + CComBSTR bstrTypeAttribName(m_bstrSchemaInstPrefix); + bstrTypeAttribName += SCHEMA_TYPE; + + CComBSTR bstrTypeAttribValue(m_bstrSchemaPrefix); + bstrTypeAttribValue += bstrType; + + hr = CreateXMLElement(bstrValueElement, FRAMEWORK_URI, &pValue); + + if(SUCCEEDED(hr)) + { + if (SUCCEEDED(hr = CreateXMLAttribute(pValue, bstrTypeAttribName, SCHEMA_INST_URI, bstrTypeAttribValue )) && + SUCCEEDED(hr = pValue->put_text(bstrValue))) + { + hr = (*ppPropElement)->appendChild(pValue, NULL); + } + } + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CPSHandler::CreateScoredProperty + +Routine Description: + + This routine creates a scored property. Note: this does not intialise + the scored property value - this is the responsibility of the caller + +Arguments: + + bstrPropName - The name of the property element to be created + ppScoredPropElement - Pointer to an IXMLDOMElement that recieves the new element + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPSHandler::CreateScoredProperty( + _In_ CONST BSTR bstrPropName, + _Outptr_ IXMLDOMElement** ppScoredPropElement + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(ppScoredPropElement, E_POINTER))) + { + *ppScoredPropElement = NULL; + + if (SysStringLen(bstrPropName) <= 0) + { + hr = E_INVALIDARG; + } + } + + if (SUCCEEDED(hr)) + { + CComBSTR bstrTagName(m_bstrFrameworkPrefix); + bstrTagName += SCORED_PROP_ELEMENT_NAME; + + CComBSTR bstrAttribName(m_bstrKeywordsPrefix); + bstrAttribName += bstrPropName; + + hr = CreateXMLElement(bstrTagName, FRAMEWORK_URI, ppScoredPropElement); + + if (SUCCEEDED(hr)) + { + if (*ppScoredPropElement != NULL) + { + hr = CreateXMLAttribute(*ppScoredPropElement, NAME_ATTRIBUTE_NAME, NULL, bstrAttribName ); + } + else + { + hr = E_FAIL; + } + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CPSHandler::CreateScoredProperty + +Routine Description: + + This routine creates a scored property. + +Arguments: + + bstrPropName - The name of the property element to be created + bstrType - The type of the value to be created (integer, string etc.) + bstrValue - The value to be set as a string + ppScoredPropElement - Pointer to an IXMLDOMElement that recieves the new element + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPSHandler::CreateScoredProperty( + _In_ CONST BSTR bstrPropName, + _In_ CONST BSTR bstrType, + _In_ CONST BSTR bstrValue, + _Outptr_ IXMLDOMElement** ppScoredPropElement + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(ppScoredPropElement, E_POINTER))) + { + if (SysStringLen(bstrPropName) <= 0 || + SysStringLen(bstrType) <= 0 || + SysStringLen(bstrValue) <= 0) + { + hr = E_INVALIDARG; + } + } + + if (SUCCEEDED(hr)) + { + // + // Create the scored property and value node + // + if (SUCCEEDED(hr = CreateScoredProperty(bstrPropName, ppScoredPropElement))) + { + CComPtr pValue(NULL); + + CComBSTR bstrValueElement(m_bstrFrameworkPrefix); + bstrValueElement += VALUE_ELEMENT_NAME; + + CComBSTR bstrTypeAttribName(m_bstrSchemaInstPrefix); + bstrTypeAttribName += SCHEMA_TYPE; + + CComBSTR bstrTypeAttribValue(m_bstrSchemaPrefix); + bstrTypeAttribValue += bstrType; + + hr = CreateXMLElement(bstrValueElement, FRAMEWORK_URI, &pValue); + + if(SUCCEEDED(hr)) + { + if (SUCCEEDED(hr = CreateXMLAttribute(pValue, bstrTypeAttribName, SCHEMA_INST_URI, bstrTypeAttribValue )) && + SUCCEEDED(hr = pValue->put_text(bstrValue))) + { + hr = (*ppScoredPropElement)->appendChild(pValue, NULL); + } + } + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CPSHandler::CreateScoredProperty + +Routine Description: + + This routine creates a scored property of type string. + +Arguments: + + bstrPropName - The name of the property element to be created + bstrValue - The string value to be set + ppScoredPropElement - Pointer to an IXMLDOMElement that recieves the new element + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPSHandler::CreateScoredProperty( + _In_ CONST BSTR bstrPropName, + _In_ CONST BSTR bstrValue, + _Outptr_ IXMLDOMElement** ppScoredPropElement + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(ppScoredPropElement, E_POINTER))) + { + if (SysStringLen(bstrPropName) > 0 && + SysStringLen(bstrValue) > 0) + { + // + // Create the scored property and value node + // + hr = CreateScoredProperty(bstrPropName, CComBSTR(SCHEMA_STRING), bstrValue, ppScoredPropElement); + } + else + { + hr = E_INVALIDARG; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CPSHandler::CreateScoredProperty + +Routine Description: + + This routine creates a scored property of type INT. + +Arguments: + + bstrPropName - The name of the property element to be created + intValue - The INT value to be set + ppScoredPropElement - Pointer to an IXMLDOMElement that recieves the new element + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPSHandler::CreateScoredProperty( + _In_ CONST BSTR bstrPropName, + _In_ CONST INT intValue, + _Outptr_ IXMLDOMElement** ppScoredPropElement + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(ppScoredPropElement, E_POINTER))) + { + if (SysStringLen(bstrPropName) <= 0) + { + hr = E_INVALIDARG; + } + } + + if (SUCCEEDED(hr)) + { + try + { + // + // Construct the value string + // + CStringXDW cstrValue; + cstrValue.Format(L"%i", intValue); + + // + // Create the scored property and value node + // + hr = CreateScoredProperty(bstrPropName, + CComBSTR(SCHEMA_INTEGER), + CComBSTR(cstrValue.AllocSysString()), + ppScoredPropElement); + } + catch (CXDException& e) + { + hr = e; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CPSHandler::CreateScoredProperty + +Routine Description: + + This routine creates a scored property of type REAL. + +Arguments: + + bstrPropName - The name of the property element to be created + realValue - The REAL value to be set + ppScoredPropElement - Pointer to an IXMLDOMElement that recieves the new element + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPSHandler::CreateScoredProperty( + _In_ CONST BSTR bstrPropName, + _In_ CONST REAL realValue, + _Outptr_ IXMLDOMElement** ppScoredPropElement + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(ppScoredPropElement, E_POINTER))) + { + if (SysStringLen(bstrPropName) <= 0) + { + hr = E_INVALIDARG; + } + } + + if (SUCCEEDED(hr)) + { + try + { + // + // Construct the value string + // + CStringXDW cstrValue; + cstrValue.Format(L"%.2f", realValue); + + // + // Create the scored property and value node + // + hr = CreateScoredProperty(bstrPropName, + CComBSTR(SCHEMA_DECIMAL), + CComBSTR(cstrValue.AllocSysString()), + ppScoredPropElement); + } + catch (CXDException& e) + { + hr = e; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CPSHandler::QueryNode + +Routine Description: + + This routine checks for the existence of a node given the XPath + query passed in + +Arguments: + + bstrQuery - The XPath query defining the node or nodes to be located + +Return Value: + + HRESULT + S_OK - On success + E_ELEMENT_NOT_FOUND - If node does not exist + E_* - On error + +--*/ +HRESULT +CPSHandler::QueryNode( + _In_z_ BSTR bstrQuery + ) +{ + HRESULT hr = S_OK; + + // + // Validate input parameters + // + if (SysStringLen(bstrQuery) > 0) + { + CComPtr pNode(NULL); + + hr = GetNode(bstrQuery, &pNode); + } + else + { + hr = E_INVALIDARG; + } + + if (hr == S_FALSE) + { + hr = E_ELEMENT_NOT_FOUND; + } + + ERR_ON_HR_EXC(hr, E_ELEMENT_NOT_FOUND); + return hr; +} + +/*++ + +Routine Name: + + CPSHandler::QueryNodeValue + +Routine Description: + + This routine locates the node specified by the XPath query passed in and + returns the value of the "value" attribute as a string. + +Arguments: + + bstrQuery - The XPath query locating the node to retrieve the value for + pbstrOption - Pointer to a BSTR to recieve the value string + +Return Value: + + HRESULT + S_OK - On success + E_ELEMENT_NOT_FOUND - If node does not exist + E_* - On error + +--*/ +HRESULT +CPSHandler::QueryNodeValue( + _In_z_ BSTR bstrQuery, + _Outptr_ BSTR* pbstrValue + ) +{ + HRESULT hr = S_OK; + + // + // Validate input parameters + // + if (SUCCEEDED(hr = CHECK_POINTER(pbstrValue, E_POINTER))) + { + *pbstrValue = NULL; + + if (SysStringLen(bstrQuery) > 0) + { + hr = GetNodeValue(bstrQuery, pbstrValue); + } + else + { + hr = E_INVALIDARG; + } + } + + if (hr == S_FALSE) + { + hr = E_ELEMENT_NOT_FOUND; + } + + ERR_ON_HR_EXC(hr, E_ELEMENT_NOT_FOUND); + return hr; +} + +/*++ + +Routine Name: + + CPSHandler::QueryNodeValue + +Routine Description: + + This routine locates the node specified by the XPath query passed in and + returns the value of the "value" attribute as an INT. + +Arguments: + + bstrQuery - The XPath query locating the node to retrieve the value for + pValue - Pointer to an INT to recieve the value + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPSHandler::QueryNodeValue( + _In_z_ BSTR bstrQuery, + _Out_ INT* pValue + ) +{ + HRESULT hr = S_OK; + + CComBSTR bstrValue; + if (SUCCEEDED(hr = CHECK_POINTER(pValue, E_POINTER))) + { + if (SysStringLen(bstrQuery) <= 0) + { + hr = E_INVALIDARG; + } + } + + if (SUCCEEDED(hr) && + SUCCEEDED(hr = QueryNodeValue(bstrQuery, &bstrValue))) + { + *pValue = static_cast(_wtoi(bstrValue)); + } + + ERR_ON_HR_EXC(hr, E_ELEMENT_NOT_FOUND); + return hr; +} + +/*++ + +Routine Name: + + CPSHandler::QueryNodeValue + +Routine Description: + + This routine locates the node specified by the XPath query passed in and + returns the value of the "value" attribute as a REAL. + +Arguments: + + bstrQuery - The XPath query locating the node to retrieve the value for + pValue - Pointer to a REAL to recieve the value + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPSHandler::QueryNodeValue( + _In_z_ BSTR bstrQuery, + _Out_ REAL* pValue + ) +{ + HRESULT hr = S_OK; + + CComBSTR bstrValue; + if (SUCCEEDED(hr = CHECK_POINTER(pValue, E_POINTER))) + { + if (SysStringLen(bstrQuery) <= 0) + { + hr = E_INVALIDARG; + } + } + + if (SUCCEEDED(hr) && + SUCCEEDED(hr = QueryNodeValue(bstrQuery, &bstrValue))) + { + *pValue = static_cast(_wtof(bstrValue)); + } + + ERR_ON_HR_EXC(hr, E_ELEMENT_NOT_FOUND); + return hr; +} + +/*++ + +Routine Name: + + CPSHandler::GetNodeValue + +Routine Description: + + This routine retrieves the value of a node given the XPath query to the node + +Arguments: + + bstrNodeQuery - The XPath query for the node from which the value should be retrieved + pbstrValue - Pointer to ta BSTR that recieves the value of the node + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +Note: + + The annotation for pbstrValue is intended to express that the BSTR may + be NULL when S_FALSE is returned, but not when S_OK is returned. + + In any case, when a failure HRESULT is returned, all out parameter + annotations are ignored. + +--*/ +HRESULT +CPSHandler::GetNodeValue( + _In_z_ BSTR bstrNodeQuery, + _Inout_ _At_(*pbstrValue, _Pre_maybenull_) + _When_(return == S_FALSE, _At_(*pbstrValue, _Post_maybenull_)) + _When_(return != S_FALSE, _At_(*pbstrValue, _Post_valid_)) + BSTR* pbstrValue + ) +{ + HRESULT hr = S_OK; + + CComPtr pFeatureNode(NULL); + + if (SUCCEEDED(hr = CHECK_POINTER(pbstrValue, E_POINTER))) + { + SysFreeString(*pbstrValue); + *pbstrValue = NULL; + if (SysStringLen(bstrNodeQuery) <= 0) + { + hr = E_INVALIDARG; + } + } + + if (SUCCEEDED(hr) && + SUCCEEDED(hr = GetNode(bstrNodeQuery, &pFeatureNode)) && + hr != S_FALSE) + { + // + // Scored properties can either be defined as "Value" or "ParameterRef" + // Find out which of these applies to this property and handle accordingly + // + CComBSTR bstrValue(m_bstrFrameworkPrefix); + bstrValue += VALUE_ELEMENT_NAME; + + CComBSTR bstrParamRef(m_bstrFrameworkPrefix); + bstrParamRef += PARAM_REF_ELEMENT_NAME; + + CComVariant varValue; + + CComPtr pPropertyNode(NULL); + if (SUCCEEDED(hr = pFeatureNode->selectSingleNode(bstrValue, &pPropertyNode)) && + hr != S_FALSE) + { + // + // Value node. Just retrieve the node value + // + hr = pPropertyNode->get_nodeTypedValue(&varValue); + } + else if (SUCCEEDED(hr = pFeatureNode->selectSingleNode(bstrParamRef, &pPropertyNode)) && + hr != S_FALSE) + { + // + // Property defined by parameter ref. Retrieve the name and look up the value + // from the parameter init elements + // + CComPtr pParamInitList(NULL); + CComBSTR bstrParamRefValue; + + if (SUCCEEDED(hr = GetAttributeValue(pPropertyNode, CComBSTR(NAME_ATTRIBUTE_NAME), &bstrParamRefValue)) && + hr != S_FALSE && + SUCCEEDED(hr = GetNodes(CComBSTR(PARAM_INIT_ELEMENT_NAME), &pParamInitList)) && + hr != S_FALSE) + { + CComBSTR bstrParamInit; + CComPtr pInitNode(NULL); + + hr = pParamInitList->reset(); + + while (SUCCEEDED(hr) && + hr != S_FALSE) + { + if (SUCCEEDED(hr = pParamInitList->nextNode(&pInitNode)) && hr != S_FALSE && pInitNode != NULL) + { + hr = GetAttributeValue(pInitNode, CComBSTR(NAME_ATTRIBUTE_NAME), &bstrParamInit); + if (SUCCEEDED(hr) && bstrParamInit == bstrParamRefValue) + { + hr = pInitNode->get_nodeTypedValue(&varValue); + break; + } + } + + + // + // Release the node and name before getting the next + // + pInitNode = NULL; + bstrParamInit.Empty(); + } + } + } + + if (SUCCEEDED(hr) && + hr != S_FALSE && + SysStringLen(varValue.bstrVal) > 0) + { + *pbstrValue = ::SysAllocString(varValue.bstrVal); + + if (*pbstrValue == NULL) + { + hr = E_OUTOFMEMORY; + } + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CPSHandler::GetAttributeValue + +Routine Description: + + This routine retrieves the value of a named attribute as a string from a DOM node + +Arguments: + + pNode - Pointer to the DOM node to retrieve the attribute value from + bstrAttribName - The name of the attribute + pbstrResult - Pointer to a BSTR that recieves the attribute value + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPSHandler::GetAttributeValue( + _In_ CONST IXMLDOMNode* pNode, + _In_z_ BSTR bstrAttribName, + _Outptr_result_maybenull_ BSTR* pbstrResult + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pNode, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pbstrResult, E_POINTER))) + { + if (SysStringLen(bstrAttribName) <= 0) + { + hr = E_INVALIDARG; + } + } + + if (SUCCEEDED(hr)) + { + *pbstrResult = NULL; + + // + // Map the associated attributes and get the string result + // + CComPtr pIXMLDOMNamedNodeMap(NULL); + CComPtr pSubNode(NULL); + + if (SUCCEEDED(hr = const_cast(pNode)->get_attributes(&pIXMLDOMNamedNodeMap)) && + hr != S_FALSE && + SUCCEEDED(hr = pIXMLDOMNamedNodeMap->getNamedItem(bstrAttribName, &pSubNode)) && + hr != S_FALSE) + { + hr = pSubNode->get_text(pbstrResult); + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CPSHandler::GetNodes + +Routine Description: + + This routine returns a list of all the nodes in the PrintTicket with the + specified element name + +Arguments: + + ppParamInit - Pointer to an IXMLDOMNodeList pointer that recieves the node list + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPSHandler::GetNodes( + _In_ BSTR bstrElementName, + _Outptr_ IXMLDOMNodeList** ppNodeList + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(ppNodeList, E_POINTER))) + { + if (SysStringLen(bstrElementName) > 0) + { + *ppNodeList = NULL; + + // + // Retrieve all psf:ParameterInit nodes in the PrintTicket + // + CComBSTR bstrParamInitQuery(L"//"); + bstrParamInitQuery += m_bstrFrameworkPrefix; + bstrParamInitQuery += bstrElementName; + + hr = m_pPrintDocument->selectNodes(bstrParamInitQuery, ppNodeList); + } + else + { + hr = E_FAIL; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CPSHandler::CreateScoredProperty + +Routine Description: + + This routine creates a scored property using the value node passed in. + +Arguments: + + bstrPropName - The name of the property element to be created + pValueNode - Pointer to the IXMLDOMNode that represents the scored property value + ppScoredPropElement - Pointer to an IXMLDOMElement that recieves the new element + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPSHandler::CreateScoredProperty( + _In_ CONST BSTR bstrPropName, + _In_ IXMLDOMNode* pValueNode, + _Outptr_ IXMLDOMElement** ppScoredPropElement + ) +{ + HRESULT hr = S_OK; + + // + // Validate parameters then create the scored property and value node + // + if (SUCCEEDED(hr = CHECK_POINTER(pValueNode, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(ppScoredPropElement, E_POINTER))) + { + if (SysStringLen(bstrPropName) <= 0) + { + hr = E_INVALIDARG; + } + } + + if (SUCCEEDED(hr) && + SUCCEEDED(hr = CreateScoredProperty(bstrPropName, ppScoredPropElement))) + { + hr = (*ppScoredPropElement)->appendChild(pValueNode, NULL); + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CPSHandler::GetPrefixFromURI + +Routine Description: + + Obtains the Prefix associated with a Namespace URI from an XML PrintSchema Document. + +Arguments: + + bstrNamespaceURI - Namespace URI to be used in look-up. + bstrNamespacePrefix - Namespace Prefix to be returned. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPSHandler::GetPrefixFromURI( + _In_z_ BSTR bstrNamespaceURI, + _Outptr_result_maybenull_ BSTR* bstrNamespacePrefix + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(bstrNamespacePrefix, E_POINTER))) + { + if (SysStringLen(bstrNamespaceURI) <= 0) + { + hr = E_INVALIDARG; + } + } + + if (SUCCEEDED(hr)) + { + *bstrNamespacePrefix = NULL; + + try + { + // + // Construct the Root Query string + // + CStringXDW cstrRootQuery; + cstrRootQuery.Format(szPTRootQuery, szTmpNS, m_bstrDocumentType); + + // + // Find the PrintSchema element so we can retrieve the private namespace prefix + // + CComPtr pPTNode(NULL); + CComPtr pPTAtts(NULL); + + if (SUCCEEDED(hr = GetNode(CComBSTR(cstrRootQuery), &pPTNode)) && + hr != S_FALSE && + SUCCEEDED(hr = pPTNode->get_attributes(&pPTAtts)) && + SUCCEEDED(hr = pPTAtts->reset())) + { + // + // Iterate over all attributes and match the node value against + // the namespace URI + // + BOOL bMatched = FALSE; + CComPtr pAttNode(NULL); + + while (SUCCEEDED(hr) && + !bMatched && + SUCCEEDED(hr = pPTAtts->nextNode(&pAttNode)) && + hr != S_FALSE) + { + CComVariant varValue; + + if (SUCCEEDED(hr = pAttNode->get_nodeValue(&varValue))) + { + if (CComBSTR(varValue.bstrVal) == bstrNamespaceURI) + { + bMatched = TRUE; + } + } + + if (!bMatched) + { + // + // No match - free the attribute node before retrieving the next + // + pAttNode = NULL; + } + } + + if (SUCCEEDED(hr) && + bMatched) + { + // + // If we match then get the node name and strip xmlns: to derive + // the private namespace prefix + // + CStringXDW cstrNSPrefix; + CComBSTR bstrNodeName; + + if (SUCCEEDED(hr = pAttNode->get_nodeName(&bstrNodeName))) + { + cstrNSPrefix = bstrNodeName; + CStringXDW cstrXMLNS(L"xmlns:"); + + if (cstrNSPrefix.Find(cstrXMLNS) != 0 || + cstrNSPrefix.Delete(0, cstrXMLNS.GetLength()) <= 0) + { + ERR("Could not create private namespace prefix correctly\n"); + + hr = E_FAIL; + } + else + { + cstrNSPrefix += L":"; + + SysFreeString(*bstrNamespacePrefix); + *bstrNamespacePrefix = cstrNSPrefix.AllocSysString(); + } + } + } + } + else + { + ERR("Failed to find the PC root element.\n"); + } + } + catch (CXDException& e) + { + hr = e; + } + } + + ERR_ON_HR(hr); + return hr; +} + +HRESULT +CPSHandler::CreateXMLAttribute( + _Inout_ IXMLDOMElement *pTarget, + _In_ PCWSTR pszName, + _In_opt_ PCWSTR pszTargetURI, + _In_ PCWSTR pszValue + ) +/*++ + +Routine Description: + + This routine adds a new attribute to the given XML element. The URI + parameter must be present, but may be an empty string. + + If this routine fails, the document being constructed should be + considered invalid, and be thrown out in its entirity. + + The newly created attribute will be appended to the list of attributes on the element + +Arguments: + + pTarget - the element to which the attribute is to be added + pszName - the name of the attribtue + pszTargetURI - the URI in which the attribute should reside + pszValue - the value to put in the attribute + +Returns: + + S_OK on success, else + E_* on failure + +--*/ +{ + HRESULT hr = S_OK; + CComPtr pCurrentAttr; + CComPtr pCurrentNode; + + if( !( pTarget && pszName && pszValue ) ) + { + hr = E_INVALIDARG; + } + + if(SUCCEEDED(hr)) + { + VARIANT type; + VariantInit( &type ); + V_VT(&type) = VT_I4; + V_I4(&type) = NODE_ATTRIBUTE; + + hr = m_pPrintDocument->createNode(type, const_cast(pszName), const_cast(pszTargetURI), &pCurrentNode); + + VariantClear( &type ); + } + + if( SUCCEEDED(hr) ) + { + hr = pCurrentNode->QueryInterface( IID_IXMLDOMAttribute, (void**)&pCurrentAttr ); + } + + if( SUCCEEDED(hr) ) + { + VARIANT attrVal; + BSTR bstrValue = SysAllocString(pszValue); + + if( bstrValue ) + { + VariantInit(&attrVal); + V_VT(&attrVal) = VT_BSTR; + V_BSTR(&attrVal) = bstrValue; + hr = pCurrentAttr->put_value(attrVal); + + if( SUCCEEDED(hr) ) + { + hr = VariantClear(&attrVal); + } + else + { + VariantClear(&attrVal); + } + } + else + { + hr = E_OUTOFMEMORY; + } + } + + if( SUCCEEDED(hr) ) + { + hr = pTarget->setAttributeNode( pCurrentAttr, NULL ); + } + + return hr; +} + +HRESULT +CPSHandler::CreateXMLElement( + _In_ PCWSTR pszName, + _In_ PCWSTR pszTargetURI, + _Out_opt_ IXMLDOMElement **ppEl + ) +/*++ + +Routine Description: + + Create a new DOM element using the given QName and URI. Implemented using DOMDocument->CreateNode. + +Arguments: + + pszName - The QName of the element to be created + pszTargetUri - The namespace in which the created element lives. The + caller does not have control over the prefix... just the URI + ppEl - If the caller needs a pointer to the newly created node, this should + be a non-null + +Return Value: + + S_OK on success, + E_* on failure. Common values that would be expected + include E_OUTOFMEMORY, and E_INVALIDARG. + +--*/ +{ + HRESULT hr = S_OK; + CComPtr pCurrentNode; + + if( !( pszName && pszTargetURI ) ) + { + hr = E_INVALIDARG; + } + + if(SUCCEEDED(hr)) + { + VARIANT type; + VariantInit( &type ); + V_VT(&type) = VT_I4; + V_I4(&type) = NODE_ELEMENT; + hr = m_pPrintDocument->createNode( type, const_cast(pszName), const_cast(pszTargetURI), &pCurrentNode ); + VariantClear( &type ); + } + + // + // Only give the client back the new value element if we succeed. + // + if( SUCCEEDED(hr) && ppEl ) + { + hr = pCurrentNode->QueryInterface( IID_IXMLDOMElement, (void**)ppEl ); + } + + return hr; +} diff --git a/print/XPSDrvSmpl/src/common/pshndlr.h b/print/XPSDrvSmpl/src/common/pshndlr.h new file mode 100644 index 00000000..22d76863 --- /dev/null +++ b/print/XPSDrvSmpl/src/common/pshndlr.h @@ -0,0 +1,218 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +File Name: + + pshndlr.h + +Abstract: + + Base PrintSchema Document handler class definition. + This class provides common PrintTicket / PrintCapabilities handling functionality. + A class can derive from this base class to get PrintTicket/PrintCapabilities + unspecific XML handling functionality. + + Note: The PrintSchema handler code is only intended to work with the sdtandard + public PrintSchema keywords. + +--*/ + +#pragma once + +#include "schema.h" + +typedef vector< CComPtr > PTDOMElementVector; + +class CPSHandler +{ +public: + // + // Constructors and destructors + // + CPSHandler( + _In_z_ BSTR bstrDocumentType, + _In_ IXMLDOMDocument2 *pPrintDocument + ); + + virtual ~CPSHandler(); + +public: + HRESULT + DeleteNode( + _In_ IXMLDOMNode* pNode + ); + + HRESULT + DeletePrivateFeatures( + _In_z_ BSTR bstrPrivateNS + ); + +protected: + HRESULT + QueryNode( + _In_z_ BSTR bstrQuery + ); + + HRESULT + QueryNodeValue( + _In_z_ BSTR bstrQuery, + _Outptr_ BSTR* pbstrValue + ); + + HRESULT + QueryNodeValue( + _In_z_ BSTR bstrQuery, + _Out_ REAL* pValue + ); + + HRESULT + QueryNodeValue( + _In_z_ BSTR bstrQuery, + _Out_ INT* pValue + ); + + HRESULT + GetNodeValue( + _In_z_ BSTR bstrNodeQuery, + _Inout_ _At_(*pbstrValue, _Pre_maybenull_) + _When_(return == S_FALSE, _At_(*pbstrValue, _Post_maybenull_)) + _When_(return != S_FALSE, _At_(*pbstrValue, _Post_valid_)) + BSTR* pbstrValue + ); + + HRESULT + GetAttributeValue( + _In_ CONST IXMLDOMNode* pNode, + _In_z_ BSTR bstrAttribName, + _Outptr_result_maybenull_ BSTR* pbstrResult + ); + + HRESULT + GetNodes( + _In_ BSTR bstrElementName, + _Outptr_ IXMLDOMNodeList** ppNodeList + ); + + HRESULT + CreateProperty( + _In_ CONST BSTR bstrPropName, + _Outptr_ IXMLDOMElement** ppPropElement + ); + + HRESULT + CreateProperty( + _In_ CONST BSTR bstrPropName, + _In_ CONST BSTR bstrType, + _In_ CONST BSTR bstrValue, + _Outptr_ IXMLDOMElement** ppPropElement + ); + + HRESULT + CreateFWProperty( + _In_ CONST BSTR bstrPropName, + _Outptr_ IXMLDOMElement** ppPropElement + ); + + HRESULT + CreateFWProperty( + _In_ CONST BSTR bstrPropName, + _In_ CONST BSTR bstrType, + _In_ CONST BSTR bstrValue, + _Outptr_ IXMLDOMElement** ppPropElement + ); + + HRESULT + CreateScoredProperty( + _In_ CONST BSTR bstrPropName, + _Outptr_ IXMLDOMElement** ppScoredPropElement + ); + + HRESULT + CreateScoredProperty( + _In_ CONST BSTR bstrPropName, + _In_ CONST BSTR bstrType, + _In_ CONST BSTR bstrValue, + _Outptr_ IXMLDOMElement** ppScoredPropElement + ); + + HRESULT + CreateScoredProperty( + _In_ CONST BSTR bstrPropName, + _In_ CONST BSTR bstrValue, + _Outptr_ IXMLDOMElement** ppScoredPropElement + ); + + HRESULT + CreateScoredProperty( + _In_ CONST BSTR bstrPropName, + _In_ CONST INT intValue, + _Outptr_ IXMLDOMElement** ppScoredPropElement + ); + + HRESULT + CreateScoredProperty( + _In_ CONST BSTR bstrPropName, + _In_ CONST REAL realValue, + _Outptr_ IXMLDOMElement** ppScoredPropElement + ); + + HRESULT + CreateScoredProperty( + _In_ CONST BSTR bstrPropName, + _In_ IXMLDOMNode* pValueNode, + _Outptr_ IXMLDOMElement** ppScoredPropElement + ); + + HRESULT + GetNode( + _In_z_ BSTR bstrNodeQuery, + _Outptr_ IXMLDOMNode** ppNode + ); + + HRESULT + CreateXMLAttribute( + _Inout_ IXMLDOMElement *pTarget, + _In_ PCWSTR pszName, + _In_opt_ PCWSTR pszTargetURI, + _In_ PCWSTR pszValue + ); + + HRESULT + CreateXMLElement( + _In_ PCWSTR pszName, + _In_ PCWSTR pszTargetURI, + _Out_opt_ IXMLDOMElement **ppEl + ); + +private: + + HRESULT + GetPrefixFromURI( + _In_z_ BSTR bstrNSURI, + _Outptr_result_maybenull_ BSTR* bstrNSPrefix + ); + +protected: + // + // Document and Type + // + CComPtr m_pPrintDocument; + CComBSTR m_bstrDocumentType; + + // + // W3 namespace prefixes + // + CComBSTR m_bstrSchemaPrefix; + CComBSTR m_bstrSchemaInstPrefix; + + // + // Namespace abbreviations + // + CComBSTR m_bstrFrameworkPrefix; + CComBSTR m_bstrKeywordsPrefix; + CComBSTR m_bstrUserKeywordsPrefix; +}; + diff --git a/print/XPSDrvSmpl/src/common/psizedata.h b/print/XPSDrvSmpl/src/common/psizedata.h new file mode 100644 index 00000000..aad375a4 --- /dev/null +++ b/print/XPSDrvSmpl/src/common/psizedata.h @@ -0,0 +1,44 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + psizedata.h + +Abstract: + + PageMediaSize data structure definition. This provides a convenient + description of the PrintSchema PageMediaSize feature. + +--*/ + +#pragma once + +#include "psizeschema.h" + +namespace XDPrintSchema +{ + namespace PageMediaSize + { + struct PageMediaSizeData + { + PageMediaSizeData() : + pageWidth(215900), + pageHeight(279400) + { + } + + INT pageWidth; + INT pageHeight; + }; + } +} + diff --git a/print/XPSDrvSmpl/src/common/psizepthndlr.cpp b/print/XPSDrvSmpl/src/common/psizepthndlr.cpp new file mode 100644 index 00000000..893c16df --- /dev/null +++ b/print/XPSDrvSmpl/src/common/psizepthndlr.cpp @@ -0,0 +1,136 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + psizepthndlr.cpp + +Abstract: + + PageMediaSize PrintTicket handler implementation. Derived from CPTHandler, + this provides PageMediaSize specific Get method acting on the passed in + PrintTicket (as a DOM document). + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdexcept.h" +#include "psizepthndlr.h" + +using XDPrintSchema::PageMediaSize::PageMediaSizeData; +using XDPrintSchema::PageMediaSize::MediaSizeHeight; +using XDPrintSchema::PageMediaSize::MediaSizeWidth; +using XDPrintSchema::PageMediaSize::PAGESIZE_FEATURE; +using XDPrintSchema::PageMediaSize::PAGESIZE_PROPS; + +/*++ + +Routine Name: + + CPageSizePTHandler::CPageSizePTHandler + +Routine Description: + + CPageSizePTHandler class constructor + +Arguments: + + pPrintTicket - Pointer to the DOM document representation of the PrintTicket + +Return Value: + + None + +--*/ +CPageSizePTHandler::CPageSizePTHandler( + _In_ IXMLDOMDocument2* pPrintTicket + ) : + CPTHandler(pPrintTicket) +{ +} + +/*++ + +Routine Name: + + CPageSizePTHandler::~CPageSizePTHandler + +Routine Description: + + CPageSizePTHandler class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CPageSizePTHandler::~CPageSizePTHandler() +{ +} + +/*++ + +Routine Name: + + CPageSizePTHandler::GetData + +Routine Description: + + The routine fills the data structure passed in with page size data retrieved from + the PrintTicket passed to the class constructor. + +Arguments: + + pPageMediaSizeData - Pointer to the page size data structure to be filled in + +Return Value: + + HRESULT + S_OK - On success + E_ELEMENT_NOT_FOUND - Feature not present in PrintTicket + E_* - On error + +--*/ +HRESULT +CPageSizePTHandler::GetData( + _Out_ PageMediaSizeData* pPageMediaSizeData + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pPageMediaSizeData, E_POINTER))) + { + CComBSTR bstrPageSizeOption; + + // + // We don't actually need the pages size option name, just the dimensions + // + if (SUCCEEDED(hr = GetFeatureOption(CComBSTR(PAGESIZE_FEATURE), &bstrPageSizeOption)) && + SUCCEEDED(hr = GetScoredPropertyValue(CComBSTR(PAGESIZE_FEATURE), + CComBSTR(PAGESIZE_PROPS[MediaSizeWidth]), + &pPageMediaSizeData->pageWidth))) + { + hr = GetScoredPropertyValue(CComBSTR(PAGESIZE_FEATURE), + CComBSTR(PAGESIZE_PROPS[MediaSizeHeight]), + &pPageMediaSizeData->pageHeight); + } + } + + ERR_ON_HR_EXC(hr, E_ELEMENT_NOT_FOUND); + return hr; +} + diff --git a/print/XPSDrvSmpl/src/common/psizepthndlr.h b/print/XPSDrvSmpl/src/common/psizepthndlr.h new file mode 100644 index 00000000..68e77fdb --- /dev/null +++ b/print/XPSDrvSmpl/src/common/psizepthndlr.h @@ -0,0 +1,45 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + psizepthndlr.h + +Abstract: + + PageMediaSize PrintTicket handling definition. The PageMediaSize PT handler + is used to extract PageMediaSize settings from a PrintTicket and populate + the PageMediaSize data structure with the retrieved settings. The class also + defines a method for setting the feature in the PrintTicket given the + data structure. + +--*/ + +#pragma once + +#include "pthndlr.h" +#include "psizedata.h" + +class CPageSizePTHandler : public CPTHandler +{ +public: + CPageSizePTHandler( + _In_ IXMLDOMDocument2* pPrintTicket + ); + + virtual ~CPageSizePTHandler(); + + HRESULT + GetData( + _Out_ XDPrintSchema::PageMediaSize::PageMediaSizeData* pPageMediaSizeData + ); +}; + diff --git a/print/XPSDrvSmpl/src/common/psizeschema.cpp b/print/XPSDrvSmpl/src/common/psizeschema.cpp new file mode 100644 index 00000000..448ccb2c --- /dev/null +++ b/print/XPSDrvSmpl/src/common/psizeschema.cpp @@ -0,0 +1,32 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + psizeschema.cpp + +Abstract: + + PageMediaSize PrintSchema implementation. This implements the features, + options and enumerations that describe the PrintSchema PageMediaSize feature. + +--*/ + +#include "precomp.h" +#include "psizeschema.h" + +LPCWSTR XDPrintSchema::PageMediaSize::PAGESIZE_FEATURE = L"PageMediaSize"; + +LPCWSTR XDPrintSchema::PageMediaSize::PAGESIZE_PROPS[] = { + L"MediaSizeWidth", + L"MediaSizeHeight" +}; + diff --git a/print/XPSDrvSmpl/src/common/psizeschema.h b/print/XPSDrvSmpl/src/common/psizeschema.h new file mode 100644 index 00000000..253846c7 --- /dev/null +++ b/print/XPSDrvSmpl/src/common/psizeschema.h @@ -0,0 +1,55 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + psizeschema.h + +Abstract: + + PageMediaSize PrintSchema definition. This defines the features, options + and enumerations that describe the PrintSchema PageMediaSize feature within + a XDPrintSchema::PageMediaSize namespace. + +--*/ + +#pragma once + +#include "schema.h" + +namespace XDPrintSchema +{ + // + // PageMediaSize elements described as Printschema keywords + // + namespace PageMediaSize + { + // + // The feature name + // + extern LPCWSTR PAGESIZE_FEATURE; + + // + // We don't actually ever use the page size option names so they are + // omitted for brevity as there are many of them. + // + + enum EPageSizeProps + { + MediaSizeWidth = 0, EPageSizePropsMin = 0, + MediaSizeHeight, + EPageSizePropsMax + }; + + extern LPCWSTR PAGESIZE_PROPS[EPageSizePropsMax]; + } +} + diff --git a/print/XPSDrvSmpl/src/common/pthndlr.cpp b/print/XPSDrvSmpl/src/common/pthndlr.cpp new file mode 100644 index 00000000..61158c1f --- /dev/null +++ b/print/XPSDrvSmpl/src/common/pthndlr.cpp @@ -0,0 +1,1385 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +File Name: + + pthndlr.cpp + +Abstract: + + Base PrintTicket handler class implementation. This class provides common + PrintTicket handling functionality for any filter that requires print + ticket handling. A feature specific handler can derive from + this class to get feature unspecific XML handling functionality. + +--*/ + + +// +// Note on handling missing DOM nodes: +// +// Convert MSXML's S_FALSE to E_ELEMENT_NOT_FOUND. This allows clients to +// use the SUCCEEDED macro more effectively. +// +// E_ELEMENT_NOT_FOUND should not be propogated as an error to the +// filter pipeline or config module - treat as though the requested feature +// has not been enabled. +// + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdstring.h" +#include "pthndlr.h" +#include "ptquerybld.h" + +using XDPrintSchema::PRINTTICKET_NAME; +using XDPrintSchema::PARAM_INIT_ELEMENT_NAME; +using XDPrintSchema::PARAM_REF_ELEMENT_NAME; +using XDPrintSchema::NAME_ATTRIBUTE_NAME; +using XDPrintSchema::VALUE_ELEMENT_NAME; +using XDPrintSchema::SCHEMA_TYPE; +using XDPrintSchema::SCHEMA_INTEGER; +using XDPrintSchema::FEATURE_ELEMENT_NAME; +using XDPrintSchema::OPTION_ELEMENT_NAME; +using XDPrintSchema::FRAMEWORK_URI; +using XDPrintSchema::SCHEMA_INST_URI; + +/*++ + +Routine Name: + + CPTHandler::CPTHandler + +Routine Description: + + CPTHandler class constructor + +Arguments: + + pPrintTicket - Pointer to the DOM document representation of the PrintTicket + +Return Value: + + None + + Note: Base Class (CPSHandler) - Throws CXDException(HRESULT) on an error + +--*/ +CPTHandler::CPTHandler( + _In_ IXMLDOMDocument2 *pDOMDocument + ) : + CPSHandler(CComBSTR(PRINTTICKET_NAME), pDOMDocument) +{ +} + +/*++ + +Routine Name: + + CPTHandler::~CPTHandler + +Routine Description: + + CPTHandler class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CPTHandler::~CPTHandler() +{ +} + +/*++ + +Routine Name: + + CPTHandler::DeleteFeature + +Routine Description: + + This routine finds and deletes the named feature + +Arguments: + + bstrFeature - the feature name to be deleted + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPTHandler::DeleteFeature( + _In_z_ BSTR bstrFeature + ) +{ + HRESULT hr = S_OK; + + if (SysStringLen(bstrFeature) > 0) + { + // + // Find the feature node + // + CPTQueryBuilder propertyQuery(m_bstrFrameworkPrefix); + CComBSTR bstrQuery; + + CComPtr pFeatureNode(NULL); + + if (SUCCEEDED(hr = propertyQuery.AddFeature(m_bstrKeywordsPrefix, bstrFeature)) && + SUCCEEDED(hr = propertyQuery.GetQuery(&bstrQuery))) + { + // + // Keep querying and deleting till all instances of the feature are + // removed - generally this should be a single instance + // + while (SUCCEEDED(hr) && + SUCCEEDED(hr = GetNode(bstrQuery, &pFeatureNode)) && + hr != S_FALSE) + { + // + // Delete the feature node and all children, then locate and delete + // all orphaned parameter init nodes + // + if (SUCCEEDED(hr = DeleteNode(pFeatureNode))) + { + // + // We need to delete all orphaned paramater init elements. Construct a + // list of parameter ref nodes and parameter init nodes and delete parameter + // init nodes that do not have a corresponding reference. + // + CComPtr pInitList(NULL); + CComPtr pRefList(NULL); + + if (SUCCEEDED(hr = GetNodes(CComBSTR(PARAM_INIT_ELEMENT_NAME), &pInitList)) && + hr != S_FALSE && + SUCCEEDED(hr = GetNodes(CComBSTR(PARAM_REF_ELEMENT_NAME), &pRefList)) && + hr != S_FALSE) + { + hr = DeleteParamInitOrphans(pRefList, pInitList); + } + } + + // + // Release the feature node for the next pass + // + pFeatureNode = NULL; + } + } + } + else + { + hr = E_INVALIDARG; + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CPTHandler::DeleteParamInitOrphans + +Routine Description: + + When a feature is deleted it may orphan a set of parameter init nodes. + This routine takes a list of parameter init nodes and a list of parameter + ref nodes and deletes the init nodes with no corresponding ref node. + +Arguments: + + pRefList - pointer to a node list containined the ref nodes + pInitList - pointer to a node list containined the init nodes + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPTHandler::DeleteParamInitOrphans( + _In_ IXMLDOMNodeList* pRefList, + _Inout_ IXMLDOMNodeList* pInitList + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pRefList, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pInitList, E_POINTER))) + { + LONG cRefNodes = 0; + + if (SUCCEEDED(hr = pRefList->get_length(&cRefNodes)) && + cRefNodes == 0) + { + // + // There are no ref nodes - delete all init nodes + // + hr = DeleteNodeList(pInitList); + } + else + { + // + // Iterate over init list and search for a corresponding ref node + // + LONG cInitNodes = 0; + hr = pInitList->get_length(&cInitNodes); + + for (LONG cInitNode = 0; cInitNode < cInitNodes && SUCCEEDED(hr); cInitNode++) + { + CComPtr pInitNode(NULL); + CComBSTR bstrInitName; + + if (SUCCEEDED(hr = pInitList->get_item(cInitNode, &pInitNode)) && + hr != S_FALSE && + SUCCEEDED(hr = GetAttributeValue(pInitNode, + CComBSTR(NAME_ATTRIBUTE_NAME), + &bstrInitName)) && + hr != S_FALSE && + SUCCEEDED(hr = pRefList->reset())) + { + // + // Iterate over the ref list tring to match + // + BOOL bMatched = FALSE; + + for (LONG cRefNode = 0; cRefNode < cRefNodes && SUCCEEDED(hr) && !bMatched; cRefNode++) + { + CComPtr pRefNode(NULL); + CComBSTR bstrRefName; + if (SUCCEEDED(hr = pRefList->get_item(cRefNode, &pRefNode)) && + hr != S_FALSE && + SUCCEEDED(hr = GetAttributeValue(pRefNode, + CComBSTR(NAME_ATTRIBUTE_NAME), + &bstrRefName)) && + hr != S_FALSE) + { + if (bstrRefName == bstrInitName) + { + bMatched = TRUE; + } + } + } + + if (!bMatched) + { + // + // There were no matches - delete the init node + // + hr = DeleteNode(pInitNode); + } + } + } + } + } + + ERR_ON_HR(hr); + return hr; +} + + +/*++ + +Routine Name: + + CPTHandler::DeleteNodeList + +Routine Description: + + This routine deletes all nodes in a node list + +Arguments: + + pNodeList - the node list containing the nodes to be deleted + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPTHandler::DeleteNodeList( + _Inout_ IXMLDOMNodeList* pNodeList + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pNodeList, E_POINTER))) + { + LONG cNodes = 0; + + hr = pNodeList->get_length(&cNodes); + + for (LONG cNode = 0; cNode < cNodes && SUCCEEDED(hr); cNode++) + { + CComPtr pNode(NULL); + if (SUCCEEDED(hr = pNodeList->get_item(cNode, &pNode)) && + hr != S_FALSE) + { + hr = DeleteNode(pNode); + } + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CPTHandler::DeleteProperty + +Routine Description: + + This routine finds and deletes the named property + +Arguments: + + bstrProperty - the property name to be deleted + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPTHandler::DeleteProperty( + _In_z_ BSTR bstrProperty + ) +{ + HRESULT hr = S_OK; + + if (SysStringLen(bstrProperty) > 0) + { + // + // Find the property node + // + CPTQueryBuilder propertyQuery(m_bstrFrameworkPrefix); + CComBSTR bstrQuery; + + CComPtr pPropertyNode(NULL); + + if (SUCCEEDED(hr = propertyQuery.AddProperty(m_bstrFrameworkPrefix, bstrProperty)) && + SUCCEEDED(hr = propertyQuery.GetQuery(&bstrQuery)) && + SUCCEEDED(hr = GetNode(bstrQuery, &pPropertyNode)) && + hr != S_FALSE) + { + // + // Delete the property node and all children + // + hr = DeleteNode(pPropertyNode); + } + } + else + { + hr = E_INVALIDARG; + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CPTHandler::QueryNodeOption + +Routine Description: + + This routine locates the node specified by the XPath query passed in and + returns the value of the "name" attribute as a string. The PrintSchema + keyword prefix is stripped from the result. + +Arguments: + + bstrQuery - The XPath query locating the node to retrieve the value for + pbstrOption - Pointer to a BSTR to recieve the option string + +Return Value: + + HRESULT + S_OK - On success + E_ELEMENT_NOT_FOUND - If node does not exist + E_* - On error + +--*/ +HRESULT +CPTHandler::QueryNodeOption( + _In_z_ BSTR bstrQuery, + _Outptr_result_maybenull_z_ BSTR* pbstrOption + ) +{ + HRESULT hr = S_OK; + + // + // Validate input parameters + // + if (SUCCEEDED(hr = CHECK_POINTER(pbstrOption, E_POINTER))) + { + *pbstrOption = NULL; + + if (SysStringLen(bstrQuery) <= 0) + { + hr = E_INVALIDARG; + } + } + + // + // Given a bare PrintSchema query, retrieve the selected option + // + if (SUCCEEDED(hr)) + { + CComPtr pQueryNode(NULL); + + if (SUCCEEDED(hr = GetNode(bstrQuery, &pQueryNode)) && + hr != S_FALSE && + SUCCEEDED(hr = GetAttributeValue(pQueryNode, CComBSTR(NAME_ATTRIBUTE_NAME), pbstrOption)) && + hr != S_FALSE) + { + hr = StripKeywordNamespace(pbstrOption); + } + } + + if (hr == S_FALSE) + { + hr = E_ELEMENT_NOT_FOUND; + } + + ERR_ON_HR_EXC(hr, E_ELEMENT_NOT_FOUND); + return hr; +} + +/*++ + +Routine Name: + + CPTHandler::FeaturePresent + +Routine Description: + + This routine checks if the named feature is present in the PrintTicket + and optionally returns that node + +Arguments: + + bstrFeature - The feature name to be located + ppFeatureNode - optional paramter that recieves the node + +Return Value: + + HRESULT + S_OK - On success + E_ELEMENT_NOT_FOUND - If node does not exist + E_* - On error + +--*/ +HRESULT +CPTHandler::FeaturePresent( + _In_z_ BSTR bstrFeature, + _Outptr_opt_ IXMLDOMNode** ppFeatureNode + ) +{ + HRESULT hr = S_OK; + + // + // Validate input parameters + // + if (SysStringLen(bstrFeature) > 0) + { + // + // Find the feature node + // + CPTQueryBuilder propertyQuery(m_bstrFrameworkPrefix); + CComBSTR bstrQuery; + + CComPtr pFeatureNode(NULL); + + if (SUCCEEDED(hr = propertyQuery.AddFeature(m_bstrKeywordsPrefix, bstrFeature)) && + SUCCEEDED(hr = propertyQuery.GetQuery(&bstrQuery))) + { + if (ppFeatureNode == NULL) + { + hr = GetNode(bstrQuery, &pFeatureNode); + } + else + { + hr = GetNode(bstrQuery, ppFeatureNode); + } + } + } + else + { + hr = E_INVALIDARG; + } + + if (hr == S_FALSE) + { + hr = E_ELEMENT_NOT_FOUND; + } + + ERR_ON_HR_EXC(hr, E_ELEMENT_NOT_FOUND); + return hr; +} + +/*++ + +Routine Name: + + CPTHandler::GetFeatureOption + +Routine Description: + + This routine retrieves the option set for the named feature passed in. + +Arguments: + + bstrFeature - The feature name to retrieve the option for + pbstrOption - Pointer to a BSTR to recieve the option + +Return Value: + + HRESULT + S_OK - On success + E_ELEMENT_NOT_FOUND - If node does not exist + E_* - On error + +--*/ +HRESULT +CPTHandler::GetFeatureOption( + _In_z_ BSTR bstrFeature, + _Outptr_result_maybenull_z_ BSTR* pbstrOption + ) +{ + HRESULT hr = S_OK; + + // + // Validate input parameters + // + if (SUCCEEDED(hr = CHECK_POINTER(pbstrOption, E_POINTER))) + { + if (SysStringLen(bstrFeature) <= 0) + { + hr = E_INVALIDARG; + } + } + + // + // Given a bare PrintSchema feature name, retrieve the selected option + // + if (SUCCEEDED(hr)) + { + // + // Find the feature option node + // + CPTQueryBuilder propertyQuery(m_bstrFrameworkPrefix); + CComBSTR bstrQuery; + + CComPtr pOptionNode(NULL); + + if (SUCCEEDED(hr = propertyQuery.AddFeature(m_bstrKeywordsPrefix, bstrFeature)) && + SUCCEEDED(hr = propertyQuery.AddOption(m_bstrKeywordsPrefix)) && + SUCCEEDED(hr = propertyQuery.GetQuery(&bstrQuery)) && + SUCCEEDED(hr = GetNode(bstrQuery, &pOptionNode)) && + hr != S_FALSE) + { + // + // If this is a shorthand option then the option is stored in the "name" attribute + // + hr = GetAttributeValue(pOptionNode, CComBSTR(NAME_ATTRIBUTE_NAME), pbstrOption); + + if (hr == S_FALSE) + { + // + // This might be a longhand option in which case the node we have retrieved + // is pointing at a scored property the value of which is the option + // + CComVariant varValue; + if (SUCCEEDED(hr = pOptionNode->get_nodeTypedValue(&varValue)) && + hr != S_FALSE) + { + *pbstrOption = ::SysAllocString(varValue.bstrVal); + + if (*pbstrOption == NULL) + { + hr = E_OUTOFMEMORY; + } + } + } + + if (SUCCEEDED(hr) && + hr != S_FALSE) + { + hr = StripKeywordNamespace(pbstrOption); + } + } + } + + if (hr == S_FALSE) + { + hr = E_ELEMENT_NOT_FOUND; + } + + ERR_ON_HR_EXC(hr, E_ELEMENT_NOT_FOUND); + return hr; +} + +/*++ + +Routine Name: + + CPTHandler::GetSubFeatureOption + +Routine Description: + + This routine retrieves the current option for a sub feature. The routine + finds the named parent feature, then the sub-feature and retrieves the + option that is set. + +Arguments: + + bstrParentFeature - The parent feature name + bstrFeature - The sub-feature name + pbstrOption - Pointer to a BSTR to recieve the option + +Return Value: + + HRESULT + S_OK - On success + E_ELEMENT_NOT_FOUND - If node does not exist + E_* - On error + +--*/ +HRESULT +CPTHandler::GetSubFeatureOption( + _In_z_ BSTR bstrParentFeature, + _In_z_ BSTR bstrFeature, + _Outptr_result_maybenull_z_ BSTR* pbstrOption + ) +{ + HRESULT hr = S_OK; + + // + // Validate input parameters + // + if (SUCCEEDED(hr = CHECK_POINTER(pbstrOption, E_POINTER))) + { + *pbstrOption = NULL; + + if (SysStringLen(bstrFeature) <= 0 || + SysStringLen(bstrParentFeature) <= 0) + { + hr = E_INVALIDARG; + } + } + + // + // Given a bare PrintSchema feature name, retrieve the selected option + // + if (SUCCEEDED(hr)) + { + // + // Find the sub feature option node + // + CPTQueryBuilder propertyQuery(m_bstrFrameworkPrefix); + CComBSTR bstrQuery; + + CComPtr pFeatureNode(NULL); + + if (SUCCEEDED(hr = propertyQuery.AddFeature(m_bstrKeywordsPrefix, bstrParentFeature)) && + SUCCEEDED(hr = propertyQuery.AddFeature(m_bstrKeywordsPrefix, bstrFeature)) && + SUCCEEDED(hr = propertyQuery.AddOption(m_bstrKeywordsPrefix)) && + SUCCEEDED(hr = propertyQuery.GetQuery(&bstrQuery)) && + SUCCEEDED(hr = GetNode(bstrQuery, &pFeatureNode)) && + hr != S_FALSE && + SUCCEEDED(hr = GetAttributeValue(pFeatureNode, CComBSTR(NAME_ATTRIBUTE_NAME), pbstrOption)) && + hr != S_FALSE) + { + hr = StripKeywordNamespace(pbstrOption); + } + } + + if (hr == S_FALSE) + { + hr = E_ELEMENT_NOT_FOUND; + } + + ERR_ON_HR_EXC(hr, E_ELEMENT_NOT_FOUND); + return hr; +} + +/*++ + +Routine Name: + + CPTHandler::GetScoredPropertyValue + +Routine Description: + + This routine retrieves the scored property value as a string for a given feature. + +Arguments: + + bstrParentFeature - The parent feature name + bstrProperty - The scored property name + pbstrValue - Pointer to a BSTR to recieve the scored property value + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPTHandler::GetScoredPropertyValue( + _In_z_ BSTR bstrParentFeature, + _In_z_ BSTR bstrProperty, + _Outptr_result_maybenull_ BSTR* pbstrValue + ) +{ + HRESULT hr = S_OK; + + // + // Validate input parameters + // + if (SUCCEEDED(hr = CHECK_POINTER(pbstrValue, E_POINTER))) + { + *pbstrValue = NULL; + + if (SysStringLen(bstrProperty) <= 0 || + SysStringLen(bstrParentFeature) <= 0) + { + hr = E_INVALIDARG; + } + } + + if (SUCCEEDED(hr)) + { + // + // Get the scored property value + // + CPTQueryBuilder propertyQuery(m_bstrFrameworkPrefix); + CComBSTR bstrQuery; + + if (SUCCEEDED(hr = propertyQuery.AddFeature(m_bstrKeywordsPrefix, bstrParentFeature)) && + SUCCEEDED(hr = propertyQuery.AddScoredProperty(m_bstrKeywordsPrefix, bstrProperty)) && + SUCCEEDED(hr = propertyQuery.GetQuery(&bstrQuery))) + { + hr = GetNodeValue(bstrQuery, pbstrValue); + } + } + + if (hr == S_FALSE) + { + hr = E_ELEMENT_NOT_FOUND; + } + + ERR_ON_HR_EXC(hr, E_ELEMENT_NOT_FOUND); + return hr; +} + +/*++ + +Routine Name: + + CPTHandler::GetScoredPropertyValue + +Routine Description: + + This routine retrieves the integer value of a scored property from a named + feature + +Arguments: + + bstrParentFeature - The name of the parent feature + bstrProperty - The name of the scored property to retrieve the value of + pValue - Pointer to an INT that recieves the property value + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPTHandler::GetScoredPropertyValue( + _In_z_ BSTR bstrParentFeature, + _In_z_ BSTR bstrProperty, + _Out_ INT* pValue + ) +{ + HRESULT hr = S_OK; + + CComBSTR bstrValue; + if (SUCCEEDED(hr = CHECK_POINTER(pValue, E_POINTER))) + { + if (SysStringLen(bstrParentFeature) <= 0 || + SysStringLen(bstrProperty) <= 0) + { + hr = E_INVALIDARG; + } + } + + if (SUCCEEDED(hr) && + SUCCEEDED(hr = GetScoredPropertyValue(bstrParentFeature, bstrProperty, &bstrValue))) + { + *pValue = static_cast(_wtoi(bstrValue)); + } + + ERR_ON_HR_EXC(hr, E_ELEMENT_NOT_FOUND); + return hr; +} + +/*++ + +Routine Name: + + CPTHandler::GetScoredPropertyValue + +Routine Description: + + This routine retrieves the REAL value of a scored property from a named + feature + +Arguments: + + bstrParentFeature - The name of the parent feature + bstrProperty - The name of the scored property to retrieve the value of + pValue - Pointer to a REAL that recieves the property value + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPTHandler::GetScoredPropertyValue( + _In_z_ BSTR bstrParentFeature, + _In_z_ BSTR bstrProperty, + _Out_ REAL* pValue + ) +{ + HRESULT hr = S_OK; + + CComBSTR bstrValue; + if (SUCCEEDED(hr = CHECK_POINTER(pValue, E_POINTER))) + { + if (SysStringLen(bstrParentFeature) <= 0 || + SysStringLen(bstrProperty) <= 0) + { + hr = E_INVALIDARG; + } + } + + if (SUCCEEDED(hr) && + SUCCEEDED(hr = GetScoredPropertyValue(bstrParentFeature, bstrProperty, &bstrValue))) + { + *pValue = static_cast(_wtof(bstrValue)); + } + + ERR_ON_HR_EXC(hr, E_ELEMENT_NOT_FOUND); + return hr; +} + +/*++ + +Routine Name: + + CPTHandler::StripKeywordNamespace + +Routine Description: + + This routine strips the PrintSchema keyword namespace prefix from a value + +Arguments: + + pbstrValue - Pointer to the value string to have the prefix stripped + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPTHandler::StripKeywordNamespace( + _Inout_ BSTR* pbstrValue + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pbstrValue, E_POINTER))) + { + if (SysStringLen(*pbstrValue) <= 0) + { + hr = E_INVALIDARG; + } + } + + if (SUCCEEDED(hr)) + { + try + { + CStringXDW cstrStrippedName(*pbstrValue); + + INT cchStringStart = cstrStrippedName.Find(m_bstrKeywordsPrefix); + size_t cchKWPrefix = 0; + if (cchStringStart != -1 && + SUCCEEDED(hr = StringCchLength(m_bstrKeywordsPrefix, STRSAFE_MAX_CCH, &cchKWPrefix))) + { + cstrStrippedName.Delete(cchStringStart, static_cast(cchKWPrefix)); + SysFreeString(*pbstrValue); + *pbstrValue = cstrStrippedName.AllocSysString(); + } + } + catch (CXDException& e) + { + hr = e; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CPTHandler::CreateParamRefInitPair + +Routine Description: + + This routine create a pair of DOM elements corresponding to the ParameterRef and + the ParameterInit that describe a ScoredProperty value. + +Arguments: + + bstrParam - The name of the property + bstrType - The type of the value (string, integer etc.) + bstrValue - The value of the property + ppParamRef - Pointer to a IXMLDOMElement pointer that recives the new ParameterRef + ppParamInit - Pointer to a IXMLDOMElement pointer that recives the new ParameterInit + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPTHandler::CreateParamRefInitPair( + _In_ CONST BSTR bstrParam, + _In_ CONST BSTR bstrType, + _In_ CONST BSTR bstrValue, + _Outptr_ IXMLDOMElement** ppParamRef, + _Outptr_ IXMLDOMElement** ppParamInit + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(ppParamRef, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(ppParamInit, E_POINTER))) + { + *ppParamRef = NULL; + *ppParamInit = NULL; + + if (SysStringLen(bstrParam) <= 0 || + SysStringLen(bstrType) <= 0 || + SysStringLen(bstrValue) <= 0) + { + hr = E_INVALIDARG; + } + } + + CComPtr pParamInit(NULL); + CComPtr pParamRef(NULL); + + if (SUCCEEDED(hr)) + { + CComBSTR bstrPRefName; + if (wcscmp(bstrParam, L"PageWatermarkSizeWidth") == 0 || + wcscmp(bstrParam, L"PageWatermarkSizeHeight") == 0) + { + bstrPRefName += m_bstrUserKeywordsPrefix; + } + else + { + bstrPRefName += m_bstrKeywordsPrefix; + } + + bstrPRefName += bstrParam; + + // + // Create the parameter ref element + // + CComBSTR bstrTagName(m_bstrFrameworkPrefix); + bstrTagName += PARAM_REF_ELEMENT_NAME; + + if(SUCCEEDED(hr)) + { + hr = CreateXMLElement(bstrTagName, FRAMEWORK_URI, &pParamRef); + } + + if (SUCCEEDED(hr)) + { + hr = CreateXMLAttribute(pParamRef, NAME_ATTRIBUTE_NAME, NULL, bstrPRefName ); + } + + // + // Create the parameter init element + // + bstrTagName.Empty(); + bstrTagName += m_bstrFrameworkPrefix; + bstrTagName += PARAM_INIT_ELEMENT_NAME; + + if(SUCCEEDED(hr)) + { + hr = CreateXMLElement(bstrTagName, FRAMEWORK_URI, &pParamInit); + } + + if (SUCCEEDED(hr)) + { + hr = CreateXMLAttribute(pParamInit, NAME_ATTRIBUTE_NAME, NULL, bstrPRefName ); + } + + // + // Create the parameter init value and add to the parameter init element + // + CComPtr pValue(NULL); + + bstrTagName.Empty(); + bstrTagName += m_bstrFrameworkPrefix; + bstrTagName += VALUE_ELEMENT_NAME; + + CComBSTR bstrAttrib(m_bstrSchemaInstPrefix); + bstrAttrib += SCHEMA_TYPE; + + CComBSTR bstrAttribValue(m_bstrSchemaPrefix); + bstrAttribValue += bstrType; + + if(SUCCEEDED(hr)) + { + hr = CreateXMLElement(bstrTagName, FRAMEWORK_URI, &pValue); + } + + if (SUCCEEDED(hr)) + { + if( SUCCEEDED(hr = CreateXMLAttribute(pValue, bstrAttrib, SCHEMA_INST_URI, bstrAttribValue )) && + SUCCEEDED(hr = pValue->put_text(bstrValue))) + { + hr = pParamInit->appendChild(pValue, NULL); + } + } + } + + if (SUCCEEDED(hr)) + { + // + // Assign the outgoing element pointers - detach from CComPtr to release ownership + // + *ppParamRef = pParamRef.Detach(); + *ppParamInit = pParamInit.Detach(); + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CPTHandler::CreateParamRefInitPair + +Routine Description: + + This routine create a pair of DOM elements corresponding to the ParameterRef and + the ParameterInit that describe a ScoredProperty value. This overload is INT specific + +Arguments: + + bstrParam - The name of the property + intValue - The integer value of the scored property + ppParamRef - Pointer to a IXMLDOMElement pointer that recives the new ParameterRef + ppParamInit - Pointer to a IXMLDOMElement pointer that recives the new ParameterInit + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPTHandler::CreateParamRefInitPair( + _In_ CONST BSTR bstrParam, + _In_ CONST INT intValue, + _Outptr_ IXMLDOMElement** ppParamRef, + _Outptr_ IXMLDOMElement** ppParamInit + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(ppParamRef, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(ppParamInit, E_POINTER))) + { + if (SysStringLen(bstrParam) <= 0) + { + hr = E_INVALIDARG; + } + } + + if (SUCCEEDED(hr)) + { + try + { + CStringXDW cstrValue; + cstrValue.Format(L"%i", intValue); + + hr = CreateParamRefInitPair(bstrParam, + CComBSTR(SCHEMA_INTEGER), + CComBSTR(cstrValue.AllocSysString()), + ppParamRef, + ppParamInit); + } + catch (CXDException& e) + { + hr = e; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CPTHandler::CreateFeatureOptionPair + +Routine Description: + + This routine create a pair of DOM elements corresponding to Feature and Option. + Note this method does not intialise the option element, it merely creates an Option + node appended to the Feature element. It is up to the caller to set the option value. + +Arguments: + + bstrFeatureName - The name of the feature + ppFeatureElement - Pointer to a IXMLDOMElement pointer that recives the new Feature + ppOptionElement - Pointer to a IXMLDOMElement pointer that recives the new Option + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPTHandler::CreateFeatureOptionPair( + _In_ CONST BSTR bstrFeatureName, + _Outptr_ IXMLDOMElement** ppFeatureElement, + _Outptr_ IXMLDOMElement** ppOptionElement + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(ppFeatureElement, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(ppOptionElement, E_POINTER))) + { + *ppFeatureElement = NULL; + *ppOptionElement = NULL; + + if (SysStringLen(bstrFeatureName) <= 0) + { + hr = E_INVALIDARG; + } + } + else + { + hr = E_POINTER; + } + + if (SUCCEEDED(hr)) + { + CComBSTR bstrFeature(m_bstrFrameworkPrefix); + bstrFeature += FEATURE_ELEMENT_NAME; + + CComBSTR bstrAttribName(m_bstrKeywordsPrefix); + bstrAttribName += bstrFeatureName; + + CComBSTR bstrOption(m_bstrFrameworkPrefix); + bstrOption += OPTION_ELEMENT_NAME; + + if(SUCCEEDED(hr)) + { + hr = CreateXMLElement(bstrFeature, FRAMEWORK_URI, ppFeatureElement); + } + + if(SUCCEEDED(hr)) + { + hr = CreateXMLElement(bstrOption, FRAMEWORK_URI, ppOptionElement); + } + + if(SUCCEEDED(hr)) + { + if (SUCCEEDED(hr = CreateXMLAttribute(*ppFeatureElement, NAME_ATTRIBUTE_NAME, NULL, bstrAttribName ))) + { + hr = (*ppFeatureElement)->appendChild(*ppOptionElement, NULL); + } + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CPTHandler::CreateFeatureOptionPair + +Routine Description: + + This routine create a pair of DOM elements corresponding to Feature and Option. + +Arguments: + + bstrFeatureName - The name of the feature + bstrOptionName - The name of the option + ppFeatureElement - Pointer to a IXMLDOMElement pointer that recives the new Feature + ppOptionElement - Pointer to a IXMLDOMElement pointer that recives the new Option + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPTHandler::CreateFeatureOptionPair( + _In_ CONST BSTR bstrFeatureName, + _In_ CONST BSTR bstrOptionName, + _Outptr_ IXMLDOMElement** ppFeatureElement, + _Outptr_ IXMLDOMElement** ppOptionElement + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(ppFeatureElement, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(ppOptionElement, E_POINTER))) + { + if (SysStringLen(bstrFeatureName) <= 0 || + SysStringLen(bstrOptionName) <= 0) + { + hr = E_INVALIDARG; + } + } + + if (SUCCEEDED(hr)) + { + if (SUCCEEDED(hr = CreateFeatureOptionPair(bstrFeatureName, ppFeatureElement, ppOptionElement))) + { + // + // Set the option name attribute + // + CComBSTR bstrAttribValue(m_bstrKeywordsPrefix); + bstrAttribValue += bstrOptionName; + + hr = CreateXMLAttribute(*ppOptionElement, NAME_ATTRIBUTE_NAME, NULL, bstrAttribValue ); + + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CPTHandler::AppendToElement + +Routine Description: + + This routine uses the passed element name to locate the node to which + it will append the DOM node passed in. + +Arguments: + + bstrElementName - The name of the element to append to + pAppendNode - The node to append + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPTHandler::AppendToElement( + _In_ CONST BSTR bstrElementName, + _In_ IXMLDOMNode* pAppendNode + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pAppendNode, E_POINTER))) + { + if (SysStringLen(bstrElementName) <= 0) + { + hr = E_INVALIDARG; + } + } + + if (SUCCEEDED(hr)) + { + CComPtr pNode(NULL); + + CComBSTR bstrQuery(m_bstrFrameworkPrefix); + bstrQuery += bstrElementName; + + if (SUCCEEDED(hr = GetNode(bstrQuery, &pNode))) + { + hr = pNode->appendChild(pAppendNode, NULL); + } + } + + ERR_ON_HR(hr); + return hr; +} + diff --git a/print/XPSDrvSmpl/src/common/pthndlr.h b/print/XPSDrvSmpl/src/common/pthndlr.h new file mode 100644 index 00000000..e8bd8a08 --- /dev/null +++ b/print/XPSDrvSmpl/src/common/pthndlr.h @@ -0,0 +1,178 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +File Name: + + pthndlr.h + +Abstract: + + Base PrintTicket handler class definition. This class provides common + PrintTicket handling functionality for any filter that requires print + ticket handling. A filter can from this class to get feature unspecific + XML handling functionality. + +--*/ + +#pragma once + +#include "schema.h" +#include "pshndlr.h" + +class CPTHandler : public CPSHandler +{ +public: + // + // Constructors and destructors + // + CPTHandler( + _In_ IXMLDOMDocument2 *pPrintTicket + ); + + virtual ~CPTHandler(); + +public: + HRESULT + DeleteFeature( + _In_z_ BSTR bstrFeature + ); + + HRESULT + DeleteProperty( + _In_z_ BSTR bstrProperty + ); + +protected: + HRESULT + QueryNodeOption( + _In_z_ BSTR bstrQuery, + _Outptr_result_maybenull_z_ BSTR* pbstrOption + ); + + HRESULT + FeaturePresent( + _In_z_ BSTR bstrFeature, + _Outptr_opt_ IXMLDOMNode** ppFeatureNode = NULL + ); + + HRESULT + GetFeatureOption( + _In_z_ BSTR bstrFeature, + _Outptr_result_maybenull_z_ BSTR* pbstrOption + ); + + HRESULT + GetSubFeatureOption( + _In_z_ BSTR bstrParentFeature, + _In_z_ BSTR bstrFeature, + _Outptr_result_maybenull_z_ BSTR* pbstrOption + ); + + HRESULT + GetScoredPropertyValue( + _In_z_ BSTR bstrParentFeature, + _In_z_ BSTR bstrProperty, + _Outptr_result_maybenull_ BSTR* pbstrValue + ); + + HRESULT + GetScoredPropertyValue( + _In_z_ BSTR bstrParentFeature, + _In_z_ BSTR bstrProperty, + _Out_ INT* pValue + ); + + HRESULT + GetScoredPropertyValue( + _In_z_ BSTR bstrParentFeature, + _In_z_ BSTR bstrProperty, + _Out_ REAL* pValue + ); + + HRESULT + SetFeatureOption( + _In_z_ BSTR bstrFeature, + _In_z_ BSTR bstrOption + ); + + HRESULT + SetSubFeatureOption( + _In_z_ BSTR bstrParentFeature, + _In_z_ BSTR bstrFeature, + _In_z_ BSTR bstrOption + ); + + HRESULT + SetPropertyAsValue( + _In_z_ BSTR bstrFeature, + _In_z_ BSTR bstrProperty, + _In_z_ BSTR bstrValue + ); + + HRESULT + SetPropertyAsParameterRef( + _In_z_ BSTR bstrFeature, + _In_z_ BSTR bstrProperty, + _In_z_ BSTR bstrParameterRef, + _In_z_ BSTR bstrValue + ); + + HRESULT + CreateParamRefInitPair( + _In_ CONST BSTR bstrParam, + _In_ CONST BSTR bstrType, + _In_ CONST BSTR bstrValue, + _Outptr_ IXMLDOMElement** ppParamRef, + _Outptr_ IXMLDOMElement** ppParamInit + ); + + HRESULT + CreateParamRefInitPair( + _In_ CONST BSTR bstrParam, + _In_ CONST INT intValue, + _Outptr_ IXMLDOMElement** ppParamRef, + _Outptr_ IXMLDOMElement** ppParamInit + ); + + HRESULT + CreateFeatureOptionPair( + _In_ CONST BSTR bstrFeatureName, + _Outptr_ IXMLDOMElement** ppFeatureElement, + _Outptr_ IXMLDOMElement** ppOptionElement + ); + + HRESULT + CreateFeatureOptionPair( + _In_ CONST BSTR bstrFeatureName, + _In_ CONST BSTR bstrOptionName, + _Outptr_ IXMLDOMElement** ppFeatureElement, + _Outptr_ IXMLDOMElement** ppOptionElement + ); + + HRESULT + AppendToElement( + _In_ CONST BSTR bstrElementName, + _In_ IXMLDOMNode* pAppendNode + ); + +private: + HRESULT + StripKeywordNamespace( + _Inout_ BSTR* pbstrValue + ); + + HRESULT + DeleteNodeList( + _Inout_ IXMLDOMNodeList* pNodeList + ); + + HRESULT + DeleteParamInitOrphans( + _In_ IXMLDOMNodeList* pRefList, + _Inout_ IXMLDOMNodeList* pInitList + ); +}; + diff --git a/print/XPSDrvSmpl/src/common/ptquerybld.cpp b/print/XPSDrvSmpl/src/common/ptquerybld.cpp new file mode 100644 index 00000000..885af0b2 --- /dev/null +++ b/print/XPSDrvSmpl/src/common/ptquerybld.cpp @@ -0,0 +1,515 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + ptquerybld.cpp + +Abstract: + + PrintTicket XPath query builder implementation. The CPTQueryBuilder class + provides a means of constructing PrintTicket specific XPath queries for + retrieving nodes from within the DOM document describing the PrintTicket. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdstring.h" +#include "ptquerybld.h" + +// +// XML PrintTicket Query Builder Format Strings +// +static PCWSTR szPTQFeature = L"//%sFeature[@name = \"%s\"]"; +static PCWSTR szPTQProperty = L"//%sProperty[@name = \"%s\"]"; +static PCWSTR szPTQScoredProperty = L"//%sScoredProperty[@name = \"%s\"]"; +static PCWSTR szPTQParamRef = L"//%sParameterRef[@name = \"%s\"]"; +static PCWSTR szPTQOptionSH = L"/%sOption"; +static PCWSTR szPTQOptionLH = L"/%sScoredProperty[@name = \"%sOptionName\"]/%sValue"; +static PCWSTR szPTQOrNodes = L" | "; + +/*++ + +Routine Name: + + CPTQueryBuilder::CPTQueryBuilder + +Routine Description: + + CPTQueryBuilder class default constructor + +Arguments: + + bstrFrameworkNS - PrintTicket framework namespace prefix + +Return Value: + + None + +--*/ +CPTQueryBuilder::CPTQueryBuilder( + _In_z_ BSTR bstrFrameworkNS + ) : + m_bstrFrameworkNS(bstrFrameworkNS) +{ +} + +/*++ + +Routine Name: + + CPTQueryBuilder::CPTQueryBuilder + +Routine Description: + + CPTQueryBuilder class constructor + +Arguments: + + bstrFrameworkNS - PrintTicket framework namespace prefix + bstrQuery - String containing base query to use on construction. + +Return Value: + + None + +--*/ +CPTQueryBuilder::CPTQueryBuilder( + _In_z_ BSTR bstrFrameworkNS, + _In_z_ BSTR bstrQuery + ) : + m_bstrFrameworkNS(bstrFrameworkNS), + m_bstrQuery(bstrQuery) +{ +} + +/*++ + +Routine Name: + + CPTQueryBuilder::~CPTQueryBuilder + +Routine Description: + + CPTQueryBuilder class destructor. + +Arguments: + + None + +Return Value: + + None + +--*/ +CPTQueryBuilder::~CPTQueryBuilder( + ) +{ +} + +/*++ + +Routine Name: + + CPTQueryBuilder::Clear + +Routine Description: + + Clears the current query string. + +Arguments: + + None + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPTQueryBuilder::Clear( + VOID + ) +{ + m_bstrQuery.Empty(); + + return S_OK; +} + +/*++ + +Routine Name: + + CPTQueryBuilder::GetQuery + +Routine Description: + + Makes a copy of the current query string and returns it to the caller. + +Arguments: + + bstrQuery - Address of a pointer that will be modified to point to a string + that is filled out with a copy of the current query. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPTQueryBuilder::GetQuery( + _Inout_ _At_(*pbstrQuery, _Pre_maybenull_ _Post_valid_) BSTR* pbstrQuery + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pbstrQuery, E_POINTER))) + { + SysFreeString(*pbstrQuery); + hr = m_bstrQuery.CopyTo(pbstrQuery); + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CPTQueryBuilder::AddFeature + +Routine Description: + + Appends a feature query to the query builder class. + +Arguments: + + bstrKeywordNS - Optional parameter defining the keyword namespace to prefix. + bstrFeature - Pointer to a string defining the feature name to be appended. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPTQueryBuilder::AddFeature( + _In_opt_z_ BSTR bstrKeywordNS, + _In_z_ BSTR bstrFeature + ) +{ + HRESULT hr = S_OK; + + if (m_bstrFrameworkNS.Length() > 0) + { + try + { + CComBSTR bstrKeyword; + + if (SysStringLen(bstrKeywordNS) > 0) + { + hr = bstrKeyword.Append(bstrKeywordNS); + } + + if (SUCCEEDED(hr)) + { + hr = bstrKeyword.Append(bstrFeature); + } + + if (SUCCEEDED(hr)) + { + CStringXDW cstrFeatureQuery; + cstrFeatureQuery.Format(szPTQFeature, m_bstrFrameworkNS, bstrKeyword); + + hr = m_bstrQuery.Append(cstrFeatureQuery); + } + } + catch (CXDException& e) + { + hr = e; + } + } + else + { + hr = E_FAIL; + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CPTQueryBuilder::AddProperty + +Routine Description: + + Appends a property query to the query builder class. + +Arguments: + + bstrKeywordNS - Optional parameter defining the keyword namespace to prefix. + bstrProperty - Pointer to a string defining the property name to be appended. + + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPTQueryBuilder::AddProperty( + _In_opt_z_ BSTR bstrKeywordNS, + _In_z_ BSTR bstrProperty + ) +{ + HRESULT hr = S_OK; + + if (m_bstrFrameworkNS.Length() > 0) + { + try + { + CComBSTR bstrKeyword; + + if (SysStringLen(bstrKeywordNS) > 0) + { + hr = bstrKeyword.Append(bstrKeywordNS); + } + + if (SUCCEEDED(hr)) + { + hr = bstrKeyword.Append(bstrProperty); + } + + if (SUCCEEDED(hr)) + { + CStringXDW cstrPropertyQuery; + cstrPropertyQuery.Format(szPTQProperty, m_bstrFrameworkNS, bstrKeyword); + + hr = m_bstrQuery.Append(cstrPropertyQuery); + } + } + catch (CXDException& e) + { + hr = e; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CPTQueryBuilder::AddScoredProperty + +Routine Description: + + Appends a scored property query to the query builder class. + +Arguments: + + bstrKeywordNS - Optional parameter defining the keyword namespace to prefix. + bstrScoredProperty - Pointer to a string defining the scored property name to be appended. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPTQueryBuilder::AddScoredProperty( + _In_opt_z_ BSTR bstrKeywordNS, + _In_z_ BSTR bstrScoredProperty + ) +{ + HRESULT hr = S_OK; + + if (m_bstrFrameworkNS.Length() > 0) + { + try + { + CComBSTR bstrKeyword; + + if (SysStringLen(bstrKeywordNS) > 0) + { + hr = bstrKeyword.Append(bstrKeywordNS); + } + + if (SUCCEEDED(hr)) + { + hr = bstrKeyword.Append(bstrScoredProperty); + } + + if (SUCCEEDED(hr)) + { + CStringXDW cstrScoredPropertyQuery; + cstrScoredPropertyQuery.Format(szPTQScoredProperty, m_bstrFrameworkNS, bstrKeyword); + + hr = m_bstrQuery.Append(cstrScoredPropertyQuery); + } + } + catch (CXDException& e) + { + hr = e; + } + } + else + { + hr = E_FAIL; + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CPTQueryBuilder::AddScoredProperty + +Routine Description: + + Appends a Parameter Reference query to the query builder class. + +Arguments: + + bstrKeywordNS - Optional parameter defining the keyword namespace to prefix. + bstrScoredProperty - Pointer to a string defining the scored property name to be appended. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPTQueryBuilder::AddParamRef( + _In_opt_z_ BSTR bstrKeywordNS, + _In_z_ BSTR bstrParameterRef + ) +{ + HRESULT hr = S_OK; + + if (m_bstrFrameworkNS.Length() > 0) + { + try + { + CComBSTR bstrKeyword; + + if (SysStringLen(bstrKeywordNS) > 0) + { + hr = bstrKeyword.Append(bstrKeywordNS); + } + + if (SUCCEEDED(hr)) + { + hr = bstrKeyword.Append(bstrParameterRef); + } + + if (SUCCEEDED(hr)) + { + CStringXDW cstrParamRefQuery; + cstrParamRefQuery.Format(szPTQParamRef, m_bstrFrameworkNS, bstrKeyword); + + hr = m_bstrQuery.Append(cstrParamRefQuery); + } + } + catch (CXDException& e) + { + hr = e; + } + } + else + { + hr = E_FAIL; + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CPTQueryBuilder::AddOption + +Routine Description: + + Appends the option query to the query builder class. + +Arguments: + + None + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPTQueryBuilder::AddOption( + _In_opt_z_ BSTR bstrKeywordNS + ) +{ + HRESULT hr = S_OK; + + if (m_bstrFrameworkNS.Length() > 0) + { + try + { + CStringXDW cstrQueryRoot(m_bstrQuery); + CStringXDW cstrOptionQuery; + cstrOptionQuery.Format(szPTQOptionSH, m_bstrFrameworkNS); + + if (SUCCEEDED(hr = m_bstrQuery.Append(cstrOptionQuery)) && + SUCCEEDED(hr = m_bstrQuery.Append(szPTQOrNodes)) && + SUCCEEDED(hr = m_bstrQuery.Append(cstrQueryRoot))) + { + cstrOptionQuery.Format(szPTQOptionLH, m_bstrFrameworkNS, bstrKeywordNS, m_bstrFrameworkNS); + hr = m_bstrQuery.Append(cstrOptionQuery); + } + } + catch (CXDException& e) + { + hr = e; + } + } + else + { + hr = E_FAIL; + } + + ERR_ON_HR(hr); + return hr; +} diff --git a/print/XPSDrvSmpl/src/common/ptquerybld.h b/print/XPSDrvSmpl/src/common/ptquerybld.h new file mode 100644 index 00000000..a82172ea --- /dev/null +++ b/print/XPSDrvSmpl/src/common/ptquerybld.h @@ -0,0 +1,84 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + ptquerybld.h + +Abstract: + + PrintTicket XPath query builder definition. The CPTQueryBuilder class + provides a means of constructing PrintTicket specific XPath queries for + retrieving nodes from within the DOM document describing the PrintTicket. + +--*/ + +#pragma once + +class CPTQueryBuilder +{ +public: + CPTQueryBuilder( + _In_z_ BSTR bstrFrameworkNS + ); + + CPTQueryBuilder( + _In_z_ BSTR bstrFrameworkNS, + _In_z_ BSTR bstrQuery + ); + + virtual ~CPTQueryBuilder(); + + HRESULT + Clear( + VOID + ); + + HRESULT + GetQuery( + _Inout_ _At_(*pbstrQuery, _Pre_maybenull_ _Post_valid_) BSTR* pbstrQuery + ); + + HRESULT + AddFeature( + _In_opt_z_ BSTR bstrKeywordNS, + _In_z_ BSTR bstrPropertyName + ); + + HRESULT + AddProperty( + _In_opt_z_ BSTR bstrKeywordNS, + _In_z_ BSTR bstrPropertyName + ); + + HRESULT + AddScoredProperty( + _In_opt_z_ BSTR bstrKeywordNS, + _In_z_ BSTR bstrPropertyName + ); + + HRESULT + AddParamRef( + _In_opt_z_ BSTR bstrKeywordNS, + _In_z_ BSTR bstrParameterRef + ); + + HRESULT + AddOption( + _In_opt_z_ BSTR bstrKeywordNS + ); + +private: + CComBSTR m_bstrQuery; + + CComBSTR m_bstrFrameworkNS; +}; + diff --git a/print/XPSDrvSmpl/src/common/schema.cpp b/print/XPSDrvSmpl/src/common/schema.cpp new file mode 100644 index 00000000..ce2aa2c2 --- /dev/null +++ b/print/XPSDrvSmpl/src/common/schema.cpp @@ -0,0 +1,70 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + schema.cpp + +Abstract: + + PrintSchema implementation. This provides the definition of keywords common + to all features within the PrintSchema. + +--*/ + +#include "precomp.h" +#include "schema.h" + +LPCWSTR XDPrintSchema::SCHEMA_INST_URI = + L"http://www.w3.org/2001/XMLSchema-instance"; + +LPCWSTR XDPrintSchema::SCHEMA_DEF_URI = + L"http://www.w3.org/2001/XMLSchema"; + +LPCWSTR XDPrintSchema::SCHEMA_TYPE = L"type"; +LPCWSTR XDPrintSchema::SCHEMA_INTEGER = L"integer"; +LPCWSTR XDPrintSchema::SCHEMA_DECIMAL = L"decimal"; +LPCWSTR XDPrintSchema::SCHEMA_STRING = L"string"; +LPCWSTR XDPrintSchema::SCHEMA_QNAME = L"QName"; +LPCWSTR XDPrintSchema::SCHEMA_CONDITIONAL = L"Conditional"; + +LPCWSTR XDPrintSchema::FRAMEWORK_URI = + L"http://schemas.microsoft.com/windows/2003/08/printing/printschemaframework"; + +LPCWSTR XDPrintSchema::KEYWORDS_URI = + L"http://schemas.microsoft.com/windows/2003/08/printing/printschemakeywords"; + +LPCWSTR XDPrintSchema::FEATURE_ELEMENT_NAME = L"Feature"; +LPCWSTR XDPrintSchema::OPTION_ELEMENT_NAME = L"Option"; +LPCWSTR XDPrintSchema::PARAM_INIT_ELEMENT_NAME = L"ParameterInit"; +LPCWSTR XDPrintSchema::PARAM_REF_ELEMENT_NAME = L"ParameterRef"; +LPCWSTR XDPrintSchema::PARAM_DEF_ELEMENT_NAME = L"ParameterDef"; +LPCWSTR XDPrintSchema::SCORED_PROP_ELEMENT_NAME = L"ScoredProperty"; +LPCWSTR XDPrintSchema::PROPERTY_ELEMENT_NAME = L"Property"; +LPCWSTR XDPrintSchema::VALUE_ELEMENT_NAME = L"Value"; +LPCWSTR XDPrintSchema::NAME_ATTRIBUTE_NAME = L"name"; + + +LPCWSTR XDPrintSchema::PICKONE_VALUE_NAME = L"PickOne"; +LPCWSTR XDPrintSchema::SELECTIONTYPE_VALUE_NAME = L"SelectionType"; +LPCWSTR XDPrintSchema::DATATYPE_VALUE_NAME = L"DataType"; +LPCWSTR XDPrintSchema::DEFAULTVAL_VALUE_NAME = L"DefaultValue"; +LPCWSTR XDPrintSchema::MAX_VALUE_NAME = L"MaxValue"; +LPCWSTR XDPrintSchema::MIN_VALUE_NAME = L"MinValue"; +LPCWSTR XDPrintSchema::MAX_LENGTH_NAME = L"MaxLength"; +LPCWSTR XDPrintSchema::MIN_LENGTH_NAME = L"MinLength"; +LPCWSTR XDPrintSchema::MULTIPLE_VALUE_NAME = L"Multiple"; +LPCWSTR XDPrintSchema::MANDATORY_VALUE_NAME = L"Mandatory"; +LPCWSTR XDPrintSchema::UNITTYPE_VALUE_NAME = L"UnitType"; +LPCWSTR XDPrintSchema::DISPLAYNAME_VALUE_NAME = L"DisplayName"; + +LPCWSTR XDPrintSchema::PRINTTICKET_NAME = L"PrintTicket"; +LPCWSTR XDPrintSchema::PRINTCAPABILITIES_NAME = L"PrintCapabilities"; diff --git a/print/XPSDrvSmpl/src/common/schema.h b/print/XPSDrvSmpl/src/common/schema.h new file mode 100644 index 00000000..540de949 --- /dev/null +++ b/print/XPSDrvSmpl/src/common/schema.h @@ -0,0 +1,94 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + schema.h + +Abstract: + + PrintSchema definition. This provides the definition of keywords common + to all features within the PrintSchema. The description is placed within a + XDPrintSchema namespace. + +--*/ + +#pragma once + +enum EPrintschemaVersion +{ + PRINTSCHEMA_VERSION_NUMBER = 1 +}; + +namespace XDPrintSchema +{ + // + // W3 namespaces + // + extern LPCWSTR SCHEMA_INST_URI; + extern LPCWSTR SCHEMA_DEF_URI; + + // + // W3 type prefixes + // + extern LPCWSTR SCHEMA_TYPE; + extern LPCWSTR SCHEMA_INTEGER; + extern LPCWSTR SCHEMA_DECIMAL; + extern LPCWSTR SCHEMA_STRING; + extern LPCWSTR SCHEMA_QNAME; + extern LPCWSTR SCHEMA_CONDITIONAL; + + // + // Namespaces + // + extern LPCWSTR FRAMEWORK_URI; + extern LPCWSTR KEYWORDS_URI; + + // + // Element and attribute types defined in Printschema framework + // + extern LPCWSTR FEATURE_ELEMENT_NAME; + extern LPCWSTR OPTION_ELEMENT_NAME; + extern LPCWSTR PARAM_INIT_ELEMENT_NAME; + extern LPCWSTR PARAM_REF_ELEMENT_NAME; + extern LPCWSTR PARAM_DEF_ELEMENT_NAME; + extern LPCWSTR SCORED_PROP_ELEMENT_NAME; + extern LPCWSTR VALUE_ELEMENT_NAME; + extern LPCWSTR NAME_ATTRIBUTE_NAME; + extern LPCWSTR PROPERTY_ELEMENT_NAME; + + // + // Value types defined in the PrintSchema Keywords + // + extern LPCWSTR PICKONE_VALUE_NAME; + extern LPCWSTR SELECTIONTYPE_VALUE_NAME; + extern LPCWSTR DATATYPE_VALUE_NAME; + extern LPCWSTR DEFAULTVAL_VALUE_NAME; + extern LPCWSTR MAX_VALUE_NAME; + extern LPCWSTR MIN_VALUE_NAME; + extern LPCWSTR MAX_LENGTH_NAME; + extern LPCWSTR MIN_LENGTH_NAME; + extern LPCWSTR MULTIPLE_VALUE_NAME; + extern LPCWSTR MANDATORY_VALUE_NAME; + extern LPCWSTR UNITTYPE_VALUE_NAME; + extern LPCWSTR DISPLAYNAME_VALUE_NAME; + + // + // Root PrintTicket element + // + extern LPCWSTR PRINTTICKET_NAME; + + // + // Root PrintCapabilities element + // + extern LPCWSTR PRINTCAPABILITIES_NAME; +} + diff --git a/print/XPSDrvSmpl/src/common/wmdata.h b/print/XPSDrvSmpl/src/common/wmdata.h new file mode 100644 index 00000000..effe32a5 --- /dev/null +++ b/print/XPSDrvSmpl/src/common/wmdata.h @@ -0,0 +1,71 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + wmdata.h + +Abstract: + + PageWatermark data structure definition. This provides a convenient + description of the PrintSchema PageWatermark feature. + +--*/ + +#pragma once + +#include "wmschema.h" + +namespace XDPrintSchema +{ + namespace PageWatermark + { + struct WMTextData + { + WMTextData() : + bstrFontColor(L"#FFFFFF"), + fontSize(12), + bstrText(L"Undefined") + { + } + + CComBSTR bstrFontColor; + INT fontSize; + CComBSTR bstrText; + }; + + struct WatermarkData + { + WatermarkData() : + type(TextWatermark), + widthOrigin(0), + heightOrigin(0), + widthExtent(215900), + heightExtent(279400), + transparency(0), + angle(0), + layering(Layering::Overlay) + { + } + + EWatermarkOption type; + INT widthOrigin; + INT heightOrigin; + INT widthExtent; + INT heightExtent; + INT transparency; + INT angle; + WMTextData txtData; + Layering::ELayeringOption layering; + }; + } +} + diff --git a/print/XPSDrvSmpl/src/common/wmpchndlr.cpp b/print/XPSDrvSmpl/src/common/wmpchndlr.cpp new file mode 100644 index 00000000..bab943b8 --- /dev/null +++ b/print/XPSDrvSmpl/src/common/wmpchndlr.cpp @@ -0,0 +1,555 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + wmpchndlr.cpp + +Abstract: + + Page watermark PrintCapabilities handling implementation. The watermark PC handler + is used to set Page Watermark settings in a PrintCapabilities. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdexcept.h" +#include "xdexcept.h" +#include "wmpchndlr.h" +#include "privatedefs.h" + +using XDPrintSchema::PRINTCAPABILITIES_NAME; + +using XDPrintSchema::PageWatermark::TextWatermark; +using XDPrintSchema::PageWatermark::BitmapWatermark; +using XDPrintSchema::PageWatermark::VectorWatermark; +using XDPrintSchema::PageWatermark::ECommonWatermarkProps; +using XDPrintSchema::PageWatermark::ECommonWatermarkPropsMin; +using XDPrintSchema::PageWatermark::ECommonWatermarkPropsMax; +using XDPrintSchema::PageWatermark::ETextWatermarkProps; +using XDPrintSchema::PageWatermark::ETextWatermarkPropsMin; +using XDPrintSchema::PageWatermark::ETextWatermarkPropsMax; +using XDPrintSchema::PageWatermark::EVectBmpWatermarkProps; +using XDPrintSchema::PageWatermark::EVectBmpWatermarkPropsMin; +using XDPrintSchema::PageWatermark::EVectBmpWatermarkPropsMax; +using XDPrintSchema::PageWatermark::WATERMARK_FEATURE; +using XDPrintSchema::PageWatermark::WATERMARK_OPTIONS; +using XDPrintSchema::PageWatermark::CMN_WATERMARK_PROPS; +using XDPrintSchema::PageWatermark::TXT_WATERMARK_PROPS; +using XDPrintSchema::PageWatermark::VECTBMP_WATERMARK_PROPS; + +using XDPrintSchema::PageWatermark::Layering::ELayeringOption; +using XDPrintSchema::PageWatermark::Layering::ELayeringOptionMin; +using XDPrintSchema::PageWatermark::Layering::ELayeringOptionMax; +using XDPrintSchema::PageWatermark::Layering::LAYERING_FEATURE; +using XDPrintSchema::PageWatermark::Layering::LAYERING_OPTIONS; + +/*++ + +Routine Name: + + CWMPCHandler::CWMPCHandler + +Routine Description: + + CWMPCHandler class constructor + +Arguments: + + pPrintCapabilities - Pointer to the DOM document representation of the PrintCapabilities + +Return Value: + + None + +--*/ +CWMPCHandler::CWMPCHandler( + _In_ IXMLDOMDocument2* pPrintCapabilities + ) : + CPCHandler(pPrintCapabilities) +{ +} + +/*++ + +Routine Name: + + CWMPCHandler::~CWMPCHandler + +Routine Description: + + CWMPCHandler class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CWMPCHandler::~CWMPCHandler() +{ +} + +/*++ + +Routine Name: + + CWMPCHandler::SetCapabilities + +Routine Description: + + This routine sets watermark capabilities in the PrintCapabilities passed to the + class constructor. + +Arguments: + + None + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CWMPCHandler::SetCapabilities( + VOID + ) +{ + HRESULT hr = S_OK; + + try + { + // + // Retrieve the PrintTicket root + // + CComPtr pPTRoot(NULL); + + CComBSTR bstrPTQuery(m_bstrFrameworkPrefix); + bstrPTQuery += PRINTCAPABILITIES_NAME; + + if (SUCCEEDED(hr = GetNode(bstrPTQuery, &pPTRoot))) + { + CComPtr pFeatureElement(NULL); + + if (SUCCEEDED(hr = CreateFeatureSelection(CComBSTR(WATERMARK_FEATURE), NULL, &pFeatureElement))) + { + CComPtr pTextOption(NULL); + + // + // Create the Text Watermark Options + // + if (SUCCEEDED(hr = CreateOption(CComBSTR(WATERMARK_OPTIONS[TextWatermark]), NULL, &pTextOption))) + { + PTDOMElementVector propertList; + + // + // Create the common scored property list + // + for (ECommonWatermarkProps cmnProps = ECommonWatermarkPropsMin; + cmnProps < ECommonWatermarkPropsMax && SUCCEEDED(hr); + cmnProps = static_cast(cmnProps + 1)) + { + CComPtr pScoredProperty(NULL); + + if (SUCCEEDED(hr = CreateScoredProperty(CComBSTR(CMN_WATERMARK_PROPS[cmnProps]), &pScoredProperty))) + { + CComPtr pParamRef(NULL); + + // + // Construct the parameter reference elements + // + CComBSTR bstrPRefName(WATERMARK_FEATURE); + + if (wcscmp(CMN_WATERMARK_PROPS[cmnProps], L"Angle") == 0) + { + hr = bstrPRefName.Append(L"Text"); + } + + bstrPRefName += CMN_WATERMARK_PROPS[cmnProps]; + + if (SUCCEEDED(hr) && + SUCCEEDED(hr = CreateParameterRef(bstrPRefName, &pParamRef))) + { + hr = pScoredProperty->appendChild(pParamRef, NULL); + } + + propertList.push_back(pScoredProperty); + } + } + + // + // Create the text specific scored property list + // + for (ETextWatermarkProps txtProps = ETextWatermarkPropsMin; + txtProps < ETextWatermarkPropsMax && SUCCEEDED(hr); + txtProps = static_cast(txtProps + 1)) + { + CComPtr pScoredProperty(NULL); + + if (SUCCEEDED(hr = CreateScoredProperty(CComBSTR(TXT_WATERMARK_PROPS[txtProps]), &pScoredProperty))) + { + CComPtr pParamRef(NULL); + + // + // Construct the parameter reference elements + // + CComBSTR bstrPRefName(WATERMARK_FEATURE); + bstrPRefName += TXT_WATERMARK_PROPS[txtProps]; + + if (SUCCEEDED(hr = CreateParameterRef(bstrPRefName, &pParamRef))) + { + hr = pScoredProperty->appendChild(pParamRef, NULL); + } + + propertList.push_back(pScoredProperty); + } + } + + // + // Add the properties to the text option + // + PTDOMElementVector::iterator iterPropertList = propertList.begin(); + + for (;iterPropertList != propertList.end() && SUCCEEDED(hr); iterPropertList++) + { + hr = pTextOption->appendChild(*iterPropertList, NULL); + } + + if (SUCCEEDED(hr)) + { + hr = pFeatureElement->appendChild(pTextOption, NULL); + } + } + + CComPtr pVectorOption(NULL); + + // + // Create the Vector Watermark Options + // + if (SUCCEEDED(hr) && + SUCCEEDED(hr = CreateOption(CComBSTR(WATERMARK_OPTIONS[VectorWatermark]), NULL, &pVectorOption))) + { + PTDOMElementVector propertList; + + // + // Create the common scored property list + // + for (ECommonWatermarkProps cmnProps = ECommonWatermarkPropsMin; + cmnProps < ECommonWatermarkPropsMax && SUCCEEDED(hr); + cmnProps = static_cast(cmnProps + 1)) + { + CComPtr pScoredProperty(NULL); + + if (SUCCEEDED(hr = CreateScoredProperty(CComBSTR(CMN_WATERMARK_PROPS[cmnProps]), &pScoredProperty))) + { + CComPtr pParamRef(NULL); + + // + // Construct the parameter reference elements + // + CComBSTR bstrPRefName(WATERMARK_FEATURE); + + if (wcscmp(CMN_WATERMARK_PROPS[cmnProps], L"Angle") == 0) + { + bstrPRefName += WATERMARK_OPTIONS[TextWatermark]; + } + + bstrPRefName += CMN_WATERMARK_PROPS[cmnProps]; + + if (SUCCEEDED(hr = CreateParameterRef(bstrPRefName, &pParamRef))) + { + hr = pScoredProperty->appendChild(pParamRef, NULL); + } + + propertList.push_back(pScoredProperty); + } + } + + // + // Create the vector specific property list + // + for (EVectBmpWatermarkProps vectProps = EVectBmpWatermarkPropsMin; + vectProps < EVectBmpWatermarkPropsMax && SUCCEEDED(hr); + vectProps = static_cast(vectProps + 1)) + { + // + // Create the scored property element + // + CComPtr pScoredProperty(NULL); + + if (SUCCEEDED(hr = CreateScoredProperty(CComBSTR(VECTBMP_WATERMARK_PROPS[vectProps]), &pScoredProperty))) + { + CComPtr pParamRef(NULL); + + // + // Construct the parameter reference elements + // + CComBSTR bstrPRefName(WATERMARK_FEATURE); + bstrPRefName += VECTBMP_WATERMARK_PROPS[vectProps]; + + if (SUCCEEDED(hr = CreateParameterRef(bstrPRefName, &pParamRef))) + { + hr = pScoredProperty->appendChild(pParamRef, NULL); + } + + propertList.push_back(pScoredProperty); + } + } + + // + // Add the properties to the vector option + // + PTDOMElementVector::iterator iterPropertList = propertList.begin(); + + for (;iterPropertList != propertList.end() && SUCCEEDED(hr); iterPropertList++) + { + hr = pVectorOption->appendChild(*iterPropertList, NULL); + } + + if (SUCCEEDED(hr)) + { + hr = pFeatureElement->appendChild(pVectorOption, NULL); + } + } + + CComPtr pBitmapOption(NULL); + + // + // Create the Bitmap Watermark Options + // + if (SUCCEEDED(hr) && + SUCCEEDED(hr = CreateOption(CComBSTR(WATERMARK_OPTIONS[BitmapWatermark]), NULL, &pBitmapOption))) + { + PTDOMElementVector propertList; + + // + // Create the common scored property list + // + for (ECommonWatermarkProps cmnProps = ECommonWatermarkPropsMin; + cmnProps < ECommonWatermarkPropsMax && SUCCEEDED(hr); + cmnProps = static_cast(cmnProps + 1)) + { + CComPtr pScoredProperty(NULL); + + if (SUCCEEDED(hr = CreateScoredProperty(CComBSTR(CMN_WATERMARK_PROPS[cmnProps]), &pScoredProperty))) + { + CComPtr pParamRef(NULL); + + // + // Construct the parameter reference elements + // + CComBSTR bstrPRefName(WATERMARK_FEATURE); + + if (wcscmp(CMN_WATERMARK_PROPS[cmnProps], L"Angle") == 0) + { + hr = bstrPRefName.Append(L"Text"); + } + + bstrPRefName += CMN_WATERMARK_PROPS[cmnProps]; + + if (SUCCEEDED(hr) && + SUCCEEDED(hr = CreateParameterRef(bstrPRefName, &pParamRef))) + { + hr = pScoredProperty->appendChild(pParamRef, NULL); + } + + propertList.push_back(pScoredProperty); + } + } + + // + // Create the bitmap specific property list + // + for (EVectBmpWatermarkProps bmpProps = EVectBmpWatermarkPropsMin; + bmpProps < EVectBmpWatermarkPropsMax && SUCCEEDED(hr); + bmpProps = static_cast(bmpProps + 1)) + { + // + // Create the scored property element + // + CComPtr pScoredProperty(NULL); + + if (SUCCEEDED(hr = CreateScoredProperty(CComBSTR(VECTBMP_WATERMARK_PROPS[bmpProps]), &pScoredProperty))) + { + CComPtr pParamRef(NULL); + + // + // Construct the parameter reference elements + // + CComBSTR bstrPRefName(WATERMARK_FEATURE); + bstrPRefName += VECTBMP_WATERMARK_PROPS[bmpProps]; + + if (SUCCEEDED(hr = CreateParameterRef(bstrPRefName, &pParamRef))) + { + hr = pScoredProperty->appendChild(pParamRef, NULL); + } + + propertList.push_back(pScoredProperty); + } + } + + // + // Add the properties to the bitmap option + // + PTDOMElementVector::iterator iterPropertList = propertList.begin(); + + for (;iterPropertList != propertList.end() && SUCCEEDED(hr); iterPropertList++) + { + hr = pBitmapOption->appendChild(*iterPropertList, NULL); + } + + if (SUCCEEDED(hr)) + { + hr = pFeatureElement->appendChild(pBitmapOption, NULL); + } + } + + CComPtr pLayeringFeature(NULL); + + // + // Create the layering feature options + // + if (SUCCEEDED(hr) && + SUCCEEDED(hr = CreateFeature(CComBSTR(LAYERING_FEATURE), NULL, &pLayeringFeature))) + { + PTDOMElementVector optionList; + + // + // Create the layering option list + // + for (ELayeringOption wmLayering = ELayeringOptionMin; + wmLayering < ELayeringOptionMax && SUCCEEDED(hr); + wmLayering = static_cast(wmLayering + 1)) + { + CComPtr pOptionProperty(NULL); + + if (SUCCEEDED(hr = CreateOption(CComBSTR(LAYERING_OPTIONS[wmLayering]), NULL, &pOptionProperty))) + { + optionList.push_back(pOptionProperty); + } + } + + // + // Add the options to the layering feature + // + PTDOMElementVector::iterator iterOptionList = optionList.begin(); + + for (;iterOptionList != optionList.end() && SUCCEEDED(hr); iterOptionList++) + { + hr = pLayeringFeature->appendChild(*iterOptionList, NULL); + } + + if (SUCCEEDED(hr)) + { + hr = pFeatureElement->appendChild(pLayeringFeature, NULL); + } + } + + if (SUCCEEDED(hr)) + { + hr = pPTRoot->appendChild(pFeatureElement, NULL); + } + } + + // + // Create the integer parameter defs + // + for (UINT cIndex = 0; SUCCEEDED(hr) && cIndex < numof(wmParamDefIntegers); cIndex++) + { + CComPtr pParameterDef(NULL); + + // + // PageWatermarkTextColor has no associated multiple value + // + INT multiple; + if (wcscmp(CComBSTR(wmParamDefIntegers[cIndex].property_name), L"PageWatermarkTextColor") == 0) + { + // + // convert integer representation into a string parameter in the + // PrintCapabilities. This is a special case because it's treated + // as an int in the DEVMODE & a string in the PrintTicket + // + CComBSTR bstrDefault(L"#AARRGGBB"); + hr = StringCchPrintf(bstrDefault, SysStringLen(bstrDefault)+1, TEXT("#%.8X"), wmParamDefIntegers[cIndex].default_value); + + if (SUCCEEDED(hr)) + { + hr = CreateStringParameterDef(CComBSTR(wmParamDefIntegers[cIndex].property_name), // Paramater Name + TRUE, // Is Print Schema keyword? + CComBSTR(wmParamDefIntegers[cIndex].display_name), // Display Text + bstrDefault, // Default + 9, // Min Length: + // table contains min value, which is different + 9, // Max Length: + // table contains min value, which is different + CComBSTR(wmParamDefIntegers[cIndex].unit_type), // Unit Type + &pParameterDef); // Parameter Def + } + } + else + { + multiple = wmParamDefIntegers[cIndex].multiple; + + hr = CreateIntParameterDef(CComBSTR(wmParamDefIntegers[cIndex].property_name), // Paramater Name + wmParamDefIntegers[cIndex].is_public, // Is Print Schema keyword? + CComBSTR(wmParamDefIntegers[cIndex].display_name), // Display Text + wmParamDefIntegers[cIndex].default_value, // Default + wmParamDefIntegers[cIndex].min_length, // Min value + wmParamDefIntegers[cIndex].max_length, // Max value + multiple, // Multiple + CComBSTR(wmParamDefIntegers[cIndex].unit_type), // Unit Type + &pParameterDef); // Parameter Def + } + + if (SUCCEEDED(hr)) + { + hr = pPTRoot->appendChild(pParameterDef, NULL); + } + } + + // + // Create the string parameter defs + // + for (UINT cIndex = 0; SUCCEEDED(hr) && cIndex < numof(wmParamDefStrings); cIndex++) + { + CComPtr pParameterDef(NULL); + + if (SUCCEEDED(hr = CreateStringParameterDef(CComBSTR(wmParamDefStrings[cIndex].property_name), // Paramater Name + TRUE, // Is Print Schema keyword? + CComBSTR(wmParamDefStrings[cIndex].display_name), // Display Text + CComBSTR(wmParamDefStrings[cIndex].default_value), // Default + wmParamDefStrings[cIndex].min_length, // Min Length + wmParamDefStrings[cIndex].max_length, // Max Length + CComBSTR(wmParamDefStrings[cIndex].unit_type), // Unit Type + &pParameterDef))) // Parameter Def + { + hr = pPTRoot->appendChild(pParameterDef, NULL); + } + } + } + } + catch (exception& DBG_ONLY(e)) + { + ERR(e.what()); + hr = E_FAIL; + } + + ERR_ON_HR(hr); + return hr; +} + diff --git a/print/XPSDrvSmpl/src/common/wmpchndlr.h b/print/XPSDrvSmpl/src/common/wmpchndlr.h new file mode 100644 index 00000000..2ffcaada --- /dev/null +++ b/print/XPSDrvSmpl/src/common/wmpchndlr.h @@ -0,0 +1,41 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + wmpchndlr.h + +Abstract: + + Page Watermark PrintCapabilities handling definition. The booklet PC handler + is used to set booklet settings in a PrintCapabilities. + +--*/ + +#pragma once + +#include "pchndlr.h" +#include "wmdata.h" + +class CWMPCHandler : public CPCHandler +{ +public: + CWMPCHandler( + _In_ IXMLDOMDocument2* pPrintCapabilities + ); + + virtual ~CWMPCHandler(); + + HRESULT + SetCapabilities( + VOID + ); +}; diff --git a/print/XPSDrvSmpl/src/common/wmpthndlr.cpp b/print/XPSDrvSmpl/src/common/wmpthndlr.cpp new file mode 100644 index 00000000..dcb1eff7 --- /dev/null +++ b/print/XPSDrvSmpl/src/common/wmpthndlr.cpp @@ -0,0 +1,1167 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + wmpthndlr.cpp + +Abstract: + + PageWatermark PrintTicket handler implementation. Derived from CPTHandler, + this provides PageWatermark specific Get and Set methods acting on the + PrintTicket passed (as a DOM document). + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdstring.h" +#include "xdexcept.h" +#include "wmpthndlr.h" + +using XDPrintSchema::PRINTTICKET_NAME; +using XDPrintSchema::NAME_ATTRIBUTE_NAME; +using XDPrintSchema::SCHEMA_DECIMAL; +using XDPrintSchema::SCHEMA_INTEGER; +using XDPrintSchema::SCHEMA_STRING; + +using XDPrintSchema::PageWatermark::WatermarkData; + +using XDPrintSchema::PageWatermark::EWatermarkOption; +using XDPrintSchema::PageWatermark::EWatermarkOptionMin; +using XDPrintSchema::PageWatermark::NoWatermark; +using XDPrintSchema::PageWatermark::TextWatermark; +using XDPrintSchema::PageWatermark::BitmapWatermark; +using XDPrintSchema::PageWatermark::VectorWatermark; +using XDPrintSchema::PageWatermark::EWatermarkOptionMax; + +using XDPrintSchema::PageWatermark::ECommonWatermarkProps; +using XDPrintSchema::PageWatermark::ECommonWatermarkPropsMin; +using XDPrintSchema::PageWatermark::WidthOrigin; +using XDPrintSchema::PageWatermark::HeightOrigin; +using XDPrintSchema::PageWatermark::Transparency; +using XDPrintSchema::PageWatermark::Angle; +using XDPrintSchema::PageWatermark::ECommonWatermarkPropsMax; + +using XDPrintSchema::PageWatermark::ETextWatermarkProps; +using XDPrintSchema::PageWatermark::ETextWatermarkPropsMin; +using XDPrintSchema::PageWatermark::FontColor; +using XDPrintSchema::PageWatermark::FontSize; +using XDPrintSchema::PageWatermark::Text; +using XDPrintSchema::PageWatermark::ETextWatermarkPropsMax; + +using XDPrintSchema::PageWatermark::EVectBmpWatermarkProps; +using XDPrintSchema::PageWatermark::EVectBmpWatermarkPropsMin; +using XDPrintSchema::PageWatermark::WidthExtent; +using XDPrintSchema::PageWatermark::HeightExtent; +using XDPrintSchema::PageWatermark::EVectBmpWatermarkPropsMax; + +using XDPrintSchema::PageWatermark::WATERMARK_FEATURE; +using XDPrintSchema::PageWatermark::WATERMARK_OPTIONS; +using XDPrintSchema::PageWatermark::CMN_WATERMARK_PROPS; +using XDPrintSchema::PageWatermark::TXT_WATERMARK_PROPS; +using XDPrintSchema::PageWatermark::VECTBMP_WATERMARK_PROPS; + +using XDPrintSchema::PageWatermark::Layering::ELayeringOption; + +using XDPrintSchema::PageWatermark::Layering::ELayeringOptionMin; +using XDPrintSchema::PageWatermark::Layering::Overlay; +using XDPrintSchema::PageWatermark::Layering::Underlay; +using XDPrintSchema::PageWatermark::Layering::ELayeringOptionMax; + +using XDPrintSchema::PageWatermark::Layering::LAYERING_FEATURE; +using XDPrintSchema::PageWatermark::Layering::LAYERING_OPTIONS; + +/*++ + +Routine Name: + + CWMPTHandler::CWMPTHandler + +Routine Description: + + CWMPTHandler class constructor + +Arguments: + + pPrintTicket - Pointer to the DOM document representation of the PrintTicket + +Return Value: + + None + +--*/ +CWMPTHandler::CWMPTHandler( + _In_ IXMLDOMDocument2* pPrintTicket + ) : + CPTHandler(pPrintTicket) +{ +} + +/*++ + +Routine Name: + + CWMPTHandler::~CWMPTHandler + +Routine Description: + + CWMPTHandler class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CWMPTHandler::~CWMPTHandler() +{ +} + +/*++ + +Routine Name: + + CWMPTHandler::GetData + +Routine Description: + + The routine fills the data structure passed in with watermark data retrieved from + the PrintTicket passed to the class constructor. + +Arguments: + + pWmData - Pointer to the watermark data structure to be filled in + +Return Value: + + HRESULT + S_OK - On success + E_ELEMENT_NOT_FOUND - Feature not present in PrintTicket + E_* - On error + +--*/ +HRESULT +CWMPTHandler::GetData( + _Out_ WatermarkData* pWmData + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pWmData, E_POINTER))) + { + CComBSTR bstrWMOption; + CComBSTR bstrLayerOption; + + if (SUCCEEDED(hr = GetFeatureOption(CComBSTR(WATERMARK_FEATURE), &bstrWMOption)) && + SUCCEEDED(hr = GetSubFeatureOption(CComBSTR(WATERMARK_FEATURE), + CComBSTR(LAYERING_FEATURE), + &bstrLayerOption)) && + SUCCEEDED(hr = GetScoredPropertyValue(CComBSTR(WATERMARK_FEATURE), + CComBSTR(CMN_WATERMARK_PROPS[WidthOrigin]), + &pWmData->widthOrigin)) && + SUCCEEDED(hr = GetScoredPropertyValue(CComBSTR(WATERMARK_FEATURE), + CComBSTR(CMN_WATERMARK_PROPS[HeightOrigin]), + &pWmData->heightOrigin)) && + SUCCEEDED(hr = GetScoredPropertyValue(CComBSTR(WATERMARK_FEATURE), + CComBSTR(CMN_WATERMARK_PROPS[Transparency]), + &pWmData->transparency)) && + SUCCEEDED(hr = GetScoredPropertyValue(CComBSTR(WATERMARK_FEATURE), + CComBSTR(CMN_WATERMARK_PROPS[Angle]), + &pWmData->angle))) + { + if (bstrWMOption == WATERMARK_OPTIONS[BitmapWatermark]) + { + pWmData->type = BitmapWatermark; + + if (SUCCEEDED(hr = GetScoredPropertyValue(CComBSTR(WATERMARK_FEATURE), + CComBSTR(VECTBMP_WATERMARK_PROPS[WidthExtent]), + &pWmData->widthExtent))) + { + hr = GetScoredPropertyValue(CComBSTR(WATERMARK_FEATURE), + CComBSTR(VECTBMP_WATERMARK_PROPS[HeightExtent]), + &pWmData->heightExtent); + } + + } + else if (bstrWMOption == WATERMARK_OPTIONS[TextWatermark]) + { + pWmData->type = TextWatermark; + if (SUCCEEDED(hr = GetScoredPropertyValue(CComBSTR(WATERMARK_FEATURE), + CComBSTR(TXT_WATERMARK_PROPS[FontColor]), + &pWmData->txtData.bstrFontColor)) && + SUCCEEDED(hr = GetScoredPropertyValue(CComBSTR(WATERMARK_FEATURE), + CComBSTR(TXT_WATERMARK_PROPS[FontSize]), + &pWmData->txtData.fontSize))) + { + hr = GetScoredPropertyValue(CComBSTR(WATERMARK_FEATURE), + CComBSTR(TXT_WATERMARK_PROPS[Text]), + &pWmData->txtData.bstrText); + } + } + else if (bstrWMOption == WATERMARK_OPTIONS[VectorWatermark]) + { + pWmData->type = VectorWatermark; + + if (SUCCEEDED(hr = GetScoredPropertyValue(CComBSTR(WATERMARK_FEATURE), + CComBSTR(VECTBMP_WATERMARK_PROPS[WidthExtent]), + &pWmData->widthExtent))) + { + hr = GetScoredPropertyValue(CComBSTR(WATERMARK_FEATURE), + CComBSTR(VECTBMP_WATERMARK_PROPS[HeightExtent]), + &pWmData->heightExtent); + } + } + else + { + hr = E_FAIL; + } + + if (SUCCEEDED(hr)) + { + if (bstrLayerOption == LAYERING_OPTIONS[Underlay]) + { + pWmData->layering = Underlay; + } + else if (bstrLayerOption == LAYERING_OPTIONS[Overlay]) + { + pWmData->layering = Overlay; + } + else + { + hr = E_FAIL; + } + } + } + + if (hr == E_ELEMENT_NOT_FOUND) + { + pWmData->type = NoWatermark; + } + } + + // + // Validate the data + // + if (SUCCEEDED(hr)) + { + if (pWmData->type < EWatermarkOptionMin || + pWmData->type >= EWatermarkOptionMax || + pWmData->layering < ELayeringOptionMin || + pWmData->layering >= ELayeringOptionMax) + { + hr = E_FAIL; + } + } + + ERR_ON_HR_EXC(hr, E_ELEMENT_NOT_FOUND); + return hr; +} + +/*++ + +Routine Name: + + CWMPTHandler::SetData + +Routine Description: + + This routine sets the watermark data in the PrintTicket passed to the + class constructor. + +Arguments: + + pWmData - Pointer to the watermark data to be set in the PrintTicket + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CWMPTHandler::SetData( + _In_ CONST WatermarkData* pWmData + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pWmData, E_POINTER))) + { + try + { + // + // Remove any existing watermark feature node + // + if (SUCCEEDED(hr = Delete()) && + pWmData->type != NoWatermark) + { + // + // Construct the appropriate watermark element + // + CComPtr pWMDataElem(NULL); + PTDOMElementVector paramInitList; + + switch (pWmData->type) + { + case TextWatermark: + { + hr = CreateTextWMElements(pWmData, &pWMDataElem, ¶mInitList); + } + break; + + case BitmapWatermark: + { + hr = CreateBitmapWMElements(pWmData, &pWMDataElem, ¶mInitList); + } + break; + + case VectorWatermark: + { + hr = CreateVectorWMElements(pWmData, &pWMDataElem, ¶mInitList); + } + break; + + default: + { + hr = E_FAIL; + } + break; + } + + // + // Insert the watermark and paramater init nodes + // + CComPtr pPTRoot(NULL); + + CComBSTR bstrPTQuery(m_bstrFrameworkPrefix); + bstrPTQuery += PRINTTICKET_NAME; + + if (SUCCEEDED(hr) && + SUCCEEDED(hr = GetNode(bstrPTQuery, &pPTRoot))) + { + hr = pPTRoot->appendChild(pWMDataElem, NULL); + + PTDOMElementVector::iterator iterParamInit = paramInitList.begin(); + + for (;iterParamInit != paramInitList.end() && SUCCEEDED(hr); iterParamInit++) + { + hr = pPTRoot->appendChild(*iterParamInit, NULL); + } + } + } + } + catch (exception& DBG_ONLY(e)) + { + ERR(e.what()); + hr = E_FAIL; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CWMPTHandler::Delete + +Routine Description: + + This routine deletes the watermark feature from the PrintTicket passed to the + class constructor + +Arguments: + + None + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CWMPTHandler::Delete( + VOID + ) +{ + // + // Remove any existing watermark feature node + // + HRESULT hr = DeleteFeature(CComBSTR(WATERMARK_FEATURE)); + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CWMPTHandler::CreateCommonWMElements + +Routine Description: + + This routine creates all the DOM elements common to all Watermark types. Note that + this routine also returns the option element seperately (so the caller can specify the + watermark type) and a list of the ParameterInit elements (so the caller can append them + to the root PrintTicket element) + +Arguments: + + pWmData - Pointer to the watermark data structure + ppWMDataElem - Pointer to an IXMLDOMElement pointer that recieves feature element + ppOptionElem - Pointer to an IXMLDOMElement pointer that recieves option element + pParamInitList - Pointer to a vector of DOM element pointers that recieves the parameter init elements + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CWMPTHandler::CreateCommonWMElements( + _In_ CONST WatermarkData* pWmData, + _Outptr_ IXMLDOMElement** ppWMDataElem, + _Outptr_ IXMLDOMElement** ppOptionElem, + _Out_ PTDOMElementVector* pParamInitList + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pWmData, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(ppWMDataElem, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(ppOptionElem, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pParamInitList, E_POINTER))) + { + *ppWMDataElem = NULL; + + if (pWmData->layering < ELayeringOptionMin || + pWmData->layering >= ELayeringOptionMax) + { + hr = E_INVALIDARG; + } + } + + if (SUCCEEDED(hr)) + { + // + // Create the feature option pair - CreateFeatureOptionPair does not + // set the option name, this is done in the calling function + // + if (SUCCEEDED(hr = CreateFeatureOptionPair(CComBSTR(WATERMARK_FEATURE), ppWMDataElem, ppOptionElem))) + { + // + // Over all common properties, create and insert the element + // + for (ECommonWatermarkProps cmnProps = ECommonWatermarkPropsMin; + cmnProps < ECommonWatermarkPropsMax && SUCCEEDED(hr); + cmnProps = static_cast(cmnProps + 1)) + { + // + // Create the scored property element + // + CComPtr pScoredProperty(NULL); + + if (SUCCEEDED(hr = CreateScoredProperty(CComBSTR(CMN_WATERMARK_PROPS[cmnProps]), &pScoredProperty))) + { + // + // Construct the param ref and param init elements + // + CComBSTR bstrPRefName(WATERMARK_FEATURE); + + if (wcscmp(CMN_WATERMARK_PROPS[cmnProps], L"Angle") == 0) + { + bstrPRefName += L"Text"; + } + + bstrPRefName += CMN_WATERMARK_PROPS[cmnProps]; + + CComPtr pParamRef(NULL); + CComPtr pParamInit(NULL); + + CComBSTR bstrType; + CComBSTR bstrValue; + + if (SUCCEEDED(hr = GetCmnPropTypeAndValue(pWmData, cmnProps, &bstrType, &bstrValue)) && + SUCCEEDED(hr = CreateParamRefInitPair(bstrPRefName, bstrType, bstrValue, &pParamRef, &pParamInit))) + { + // + // Append the parameter ref element to the scored property, append the + // scored property to the option element and add the parameter init + // element to the vector + // + CComPtr pPRInserted(NULL); + CComPtr pSPInserted(NULL); + + if (SUCCEEDED(hr = pScoredProperty->appendChild(pParamRef, &pPRInserted)) && + SUCCEEDED(hr = (*ppOptionElem)->appendChild(pScoredProperty, &pSPInserted))) + { + try + { + pParamInitList->push_back(pParamInit); + } + catch (exception& DBG_ONLY(e)) + { + ERR(e.what()); + hr = E_FAIL; + } + } + } + } + } + } + + // + // Create the layering feature + // + CComPtr pLayeringElement(NULL); + CComPtr pLayeringOptionElement(NULL); + + CComBSTR bstrAttribName(m_bstrKeywordsPrefix); + bstrAttribName += LAYERING_OPTIONS[pWmData->layering]; + + if (SUCCEEDED(hr) && + SUCCEEDED(hr = CreateFeatureOptionPair(CComBSTR(LAYERING_FEATURE), + CComBSTR(LAYERING_OPTIONS[pWmData->layering]), + &pLayeringElement, + &pLayeringOptionElement))) + { + // + // Append the layering feature to the watermark feature node + // + hr = (*ppWMDataElem)->appendChild(pLayeringElement, NULL); + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CWMPTHandler::CreateCommonVectBmpWMElements + +Routine Description: + + This routine creates all the DOM elements common to all the vector and bitmap Watermark types. + +Arguments: + + pWmData - Pointer to the watermark data structure + pOptionElem - Pointer to an IXMLDOMElement to append the elements to + pParamInitList - Pointer to a vector of DOM element pointers that recieves the parameter init elements + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CWMPTHandler::CreateCommonVectBmpWMElements( + _In_ CONST WatermarkData* pWmData, + _In_ IXMLDOMElement* pOptionElem, + _Out_ PTDOMElementVector* pParamInitList + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pWmData, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pOptionElem, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pParamInitList, E_POINTER))) + { + // + // Over all common properties, create and insert the element + // + for (EVectBmpWatermarkProps vectBmpProps = EVectBmpWatermarkPropsMin; + vectBmpProps < EVectBmpWatermarkPropsMax && SUCCEEDED(hr); + vectBmpProps = static_cast(vectBmpProps + 1)) + { + // + // Create the scored property element + // + CComPtr pScoredProperty(NULL); + + if (SUCCEEDED(hr = CreateScoredProperty(CComBSTR(VECTBMP_WATERMARK_PROPS[vectBmpProps]), &pScoredProperty))) + { + // + // Construct the param ref and param init elements + // + CComBSTR bstrPRefName(WATERMARK_FEATURE); + bstrPRefName += VECTBMP_WATERMARK_PROPS[vectBmpProps]; + + CComPtr pParamRef(NULL); + CComPtr pParamInit(NULL); + + CComBSTR bstrType; + CComBSTR bstrValue; + + if (SUCCEEDED(hr = GetCmnVectBmpPropTypeAndValue(pWmData, vectBmpProps, &bstrType, &bstrValue)) && + SUCCEEDED(hr = CreateParamRefInitPair(bstrPRefName, bstrType, bstrValue, &pParamRef, &pParamInit))) + { + // + // Append the parameter ref element to the scored property, append the + // scored property to the option element and add the parameter init + // element to the vector + // + CComPtr pPRInserted(NULL); + CComPtr pSPInserted(NULL); + + if (SUCCEEDED(hr = pScoredProperty->appendChild(pParamRef, &pPRInserted)) && + SUCCEEDED(hr = pOptionElem->appendChild(pScoredProperty, &pSPInserted))) + { + try + { + pParamInitList->push_back(pParamInit); + } + catch (exception& DBG_ONLY(e)) + { + ERR(e.what()); + hr = E_FAIL; + } + } + } + } + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CWMPTHandler::CreateTextWMElements + +Routine Description: + + This routine creates a text watermark feature in the PrintTicket + +Arguments: + + pWmData - Pointer to the watermark data structure + ppWMDataElem - Pointer to an IXMLDOMElement pointer that recieves feature element + pParamInitList - P:ointer to a vector of DOM element pointers that recieves the parameter init elements + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CWMPTHandler::CreateTextWMElements( + _In_ CONST WatermarkData* pWmData, + _Outptr_ IXMLDOMElement** ppWMDataElem, + _Out_ PTDOMElementVector* pParamInitList + ) +{ + HRESULT hr = S_OK; + + CComPtr pOptionElem(NULL); + + if (SUCCEEDED(hr = CHECK_POINTER(pWmData, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(ppWMDataElem, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pParamInitList, E_POINTER)) && + SUCCEEDED(hr = CreateCommonWMElements(pWmData, ppWMDataElem, &pOptionElem, pParamInitList))) + { + // + // Set the option node name attribute + // + CComBSTR bstrAttribName(m_bstrKeywordsPrefix); + bstrAttribName += WATERMARK_OPTIONS[TextWatermark]; + + hr = CreateXMLAttribute(pOptionElem, NAME_ATTRIBUTE_NAME, NULL, bstrAttribName ); + } + + // + // Write out the text specific options + // + if (SUCCEEDED(hr)) + { + for (ETextWatermarkProps txtProps = ETextWatermarkPropsMin; + txtProps < ETextWatermarkPropsMax && SUCCEEDED(hr); + txtProps = static_cast(txtProps + 1)) + { + // + // Create the scored property element + // + CComPtr pScoredProperty(NULL); + + if (SUCCEEDED(hr = CreateScoredProperty(CComBSTR(TXT_WATERMARK_PROPS[txtProps]), &pScoredProperty))) + { + // + // Construct the param ref and param init elements + // + CComBSTR bstrPRefName(WATERMARK_FEATURE); + bstrPRefName += TXT_WATERMARK_PROPS[txtProps]; + + CComPtr pParamRef(NULL); + CComPtr pParamInit(NULL); + + CComBSTR bstrType; + CComBSTR bstrValue; + + if (SUCCEEDED(hr = GetTxtPropTypeAndValue(pWmData, txtProps, &bstrType, &bstrValue)) && + SUCCEEDED(hr = CreateParamRefInitPair(bstrPRefName, bstrType, bstrValue, &pParamRef, &pParamInit))) + { + // + // Append the parameter ref element to the scored property, append the + // scored property to the option element and add the parameter init + // element to the param init list + // + CComPtr pPRInserted(NULL); + CComPtr pSPInserted(NULL); + + if (SUCCEEDED(hr = pScoredProperty->appendChild(pParamRef, &pPRInserted)) && + SUCCEEDED(hr = pOptionElem->appendChild(pScoredProperty, &pSPInserted))) + { + try + { + pParamInitList->push_back(pParamInit); + } + catch (exception& DBG_ONLY(e)) + { + ERR(e.what()); + hr = E_FAIL; + } + } + } + } + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CWMPTHandler::CreateBitmapWMElements + +Routine Description: + + This routine creates a bitmap watermark feature in the PrintTicket + +Arguments: + + pWmData - Pointer to the watermark data structure + ppWMDataElem - Pointer to an IXMLDOMElement pointer that recieves feature element + pParamInitList - P:ointer to a vector of DOM element pointers that recieves the parameter init elements + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CWMPTHandler::CreateBitmapWMElements( + _In_ CONST WatermarkData* pWmData, + _Outptr_ IXMLDOMElement** ppWMDataElem, + _Out_ PTDOMElementVector* pParamInitList + ) +{ + HRESULT hr = S_OK; + + CComPtr pOptionElem(NULL); + + if (SUCCEEDED(hr = CHECK_POINTER(pWmData, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(ppWMDataElem, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pParamInitList, E_POINTER)) && + SUCCEEDED(hr = CreateCommonWMElements(pWmData, ppWMDataElem, &pOptionElem, pParamInitList)) && + SUCCEEDED(hr = CreateCommonVectBmpWMElements(pWmData, pOptionElem, pParamInitList))) + { + // + // Set the option node name attribute + // + CComBSTR bstrAttribName(m_bstrKeywordsPrefix); + bstrAttribName += WATERMARK_OPTIONS[BitmapWatermark]; + + hr = CreateXMLAttribute(pOptionElem, NAME_ATTRIBUTE_NAME, NULL, bstrAttribName ); + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CWMPTHandler::CreateVectorWMElements + +Routine Description: + + This routine creates a vector watermark feature in the PrintTicket + +Arguments: + + pWmData - Pointer to the watermark data structure + ppWMDataElem - Pointer to an IXMLDOMElement pointer that recieves feature element + pParamInitList - P:ointer to a vector of DOM element pointers that recieves the parameter init elements + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CWMPTHandler::CreateVectorWMElements( + _In_ CONST WatermarkData* pWmData, + _Outptr_ IXMLDOMElement** ppWMDataElem, + _Out_ PTDOMElementVector* pParamInitList + ) +{ + HRESULT hr = S_OK; + + CComPtr pOptionElem(NULL); + + if (SUCCEEDED(hr = CHECK_POINTER(pWmData, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(ppWMDataElem, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pParamInitList, E_POINTER)) && + SUCCEEDED(hr = CreateCommonWMElements(pWmData, ppWMDataElem, &pOptionElem, pParamInitList)) && + SUCCEEDED(hr = CreateCommonVectBmpWMElements(pWmData, pOptionElem, pParamInitList))) + { + // + // Set the option node name attribute + // + CComBSTR bstrAttribName(m_bstrKeywordsPrefix); + bstrAttribName += WATERMARK_OPTIONS[VectorWatermark]; + + hr = CreateXMLAttribute(pOptionElem, NAME_ATTRIBUTE_NAME, NULL, bstrAttribName ); + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CWMPTHandler::GetCmnPropTypeAndValue + +Routine Description: + + This routine initalises the type and value strings for a given common watermark property + +Arguments: + + pWmData - Pointer to a watermark data structure with the watermark settings + cmnProps - The watermark setting to retrieve the type and value for + pbstrType - Pointer to a BSTR that recieves the type of the value + pbstrValue - Pointer to a BSTR that recieves the value as a string + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CWMPTHandler::GetCmnPropTypeAndValue( + _In_ CONST WatermarkData* pWmData, + _In_ CONST ECommonWatermarkProps cmnProps, + _Outptr_ BSTR* pbstrType, + _Outptr_ BSTR* pbstrValue + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pWmData, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pbstrType, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pbstrValue, E_POINTER))) + { + if (cmnProps < ECommonWatermarkPropsMin || + cmnProps >= ECommonWatermarkPropsMax) + { + hr = E_INVALIDARG; + } + } + + if (SUCCEEDED(hr)) + { + try + { + CStringXDW cstrType; + CStringXDW cstrValue; + + switch (cmnProps) + { + case WidthOrigin: + { + cstrType = SCHEMA_INTEGER; + cstrValue.Format(L"%i", pWmData->widthOrigin); + } + break; + + case HeightOrigin: + { + cstrType = SCHEMA_INTEGER; + cstrValue.Format(L"%i", pWmData->heightOrigin); + } + break; + + case Transparency: + { + cstrType = SCHEMA_INTEGER; + cstrValue.Format(L"%i", pWmData->transparency); + } + break; + + case Angle: + { + cstrType = SCHEMA_INTEGER; + cstrValue.Format(L"%i", pWmData->angle); + } + break; + + default: + { + hr = E_FAIL; + ERR("Unknown common watermark property\n"); + } + break; + } + + if (SUCCEEDED(hr)) + { + *pbstrType = cstrType.AllocSysString(); + *pbstrValue = cstrValue.AllocSysString(); + } + } + catch (CXDException& e) + { + hr = e; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CWMPTHandler::GetCmnVectBmpPropTypeAndValue + +Routine Description: + + This routine initalises the type and value strings for a common vector and bitmap + watermark properties + +Arguments: + + pWmData - Pointer to a watermark data structure with the watermark settings + cmnProps - The setting to retrieve the type and value for + pbstrType - Pointer to a BSTR that recieves the type of the value + pbstrValue - Pointer to a BSTR that recieves the value as a string + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CWMPTHandler::GetCmnVectBmpPropTypeAndValue( + _In_ CONST WatermarkData* pWmData, + _In_ CONST EVectBmpWatermarkProps cmnProps, + _Outptr_ BSTR* pbstrType, + _Outptr_ BSTR* pbstrValue + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pWmData, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pbstrType, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pbstrValue, E_POINTER))) + { + if (cmnProps < EVectBmpWatermarkPropsMin || + cmnProps >= EVectBmpWatermarkPropsMax) + { + hr = E_INVALIDARG; + } + } + + if (SUCCEEDED(hr)) + { + try + { + CStringXDW cstrType; + CStringXDW cstrValue; + + switch (cmnProps) + { + case WidthExtent: + { + cstrType = SCHEMA_INTEGER; + cstrValue.Format(L"%i", pWmData->widthExtent); + } + break; + + case HeightExtent: + { + cstrType = SCHEMA_INTEGER; + cstrValue.Format(L"%i", pWmData->heightExtent); + } + break; + + default: + { + hr = E_FAIL; + ERR("Unknown common watermark property\n"); + } + break; + } + + if (SUCCEEDED(hr)) + { + *pbstrType = cstrType.AllocSysString(); + *pbstrValue = cstrValue.AllocSysString(); + } + } + catch (CXDException& e) + { + hr = e; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CWMPTHandler::GetTxtPropTypeAndValue + +Routine Description: + + This routine initalises the type and value strings for a given text watermark property + +Arguments: + + pWmData - Pointer to a watermark data structure with the watermark settings + txtProps - The text watermark setting to retrieve the type and value for + pbstrType - Pointer to a BSTR that recieves the type of the value + pbstrValue - Pointer to a BSTR that recieves the value as a string + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CWMPTHandler::GetTxtPropTypeAndValue( + _In_ CONST WatermarkData* pWmData, + _In_ CONST ETextWatermarkProps txtProps, + _Outptr_ BSTR* pbstrType, + _Outptr_ BSTR* pbstrValue + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pWmData, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pbstrType, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pbstrValue, E_POINTER))) + { + if (txtProps < ETextWatermarkPropsMin || + txtProps >= ETextWatermarkPropsMax) + { + hr = E_INVALIDARG; + } + } + + if (SUCCEEDED(hr)) + { + try + { + CStringXDW cstrType; + CStringXDW cstrValue; + + switch (txtProps) + { + case FontColor: + { + cstrType = SCHEMA_STRING; + cstrValue.Format(L"%s", pWmData->txtData.bstrFontColor); + } + break; + + case FontSize: + { + cstrType = SCHEMA_INTEGER; + cstrValue.Format(L"%i", pWmData->txtData.fontSize); + } + break; + + case Text: + { + cstrType = SCHEMA_STRING; + cstrValue.Format(L"%s", pWmData->txtData.bstrText); + } + break; + + default: + { + hr = E_FAIL; + ERR("Unknown text watermark property\n"); + } + break; + } + + if (SUCCEEDED(hr)) + { + *pbstrType = cstrType.AllocSysString(); + *pbstrValue = cstrValue.AllocSysString(); + } + } + catch (CXDException& e) + { + hr = e; + } + } + + ERR_ON_HR(hr); + return hr; +} + diff --git a/print/XPSDrvSmpl/src/common/wmpthndlr.h b/print/XPSDrvSmpl/src/common/wmpthndlr.h new file mode 100644 index 00000000..0cfd24e8 --- /dev/null +++ b/print/XPSDrvSmpl/src/common/wmpthndlr.h @@ -0,0 +1,116 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + wmpthnlr.h + +Abstract: + + PageWatermark PrintTicket handling definition. The watermark PT handler + is used to extract watermark settings from a PrintTicket and populate + the watermark properties class with the retrieved settings. The class also + defines a method for setting the feature in the PrintTicket given the + data structure. + +--*/ + +#pragma once + +#include "pthndlr.h" +#include "wmdata.h" + +class CWMPTHandler : public CPTHandler +{ +public: + CWMPTHandler( + _In_ IXMLDOMDocument2* pPrintTicket + ); + + virtual ~CWMPTHandler(); + + HRESULT + GetData( + _Out_ XDPrintSchema::PageWatermark::WatermarkData* pWmData + ); + + HRESULT + SetData( + _In_ CONST XDPrintSchema::PageWatermark::WatermarkData* pWmData + ); + + HRESULT + Delete( + VOID + ); + +private: + HRESULT + CreateCommonWMElements( + _In_ CONST XDPrintSchema::PageWatermark::WatermarkData* pWmData, + _Outptr_ IXMLDOMElement** ppWMDataElem, + _Outptr_ IXMLDOMElement** ppOptionElem, + _Out_ PTDOMElementVector* pParamInitList + ); + + HRESULT + CreateCommonVectBmpWMElements( + _In_ CONST XDPrintSchema::PageWatermark::WatermarkData* pWmData, + _In_ IXMLDOMElement* pOptionElem, + _Out_ PTDOMElementVector* pParamInitList + ); + + HRESULT + CreateTextWMElements( + _In_ CONST XDPrintSchema::PageWatermark::WatermarkData* pWmData, + _Outptr_ IXMLDOMElement** ppWMDataElem, + _Out_ PTDOMElementVector* pParamInitList + ); + + HRESULT + CreateBitmapWMElements( + _In_ CONST XDPrintSchema::PageWatermark::WatermarkData* pWmData, + _Outptr_ IXMLDOMElement** ppWMDataElem, + _Out_ PTDOMElementVector* pParamInitList + ); + + HRESULT + CreateVectorWMElements( + _In_ CONST XDPrintSchema::PageWatermark::WatermarkData* pWmData, + _Outptr_ IXMLDOMElement** ppWMDataElem, + _Out_ PTDOMElementVector* pParamInitList + ); + + HRESULT + GetCmnPropTypeAndValue( + _In_ CONST XDPrintSchema::PageWatermark::WatermarkData* pWmData, + _In_ CONST XDPrintSchema::PageWatermark::ECommonWatermarkProps cmnProps, + _Outptr_ BSTR* pbstrType, + _Outptr_ BSTR* pbstrValue + ); + + HRESULT + GetCmnVectBmpPropTypeAndValue( + _In_ CONST XDPrintSchema::PageWatermark::WatermarkData* pWmData, + _In_ CONST XDPrintSchema::PageWatermark::EVectBmpWatermarkProps cmnProps, + _Outptr_ BSTR* pbstrType, + _Outptr_ BSTR* pbstrValue + ); + + HRESULT + GetTxtPropTypeAndValue( + _In_ CONST XDPrintSchema::PageWatermark::WatermarkData* pWmData, + _In_ CONST XDPrintSchema::PageWatermark::ETextWatermarkProps txtProps, + _Outptr_ BSTR* pbstrType, + _Outptr_ BSTR* pbstrValue + ); +}; + diff --git a/print/XPSDrvSmpl/src/common/wmschema.cpp b/print/XPSDrvSmpl/src/common/wmschema.cpp new file mode 100644 index 00000000..286e33db --- /dev/null +++ b/print/XPSDrvSmpl/src/common/wmschema.cpp @@ -0,0 +1,60 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + wmschema.cpp + +Abstract: + + PageWatermark PrintSchema implementation. This implements the features, + options and enumerations that describe the PrintSchema PageWatermark feature. + +--*/ + +#include "precomp.h" +#include "wmschema.h" + +LPCWSTR XDPrintSchema::PageWatermark::WATERMARK_FEATURE = L"PageWatermark"; + +LPCWSTR XDPrintSchema::PageWatermark::WATERMARK_OPTIONS[] = { + L"None", + L"Text", + L"BitmapGraphic", + L"VectorGraphic" +}; + +LPCWSTR XDPrintSchema::PageWatermark::CMN_WATERMARK_PROPS[] = { + L"OriginWidth", + L"OriginHeight", + L"Transparency", + L"Angle" +}; + +LPCWSTR XDPrintSchema::PageWatermark::TXT_WATERMARK_PROPS[] = { + L"TextColor", + L"TextFontSize", + L"TextText" +}; + +LPCWSTR XDPrintSchema::PageWatermark::VECTBMP_WATERMARK_PROPS[] = { + L"SizeWidth", + L"SizeHeight" +}; + +LPCWSTR XDPrintSchema::PageWatermark::Layering::LAYERING_FEATURE = L"Layering"; + +LPCWSTR XDPrintSchema::PageWatermark::Layering::LAYERING_OPTIONS[] = { + L"Underlay", + L"Overlay" +}; + + diff --git a/print/XPSDrvSmpl/src/common/wmschema.h b/print/XPSDrvSmpl/src/common/wmschema.h new file mode 100644 index 00000000..734a99df --- /dev/null +++ b/print/XPSDrvSmpl/src/common/wmschema.h @@ -0,0 +1,114 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + wmschema.h + +Abstract: + + PageWatermark PrintSchema definition. This defines the features, options + and enumerations that describe the PrintSchema PageWatermark feature within + a XDPrintSchema::PageWatermark namespace. + +--*/ + +#pragma once + +#include "schema.h" + +namespace XDPrintSchema +{ + // + // PageWatermark elements described as Printschema keywords + // + namespace PageWatermark + { + // + // Feature name + // + extern LPCWSTR WATERMARK_FEATURE; + + // + // Option names + // + enum EWatermarkOption + { + NoWatermark = 0, EWatermarkOptionMin = 0, + TextWatermark, + BitmapWatermark, + VectorWatermark, + EWatermarkOptionMax + }; + + extern LPCWSTR WATERMARK_OPTIONS[EWatermarkOptionMax]; + + // + // Common watermark properties + // + enum ECommonWatermarkProps + { + WidthOrigin = 0, ECommonWatermarkPropsMin = 0, + HeightOrigin, + Transparency, + Angle, + ECommonWatermarkPropsMax + }; + + extern LPCWSTR CMN_WATERMARK_PROPS[ECommonWatermarkPropsMax]; + + // + // Text watermark properties + // + enum ETextWatermarkProps + { + FontColor = 0, ETextWatermarkPropsMin = 0, + FontSize, + Text, + ETextWatermarkPropsMax + }; + + extern LPCWSTR TXT_WATERMARK_PROPS[ETextWatermarkPropsMax]; + + // + // Vector / Bitmap common properties + // + enum EVectBmpWatermarkProps + { + WidthExtent = 0, EVectBmpWatermarkPropsMin = 0, + HeightExtent, + EVectBmpWatermarkPropsMax + }; + + extern LPCWSTR VECTBMP_WATERMARK_PROPS[EVectBmpWatermarkPropsMax]; + + // + // Layering sub feature + // + namespace Layering + { + extern LPCWSTR LAYERING_FEATURE; + + // + // Layering options + // + enum ELayeringOption + { + Underlay = 0, ELayeringOptionMin = 0, + Overlay, + ELayeringOptionMax + }; + + extern LPCWSTR LAYERING_OPTIONS[ELayeringOptionMax]; + } + } +} + diff --git a/print/XPSDrvSmpl/src/common/workbuff.cpp b/print/XPSDrvSmpl/src/common/workbuff.cpp new file mode 100644 index 00000000..efa5fcc8 --- /dev/null +++ b/print/XPSDrvSmpl/src/common/workbuff.cpp @@ -0,0 +1,233 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + workbuff.cpp + +Abstract: + + CWorkingBuffer class implementation. This class provides a means of working + with a local buffer by defining a simple interface that allows the retrieval + of a buffer of an appropriate size, handling reallocation as necessary. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdstring.h" +#include "workbuff.h" + +/*++ + +Routine Name: + + CWorkingBuffer::CWorkingBuffer + +Routine Description: + + CWorkingBuffer class constructor + +Arguments: + + None + +Return Value: + + None + Throws CXDException(HRESULT) on an error + +--*/ +CWorkingBuffer::CWorkingBuffer() : + m_pBuffer(NULL), + m_cbSize(CB_COPY_BUFFER) +{ + m_pBuffer = HeapAlloc(GetProcessHeap(), 0, m_cbSize); + + if (m_pBuffer == NULL) + { + m_cbSize = 0; + throw CXDException(E_OUTOFMEMORY); + } +} + +/*++ + +Routine Name: + + CWorkingBuffer::~CWorkingBuffer + +Routine Description: + + CWorkingBuffer class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CWorkingBuffer::~CWorkingBuffer() +{ + if (m_pBuffer != NULL) + { + HeapFree(GetProcessHeap(), 0, m_pBuffer); + m_pBuffer = NULL; + m_cbSize = 0; + } +} + +/*++ + +Routine Name: + + CWorkingBuffer::GetBuffer + +Routine Description: + + This routine returns a pointer to a buffer of at least the requested size. If the internal + buffer is not large enough it will be resized accordingly. + +Arguments: + + cbSize - Requested size of the buffer + ppBuffer - Pointer to a VOID pointer that recieves the buffer + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CWorkingBuffer::GetBuffer( + _In_ CONST ULONGLONG cbSize, + _Outptr_result_bytebuffer_(cbSize) PVOID* ppBuffer + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(ppBuffer, E_POINTER))) + { + *ppBuffer = NULL; + + if (cbSize == 0) + { + hr = E_INVALIDARG; + } + + if (m_cbSize == 0) + { + // + // We have no existing buffer - we should have one + // + hr = E_FAIL; + } + } + + if (SUCCEEDED(hr)) + { + if (m_cbSize >= cbSize) + { + *ppBuffer = m_pBuffer; + } + else + { + // + // Double the buffer size till it is greater than the requested size + // + SIZE_T cbNewSize = m_cbSize; + while (cbNewSize < cbSize) + { + cbNewSize *= 2; + }; + + _Analysis_assume_(cbNewSize >= 1); + + // + // Reallocate the buffer + // + PVOID pNewBuffer = HeapReAlloc(GetProcessHeap(), 0, m_pBuffer, cbNewSize); + + if (pNewBuffer != NULL) + { + m_cbSize = cbNewSize; + m_pBuffer = pNewBuffer; + *ppBuffer = m_pBuffer; + } + else + { + hr = E_OUTOFMEMORY; + } + } + } + + ERR_ON_HR(hr); + return hr; +}; + +/*++ + +Routine Name: + + CWorkingBuffer::GetBufferAt + +Routine Description: + + This routine returns a pointer into the internal buffer at the requested offset. This will + not grow the size of the buffer. + +Arguments: + + cbOffset - Offset into the internal buffer + cbSize - Size of the requested buffer + ppBuffer - Pointer to a VOID pointer that recieves the buffer + +Return Value: + + HRESULT + S_OK - On success + HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) - If the internal buffer is not large enough + E_* - On error + +--*/ +HRESULT +CWorkingBuffer::GetBufferAt( + _In_ ULONG cbOffset, + _In_ CONST ULONGLONG cbSize, + _Outptr_result_bytebuffer_(cbSize) PVOID* ppBuffer + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(ppBuffer, E_POINTER))) + { + *ppBuffer = NULL; + + if (cbSize + cbOffset < m_cbSize) + { + *ppBuffer = reinterpret_cast(m_pBuffer) + cbOffset; + } + else + { + hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); + } + } + + ERR_ON_HR(hr); + return hr; +} + diff --git a/print/XPSDrvSmpl/src/common/workbuff.h b/print/XPSDrvSmpl/src/common/workbuff.h new file mode 100644 index 00000000..263e97d3 --- /dev/null +++ b/print/XPSDrvSmpl/src/common/workbuff.h @@ -0,0 +1,51 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + workbuff.h + +Abstract: + + CWorkingBuffer class definition. This class provides a means of working + with a local buffer by defining a simple interface that allows the retrieval + of a buffer of an appropriate size, handling reallocation as necessary. + +--*/ + +#pragma once + +class CWorkingBuffer +{ +public: + CWorkingBuffer(); + + virtual ~CWorkingBuffer(); + + HRESULT + GetBuffer( + _In_ CONST ULONGLONG cbSize, + _Outptr_result_bytebuffer_(cbSize) PVOID* ppBuffer + ); + + HRESULT + GetBufferAt( + _In_ ULONG cbOffset, + _In_ CONST ULONGLONG cbSize, + _Outptr_result_bytebuffer_(cbSize) PVOID* ppBuffer + ); + +private: + _Field_size_bytes_(m_cbSize) PVOID m_pBuffer; + + SIZE_T m_cbSize; +}; + diff --git a/print/XPSDrvSmpl/src/common/xdsmplcmn.vcxproj b/print/XPSDrvSmpl/src/common/xdsmplcmn.vcxproj new file mode 100644 index 00000000..663cc1c7 --- /dev/null +++ b/print/XPSDrvSmpl/src/common/xdsmplcmn.vcxproj @@ -0,0 +1,414 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {AF94DFED-1979-486B-A16E-7BBB14711EA0} + $(MSBuildProjectName) + false + true + Debug + Win32 + {C8A4DBF6-79D6-43AC-94AA-E6844FAA3175} + + + + Windows10 + False + Desktop + + WindowsApplicationForDrivers10.0 + StaticLibrary + + + Windows10 + True + Desktop + + WindowsApplicationForDrivers10.0 + StaticLibrary + + + Windows10 + False + Desktop + + WindowsApplicationForDrivers10.0 + StaticLibrary + + + Windows10 + True + Desktop + + WindowsApplicationForDrivers10.0 + StaticLibrary + + + + $(IntDir) + + + + + + + + + + + + + + + + + %(AdditionalIncludeDirectories);.\;.\..\inc;.\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + %(AdditionalIncludeDirectories);.\;.\..\inc;.\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + true + Level4 + Sync + MultiThreaded + MultiThreadedDebug + + + %(AdditionalIncludeDirectories);.\;.\..\inc;.\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + + + %(AdditionalIncludeDirectories);.\;.\..\inc;.\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + %(AdditionalIncludeDirectories);.\;.\..\inc;.\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + true + Level4 + Sync + MultiThreaded + MultiThreadedDebug + + + %(AdditionalIncludeDirectories);.\;.\..\inc;.\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + + + %(AdditionalIncludeDirectories);.\;.\..\inc;.\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + %(AdditionalIncludeDirectories);.\;.\..\inc;.\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + true + Level4 + Sync + MultiThreaded + MultiThreadedDebug + + + %(AdditionalIncludeDirectories);.\;.\..\inc;.\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + + + %(AdditionalIncludeDirectories);.\;.\..\inc;.\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + %(AdditionalIncludeDirectories);.\;.\..\inc;.\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + true + Level4 + Sync + MultiThreaded + MultiThreadedDebug + + + %(AdditionalIncludeDirectories);.\;.\..\inc;.\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + + xdsmplcmn + + + xdsmplcmn + + + xdsmplcmn + + + xdsmplcmn + + + + ;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ;%(AdditionalIncludeDirectories) + precomp.h + Create + $(IntDir)\precomp.h.pch + + + ;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/print/XPSDrvSmpl/src/common/xdsmplcmn.vcxproj.Filters b/print/XPSDrvSmpl/src/common/xdsmplcmn.vcxproj.Filters new file mode 100644 index 00000000..5129bb07 --- /dev/null +++ b/print/XPSDrvSmpl/src/common/xdsmplcmn.vcxproj.Filters @@ -0,0 +1,118 @@ + + + + + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* + {E12D861C-ACB5-4387-B204-B199497A1C30} + + + h;hpp;hxx;hm;inl;inc;xsd + {DDCEEEF8-0261-4A4E-AD8A-4CDE8C263087} + + + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml + {1E366A31-9605-41C9-A6D1-CEA007B63CEB} + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/print/XPSDrvSmpl/src/filters/booklet/bkflt.cpp b/print/XPSDrvSmpl/src/filters/booklet/bkflt.cpp new file mode 100644 index 00000000..67a4d867 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/booklet/bkflt.cpp @@ -0,0 +1,591 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + bkflt.cpp + +Abstract: + + Booklet filter implementation. This class derives from the Xps filter + class and implements the necessary part handlers to support booklet + printing. The booklet filter is responsible for re-ordering pages and re-uses + the NUp filter to provide 2-up and offset support. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdstring.h" +#include "xdexcept.h" +#include "pthndlr.h" +#include "bkflt.h" +#include "bksax.h" +#include "bkpthndlr.h" + +using XDPrintSchema::Binding::BindingData; + +/*++ + +Routine Name: + + CBookletFilter::CBookletFilter + +Routine Description: + + Default constructor for the booklet filter which initialises the + filter to sensible default values + +Arguments: + + None + +Return Value: + + None + +--*/ +CBookletFilter::CBookletFilter() : + m_bSendAllDocs(TRUE), + m_bookScope(CBkPTProperties::None) +{ +} + +/*++ + +Routine Name: + + CBookletFilter::~CBookletFilter + +Routine Description: + + Default destructor for the booklet filter + +Arguments: + + None + +Return Value: + + None + +--*/ +CBookletFilter::~CBookletFilter() +{ +} + +/*++ + +Routine Name: + + CNUpFilter::ProcessPart + +Routine Description: + + Method for processing each fixed document sequence part in a container + +Arguments: + + pFDS - Pointer to the fixed document sequence to process + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CBookletFilter::ProcessPart( + _Inout_ IFixedDocumentSequence* pFDS + ) +{ + VERBOSE("Processing Fixed Document Sequence part with booklet filter handler\n"); + + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pFDS, E_POINTER))) + { + // + // Get the PT manager to return the FixedDocumentSequence ticket. + // + IXMLDOMDocument2* pPT = NULL; + if (SUCCEEDED(hr = m_ptManager.SetTicket(pFDS)) && + SUCCEEDED(hr = m_ptManager.GetTicket(kPTJobScope, &pPT))) + { + // + // Set the binding scope from the PrintTicket + // + hr = SetBindingScope(pPT); + } + } + + if (SUCCEEDED(hr)) + { + hr = m_pXDWriter->SendFixedDocumentSequence(pFDS); + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CBookletFilter::ProcessPart + +Routine Description: + + Method for processing each fixed document part in a container + +Arguments: + + pFD - Pointer to the fixed document to process + +Return Value: + + HRESULT + S_OK - On success + S_FALSE - When not enabled in the PT + E_* - On error + +--*/ +HRESULT +CBookletFilter::ProcessPart( + _Inout_ IFixedDocument* pFD + ) +{ + VERBOSE("Processing Fixed Document part with booklet filter handler\n"); + + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pFD, E_POINTER)) && + SUCCEEDED(hr = m_ptManager.SetTicket(pFD))) + { + // + // If we are in a JobBook session we want to maintain the current + // JobBook settings + // + if (m_bookScope != CBkPTProperties::Job) + { + // + // Flush any outstanding pages in case we have just completed a + // DocNUp sequence + // + hr = FlushCache(); + + // + // Get the PT manager to return the FixedDocument ticket. + // + IXMLDOMDocument2* pPT = NULL; + if (SUCCEEDED(hr) && + SUCCEEDED(hr = m_ptManager.GetTicket(kPTDocumentScope, &pPT))) + { + // + // Set the binding scope from the PrintTicket + // + hr = SetBindingScope(pPT); + } + } + } + + if (SUCCEEDED(hr) && + m_bSendAllDocs) + { + hr = m_pXDWriter->SendFixedDocument(pFD); + + // + // If we are JobBindAllDocuments we only ever send one doc - now we have + // sent the first document we can test to see if we need to send all of them + // + if (m_bookScope == CBkPTProperties::Job) + { + m_bSendAllDocs = FALSE; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CBookletFilter::ProcessPart + +Routine Description: + + Method for processing each fixed page part in a container + +Arguments: + + pFP - Pointer to the fixed page to process + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CBookletFilter::ProcessPart( + _Inout_ IFixedPage* pFP + ) +{ + ASSERTMSG(m_pXDWriter != NULL, "XD writer is not initialised.\n"); + + VERBOSE("Processing Fixed Page with booklet filter handler\n"); + + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pFP, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(m_pXDWriter, E_PENDING))) + { + // + // Check if we are processing a booklet job + // + if (m_bookScope != CBkPTProperties::None) + { + // + // Cache pages for reordering + // + try + { + m_cacheFP.push_back(pFP); + } + catch (exception& DBG_ONLY(e)) + { + ERR(e.what()); + hr = E_FAIL; + } + } + else + { + hr = m_pXDWriter->SendFixedPage(pFP); + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CBookletFilter::Finalize + +Routine Description: + + Method to flush the cache of pages as the last action of the filter + +Arguments: + + None + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CBookletFilter::Finalize( + VOID + ) +{ + // + // Just flush the cache of pages + // + return FlushCache(); +} + +/*++ + +Routine Name: + + CBookletFilter::FlushCache + +Routine Description: + + Method to send the cached collection of pages in the correct order back + +Arguments: + + None + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CBookletFilter::FlushCache( + VOID + ) +{ + HRESULT hr = S_OK; + + if (m_pXDWriter == NULL) + { + hr = E_PENDING; + } + + size_t cPages = m_cacheFP.size(); + + if (SUCCEEDED(hr) && + cPages > 0 && + m_bookScope != CBkPTProperties::None) + { + // + // We may need to add a pad page if the page count is odd + // + CComPtr pNewFP(NULL); + if (cPages%2 == 1 && + SUCCEEDED(hr = CreatePadPage(&pNewFP))) + { + // + // We successfully created our pad page; add it to the cache + // + try + { + m_cacheFP.push_back(pNewFP); + } + catch (exception& DBG_ONLY(e)) + { + ERR(e.what()); + hr = E_FAIL; + } + + cPages++; + } + + if (SUCCEEDED(hr)) + { + try + { + // + // Re-order pages in the cache + // + map reorderedPages; + size_t newIndex = 0; + size_t pageIndex = 0; + for (pageIndex = 0; pageIndex < cPages/2; pageIndex++) + { + reorderedPages[newIndex] = m_cacheFP[pageIndex]; + newIndex += 2; + } + + newIndex = cPages - 1; + for (pageIndex = cPages/2; pageIndex < cPages; pageIndex++) + { + reorderedPages[newIndex] = m_cacheFP[pageIndex]; + newIndex -= 2; + } + + // + // Write out reordered pages + // + for (pageIndex = 0; pageIndex < cPages && SUCCEEDED(hr); pageIndex++) + { + hr = m_pXDWriter->SendFixedPage(reorderedPages[pageIndex]); + } + + // + // Clean out the cache + // + m_cacheFP.clear(); + } + catch (exception& DBG_ONLY(e)) + { + ERR(e.what()); + hr = E_FAIL; + } + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CBookletFilter::CreatePadPage + +Routine Description: + + Method to create a pad page which is required for odd page counts to + ensure pages are correctly ordered for presentation as a booklet + +Arguments: + + ppNewPage - Pointer to a pointer to the newly created fixed page + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CBookletFilter::CreatePadPage( + _Outptr_ IFixedPage** ppNewPage + ) +{ + HRESULT hr = S_OK; + + // + // Validate parameters and members before proceeding + // + if (SUCCEEDED(hr = CHECK_POINTER(ppNewPage, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(m_pXDWriter, E_PENDING))) + { + *ppNewPage = NULL; + PCWSTR pszPageName = NULL; + + try + { + // + // Create a unique name for the pad page for this print session + // + CStringXDW szNewPageName; + szNewPageName.Format(L"/Pad_page_%u.xaml", GetUniqueNumber()); + pszPageName = szNewPageName.GetBuffer(); + + // + // Create a new empty page and retrieve a writer. Also get a + // reader from the first page so we can copy the FixedPage root + // element. This ensures the page sizes match. + // + CComPtr pWriter(NULL); + CComPtr pSaxRdr(NULL); + + if (SUCCEEDED(hr) && + SUCCEEDED(hr = m_pXDWriter->GetNewEmptyPart(pszPageName, + IID_IFixedPage, + reinterpret_cast(ppNewPage), + &pWriter)) && + SUCCEEDED(hr = pSaxRdr.CoCreateInstance(CLSID_SAXXMLReader60))) + { + // + // We use a simple SAX handler which copies only the root + // element and discards all other content. + // + CBkSaxHandler bkSaxHndlr(pWriter); + CComPtr pReader(NULL); + + IFixedPage* pFP = NULL; + + pFP = m_cacheFP[0]; + + if (SUCCEEDED(hr) && + SUCCEEDED(hr = pSaxRdr->putContentHandler(&bkSaxHndlr)) && + SUCCEEDED(hr = pFP->GetStream(&pReader))) + { + CComPtr pReadStreamToSeq(NULL); + + pReadStreamToSeq.Attach(new(std::nothrow) pfp::PrintReadStreamToSeqStream(pReader)); + + if (SUCCEEDED(hr = CHECK_POINTER(pReadStreamToSeq, E_OUTOFMEMORY))) + { + hr = pSaxRdr->parse(CComVariant(static_cast(pReadStreamToSeq))); + } + } + + pWriter->Close(); + } + } + catch (CXDException& e) + { + hr = e; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CBookletFilter::SetBindingScope + +Routine Description: + + Method to retrieve the binding scope from a PrintTicket + +Arguments: + + pPT - Pointer to the PrintTicket to retrieve the scope from + +Return Value: + + HRESULT + S_OK - On success + S_FALSE - Booklet settings not present in the PT + E_* - On error + +--*/ +HRESULT +CBookletFilter::SetBindingScope( + _In_ IXMLDOMDocument2* pPT + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pPT, E_POINTER))) + { + try + { + BindingData bindingData; + CBookPTHandler bkPTHandler(pPT); + + // + // Retrieve the booklet properties from the ticket via the handler + // + if (SUCCEEDED(hr) && + SUCCEEDED(hr = bkPTHandler.GetData(&bindingData))) + { + CBkPTProperties bookletPTProps(bindingData); + + // + // Retrieve the booklet scope + // + hr = bookletPTProps.GetScope(&m_bookScope); + } + else if (hr == E_ELEMENT_NOT_FOUND) + { + // + // Booklet PT settings are not present - reset hr to S_FALSE and proceed + // + hr = S_FALSE; + } + } + catch (CXDException& e) + { + hr = e; + } + } + + return hr; +} + diff --git a/print/XPSDrvSmpl/src/filters/booklet/bkflt.h b/print/XPSDrvSmpl/src/filters/booklet/bkflt.h new file mode 100644 index 00000000..52f72378 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/booklet/bkflt.h @@ -0,0 +1,80 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + bkflt.h + +Abstract: + + Booklet filter class definition. This class derives from the Xps filter + class and implements the necessary part handlers to support booklet + printing. The booklet filter is responsible for re-ordering pages and re-uses + the NUp filter to provide 2-up and offset support. + +--*/ + +#pragma once + +#include "xdrchflt.h" +#include "bkprps.h" + +class CBookletFilter : public CXDXpsFilter +{ +public: + CBookletFilter(); + + virtual ~CBookletFilter(); + +private: + HRESULT + ProcessPart( + _Inout_ IFixedDocumentSequence* pFDS + ); + + HRESULT + ProcessPart( + _Inout_ IFixedDocument* pFD + ); + + HRESULT + ProcessPart( + _Inout_ IFixedPage* pFP + ); + + HRESULT + Finalize( + VOID + ); + + HRESULT + FlushCache( + VOID + ); + + HRESULT + CreatePadPage( + _Outptr_ IFixedPage** ppNewPage + ); + + HRESULT + SetBindingScope( + _In_ IXMLDOMDocument2* pPT + ); + +private: + vector > m_cacheFP; + + BOOL m_bSendAllDocs; + + CBkPTProperties::EBookletScope m_bookScope; +}; + diff --git a/print/XPSDrvSmpl/src/filters/booklet/bkflt.rc b/print/XPSDrvSmpl/src/filters/booklet/bkflt.rc new file mode 100644 index 00000000..4834b059 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/booklet/bkflt.rc @@ -0,0 +1,43 @@ +// +// Copyright (c) 2005 Microsoft Corporation +// +// All rights reserved. +// +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +// PARTICULAR PURPOSE. +// +// File Name: +// +// bkflt.rc +// +// Abstract: +// +// Booklet filter resource file. +// +// + +#include +#include + +#define VER_FILETYPE VFT_DLL +#define VER_FILESUBTYPE VFT2_UNKNOWN +#define VER_FILEDESCRIPTION_STR "XPSDrv Sample Booklet Filter" +#define VER_INTERNALNAME_STR "PrintFeatureFilters" + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#endif // English (U.S.) resources + +///////////////////////////////////////////////////////////////////////////// + +#include "common.ver" + diff --git a/print/XPSDrvSmpl/src/filters/booklet/bkprps.cpp b/print/XPSDrvSmpl/src/filters/booklet/bkprps.cpp new file mode 100644 index 00000000..dce58de0 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/booklet/bkprps.cpp @@ -0,0 +1,124 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + bkprps.cpp + +Abstract: + + Booklet properties class implementation. The booklet properties class + is responsible for interpreting booklet data appropriate to the booklet + filter. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "bkprps.h" + +using XDPrintSchema::Binding::BindingData; +using XDPrintSchema::Binding::JobBindAllDocuments; +using XDPrintSchema::Binding::None; + +/*++ + +Routine Name: + + CBkPTProperties::CBkPTProperties + +Routine Description: + + Default constructor for the booklet PrintTicket properties class which + sets the internal binding setting to the setting supplied + +Arguments: + + bindingData - Structure containing the booklet binding settings + from the PrintTicket + +Return Value: + + None + +--*/ +CBkPTProperties::CBkPTProperties( + _In_ CONST BindingData& bindingData + ) : + m_bindData(bindingData) +{ +} + +/*++ + +Routine Name: + + CBkPTProperties::~CBkPTProperties + +Routine Description: + + Default destructor for the CBkPTProperties class + +Arguments: + + None + +Return Value: + + None + +--*/ +CBkPTProperties::~CBkPTProperties() +{ +} + +/*++ + +Routine Name: + + CBkPTProperties::GetScope + +Routine Description: + + Method to return the booklet scope which can be either none, job wide or document wide + +Arguments: + + pBkScope - Booklet printing scope which can be None, Job wide or Document + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CBkPTProperties::GetScope( + _Out_ EBookletScope* pBkScope + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pBkScope, E_POINTER))) + { + *pBkScope = CBkPTProperties::None; + + if (m_bindData.bindOption != None) + { + *pBkScope = m_bindData.bindFeature == JobBindAllDocuments ? CBkPTProperties::Job : CBkPTProperties::Document; + } + } + + ERR_ON_HR(hr); + return hr; +} diff --git a/print/XPSDrvSmpl/src/filters/booklet/bkprps.h b/print/XPSDrvSmpl/src/filters/booklet/bkprps.h new file mode 100644 index 00000000..38d17c26 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/booklet/bkprps.h @@ -0,0 +1,52 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + bkprps.h + +Abstract: + + Booklet properties class definition. The booklet properties class + is responsible for holding and controling booklet properties. + +--*/ + +#pragma once + +#include "bkdata.h" + +class CBkPTProperties +{ +public: + enum EBookletScope + { + None = 0, + Job, + Document + }; + +public: + CBkPTProperties( + _In_ CONST XDPrintSchema::Binding::BindingData& bindingData + ); + + virtual ~CBkPTProperties(); + + HRESULT + GetScope( + _Out_ EBookletScope* pBkScope + ); + +private: + XDPrintSchema::Binding::BindingData m_bindData; +}; + diff --git a/print/XPSDrvSmpl/src/filters/booklet/bksax.cpp b/print/XPSDrvSmpl/src/filters/booklet/bksax.cpp new file mode 100644 index 00000000..8582e72c --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/booklet/bksax.cpp @@ -0,0 +1,285 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + bksax.cpp + +Abstract: + + Booklet filter SAX handler implementation. The booklet SAX handler derives + from the default SAX handler and implements the necesary SAX interfaces to + process fixed page mark-up for booklet printing. + For documents with odd page counts, we add a blank padding page so that the + 2-Up behaves correctly. All that is required of the handler is to retrieve + the fixed page open tag and write this out. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdstring.h" +#include "bksax.h" + +/*++ + +Routine Name: + + CBkSaxHandler::CBkSaxHandler + +Routine Description: + + Contructor for the booklet filters SAX handler which registers + internally the writer for sending new markup out to + +Arguments: + + pWriter - Pointer to a write stream which receives markup + +Return Value: + + None + Throws CXDException(HRESULT) on an error + +--*/ +CBkSaxHandler::CBkSaxHandler( + _In_ IPrintWriteStream* pWriter + ) : + m_pWriter(pWriter) +{ + ASSERTMSG(m_pWriter != NULL, "NULL writer passed to booklet SAX handler.\n"); + + HRESULT hr = S_OK; + if (FAILED(hr = CHECK_POINTER(m_pWriter, E_POINTER))) + { + throw CXDException(hr); + } +} + +/*++ + +Routine Name: + + CBkSaxHandler::~CBkSaxHandler + +Routine Description: + + Default destructor for the booklet filters SAX handler + +Arguments: + + None + +Return Value: + + None + +--*/ +CBkSaxHandler::~CBkSaxHandler() +{ +} + +/*++ + +Routine Name: + + CBkSaxHandler::startElement + +Routine Description: + + SAX handler method which handles each start element for the XML markup + +Arguments: + + pwchQName - Pointer to a string containing the element name + cchQName - Count of the number of characters in the element name + pAttributes - Pointer to the attribute list for the supplied element + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT STDMETHODCALLTYPE +CBkSaxHandler::startElement( + CONST wchar_t*, + INT, + CONST wchar_t*, + INT, + _In_reads_(cchQName) CONST wchar_t* pwchQName, + _In_ INT cchQName, + _In_ ISAXAttributes* pAttributes + ) +{ + HRESULT hr = S_OK; + CStringXDW cstrOut; + CComBSTR bstrElement; + + hr = bstrElement.Append(pwchQName, cchQName); + + // + // All we are doing is copying the fixed page root into the new + // document to ensure the same page size + // + INT cAttributes = 0; + if (SUCCEEDED(hr) && + bstrElement == L"FixedPage" && + SUCCEEDED(hr = pAttributes->getLength(&cAttributes))) + { + try + { + cstrOut.Append(L"<"); + cstrOut.Append(bstrElement); + } + catch (CXDException& e) + { + hr = e; + } + + // + // For all attributes + // + for (INT cIndex = 0; cIndex < cAttributes && SUCCEEDED(hr); cIndex++) + { + PCWSTR pszAttUri = NULL; + INT cchAttUri = 0; + PCWSTR pszAttName = NULL; + INT cchAttName = 0; + PCWSTR pszAttQName = NULL; + INT cchAttQName = 0; + PCWSTR pszAttValue = NULL; + INT cchAttValue = 0; + + // + // Get the attribute data ready to write out + // + if (SUCCEEDED(hr = pAttributes->getName(cIndex, + &pszAttUri, + &cchAttUri, + &pszAttName, + &cchAttName, + &pszAttQName, + &cchAttQName)) && + SUCCEEDED(hr = pAttributes->getValue(cIndex, &pszAttValue, &cchAttValue))) + { + try + { + CComBSTR bstrAttName(cchAttQName, pszAttQName); + CComBSTR bstrAttValue(cchAttValue, pszAttValue); + + // + // Delimit attributes with a space + // + cstrOut.Append(L" "); + + // + // Reconstruct the attribute and write back to + // the fixed page + // + cstrOut.Append(bstrAttName); + cstrOut.Append(L"=\""); + + // + // If this is a UnicodeString we may need to escape entities + // + if (bstrAttName == L"UnicodeString") + { + hr = EscapeEntity(&bstrAttValue); + } + + cstrOut.Append(bstrAttValue); + cstrOut.Append(L"\""); + } + catch (CXDException& e) + { + hr = e; + } + } + } + + // + // Close the fixed page tag + // + if (SUCCEEDED(hr)) + { + try + { + cstrOut.Append(L"/>"); + } + catch (CXDException& e) + { + hr = e; + } + } + + // + // Write out the empty page + // + if (SUCCEEDED(hr)) + { + hr = WriteToPrintStream(&cstrOut, m_pWriter); + } + } + + ERR_ON_HR(hr); + return hr; +} + + +/*++ + +Routine Name: + + CBkSaxHandler::startDocument + +Routine Description: + + SAX handler method which handles the start document call to ensure + the xml version is correctly set + +Arguments: + + None + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT STDMETHODCALLTYPE +CBkSaxHandler::startDocument( + void + ) +{ + HRESULT hr = S_OK; + + try + { + if (SUCCEEDED(hr = CHECK_POINTER(m_pWriter, E_FAIL))) + { + CStringXDW cstrOut(L""); + hr = WriteToPrintStream(&cstrOut, m_pWriter); + } + } + catch (CXDException& e) + { + hr = e; + } + + ERR_ON_HR(hr); + return hr; +} + diff --git a/print/XPSDrvSmpl/src/filters/booklet/bksax.h b/print/XPSDrvSmpl/src/filters/booklet/bksax.h new file mode 100644 index 00000000..7a0826b4 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/booklet/bksax.h @@ -0,0 +1,59 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + bksax.cpp + +Abstract: + + Booklet filter SAX handler definition. The booklet SAX handler derives + from the default SAX handler and implements the necesary SAX interfaces to + process fixed page mark-up for booklet printing. + For documents with odd page counts, we add a blank padding page so that the + 2-Up behaves correctly. All that is required of the handler is to retrieve + the fixed page open tag and write this out. + +--*/ + +#pragma once + +#include "saxhndlr.h" + +class CBkSaxHandler : public CSaxHandler +{ +public: + CBkSaxHandler( + _In_ IPrintWriteStream* pWriter + ); + + virtual ~CBkSaxHandler(); + + HRESULT STDMETHODCALLTYPE + startElement( + CONST wchar_t*, + INT, + CONST wchar_t*, + INT, + _In_reads_(cchQName) CONST wchar_t* pwchQName, + _In_ INT cchQName, + _In_ ISAXAttributes* pAttributes + ); + + HRESULT STDMETHODCALLTYPE + startDocument( + void + ); + +private: + CComPtr m_pWriter; +}; + diff --git a/print/XPSDrvSmpl/src/filters/booklet/dllentry.cpp b/print/XPSDrvSmpl/src/filters/booklet/dllentry.cpp new file mode 100644 index 00000000..6d6c97b9 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/booklet/dllentry.cpp @@ -0,0 +1,143 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + dllentry.cpp + +Abstract: + + Implementation of the booklet filter dllentry points. Dllmain only + stores the instance handle. DllGetClassObject calls on to a generic + get class factory template function. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "clasfact.h" +#include "bkflt.h" +#include "xdexcept.h" + +/*++ + +Routine Name: + + DllMain + +Routine Description: + + Entry point to the booklet filter which is called when a new process is started + +Arguments: + + hInst - Handle to the DLL + wReason - Specifies a flag indicating why the DLL entry-point function is being called + +Return Value: + + TRUE + +--*/ +BOOL WINAPI +DllMain( + _In_ HINSTANCE hInst, + _In_ WORD wReason, + _In_opt_ LPVOID + ) +{ + switch (wReason) + { + case DLL_PROCESS_ATTACH: + { + g_hInstance = hInst; + } + break; + } + + return TRUE; +} + +/*++ + +Routine Name: + + DllCanUnloadNow + +Routine Description: + + Method which reports whether the DLL is in use to allow the caller to unload + the DLL safely + +Arguments: + + None + +Return Value: + + HRESULT + S_OK - Dll can unload + S_FALSE - Dll can't unload + +--*/ +STDAPI +DllCanUnloadNow() +{ + if (g_cServerLocks == 0) + { + return S_OK ; + } + else + { + return S_FALSE; + } +} + +/*++ + +Routine Name: + + DllGetClassObject + +Routine Description: + + Method to return the current class object + +Arguments: + + rclsid - CLSID that will associate the correct data and code + riid - Reference to the identifier of the interface that the caller is to use to communicate with the class object + ppv - Address of pointer variable that receives the interface pointer requested in riid + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + CLASS_E_CLASSNOTAVAILABLE - On unsupported class + +--*/ +STDAPI +DllGetClassObject( + _In_ REFCLSID rclsid, + _In_ REFIID riid, + _Outptr_ LPVOID FAR* ppv + ) +{ + // + // 87AFE626-06CC-4672-A2C1-1B7CF12CBEDD + // + CLSID bookletCLSID = {0x87AFE626, 0x06CC, 0x4672, {0xA2, 0xC1, 0x1B, 0x7C, 0xF1, 0x2C, 0xBE, 0xDD}}; + + return GetFilterClassFactory(rclsid, riid, bookletCLSID, ppv); +} + diff --git a/print/XPSDrvSmpl/src/filters/booklet/precompsrc.cpp b/print/XPSDrvSmpl/src/filters/booklet/precompsrc.cpp new file mode 100644 index 00000000..5944cf51 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/booklet/precompsrc.cpp @@ -0,0 +1 @@ +#include "precomp.h" \ No newline at end of file diff --git a/print/XPSDrvSmpl/src/filters/booklet/xdbook.def b/print/XPSDrvSmpl/src/filters/booklet/xdbook.def new file mode 100644 index 00000000..ad3c7eda --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/booklet/xdbook.def @@ -0,0 +1,26 @@ +; +; Copyright (c) 2005 Microsoft Corporation +; +; All rights reserved. +; +; THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +; ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +; THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +; PARTICULAR PURPOSE. +; +; File Name: +; +; xdbook.def +; +; Abstract: +; +; Booklet filter module definition file +; + +LIBRARY XDBook + +EXPORTS + DllMain + DllCanUnloadNow PRIVATE + DllGetClassObject PRIVATE + diff --git a/print/XPSDrvSmpl/src/filters/booklet/xdbook.vcxproj b/print/XPSDrvSmpl/src/filters/booklet/xdbook.vcxproj new file mode 100644 index 00000000..47c0edb3 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/booklet/xdbook.vcxproj @@ -0,0 +1,305 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {49DD5381-63D8-41FB-B641-AFE52BFBBC32} + $(MSBuildProjectName) + false + true + Debug + Win32 + {4A9E6343-D066-42E3-BD7A-5EEE1DEFC23E} + + + + Windows10 + False + Desktop + + WindowsApplicationForDrivers10.0 + DynamicLibrary + + + Windows10 + True + Desktop + + WindowsApplicationForDrivers10.0 + DynamicLibrary + + + Windows10 + False + Desktop + + WindowsApplicationForDrivers10.0 + DynamicLibrary + + + Windows10 + True + Desktop + + WindowsApplicationForDrivers10.0 + DynamicLibrary + + + + $(IntDir) + + + + + + + + + + + + + + + + xdbook + + + xdbook + + + xdbook + + + xdbook + + + + _DllMainCRTStartup@12 + _DllMainCRTStartup + + + + + _DllMainCRTStartup@12 + _DllMainCRTStartup + + + + + _DllMainCRTStartup@12 + _DllMainCRTStartup + + + + + _DllMainCRTStartup@12 + _DllMainCRTStartup + + + + + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + MultiThreaded + MultiThreadedDebug + true + Level4 + Sync + + + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + %(AdditionalDependencies);uuid.lib;WIAGUID.lib;msxml6.lib;Kernel32.lib;ole32.lib;oleaut32.lib;prntvpt.lib;winspool.lib;gdi32.lib;gdiplus.lib;shlwapi.lib;Advapi32.lib;user32.lib;.\..\..\debug\$(IntDir)\xdsdbg.lib;.\..\..\common\$(IntDir)\xdsmplcmn.lib;.\..\..\filters\common\$(IntDir)\xdfltcmn.lib + + + + + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + MultiThreaded + MultiThreadedDebug + true + Level4 + Sync + + + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + %(AdditionalDependencies);uuid.lib;WIAGUID.lib;msxml6.lib;Kernel32.lib;ole32.lib;oleaut32.lib;prntvpt.lib;winspool.lib;gdi32.lib;gdiplus.lib;shlwapi.lib;Advapi32.lib;user32.lib;.\..\..\debug\$(IntDir)\xdsdbg.lib;.\..\..\common\$(IntDir)\xdsmplcmn.lib;.\..\..\filters\common\$(IntDir)\xdfltcmn.lib + + + + + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + MultiThreaded + MultiThreadedDebug + true + Level4 + Sync + + + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + %(AdditionalDependencies);uuid.lib;WIAGUID.lib;msxml6.lib;Kernel32.lib;ole32.lib;oleaut32.lib;prntvpt.lib;winspool.lib;gdi32.lib;gdiplus.lib;shlwapi.lib;Advapi32.lib;user32.lib;.\..\..\debug\$(IntDir)\xdsdbg.lib;.\..\..\common\$(IntDir)\xdsmplcmn.lib;.\..\..\filters\common\$(IntDir)\xdfltcmn.lib + + + + + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + MultiThreaded + MultiThreadedDebug + true + Level4 + Sync + + + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + %(AdditionalDependencies);uuid.lib;WIAGUID.lib;msxml6.lib;Kernel32.lib;ole32.lib;oleaut32.lib;prntvpt.lib;winspool.lib;gdi32.lib;gdiplus.lib;shlwapi.lib;Advapi32.lib;user32.lib;.\..\..\debug\$(IntDir)\xdsdbg.lib;.\..\..\common\$(IntDir)\xdsmplcmn.lib;.\..\..\filters\common\$(IntDir)\xdfltcmn.lib + + + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + + + ..;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ..;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ..;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ..;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + + + + xdbook.def + + + + + xdbook.def + + + + + xdbook.def + + + + + xdbook.def + + + + + ..;%(AdditionalIncludeDirectories) + precomp.h + Create + $(IntDir)\precomp.h.pch + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/print/XPSDrvSmpl/src/filters/booklet/xdbook.vcxproj.Filters b/print/XPSDrvSmpl/src/filters/booklet/xdbook.vcxproj.Filters new file mode 100644 index 00000000..bf3b77ae --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/booklet/xdbook.vcxproj.Filters @@ -0,0 +1,42 @@ + + + + + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* + {27BD41E6-67B6-4534-96A7-FFC8FA13D6ED} + + + h;hpp;hxx;hm;inl;inc;xsd + {6CF19858-A7CF-4450-B47E-44A2EE4773C2} + + + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml + {D1BDA0AD-A88B-442F-81BE-EF261866789B} + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Resource Files + + + \ No newline at end of file diff --git a/print/XPSDrvSmpl/src/filters/color/XDColMan.def b/print/XPSDrvSmpl/src/filters/color/XDColMan.def new file mode 100644 index 00000000..1e85c9f1 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/color/XDColMan.def @@ -0,0 +1,26 @@ +; +; Copyright (c) 2005 Microsoft Corporation +; +; All rights reserved. +; +; THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +; ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +; THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +; PARTICULAR PURPOSE. +; +; File Name: +; +; xdwmark.def +; +; Abstract: +; +; Watermark filter module definition file +; + +LIBRARY XDColMan + +EXPORTS + DllMain + DllCanUnloadNow PRIVATE + DllGetClassObject PRIVATE + diff --git a/print/XPSDrvSmpl/src/filters/color/XDColMan.vcxproj b/print/XPSDrvSmpl/src/filters/color/XDColMan.vcxproj new file mode 100644 index 00000000..2472150e --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/color/XDColMan.vcxproj @@ -0,0 +1,375 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {AE18BFE5-EA00-477B-A051-F28DD3078679} + $(MSBuildProjectName) + false + true + Debug + Win32 + {CE9ADAB3-2A6D-489C-BA95-DEF7AC111A28} + + + + Windows10 + False + Desktop + + WindowsApplicationForDrivers10.0 + DynamicLibrary + + + Windows10 + True + Desktop + + WindowsApplicationForDrivers10.0 + DynamicLibrary + + + Windows10 + False + Desktop + + WindowsApplicationForDrivers10.0 + DynamicLibrary + + + Windows10 + True + Desktop + + WindowsApplicationForDrivers10.0 + DynamicLibrary + + + + $(IntDir) + + + + + + + + + + + + + + + + XDColMan + + + XDColMan + + + XDColMan + + + XDColMan + + + + %(AdditionalDependencies);mscms.lib;windowscodecs.lib + _DllMainCRTStartup@12 + _DllMainCRTStartup + + + + + %(AdditionalDependencies);mscms.lib;windowscodecs.lib + _DllMainCRTStartup@12 + _DllMainCRTStartup + + + + + %(AdditionalDependencies);mscms.lib;windowscodecs.lib + _DllMainCRTStartup@12 + _DllMainCRTStartup + + + + + %(AdditionalDependencies);mscms.lib;windowscodecs.lib + _DllMainCRTStartup@12 + _DllMainCRTStartup + + + + + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + MultiThreaded + MultiThreadedDebug + true + Level4 + Sync + + + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + %(AdditionalDependencies);uuid.lib;WIAGUID.lib;msxml6.lib;Kernel32.lib;ole32.lib;oleaut32.lib;prntvpt.lib;winspool.lib;gdi32.lib;gdiplus.lib;shlwapi.lib;Advapi32.lib;user32.lib;.\..\..\debug\$(IntDir)\xdsdbg.lib;.\..\..\common\$(IntDir)\xdsmplcmn.lib;.\..\..\filters\common\$(IntDir)\xdfltcmn.lib + + + + + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + MultiThreaded + MultiThreadedDebug + true + Level4 + Sync + + + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + %(AdditionalDependencies);uuid.lib;WIAGUID.lib;msxml6.lib;Kernel32.lib;ole32.lib;oleaut32.lib;prntvpt.lib;winspool.lib;gdi32.lib;gdiplus.lib;shlwapi.lib;Advapi32.lib;user32.lib;.\..\..\debug\$(IntDir)\xdsdbg.lib;.\..\..\common\$(IntDir)\xdsmplcmn.lib;.\..\..\filters\common\$(IntDir)\xdfltcmn.lib + + + + + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + MultiThreaded + MultiThreadedDebug + true + Level4 + Sync + + + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + %(AdditionalDependencies);uuid.lib;WIAGUID.lib;msxml6.lib;Kernel32.lib;ole32.lib;oleaut32.lib;prntvpt.lib;winspool.lib;gdi32.lib;gdiplus.lib;shlwapi.lib;Advapi32.lib;user32.lib;.\..\..\debug\$(IntDir)\xdsdbg.lib;.\..\..\common\$(IntDir)\xdsmplcmn.lib;.\..\..\filters\common\$(IntDir)\xdfltcmn.lib + + + + + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + MultiThreaded + MultiThreadedDebug + true + Level4 + Sync + + + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + %(AdditionalDependencies);uuid.lib;WIAGUID.lib;msxml6.lib;Kernel32.lib;ole32.lib;oleaut32.lib;prntvpt.lib;winspool.lib;gdi32.lib;gdiplus.lib;shlwapi.lib;Advapi32.lib;user32.lib;.\..\..\debug\$(IntDir)\xdsdbg.lib;.\..\..\common\$(IntDir)\xdsmplcmn.lib;.\..\..\filters\common\$(IntDir)\xdfltcmn.lib + + + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + + + ..;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ..;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ..;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ..;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ..;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ..;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ..;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ..;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ..;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ..;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ..;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ..;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ..;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ..;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ..;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + + + + XDColMan.def + + + + + XDColMan.def + + + + + XDColMan.def + + + + + XDColMan.def + + + + + ..;%(AdditionalIncludeDirectories) + precomp.h + Create + $(IntDir)\precomp.h.pch + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/print/XPSDrvSmpl/src/filters/color/XDColMan.vcxproj.Filters b/print/XPSDrvSmpl/src/filters/color/XDColMan.vcxproj.Filters new file mode 100644 index 00000000..85d37d23 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/color/XDColMan.vcxproj.Filters @@ -0,0 +1,75 @@ + + + + + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* + {B1FD41D6-358B-4E6D-A97D-DB5CCC98735B} + + + h;hpp;hxx;hm;inl;inc;xsd + {E2C67D9D-457A-45BF-A427-1139C5F38C03} + + + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml + {08A09411-2B1D-4B63-9668-53608DD4A907} + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Resource Files + + + \ No newline at end of file diff --git a/print/XPSDrvSmpl/src/filters/color/bmpconv.cpp b/print/XPSDrvSmpl/src/filters/color/bmpconv.cpp new file mode 100644 index 00000000..8c6bd347 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/color/bmpconv.cpp @@ -0,0 +1,1187 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + bmpconv.cpp + +Abstract: + + WIC bitmap conversion class implementation. This class provides a wrapper to a bitmap + stream that uses WIC to access bitmap data and provide conversion functionality. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdstring.h" +#include "xdexcept.h" +#include "bmpconv.h" + +/*++ + +Routine Name: + + CBmpConverter::CBmpConverter + +Routine Description: + + CBmpConverter default constructor + +Arguments: + + None + +Return Value: + + None + Throws an exception on error. + +--*/ +CBmpConverter::CBmpConverter() : + m_pImagingFactory(NULL), + m_pBitmap(NULL), + m_pColorContext(NULL), + m_pCurrentLock(NULL), + m_ePixelFormat(kWICPixelFormatDontCare) +{ + // + // Make sure we have an imaging factory to work with + // + HRESULT hr = CreateImagingFactory(); + if (FAILED(hr)) + { + throw CXDException(hr); + } +} + +/*++ + +Routine Name: + + CBmpConverter::CBmpConverter + +Routine Description: + + CBmpConverter constructor + +Arguments: + + ePixFormat - Bitmap pixel format + cWidth - Bitmap width + cHeight - Bitmap height + dpiX - Bitmap horizontal resolution + dpiY - Bitmap vertical resolution + +Return Value: + + None + Throws an exception on error. + +--*/ +CBmpConverter::CBmpConverter( + _In_ CONST EWICPixelFormat& ePixFormat, + _In_ CONST UINT& cWidth, + _In_ CONST UINT& cHeight, + _In_ CONST DOUBLE& dpiX, + _In_ CONST DOUBLE& dpiY + ) : + m_pImagingFactory(NULL), + m_pBitmap(NULL), + m_pColorContext(NULL), + m_pCurrentLock(NULL), + m_ePixelFormat(ePixFormat) +{ + HRESULT hr = S_OK; + + // + // Make sure we have an imaging factory to work with... + // + if (SUCCEEDED(hr = CreateImagingFactory())) + { + // + // ...and that the underlying bitmap is created and intialized. + // + hr = Initialize(m_ePixelFormat, cWidth, cHeight, dpiX, dpiY); + } + + if (FAILED(hr)) + { + throw CXDException(hr); + } +} + +/*++ + +Routine Name: + + CBmpConverter::CBmpConverter + +Routine Description: + + CBmpConverter constructor + +Arguments: + + pStream - Stream containing the bitmap container data + +Return Value: + + None + Throws an exception on error. + +--*/ +CBmpConverter::CBmpConverter( + _In_ IStream* pStream + ) : + m_pImagingFactory(NULL), + m_pBitmap(NULL), + m_pColorContext(NULL), + m_pCurrentLock(NULL), + m_ePixelFormat(kWICPixelFormatDontCare) +{ + HRESULT hr = S_OK; + + // + // Make sure we have an imaging factory to work with... + // + if (SUCCEEDED(hr = CreateImagingFactory())) + { + // + // ...and that the underlying bitmap is created and intialized from the input stream. + // + hr = Initialize(pStream); + } + + if (FAILED(hr)) + { + throw CXDException(hr); + } +} + +/*++ + +Routine Name: + + CBmpConverter::CBmpConverter + +Routine Description: + + CBmpConverter constructor + +Arguments: + + converter - Converter class to construct from + +Return Value: + + None + Throws an exception on error. + +--*/ +CBmpConverter::CBmpConverter( + _In_ CONST CBmpConverter& converter + ) : + m_pImagingFactory(converter.m_pImagingFactory), + m_pBitmap(converter.m_pBitmap), + m_pColorContext(converter.m_pColorContext), + m_pCurrentLock(converter.m_pCurrentLock), + m_ePixelFormat(converter.m_ePixelFormat) +{ + ASSERTMSG(m_pCurrentLock == NULL, "Copying locked bitmap can lead to a deadlock when writing out the bitmap.\n"); +} + +/*++ + +Routine Name: + + CBmpConverter::~CBmpConverter + +Routine Description: + + CBmpConverter destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CBmpConverter::~CBmpConverter() +{ +} + +/*++ + +Routine Name: + + CBmpConverter::Initialize + +Routine Description: + + Initializes the bitmap given format, dimensions and resolution + +Arguments: + + ePixFormat - Bitmap pixel format + cWidth - Bitmap width + cHeight - Bitmap height + dpiX - Bitmap horizontal resolution + dpiY - Bitmap vertical resolution + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CBmpConverter::Initialize( + _In_ CONST EWICPixelFormat& ePixFormat, + _In_ CONST UINT& cWidth, + _In_ CONST UINT& cHeight, + _In_ CONST DOUBLE& dpiX, + _In_ CONST DOUBLE& dpiY + ) +{ + HRESULT hr = S_OK; + + if (ePixFormat <= kWICPixelFormatMin || + ePixFormat >= kWICPixelFormatMax || + cWidth == 0 || + cHeight == 0 || + dpiX <= 0 || + dpiY <= 0) + { + hr = E_INVALIDARG; + } + + if (SUCCEEDED(hr) && + SUCCEEDED(hr = CHECK_POINTER(m_pImagingFactory, E_PENDING))) + { + // + // Create the bitmap + // + m_pBitmap = NULL; + m_ePixelFormat = ePixFormat; + if (SUCCEEDED(hr = m_pImagingFactory->CreateBitmap(cWidth, + cHeight, + g_lutPixFrmtGuid[m_ePixelFormat], + WICBitmapCacheOnLoad, + &m_pBitmap)) && + SUCCEEDED(hr = CHECK_POINTER(m_pBitmap, E_FAIL))) + { + // + // Make sure the resolution is preserved - this can lead to strange scaling + // in an XPS document if the resoution changes + // + hr = m_pBitmap->SetResolution(dpiX, dpiY); + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CBmpConverter::Initialize + +Routine Description: + + Initializes the bitmap from a stream containing the container information + +Arguments: + + pStream - Streamed container information + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CBmpConverter::Initialize( + _In_ IStream* pStream + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pStream, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(m_pImagingFactory, E_PENDING))) + { + CComPtr pDecoder(NULL); + CComPtr pBitmapSrcFrame(NULL); + LARGE_INTEGER cbMoveFromStart = {0}; + + // + // Ensure we have released any current color contexts + // + m_pColorContext = NULL; + + // + // Create a decoder from the input stream and retrieve the first frame. Create a color context + // to recieve any potential embedded color profiles. + // + if (SUCCEEDED(hr = pStream->Seek(cbMoveFromStart, STREAM_SEEK_SET, NULL)) && + SUCCEEDED(hr = m_pImagingFactory->CreateDecoderFromStream(pStream, NULL, WICDecodeMetadataCacheOnDemand, &pDecoder)) && + SUCCEEDED(hr = CHECK_POINTER(pDecoder, E_FAIL)) && + SUCCEEDED(hr = pDecoder->GetFrame(0, &pBitmapSrcFrame)) && + SUCCEEDED(hr = CHECK_POINTER(pDecoder, E_FAIL)) && + SUCCEEDED(hr = m_pImagingFactory->CreateColorContext(&m_pColorContext)) && + SUCCEEDED(hr = CHECK_POINTER(m_pColorContext, E_FAIL))) + { + // + // Check for an embedded color context + // + UINT cColContexts = 0; + if (SUCCEEDED(hr = pBitmapSrcFrame->GetColorContexts(1, &(m_pColorContext.p), &cColContexts))) + { + // + // If there are no color contexts, ensure the color context is released + // + if (cColContexts == 0) + { + m_pColorContext = NULL; + } + + hr = Initialize(pBitmapSrcFrame); + } + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CBmpConverter::Initialize + +Routine Description: + + Intializes the bitmap from a WIC bitmap source + +Arguments: + + pSource - pointer to the WIC bitmap source interface to intialize from + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CBmpConverter::Initialize( + _In_ IWICBitmapSource* pSource + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pSource, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(m_pImagingFactory, E_PENDING))) + { + // + // Make sure we have released any current bitmaps + // + m_pBitmap = NULL; + + // + // Create the bitmap from the source and set the pixel format enumeration from the GUID + // + WICPixelFormatGUID guidPixFormat; + if (SUCCEEDED(hr = m_pImagingFactory->CreateBitmapFromSource(pSource, WICBitmapCacheOnDemand, &m_pBitmap)) && + SUCCEEDED(hr = CHECK_POINTER(m_pBitmap, E_FAIL)) && + SUCCEEDED(hr = m_pBitmap->GetPixelFormat(&guidPixFormat))) + { + hr = PixelFormatFromGUID(guidPixFormat, &m_ePixelFormat); + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CBmpConverter::Write + +Routine Description: + + Writes the bitmap to a stream using the requested container format + +Arguments: + + guidContainerFormat - Requested container format to write out + pStream - The destination stream to write to + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CBmpConverter::Write( + _In_ REFGUID guidContainerFormat, + _Inout_ IStream* pStream + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pStream, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(m_pBitmap, E_PENDING)) && + SUCCEEDED(hr = CHECK_POINTER(m_pImagingFactory, E_PENDING))) + { + CComPtr pEncoder(NULL); + CComPtr pFrame(NULL); + CComPtr pPropertyBag(NULL); + + UINT srcWidth = 0; + UINT srcHeight = 0; + + DOUBLE xRes = 0.0; + DOUBLE yRes = 0.0; + + WICPixelFormatGUID srcFormat; + + // + // Create the appropriate encoder, set the stream to recieve the data and retrieve a frame. + // Initialize the frame from the current bitmap data. + // + if (SUCCEEDED(hr = m_pImagingFactory->CreateEncoder(guidContainerFormat, NULL, &pEncoder)) && + SUCCEEDED(hr = pEncoder->Initialize(pStream, WICBitmapEncoderNoCache)) && + SUCCEEDED(hr = pEncoder->CreateNewFrame(&pFrame, &pPropertyBag)) && + SUCCEEDED(hr = CHECK_POINTER(pFrame, E_FAIL)) && + SUCCEEDED(hr = CHECK_POINTER(pPropertyBag, E_FAIL)) && + SUCCEEDED(hr = pFrame->Initialize(pPropertyBag)) && + SUCCEEDED(hr = m_pBitmap->GetSize(&srcWidth, &srcHeight)) && + SUCCEEDED(hr = m_pBitmap->GetResolution(&xRes, &yRes)) && + SUCCEEDED(hr = m_pBitmap->GetPixelFormat(&srcFormat))) + { + WICRect sizeSrc = {0}; + sizeSrc.Width = static_cast(srcWidth); + sizeSrc.Height = static_cast(srcHeight); + + if (SUCCEEDED(hr = pFrame->SetSize(srcWidth, srcHeight)) && + SUCCEEDED(hr = pFrame->SetResolution(xRes, yRes)) && + SUCCEEDED(hr = pFrame->SetPixelFormat(&srcFormat))) + { + if (HasColorContext()) + { + hr = pFrame->SetColorContexts(1, &m_pColorContext.p); + } + + if (SUCCEEDED(hr)) + { + // + // Write the bitmap data to the frame. + // + hr = pFrame->WriteSource(m_pBitmap, &sizeSrc); + } + } + } + + // + // Commit the frame and the encoder - this sets the bitmap data and encodes the + // bitmap into a container + // + if (SUCCEEDED(hr) && + SUCCEEDED(hr = pFrame->Commit())) + { + hr = pEncoder->Commit(); + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CBmpConverter::Convert + +Routine Description: + + Uses WIC to convert from the current pixel format to the requested pixel format + +Arguments: + + ePixFormat - the requested pixel format + pbCanConvert - variable that recieves whether the conversion is possible + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CBmpConverter::Convert( + _In_ EWICPixelFormat ePixFormat, + _Out_ BOOL* pbCanConvert + ) +{ + HRESULT hr = S_OK; + + if (ePixFormat > kWICPixelFormatDontCare && + ePixFormat < kWICPixelFormatMax) + { + if (SUCCEEDED(hr = CHECK_POINTER(pbCanConvert, E_POINTER))) + { + *pbCanConvert = TRUE; + } + } + else + { + hr = E_INVALIDARG; + } + + // + // If the requested format differs from the original we need to do some work. + // + if (SUCCEEDED(hr) && + ePixFormat != m_ePixelFormat) + { + CComPtr pConverter(NULL); + + WICPixelFormatGUID dstFormat = g_lutPixFrmtGuid[ePixFormat]; + WICPixelFormatGUID srcFormat; + + // + // Retrieve a format converter, intialize from the current bitmap the use the converter + // to reset the bitmap to the appropriate type. + // + if (SUCCEEDED(hr) && + SUCCEEDED(hr = CHECK_POINTER(m_pImagingFactory, E_PENDING)) && + SUCCEEDED(hr = CHECK_POINTER(m_pBitmap, E_PENDING)) && + SUCCEEDED(hr = m_pImagingFactory->CreateFormatConverter(&pConverter)) && + SUCCEEDED(hr = CHECK_POINTER(pConverter, E_FAIL)) && + SUCCEEDED(hr = m_pBitmap->GetPixelFormat(&srcFormat)) && + SUCCEEDED(hr = pConverter->CanConvert(srcFormat, dstFormat, pbCanConvert)) && + *pbCanConvert && + SUCCEEDED(hr = pConverter->Initialize(m_pBitmap, dstFormat, WICBitmapDitherTypeNone, NULL, 0.0f, WICBitmapPaletteTypeCustom))) + { + hr = Initialize(pConverter); + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CBmpConverter::LockSurface + +Routine Description: + + Locks the requested rectangle for reading and writing of the pixel data directly + +Arguments: + + prcLock - The rectangle area of the bitmap to lock + bReadOnly - Is this a read only lock + pcbStride - Pointer to variable that recieves the stride between scanlines + pcWidth - Pointer to variable that recieves the bitmap pixel width + pcHeight - Pointer to variable that recieves the bitmap pixel height + pcbData - Pointer to variable that recieves the size of the pixel data buffer + ppbData - Pointer to a BYTE pointer that recieves the data pointer + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CBmpConverter::LockSurface( + _In_ WICRect* prcLock, + _In_ CONST BOOL& bReadOnly, + _Out_ UINT* pcbStride, + _Out_ UINT* pcWidth, + _Out_ UINT* pcHeight, + _Inout_ UINT* pcbData, + _Outptr_result_bytebuffer_maybenull_(*pcbData) + PBYTE* ppbData + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(m_pBitmap, E_PENDING)) && + SUCCEEDED(hr = CHECK_POINTER(m_pImagingFactory, E_PENDING)) && + SUCCEEDED(hr = CHECK_POINTER(prcLock, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pcbStride, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pcWidth, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pcHeight, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pcbData, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(ppbData, E_POINTER))) + { + *pcbStride = 0; + *pcWidth = 0; + *pcHeight = 0; + *pcbData = 0; + *ppbData = NULL; + + // + // Free any current locks and acquire a new one. Get the stride, size and data from the lock. + // + m_pCurrentLock = NULL; + if (SUCCEEDED(hr) && + SUCCEEDED(hr = m_pBitmap->Lock(prcLock, bReadOnly ? WICBitmapLockRead : WICBitmapLockWrite, &m_pCurrentLock)) && + SUCCEEDED(hr = CHECK_POINTER(m_pCurrentLock, E_FAIL)) && + SUCCEEDED(hr = m_pCurrentLock->GetStride(pcbStride)) && + SUCCEEDED(hr = m_pCurrentLock->GetSize(pcWidth, pcHeight))) + { + hr = m_pCurrentLock->GetDataPointer(pcbData, ppbData); + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CBmpConverter::UnlockSurface + +Routine Description: + + Unlocks any current lock on the bitmap surface + +Arguments: + + None + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CBmpConverter::UnlockSurface( + VOID + ) +{ + m_pCurrentLock = NULL; + + return S_OK; +} + +/*++ + +Routine Name: + + CBmpConverter::GetColorContext + +Routine Description: + + Retrieves any color context associated with the bitmap + +Arguments: + + ppColorContext - Pointer to a color context interface pointer to recieve the context + +Return Value: + + HRESULT + S_OK - On success + E_ELEMENT_NOT_FOUND - On no context present + E_* - On error + +--*/ +HRESULT +CBmpConverter::GetColorContext( + _Outptr_ IWICColorContext** ppColorContext + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(ppColorContext, E_POINTER))) + { + *ppColorContext = NULL; + + if (HasColorContext()) + { + *ppColorContext = m_pColorContext; + } + else + { + hr = E_ELEMENT_NOT_FOUND; + } + } + + ERR_ON_HR_EXC(hr, E_ELEMENT_NOT_FOUND); + return hr; +} + +/*++ + +Routine Name: + + CBmpConverter::HasAlphaChannel + +Routine Description: + + Indicates if the bitmap has an alpha channel + +Arguments: + + None + +Return Value: + + TRUE - The bitmap has an alpha channel + FALSE - There is no alpha channel + +--*/ +BOOL +CBmpConverter::HasAlphaChannel( + VOID + ) CONST +{ + BOOL bHasAlpha = FALSE; + + switch (m_ePixelFormat) + { + case kWICPixelFormat32bppBGRA: + case kWICPixelFormat32bppPBGRA: + case kWICPixelFormat64bppRGBA: + case kWICPixelFormat64bppPRGBA: + case kWICPixelFormat128bppRGBAFloat: + case kWICPixelFormat128bppPRGBAFloat: + case kWICPixelFormat64bppRGBAFixedPoint: + case kWICPixelFormat128bppRGBAFixedPoint: + case kWICPixelFormat64bppRGBAHalf: + case kWICPixelFormat40bppCMYKAlpha: + case kWICPixelFormat80bppCMYKAlpha: + case kWICPixelFormat32bpp3ChannelsAlpha: + case kWICPixelFormat40bpp4ChannelsAlpha: + case kWICPixelFormat48bpp5ChannelsAlpha: + case kWICPixelFormat56bpp6ChannelsAlpha: + case kWICPixelFormat64bpp7ChannelsAlpha: + case kWICPixelFormat72bpp8ChannelsAlpha: + case kWICPixelFormat64bpp3ChannelsAlpha: + case kWICPixelFormat80bpp4ChannelsAlpha: + case kWICPixelFormat96bpp5ChannelsAlpha: + case kWICPixelFormat112bpp6ChannelsAlpha: + case kWICPixelFormat128bpp7ChannelsAlpha: + case kWICPixelFormat144bpp8ChannelsAlpha: + { + bHasAlpha = TRUE; + } + break; + + default: + { + } + break; + } + + return bHasAlpha; +} + +/*++ + +Routine Name: + + CBmpConverter::HasColorContext + +Routine Description: + + Indicates whether the bitmap has a color context + +Arguments: + + None + +Return Value: + + TRUE - The bitmap has a color context + FALSE - There is no color context associated with the bitmap + +--*/ +BOOL +CBmpConverter::HasColorContext( + VOID + ) CONST +{ + return m_pColorContext != NULL; +} + +/*++ + +Routine Name: + + CBmpConverter::HasColorProfile + +Routine Description: + + Indicates whether the color context (if present) contains a color profile + +Arguments: + + None + +Return Value: + + TRUE - There is a color context and it contains a color profile + FALSE - There is either no color context or the context does not contain a color profile + +--*/ +BOOL +CBmpConverter::HasColorProfile( + VOID + ) CONST +{ + BOOL bHasProfile = FALSE; + + if (HasColorContext()) + { + WICColorContextType wicContextType = WICColorContextUninitialized; + if (m_pColorContext != NULL && + SUCCEEDED(m_pColorContext->GetType(&wicContextType))) + { + bHasProfile = wicContextType == WICColorContextProfile; + } + } + + return bHasProfile; +} + +/*++ + +Routine Name: + + CBmpConverter::GetPixelFormat + +Routine Description: + + Retrieves the underlying pixel format + +Arguments: + + None + +Return Value: + + Enumerated value identifying the current pixel format of the bitmap + +--*/ +EWICPixelFormat +CBmpConverter::GetPixelFormat( + VOID + ) +{ + return m_ePixelFormat; +} + +/*++ + +Routine Name: + + CBmpConverter::GetSize + +Routine Description: + + Retrieves the dimensions of the bitmap + +Arguments: + + pcWidth - Pointer to a variable that recieves the pixel width + pcHeight - Pointer to a variable that recieves the pixel height + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CBmpConverter::GetSize( + _Out_ UINT* pcWidth, + _Out_ UINT* pcHeight + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(m_pBitmap, E_PENDING)) && + SUCCEEDED(hr = CHECK_POINTER(m_pImagingFactory, E_PENDING)) && + SUCCEEDED(hr = CHECK_POINTER(pcWidth, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pcHeight, E_POINTER))) + { + *pcWidth = 0; + *pcHeight = 0; + + hr = m_pBitmap->GetSize(pcWidth, pcHeight); + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CBmpConverter::GetResolution + +Routine Description: + + Retrieves the resolution of the underlying bitmap + +Arguments: + + pDpiX - Pointer to a variable that recieves the horizontal resolution + pDpiY - Pointer to a variable that recieves the vertical resolution + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CBmpConverter::GetResolution( + _Out_ DOUBLE* pDpiX, + _Out_ DOUBLE* pDpiY + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(m_pBitmap, E_PENDING)) && + SUCCEEDED(hr = CHECK_POINTER(m_pImagingFactory, E_PENDING)) && + SUCCEEDED(hr = CHECK_POINTER(pDpiX, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pDpiY, E_POINTER))) + { + *pDpiX = 0.0; + *pDpiY = 0.0; + + hr = m_pBitmap->GetResolution(pDpiX, pDpiY); + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CBmpConverter::SetProfile + +Routine Description: + + This method sets creates a color context based of the supplied profile filename and + associates that cotext with the bitmap + +Arguments: + + szProfile - The profile filename + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CBmpConverter::SetProfile( + _In_z_ LPWSTR szProfile + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(szProfile, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(m_pImagingFactory, E_PENDING))) + { + m_pColorContext = NULL; + if (SUCCEEDED(hr = m_pImagingFactory->CreateColorContext(&m_pColorContext))) + { + hr = m_pColorContext->InitializeFromFilename(szProfile); + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CBmpConverter::operator= + +Routine Description: + + Assignment operator + +Arguments: + + converter - Instance of a CBmpConverter to be assigned to + +Return Value: + + Reference to the newly assigned CBmpConverter instance + +--*/ +CBmpConverter& +CBmpConverter::operator=( + _In_ CONST CBmpConverter& converter + ) +{ + // + // Assign all the member pointers. The COM pointer takes care of reference counting. + // + m_pImagingFactory = converter.m_pImagingFactory; + m_pBitmap = converter.m_pBitmap; + m_pColorContext = converter.m_pColorContext; + m_pCurrentLock = converter.m_pCurrentLock; + m_ePixelFormat = converter.m_ePixelFormat; + + ASSERTMSG(m_pCurrentLock == NULL, "Copying locked bitmap can lead to a deadlock.\n"); + + return *this; +} + +/*++ + +Routine Name: + + CBmpConverter::CreateImagingFactory + +Routine Description: + + Creates the WIC imaging factory + +Arguments: + + None + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CBmpConverter::CreateImagingFactory( + VOID + ) +{ + m_pImagingFactory = NULL; + HRESULT hr = m_pImagingFactory.CoCreateInstance(CLSID_WICImagingFactory); + if (SUCCEEDED(hr)) + { + hr = CHECK_POINTER(m_pImagingFactory, E_FAIL); + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CBmpConverter::PixelFormatFromGUID + +Routine Description: + + Converts the WIC pixel format GUID to the matching pixel format enumeration + +Arguments: + + pixelFormat - GUID defining the pixel format + pPixFormat - Pointer to the pixel format to be set + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CBmpConverter::PixelFormatFromGUID( + _In_ REFGUID pixelFormat, + _Out_ EWICPixelFormat* pPixFormat + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pPixFormat, E_POINTER))) + { + *pPixFormat = kWICPixelFormatDontCare; + BOOL bFound = 0; + + // + // Loop all the potential formats + // + for (UINT cFormat = 0; + cFormat < kWICPixelFormatMax; + cFormat++) + { + // + // Try to match the guid + // + if (pixelFormat == g_lutPixFrmtGuid[cFormat]) + { + // + // The index provides the corresponding pixel format enumerated value + // + bFound = TRUE; + *pPixFormat = static_cast(cFormat); + break; + } + } + + if (!bFound) + { + RIP("Could not match format GUID\n"); + hr = E_FAIL; + } + } + + ERR_ON_HR(hr); + return hr; +} + diff --git a/print/XPSDrvSmpl/src/filters/color/bmpconv.h b/print/XPSDrvSmpl/src/filters/color/bmpconv.h new file mode 100644 index 00000000..5bed56b4 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/color/bmpconv.h @@ -0,0 +1,168 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + bmpconv.h + +Abstract: + + WIC bitmap conversion class definition. This class provides a wrapper to a bitmap + stream that uses WIC to access bitmap data and provide conversion functionality. + +--*/ + +#pragma once + +#include "bmpdata.h" + +class CBmpConverter +{ +public: + CBmpConverter(); + + CBmpConverter( + _In_ CONST EWICPixelFormat& ePixFormat, + _In_ CONST UINT& cWidth, + _In_ CONST UINT& cHeight, + _In_ CONST DOUBLE& dpiX, + _In_ CONST DOUBLE& dpiY + ); + + CBmpConverter( + _In_ IStream* pStream + ); + + CBmpConverter( + _In_ CONST CBmpConverter& converter + ); + + virtual ~CBmpConverter(); + + HRESULT + Initialize( + _In_ CONST EWICPixelFormat& ePixFormat, + _In_ CONST UINT& cWidth, + _In_ CONST UINT& cHeight, + _In_ CONST DOUBLE& dpiX, + _In_ CONST DOUBLE& dpiY + ); + + HRESULT + Initialize( + _In_ IStream* pStream + ); + + HRESULT + Initialize( + _In_ IWICBitmapSource* pSource + ); + + HRESULT + Write( + _In_ REFGUID guidContainerFormat, + _Inout_ IStream* pStream + ); + + HRESULT + Convert( + _In_ EWICPixelFormat ePixFormat, + _Out_ BOOL* pbCanConvert + ); + + HRESULT + LockSurface( + _In_ WICRect* prcLock, + _In_ CONST BOOL& bReadOnly, + _Out_ UINT* pcbStride, + _Out_ UINT* pcWidth, + _Out_ UINT* pcHeight, + _Inout_ UINT* pcbData, + _Outptr_result_bytebuffer_maybenull_(*pcbData) + PBYTE* ppbData + ); + + HRESULT + UnlockSurface( + VOID + ); + + HRESULT + GetColorContext( + _Outptr_ IWICColorContext** ppColorContext + ); + + BOOL + HasAlphaChannel( + VOID + ) CONST; + + BOOL + HasColorContext( + VOID + ) CONST; + + BOOL + HasColorProfile( + VOID + ) CONST; + + EWICPixelFormat + GetPixelFormat( + VOID + ); + + HRESULT + GetSize( + _Out_ UINT* pcWidth, + _Out_ UINT* pcHeight + ); + + HRESULT + GetResolution( + _Out_ DOUBLE* pDpiX, + _Out_ DOUBLE* pDpiY + ); + + HRESULT + SetProfile( + _In_z_ LPWSTR szProfile + ); + + CBmpConverter& + operator=( + _In_ CONST CBmpConverter& converter + ); + +private: + HRESULT + CreateImagingFactory( + VOID + ); + + HRESULT + PixelFormatFromGUID( + _In_ REFGUID pixelFormat, + _Out_ EWICPixelFormat* pPixFormat + ); + +protected: + CComPtr m_pImagingFactory; + + CComPtr m_pBitmap; + + CComPtr m_pColorContext; + + CComPtr m_pCurrentLock; + + EWICPixelFormat m_ePixelFormat; +}; + diff --git a/print/XPSDrvSmpl/src/filters/color/bmpdata.cpp b/print/XPSDrvSmpl/src/filters/color/bmpdata.cpp new file mode 100644 index 00000000..b4df4d02 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/color/bmpdata.cpp @@ -0,0 +1,253 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + bmpdata.cpp + +Abstract: + + This file supplies various look-up tables for use in converting and color matching + input bitmaps via WCS/ICM and WIC + +--*/ + +#include "precomp.h" +#include "globals.h" +#include "bmpdata.h" + +/* +Look up table between WIC pixel format enumeration and WIC pixel format GUID +*/ +CONST WICPixelFormatGUID g_lutPixFrmtGuid[kWICPixelFormatMax] = { + GUID_WICPixelFormatDontCare, + GUID_WICPixelFormat1bppIndexed, + GUID_WICPixelFormat2bppIndexed, + GUID_WICPixelFormat4bppIndexed, + GUID_WICPixelFormat8bppIndexed, + GUID_WICPixelFormatBlackWhite, + GUID_WICPixelFormat2bppGray, + GUID_WICPixelFormat4bppGray, + GUID_WICPixelFormat8bppGray, + GUID_WICPixelFormat16bppBGR555, + GUID_WICPixelFormat16bppBGR565, + GUID_WICPixelFormat16bppGray, + GUID_WICPixelFormat24bppBGR, + GUID_WICPixelFormat24bppRGB, + GUID_WICPixelFormat32bppBGR, + GUID_WICPixelFormat32bppBGRA, + GUID_WICPixelFormat32bppPBGRA, + GUID_WICPixelFormat32bppGrayFloat, + GUID_WICPixelFormat48bppRGBFixedPoint, + GUID_WICPixelFormat16bppGrayFixedPoint, + GUID_WICPixelFormat32bppBGR101010, + GUID_WICPixelFormat48bppRGB, + GUID_WICPixelFormat64bppRGBA, + GUID_WICPixelFormat64bppPRGBA, + GUID_WICPixelFormat96bppRGBFixedPoint, + GUID_WICPixelFormat128bppRGBAFloat, + GUID_WICPixelFormat128bppPRGBAFloat, + GUID_WICPixelFormat128bppRGBFloat, + GUID_WICPixelFormat32bppCMYK, + GUID_WICPixelFormat64bppRGBAFixedPoint, + GUID_WICPixelFormat64bppRGBFixedPoint, + GUID_WICPixelFormat128bppRGBAFixedPoint, + GUID_WICPixelFormat128bppRGBFixedPoint, + GUID_WICPixelFormat64bppRGBAHalf, + GUID_WICPixelFormat64bppRGBHalf, + GUID_WICPixelFormat48bppRGBHalf, + GUID_WICPixelFormat32bppRGBE, + GUID_WICPixelFormat16bppGrayHalf, + GUID_WICPixelFormat32bppGrayFixedPoint, + GUID_WICPixelFormat64bppCMYK, + GUID_WICPixelFormat24bpp3Channels, + GUID_WICPixelFormat32bpp4Channels, + GUID_WICPixelFormat40bpp5Channels, + GUID_WICPixelFormat48bpp6Channels, + GUID_WICPixelFormat56bpp7Channels, + GUID_WICPixelFormat64bpp8Channels, + GUID_WICPixelFormat48bpp3Channels, + GUID_WICPixelFormat64bpp4Channels, + GUID_WICPixelFormat80bpp5Channels, + GUID_WICPixelFormat96bpp6Channels, + GUID_WICPixelFormat112bpp7Channels, + GUID_WICPixelFormat128bpp8Channels, + GUID_WICPixelFormat40bppCMYKAlpha, + GUID_WICPixelFormat80bppCMYKAlpha, + GUID_WICPixelFormat32bpp3ChannelsAlpha, + GUID_WICPixelFormat40bpp4ChannelsAlpha, + GUID_WICPixelFormat48bpp5ChannelsAlpha, + GUID_WICPixelFormat56bpp6ChannelsAlpha, + GUID_WICPixelFormat64bpp7ChannelsAlpha, + GUID_WICPixelFormat72bpp8ChannelsAlpha, + GUID_WICPixelFormat64bpp3ChannelsAlpha, + GUID_WICPixelFormat80bpp4ChannelsAlpha, + GUID_WICPixelFormat96bpp5ChannelsAlpha, + GUID_WICPixelFormat112bpp6ChannelsAlpha, + GUID_WICPixelFormat128bpp7ChannelsAlpha, + GUID_WICPixelFormat144bpp8ChannelsAlpha +}; + +/* +Look-up table between WICPixelFormat enumeration and conversion information + +The aim of this table is to assist us in transforming the input WCS data into a format acceptable +to WCS/ICM TranslateBitmapBits call. The sort of problems this aims to resolve are: + + 1. The lack of S7DOT24FIXED format support in WCS/ICM. + 2. The lack of half format support in WCS/ICM. + 3. The lack of support for > 8bpc in WCS/ICM for channel counts > 4 + +The table is used in the following way: + + 1. Look-up the most appropriate WIC pixel format for color conversion by indexing into + the table using the matching WIC pixel format enumeration then using WIC to convert + to this format. + 2. Identify the matching BMFORMAT enumeration to process with WCS/ICM + 3. Identify where we need to process alpha data seperately and using an intermediate + transform buffer to pass to ICM/WCS where necessary + +Additionally the table also provides useful look-up information for use when processing +intermediate transform buffers: channel count, alpha channel placement and color data type. + +*/ +CONST WICToBMFORMAT g_lutWICToBMFormat[kWICPixelFormatMax] = { + {kWICPixelFormat24bppRGB, kBM_RGBTRIPLETS, FALSE, 3, 0, COLOR_BYTE}, // kWICPixelFormatDontCare + {kWICPixelFormat24bppRGB, kBM_RGBTRIPLETS, FALSE, 3, 0, COLOR_BYTE}, // kWICPixelFormat1bppIndexed + {kWICPixelFormat24bppRGB, kBM_RGBTRIPLETS, FALSE, 3, 0, COLOR_BYTE}, // kWICPixelFormat2bppIndexed + {kWICPixelFormat24bppRGB, kBM_RGBTRIPLETS, FALSE, 3, 0, COLOR_BYTE}, // kWICPixelFormat4bppIndexed + {kWICPixelFormat24bppRGB, kBM_RGBTRIPLETS, FALSE, 3, 0, COLOR_BYTE}, // kWICPixelFormat8bppIndexed + {kWICPixelFormat8bppGray, kBM_GRAY, FALSE, 1, 0, COLOR_BYTE}, // kWICPixelFormatBlackWhite + {kWICPixelFormat8bppGray, kBM_GRAY, FALSE, 1, 0, COLOR_BYTE}, // kWICPixelFormat2bppGray + {kWICPixelFormat8bppGray, kBM_GRAY, FALSE, 1, 0, COLOR_BYTE}, // kWICPixelFormat4bppGray + {kWICPixelFormat8bppGray, kBM_GRAY, FALSE, 1, 0, COLOR_BYTE}, // kWICPixelFormat8bppGray + {kWICPixelFormat24bppRGB, kBM_RGBTRIPLETS, FALSE, 3, 0, COLOR_BYTE}, // kWICPixelFormat16bppBGR555 + {kWICPixelFormat24bppRGB, kBM_RGBTRIPLETS, FALSE, 3, 0, COLOR_BYTE}, // kWICPixelFormat16bppBGR565 + {kWICPixelFormat16bppGray, kBM_16b_GRAY, FALSE, 1, 0, COLOR_WORD}, // kWICPixelFormat16bppGray + {kWICPixelFormat24bppBGR, kBM_BGRTRIPLETS, FALSE, 3, 0, COLOR_BYTE}, // kWICPixelFormat24bppBGR + {kWICPixelFormat24bppRGB, kBM_RGBTRIPLETS, FALSE, 3, 0, COLOR_BYTE}, // kWICPixelFormat24bppRGB + {kWICPixelFormat24bppBGR, kBM_BGRTRIPLETS, FALSE, 3, 0, COLOR_BYTE}, // kWICPixelFormat32bppBGR + {kWICPixelFormat32bppBGRA, kBM_xRGBQUADS, FALSE, 4, 3, COLOR_BYTE}, // kWICPixelFormat32bppBGRA + {kWICPixelFormat32bppPBGRA, kBM_xRGBQUADS, FALSE, 4, 3, COLOR_BYTE}, // kWICPixelFormat32bppPBGRA + {kWICPixelFormat16bppGray, kBM_16b_GRAY, FALSE, 1, 0, COLOR_WORD}, // kWICPixelFormat32bppGrayFloat + {kWICPixelFormat48bppRGBFixedPoint, kBM_S2DOT13FIXED_scRGB, FALSE, 3, 0, COLOR_S2DOT13FIXED}, // kWICPixelFormat48bppRGBFixedPoint + {kWICPixelFormat16bppGray, kBM_16b_GRAY, FALSE, 1, 0, COLOR_WORD}, // kWICPixelFormat16bppGrayFixedPoint + {kWICPixelFormat48bppRGB, kBM_16b_RGB, FALSE, 3, 0, COLOR_WORD}, // kWICPixelFormat32bppBGR101010 + {kWICPixelFormat48bppRGB, kBM_16b_RGB, FALSE, 3, 0, COLOR_WORD}, // kWICPixelFormat48bppRGB + {kWICPixelFormat64bppRGBA, kBM_16b_RGB, TRUE, 4, 3, COLOR_WORD}, // kWICPixelFormat64bppRGBA + {kWICPixelFormat64bppPRGBA, kBM_16b_RGB, TRUE, 4, 3, COLOR_WORD}, // kWICPixelFormat64bppPRGBA + {kWICPixelFormat128bppRGBFloat, kBM_32b_scRGB, TRUE, 4, 0, COLOR_FLOAT}, // kWICPixelFormat96bppRGBFixedPoint + {kWICPixelFormat128bppRGBAFloat, kBM_32b_scARGB, FALSE, 4, 3, COLOR_FLOAT}, // kWICPixelFormat128bppRGBAFloat + {kWICPixelFormat128bppPRGBAFloat, kBM_32b_scARGB, FALSE, 4, 3, COLOR_FLOAT}, // kWICPixelFormat128bppPRGBAFloat + {kWICPixelFormat128bppRGBFloat, kBM_32b_scARGB, FALSE, 4, 0, COLOR_FLOAT}, // kWICPixelFormat128bppRGBFloat + {kWICPixelFormat32bppCMYK, kBM_CMYKQUADS, FALSE, 4, 0, COLOR_BYTE}, // kWICPixelFormat32bppCMYK + {kWICPixelFormat64bppRGBAFixedPoint, kBM_S2DOT13FIXED_scARGB, FALSE, 4, 3, COLOR_S2DOT13FIXED}, // kWICPixelFormat64bppRGBAFixedPoint + {kWICPixelFormat64bppRGBFixedPoint, kBM_S2DOT13FIXED_scARGB, FALSE, 4, 0, COLOR_S2DOT13FIXED}, // kWICPixelFormat64bppRGBFixedPoint + {kWICPixelFormat128bppRGBAFloat, kBM_32b_scARGB, FALSE, 4, 3, COLOR_FLOAT}, // kWICPixelFormat128bppRGBAFixedPoint + {kWICPixelFormat128bppRGBAFloat, kBM_32b_scARGB, FALSE, 4, 0, COLOR_FLOAT}, // kWICPixelFormat128bppRGBFixedPoint + {kWICPixelFormat128bppRGBAFloat, kBM_32b_scARGB, FALSE, 4, 3, COLOR_FLOAT}, // kWICPixelFormat64bppRGBAHalf + {kWICPixelFormat128bppRGBAFloat, kBM_32b_scARGB, FALSE, 4, 0, COLOR_FLOAT}, // kWICPixelFormat64bppRGBHalf + {kWICPixelFormat128bppRGBAFloat, kBM_32b_scARGB, FALSE, 4, 0, COLOR_FLOAT}, // kWICPixelFormat48bppRGBHalf + {kWICPixelFormat128bppRGBAFloat, kBM_32b_scARGB, FALSE, 4, 3, COLOR_FLOAT}, // kWICPixelFormat32bppRGBE + {kWICPixelFormat16bppGray, kBM_16b_GRAY, FALSE, 1, 0, COLOR_WORD}, // kWICPixelFormat16bppGrayHalf + {kWICPixelFormat16bppGray, kBM_16b_GRAY, FALSE, 1, 0, COLOR_WORD}, // kWICPixelFormat32bppGrayFixedPoint + {kWICPixelFormat32bpp4Channels, kBM_CMYKQUADS, FALSE, 4, 0, COLOR_BYTE}, // kWICPixelFormat64bppCMYK + {kWICPixelFormat24bpp3Channels, kBM_RGBTRIPLETS, FALSE, 3, 0, COLOR_BYTE}, // kWICPixelFormat24bpp3Channels + {kWICPixelFormat32bpp4Channels, kBM_CMYKQUADS, FALSE, 4, 0, COLOR_BYTE}, // kWICPixelFormat32bpp4Channels + {kWICPixelFormat40bpp5Channels, kBM_5CHANNEL, FALSE, 5, 0, COLOR_BYTE}, // kWICPixelFormat40bpp5Channels + {kWICPixelFormat48bpp6Channels, kBM_6CHANNEL, FALSE, 6, 0, COLOR_BYTE}, // kWICPixelFormat48bpp6Channels + {kWICPixelFormat56bpp7Channels, kBM_7CHANNEL, FALSE, 7, 0, COLOR_BYTE}, // kWICPixelFormat56bpp7Channels + {kWICPixelFormat64bpp8Channels, kBM_8CHANNEL, FALSE, 8, 0, COLOR_BYTE}, // kWICPixelFormat64bpp8Channels + {kWICPixelFormat24bpp3Channels, kBM_RGBTRIPLETS, FALSE, 3, 0, COLOR_BYTE}, // kWICPixelFormat48bpp3Channels + {kWICPixelFormat32bpp4Channels, kBM_CMYKQUADS, FALSE, 4, 0, COLOR_BYTE}, // kWICPixelFormat64bpp4Channels + {kWICPixelFormat40bpp5Channels, kBM_5CHANNEL, FALSE, 5, 0, COLOR_BYTE}, // kWICPixelFormat80bpp5Channels + {kWICPixelFormat48bpp6Channels, kBM_6CHANNEL, FALSE, 6, 0, COLOR_BYTE}, // kWICPixelFormat96bpp6Channels + {kWICPixelFormat56bpp7Channels, kBM_7CHANNEL, FALSE, 7, 0, COLOR_BYTE}, // kWICPixelFormat112bpp7Channels + {kWICPixelFormat64bpp8Channels, kBM_8CHANNEL, FALSE, 8, 0, COLOR_BYTE}, // kWICPixelFormat128bpp8Channels + {kWICPixelFormat40bppCMYKAlpha, kBM_CMYKQUADS, TRUE, 5, 4, COLOR_BYTE}, // kWICPixelFormat40bppCMYKAlpha + {kWICPixelFormat40bppCMYKAlpha, kBM_CMYKQUADS, TRUE, 5, 4, COLOR_BYTE}, // kWICPixelFormat80bppCMYKAlpha + {kWICPixelFormat32bpp3ChannelsAlpha, kBM_RGBTRIPLETS, TRUE, 4, 3, COLOR_BYTE}, // kWICPixelFormat32bpp3ChannelsAlpha + {kWICPixelFormat40bpp4ChannelsAlpha, kBM_CMYKQUADS, TRUE, 5, 4, COLOR_BYTE}, // kWICPixelFormat40bpp4ChannelsAlpha + {kWICPixelFormat48bpp5ChannelsAlpha, kBM_5CHANNEL, TRUE, 6, 5, COLOR_BYTE}, // kWICPixelFormat48bpp5ChannelsAlpha + {kWICPixelFormat56bpp6ChannelsAlpha, kBM_6CHANNEL, TRUE, 7, 6, COLOR_BYTE}, // kWICPixelFormat56bpp6ChannelsAlpha + {kWICPixelFormat64bpp7ChannelsAlpha, kBM_7CHANNEL, TRUE, 8, 7, COLOR_BYTE}, // kWICPixelFormat64bpp7ChannelsAlpha + {kWICPixelFormat72bpp8ChannelsAlpha, kBM_8CHANNEL, TRUE, 9, 8, COLOR_BYTE}, // kWICPixelFormat72bpp8ChannelsAlpha + {kWICPixelFormat32bpp3ChannelsAlpha, kBM_RGBTRIPLETS, TRUE, 4, 3, COLOR_BYTE}, // kWICPixelFormat64bpp3ChannelsAlpha + {kWICPixelFormat40bpp4ChannelsAlpha, kBM_CMYKQUADS, TRUE, 5, 4, COLOR_BYTE}, // kWICPixelFormat80bpp4ChannelsAlpha + {kWICPixelFormat48bpp5ChannelsAlpha, kBM_5CHANNEL, TRUE, 6, 5, COLOR_BYTE}, // kWICPixelFormat96bpp5ChannelsAlpha + {kWICPixelFormat56bpp6ChannelsAlpha, kBM_6CHANNEL, TRUE, 7, 6, COLOR_BYTE}, // kWICPixelFormat112bpp6ChannelsAlpha + {kWICPixelFormat64bpp7ChannelsAlpha, kBM_7CHANNEL, TRUE, 8, 7, COLOR_BYTE}, // kWICPixelFormat128bpp7ChannelsAlpha + {kWICPixelFormat72bpp8ChannelsAlpha, kBM_8CHANNEL, TRUE, 9, 8, COLOR_BYTE}, // kWICPixelFormat144bpp8ChannelsAlpha +}; + +/* +Look up table between color data type and data type size +*/ +CONST size_t g_lutColorDataSize[] = +{ + 0, // Packing as enumeration starts from 1 + sizeof(BYTE), // COLOR_BYTE =1 + sizeof(WORD), // COLOR_WORD + sizeof(FLOAT), // COLOR_FLOAT + sizeof(WORD), // COLOR_S2DOT13FIXED +}; + +/* +Define a color type that is not valid for WCS - we use this to distinguish +BMFORMATs that do not have a corresponding WCS color type +*/ +#define COLOR_INVALID 0 + +/* +Look up between local BMFORMAT enumeration providing the underlying enumeration +value and the corresponding pixel data size +*/ +CONST BMFormatData g_lutBMFormatData[kICMPixelFormatMax] = { + {BM_x555RGB, 3, static_cast(COLOR_INVALID)}, + {BM_x555XYZ, 3, static_cast(COLOR_INVALID)}, + {BM_x555Yxy, 3, static_cast(COLOR_INVALID)}, + {BM_x555Lab, 3, static_cast(COLOR_INVALID)}, + {BM_x555G3CH, 3, static_cast(COLOR_INVALID)}, + {BM_RGBTRIPLETS, 3, COLOR_BYTE}, + {BM_BGRTRIPLETS, 3, COLOR_BYTE}, + {BM_XYZTRIPLETS, 3, COLOR_BYTE}, + {BM_YxyTRIPLETS, 3, COLOR_BYTE}, + {BM_LabTRIPLETS, 3, COLOR_BYTE}, + {BM_G3CHTRIPLETS, 3, COLOR_BYTE}, + {BM_5CHANNEL, 5, COLOR_BYTE}, + {BM_6CHANNEL, 6, COLOR_BYTE}, + {BM_7CHANNEL, 7, COLOR_BYTE}, + {BM_8CHANNEL, 8, COLOR_BYTE}, + {BM_GRAY, 1, COLOR_BYTE}, + {BM_xRGBQUADS, 4, COLOR_BYTE}, + {BM_xBGRQUADS, 4, COLOR_BYTE}, + {BM_xG3CHQUADS, 4, COLOR_BYTE}, + {BM_KYMCQUADS, 4, COLOR_BYTE}, + {BM_CMYKQUADS, 4, COLOR_BYTE}, + {BM_10b_RGB, 4, COLOR_BYTE}, + {BM_10b_XYZ, 4, COLOR_BYTE}, + {BM_10b_Yxy, 4, COLOR_BYTE}, + {BM_10b_Lab, 4, COLOR_BYTE}, + {BM_10b_G3CH, 4, COLOR_BYTE}, + {BM_NAMED_INDEX, 4, COLOR_BYTE}, + {BM_16b_RGB, 3, COLOR_WORD}, + {BM_16b_XYZ, 3, COLOR_WORD}, + {BM_16b_Yxy, 3, COLOR_WORD}, + {BM_16b_Lab, 3, COLOR_WORD}, + {BM_16b_G3CH, 3, COLOR_WORD}, + {BM_16b_GRAY, 3, COLOR_WORD}, + {BM_565RGB, 3, COLOR_WORD}, + {BM_32b_scRGB, 3, COLOR_FLOAT}, + {BM_32b_scARGB, 4, COLOR_FLOAT}, + {BM_S2DOT13FIXED_scRGB, 3, COLOR_S2DOT13FIXED}, + {BM_S2DOT13FIXED_scARGB, 4, COLOR_S2DOT13FIXED}, +}; + diff --git a/print/XPSDrvSmpl/src/filters/color/bmpdata.h b/print/XPSDrvSmpl/src/filters/color/bmpdata.h new file mode 100644 index 00000000..225b7745 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/color/bmpdata.h @@ -0,0 +1,768 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + bmpdata.h + +Abstract: + + This file supplies definitions for various look-up tables for use in converting and + color matching input bitmaps via WCS/ICM and WIC + +--*/ + +#pragma once + +// +// Macros to limit maximum buffer size allocations +// +#define MAX_COLDATATYPE_SIZE sizeof(FLOAT) +#define MAX_COLCHANNEL_COUNT 9 // 8 channel plus alpha +#define MAX_PIXELWIDTH_COUNT SIZE_MAX/MAX_COLDATATYPE_SIZE/MAX_COLCHANNEL_COUNT + + +/* +Enumeration for all WIC pixel formats +*/ +enum EWICPixelFormat +{ + kWICPixelFormatDontCare = 0, kWICPixelFormatMin = 0, + kWICPixelFormat1bppIndexed, + kWICPixelFormat2bppIndexed, + kWICPixelFormat4bppIndexed, + kWICPixelFormat8bppIndexed, + kWICPixelFormatBlackWhite, + kWICPixelFormat2bppGray, + kWICPixelFormat4bppGray, + kWICPixelFormat8bppGray, + kWICPixelFormat16bppBGR555, + kWICPixelFormat16bppBGR565, + kWICPixelFormat16bppGray, + kWICPixelFormat24bppBGR, + kWICPixelFormat24bppRGB, + kWICPixelFormat32bppBGR, + kWICPixelFormat32bppBGRA, + kWICPixelFormat32bppPBGRA, + kWICPixelFormat32bppGrayFloat, + kWICPixelFormat48bppRGBFixedPoint, + kWICPixelFormat16bppGrayFixedPoint, + kWICPixelFormat32bppBGR101010, + kWICPixelFormat48bppRGB, + kWICPixelFormat64bppRGBA, + kWICPixelFormat64bppPRGBA, + kWICPixelFormat96bppRGBFixedPoint, + kWICPixelFormat128bppRGBAFloat, + kWICPixelFormat128bppPRGBAFloat, + kWICPixelFormat128bppRGBFloat, + kWICPixelFormat32bppCMYK, + kWICPixelFormat64bppRGBAFixedPoint, + kWICPixelFormat64bppRGBFixedPoint, + kWICPixelFormat128bppRGBAFixedPoint, + kWICPixelFormat128bppRGBFixedPoint, + kWICPixelFormat64bppRGBAHalf, + kWICPixelFormat64bppRGBHalf, + kWICPixelFormat48bppRGBHalf, + kWICPixelFormat32bppRGBE, + kWICPixelFormat16bppGrayHalf, + kWICPixelFormat32bppGrayFixedPoint, + kWICPixelFormat64bppCMYK, + kWICPixelFormat24bpp3Channels, + kWICPixelFormat32bpp4Channels, + kWICPixelFormat40bpp5Channels, + kWICPixelFormat48bpp6Channels, + kWICPixelFormat56bpp7Channels, + kWICPixelFormat64bpp8Channels, + kWICPixelFormat48bpp3Channels, + kWICPixelFormat64bpp4Channels, + kWICPixelFormat80bpp5Channels, + kWICPixelFormat96bpp6Channels, + kWICPixelFormat112bpp7Channels, + kWICPixelFormat128bpp8Channels, + kWICPixelFormat40bppCMYKAlpha, + kWICPixelFormat80bppCMYKAlpha, + kWICPixelFormat32bpp3ChannelsAlpha, + kWICPixelFormat40bpp4ChannelsAlpha, + kWICPixelFormat48bpp5ChannelsAlpha, + kWICPixelFormat56bpp6ChannelsAlpha, + kWICPixelFormat64bpp7ChannelsAlpha, + kWICPixelFormat72bpp8ChannelsAlpha, + kWICPixelFormat64bpp3ChannelsAlpha, + kWICPixelFormat80bpp4ChannelsAlpha, + kWICPixelFormat96bpp5ChannelsAlpha, + kWICPixelFormat112bpp6ChannelsAlpha, + kWICPixelFormat128bpp7ChannelsAlpha, + kWICPixelFormat144bpp8ChannelsAlpha, + kWICPixelFormatMax +}; + +/* +ICM/WCS BMFORMAT enumeration indexed from 0 for use as a look-up into +a BMFORMAT data structure array +*/ +enum EICMPixelFormat +{ + kBM_x555RGB = 0, kICMPixelFormatMin = 0, + kBM_x555XYZ, + kBM_x555Yxy, + kBM_x555Lab, + kBM_x555G3CH, + kBM_RGBTRIPLETS, + kBM_BGRTRIPLETS, + kBM_XYZTRIPLETS, + kBM_YxyTRIPLETS, + kBM_LabTRIPLETS, + kBM_G3CHTRIPLETS, + kBM_5CHANNEL, + kBM_6CHANNEL, + kBM_7CHANNEL, + kBM_8CHANNEL, + kBM_GRAY, + kBM_xRGBQUADS, + kBM_xBGRQUADS, + kBM_xG3CHQUADS, + kBM_KYMCQUADS, + kBM_CMYKQUADS, + kBM_10b_RGB, + kBM_10b_XYZ, + kBM_10b_Yxy, + kBM_10b_Lab, + kBM_10b_G3CH, + kBM_NAMED_INDEX, + kBM_16b_RGB, + kBM_16b_XYZ, + kBM_16b_Yxy, + kBM_16b_Lab, + kBM_16b_G3CH, + kBM_16b_GRAY, + kBM_565RGB, + kBM_32b_scRGB, + kBM_32b_scARGB, + kBM_S2DOT13FIXED_scRGB, + kBM_S2DOT13FIXED_scARGB, + kICMPixelFormatMax +}; + +/* +This structure is used to store information for converting and processing a particular +WIC format. The structure forms the basis of a look-up table between a source WIC pixel +format and the following items: + The format to convert to before processing - + This converts to a form consumable by ICM/WCS. + The corresponding BMFORMAT enumeration - + This lets us lookup the data type to pass to TranslateBitmapBits. + Whether we need an intermediate buffer to process alpha data + The alpha channel in WIC pixel formats do not match ICM/WCS compatible + formats. Under these circumstances we need to copy the bitmap data, translate + and apply back to the WIC bitmap. + The count of channels and the channel width + This allows us to lookup the offset required when copying intermediate data to + the WIC bitmap. + The offset to the alpha channel (we actually store the COLORDATATYPE and lookup the size) + When copying alpha data we need to know where to retrieve the alpha channel from and + where to copy it to in a given scanline. + +With this data, handling intermediate buffer data follows the following algorithm: + + If no intermediate buffer is required + The locked WIC pixel data can be converted in situ + Otherwise + Color data handling + From the begining of the WIC buffer and the intermediate buffer + Copy the intermediate buffer pixel width into the locked WIC scanline + Move the WIC pixel pointer on by the WIC pixel width + Move the intermediate buffer pointer on by the BMFORMAT pixel width + Repeat till no scanline data left to process + Alpha data handling + From the begining of the source and destination WIC buffers + Offset the source to the alpha channel + Offset the destination to the alpha channel + Convert the source to format to the destination + Copy the alpha data to the destination + Move the source WIC pixel pointer on by the WIC pixel width + Move the destination WIC pixel pointer on by the WIC pixel width + Repeat till no alpha data left to process + +*/ +struct WICToBMFORMAT +{ + EWICPixelFormat m_pixFormTarget; + EICMPixelFormat m_bmFormTarget; + BOOL m_bNeedsScanBuffer; + UINT m_cChannels; + UINT m_cAlphaOffset; + COLORDATATYPE m_colDataType; +}; + +/* +Structure providing information about BMFORMAT data for use as a lookup against +the local BMFORMAT enumeration +*/ +struct BMFormatData +{ + BMFORMAT m_bmFormat; + UINT m_cChannels; + COLORDATATYPE m_colDataType; +}; + +extern CONST WICPixelFormatGUID g_lutPixFrmtGuid[kWICPixelFormatMax]; +extern CONST WICToBMFORMAT g_lutWICToBMFormat[kWICPixelFormatMax]; +extern CONST size_t g_lutColorDataSize[]; +extern CONST BMFormatData g_lutBMFormatData[kICMPixelFormatMax]; + +struct S2DOT13FIXED +{ + WORD val; +}; +typedef S2DOT13FIXED* PS2DOT13FIXED; + +/*++ + +Routine Name: + + ConvertCopy + +Routine Description: + + Inline function that converts a src channel data type to a destination + of another type. This overload converts BYTE to BYTE + +Arguments: + + dst - Destination value to be set + src - Source value + +Return Value: + + None + +--*/ +inline VOID +ConvertCopy( + _Out_ BYTE& dst, + _In_ BYTE src + ) +{ + dst = src; +} + +/*++ + +Routine Name: + + ConvertCopy + +Routine Description: + + Inline function that converts a src channel data type to a destination + of another type. This overload converts WORD to BYTE + +Arguments: + + dst - Destination value to be set + src - Source value + +Return Value: + + None + +--*/ +inline VOID +ConvertCopy( + _Out_ BYTE& dst, + _In_ WORD src + ) +{ + dst = static_cast((static_cast(src) + 0x7F) >> 8); +} + +/*++ + +Routine Name: + + ConvertCopy + +Routine Description: + + Inline function that converts a src channel data type to a destination + of another type. This overload converts FLOAT to BYTE + +Arguments: + + dst - Destination value to be set + src - Source value + +Return Value: + + None + +--*/ +inline VOID +ConvertCopy( + _Out_ BYTE& dst, + _In_ FLOAT src + ) +{ + if (src < 0.0f) + { + dst = 0x00; + } + else if (src > 1.0f) + { + dst = 0xFF; + } + else + { + dst = static_cast(src * kMaxByteAsFloat); + } +} + +/*++ + +Routine Name: + + ConvertCopy + +Routine Description: + + Inline function that converts a src channel data type to a destination + of another type. This overload converts S2DOT13FIXED to BYTE + +Arguments: + + dst - Destination value to be set + src - Source value + +Return Value: + + None + +--*/ +inline VOID +ConvertCopy( + _Out_ BYTE& dst, + _In_ S2DOT13FIXED src + ) +{ + if (src.val & kS2Dot13Neg) + { + dst = 0x00; + } + else if (src.val > kS2Dot13One) + { + dst = 0xFF; + } + else + { + dst = static_cast(MulDiv(src.val, 0xFF, kS2Dot13One)); + } +} + +/*++ + +Routine Name: + + ConvertCopy + +Routine Description: + + Inline function that converts a src channel data type to a destination + of another type. This overload converts BYTE to WORD + +Arguments: + + dst - Destination value to be set + src - Source value + +Return Value: + + None + +--*/ +inline VOID +ConvertCopy( + _Out_ WORD& dst, + _In_ BYTE src + ) +{ + dst = (src << 8) | src; +} + +/*++ + +Routine Name: + + ConvertCopy + +Routine Description: + + Inline function that converts a src channel data type to a destination + of another type. This overload converts WORD to WORD + +Arguments: + + dst - Destination value to be set + src - Source value + +Return Value: + + None + +--*/ +inline VOID +ConvertCopy( + _Out_ WORD& dst, + _In_ WORD src + ) +{ + dst = src; +} + +/*++ + +Routine Name: + + ConvertCopy + +Routine Description: + + Inline function that converts a src channel data type to a destination + of another type. This overload converts FLOAT to WORD + +Arguments: + + dst - Destination value to be set + src - Source value + +Return Value: + + None + +--*/ +inline VOID +ConvertCopy( + _Out_ WORD& dst, + _In_ FLOAT src + ) +{ + if (src < 0.0f) + { + dst = 0x0000; + } + else if (src > 1.0f) + { + dst = 0xFFFF; + } + else + { + dst = static_cast(src * kMaxWordAsFloat); + } +} + +/*++ + +Routine Name: + + ConvertCopy + +Routine Description: + + Inline function that converts a src channel data type to a destination + of another type. This overload converts S2DOT13FIXED to WORD + +Arguments: + + dst - Destination value to be set + src - Source value + +Return Value: + + None + +--*/ +inline VOID +ConvertCopy( + _Out_ WORD& dst, + _In_ S2DOT13FIXED src + ) +{ + if (src.val & kS2Dot13Neg) + { + dst = 0x0000; + } + else if (src.val > kS2Dot13One) + { + dst = 0xFFFF; + } + else + { + dst = static_cast(MulDiv(src.val, 0xFFFF, kS2Dot13One)); + } +} + +/*++ + +Routine Name: + + ConvertCopy + +Routine Description: + + Inline function that converts a src channel data type to a destination + of another type. This overload converts BYTE to FLOAT + +Arguments: + + dst - Destination value to be set + src - Source value + +Return Value: + + None + +--*/ +inline VOID +ConvertCopy( + _Out_ FLOAT& dst, + _In_ BYTE src + ) +{ + dst = src/kMaxByteAsFloat; +} + +/*++ + +Routine Name: + + ConvertCopy + +Routine Description: + + Inline function that converts a src channel data type to a destination + of another type. This overload converts WORD to FLOAT + +Arguments: + + dst - Destination value to be set + src - Source value + +Return Value: + + None + +--*/ +inline VOID +ConvertCopy( + _Out_ FLOAT& dst, + _In_ WORD src + ) +{ + dst = src/kMaxWordAsFloat; +} + +/*++ + +Routine Name: + + ConvertCopy + +Routine Description: + + Inline function that converts a src channel data type to a destination + of another type. This overload converts FLOAT to FLOAT + +Arguments: + + dst - Destination value to be set + src - Source value + +Return Value: + + None + +--*/ +inline VOID +ConvertCopy( + _Out_ FLOAT& dst, + _In_ FLOAT src + ) +{ + dst = src; +} + +/*++ + +Routine Name: + + ConvertCopy + +Routine Description: + + Inline function that converts a src channel data type to a destination + of another type. This overload converts S2DOT13FIXED to FLOAT + +Arguments: + + dst - Destination value to be set + src - Source value + +Return Value: + + None + +--*/ +inline VOID +ConvertCopy( + _Out_ FLOAT& dst, + _In_ S2DOT13FIXED src + ) +{ + if (src.val & kS2Dot13Neg) + { + dst = -static_cast(src.val^kS2Dot13Neg)/kS2Dot13One; + } + else + { + dst = static_cast(src.val)/kS2Dot13One; + } +} + +/*++ + +Routine Name: + + ConvertCopy + +Routine Description: + + Inline function that converts a src channel data type to a destination + of another type. This overload converts BYTE to S2DOT13FIXED + +Arguments: + + dst - Destination value to be set + src - Source value + +Return Value: + + None + +--*/ +inline VOID +ConvertCopy( + _Out_ S2DOT13FIXED& dst, + _In_ BYTE src + ) +{ + dst.val = static_cast(MulDiv(kS2Dot13One, src, 0xFF)); +} + +/*++ + +Routine Name: + + ConvertCopy + +Routine Description: + + Inline function that converts a src channel data type to a destination + of another type. This overload converts WORD to S2DOT13FIXED + +Arguments: + + dst - Destination value to be set + src - Source value + +Return Value: + + None + +--*/ +inline VOID +ConvertCopy( + _Out_ S2DOT13FIXED& dst, + _In_ WORD src + ) +{ + dst.val = static_cast(MulDiv(kS2Dot13One, src, 0xFFFF)); +} + +/*++ + +Routine Name: + + ConvertCopy + +Routine Description: + + Inline function that converts a src channel data type to a destination + of another type. This overload converts FLOAT to S2DOT13FIXED + +Arguments: + + dst - Destination value to be set + src - Source value + +Return Value: + + None + +--*/ +inline VOID +ConvertCopy( + _Out_ S2DOT13FIXED& dst, + _In_ FLOAT src + ) +{ + if (src < -4.0f) + { + dst.val = kS2Dot13Min; + } + else if (src > 4.0f) + { + dst.val = kS2Dot13Max; + } + else + { + dst.val = static_cast(src * kS2Dot13One); + } +} + +/*++ + +Routine Name: + + ConvertCopy + +Routine Description: + + Inline function that converts a src channel data type to a destination + of another type. This overload converts S2DOT13FIXED to S2DOT13FIXED + +Arguments: + + dst - Destination value to be set + src - Source value + +Return Value: + + None + +--*/ +inline VOID +ConvertCopy( + _Out_ S2DOT13FIXED& dst, + _In_ S2DOT13FIXED src + ) +{ + dst = src; +} + diff --git a/print/XPSDrvSmpl/src/filters/color/cmflt.cpp b/print/XPSDrvSmpl/src/filters/color/cmflt.cpp new file mode 100644 index 00000000..303cef2a --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/color/cmflt.cpp @@ -0,0 +1,264 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + cmflt.cpp + +Abstract: + + Color management filter implementation. This class derives from the Xps filter + class and implements the necessary part handlers to support color management. + The color management filter is responsible for adding and removing resources to + and from the XPS document and putting the appropriate mark-up onto pages when applying + a color transform. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdstring.h" +#include "pthndlr.h" +#include "cmflt.h" +#include "cmsax.h" +#include "colconv.h" +#include "cmpthndlr.h" +#include "cmintpthndlr.h" +#include "cmprofpthndlr.h" + +using XDPrintSchema::PageColorManagement::ColorManagementData; +using XDPrintSchema::PageColorManagement::Driver; + +using XDPrintSchema::PageSourceColorProfile::PageSourceColorProfileData; + +using XDPrintSchema::PageICMRenderingIntent::PageICMRenderingIntentData; + +/*++ + +Routine Name: + + CColorManageFilter::CColorManageFilter + +Routine Description: + + Default constructor for the color management filter which ensures GDI plus is correctly running + +Arguments: + + None + +Return Value: + + None + +--*/ +CColorManageFilter::CColorManageFilter() +{ +} + +/*++ + +Routine Name: + + CColorManageFilter::~CColorManageFilter + +Routine Description: + + Default destructor for the color management filter + +Arguments: + + None + +Return Value: + + None + +--*/ +CColorManageFilter::~CColorManageFilter() +{ +} + +/*++ + +Routine Name: + + CColorManageFilter::ProcessPart + +Routine Description: + + Method for processing each fixed page part in a container + +Arguments: + + pFP - Pointer to the fixed page to process + +Return Value: + + HRESULT + S_OK - On success + S_FALSE - When not enabled in the PT + E_* - On error + +--*/ +HRESULT +CColorManageFilter::ProcessPart( + _Inout_ IFixedPage* pFP + ) +{ + VERBOSE("Processing Fixed Page part with color management handler\n"); + + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pFP, E_POINTER))) + { + // + // Get the PT manager to return the correct ticket. Use a regular pointer + // to retrieve the ticket and assign to the smart pointer to increment + // ref count (we don't want our smart pointer to release the PT before + // the PT manager is finished with it) + // + IXMLDOMDocument2* pPT = NULL; + if (SUCCEEDED(hr = m_ptManager.SetTicket(pFP)) && + SUCCEEDED(hr = m_ptManager.GetTicket(kPTPageScope, &pPT))) + { + try + { + // + // Get data from PT handler and test if we are color matching + // + ColorManagementData cmData; + CColorManagePTHandler cmPTHandler(pPT); + + PageSourceColorProfileData cmProfData; + CColorManageProfilePTHandler profPTHandler(pPT); + + PageICMRenderingIntentData cmIntData; + CColorManageIntentsPTHandler ptIntentsHandler(pPT); + + CComVariant varName; + + if (SUCCEEDED(hr = m_pPrintPropertyBag->GetProperty(XPS_FP_PRINTER_NAME, &varName)) && + SUCCEEDED(hr = cmPTHandler.GetData(&cmData)) && + SUCCEEDED(hr = profPTHandler.GetData(&cmProfData))) + { + hr = ptIntentsHandler.GetData(&cmIntData); + } + + if (SUCCEEDED(hr) && + cmData.cmOption == Driver && + cmProfData.cmProfileName.Length() > 0) + { + // + // Retrieve the writer from the fixed page + // + CComPtr pWriter(NULL); + + // + // Create a map of the resources that need to be cleaned up after the page + // has been processed. These are bitmaps that have been replaced with color + // matched equivalents and any icc profiles that have been consumed while + // color matching. + // + ResDeleteMap resDel; + + if (SUCCEEDED(hr = pFP->GetWriteStream(&pWriter))) + { + // + // Set-up the SAX reader and begin parsing the mark-up + // + CComPtr pSaxRdr(NULL); + CComPtr pReader(NULL); + + // + // Create a profile manager which handles working with the selected profile + // + CProfileManager profManager(varName.bstrVal, cmProfData, cmIntData, pFP); + + // + // Create two color converter objects which coordinate color transforms for + // bitmaps and color mark-up strings + // + CBitmapColorConverter cmBmpConverter(m_pXDWriter, pFP, &m_resCache, &profManager, &resDel); + CColorRefConverter cmRefConverter(m_pXDWriter, pFP, &m_resCache, &profManager, &resDel); + CResourceDictionaryConverter cmDictConverter(m_pXDWriter, + pFP, + &m_resCache, + &profManager, + &resDel, + &cmBmpConverter, + &cmRefConverter); + + // + // Create a SAX handler to parse the markup in the fixed page + // + CCMSaxHandler cmSaxHndlr(pWriter, &cmBmpConverter, &cmRefConverter, &cmDictConverter); + + if (SUCCEEDED(hr = pSaxRdr.CoCreateInstance(CLSID_SAXXMLReader60)) && + SUCCEEDED(hr = pSaxRdr->putContentHandler(&cmSaxHndlr)) && + SUCCEEDED(hr = pFP->GetStream(&pReader))) + { + CComPtr pReadStreamToSeq(NULL); + + pReadStreamToSeq.Attach(new(std::nothrow) pfp::PrintReadStreamToSeqStream(pReader)); + + if (SUCCEEDED(hr = CHECK_POINTER(pReadStreamToSeq, E_OUTOFMEMORY))) + { + hr = pSaxRdr->parse(CComVariant(static_cast(pReadStreamToSeq))); + } + } + + pWriter->Close(); + } + + if (SUCCEEDED(hr)) + { + // + // We have parsed the entire page - it should be safe to delete + // all unrequired resources + // + ResDeleteMap::const_iterator iterRes = resDel.begin(); + + for (;iterRes != resDel.end(); iterRes++) + { + hr = pFP->DeleteResource(iterRes->first); + } + } + } + else if (hr == E_ELEMENT_NOT_FOUND) + { + hr = S_FALSE; + } + } + catch (CXDException& e) + { + hr = e; + } + catch (...) + { + hr = E_FAIL; + } + } + } + + if (SUCCEEDED(hr)) + { + // + // We can send the fixed page + // + hr = m_pXDWriter->SendFixedPage(pFP); + } + + ERR_ON_HR(hr); + return hr; +} + diff --git a/print/XPSDrvSmpl/src/filters/color/cmflt.h b/print/XPSDrvSmpl/src/filters/color/cmflt.h new file mode 100644 index 00000000..02c44853 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/color/cmflt.h @@ -0,0 +1,51 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + cmflt.h + +Abstract: + + Implementation of the color management filter which handles page parts from the + XPS document container. + +--*/ + +#pragma once + +#include "xdrchflt.h" +#include "ptmanage.h" + +typedef map ResDeleteMap; + +class CColorManageFilter : public CXDXpsFilter +{ +public: + CColorManageFilter(); + + virtual ~CColorManageFilter(); + +private: + virtual HRESULT + ProcessPart( + _Inout_ IFixedPage* pFP + ); + +private: + + // + // Create a resource cache object to manage the storage of bitmaps and + // color profiles in the container + // + CFileResourceCache m_resCache; +}; + diff --git a/print/XPSDrvSmpl/src/filters/color/cmflt.rc b/print/XPSDrvSmpl/src/filters/color/cmflt.rc new file mode 100644 index 00000000..19ae3e89 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/color/cmflt.rc @@ -0,0 +1,43 @@ +// +// Copyright (c) 2005 Microsoft Corporation +// +// All rights reserved. +// +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +// PARTICULAR PURPOSE. +// +// File Name: +// +// cmflt.rc +// +// Abstract: +// +// Color filter resource file. +// +// + +#include +#include + +#define VER_FILETYPE VFT_DLL +#define VER_FILESUBTYPE VFT2_UNKNOWN +#define VER_FILEDESCRIPTION_STR "XPSDrv Sample Color Filter" +#define VER_INTERNALNAME_STR "PrintFeatureFilters" + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#endif // English (U.S.) resources + +///////////////////////////////////////////////////////////////////////////// + +#include "common.ver" + diff --git a/print/XPSDrvSmpl/src/filters/color/cmimg.cpp b/print/XPSDrvSmpl/src/filters/color/cmimg.cpp new file mode 100644 index 00000000..f44fa028 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/color/cmimg.cpp @@ -0,0 +1,856 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + cmimg.cpp + +Abstract: + + Color managed image implementation. The CColorManagedImage class is responsible + for managing the image resource for a stored bitmap. This implements + the IResWriter interface so that the font can be added to the resource + cache. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdstring.h" +#include "xdexcept.h" +#include "cmimg.h" +#include "streamcnv.h" + +using XDPrintSchema::PageSourceColorProfile::EProfileOption; +using XDPrintSchema::PageSourceColorProfile::RGB; +using XDPrintSchema::PageSourceColorProfile::CMYK; + +/*++ + +Routine Name: + + CColorManagedImage::CColorManagedImage + +Routine Description: + + Constructor for the CColorManagedImage class which registers internally the + supplied resource URI and a pointer to the profile manager which will supply + suitable color transforms to apply to that resource + +Arguments: + + bstrResURI - String containing the URI to the resource to be handled + pProfManager - Pointer to a profile manager which will supply suitable + transforms to apply to the supplied resource + +Return Value: + + None + Throws CXDException(HRESULT) on an error + +--*/ +CColorManagedImage::CColorManagedImage( + _In_ BSTR bstrResURI, + _In_ CProfileManager* pProfManager, + _In_ IFixedPage* pFixedPage, + _In_ ResDeleteMap* pResDel + ) : + m_pProfManager(pProfManager), + m_pFixedPage(pFixedPage), + m_bstrSrcProfileURI(NULL), + m_pResDel(pResDel) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pProfManager, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(m_pFixedPage, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(m_pResDel, E_POINTER))) + { + if (SysStringLen(bstrResURI) <= 0) + { + hr = E_INVALIDARG; + } + } + + if (SUCCEEDED(hr)) + { + CComBSTR bstrAttribute(bstrResURI); + + if (bstrAttribute.Length() == 0) + { + hr = E_INVALIDARG; + } + else + { + try + { + // + // Process the mark-up looking for the bitmap URI and any associated profiles + // + CStringXDW cstrAttribute(bstrResURI); + CStringXDW cstrColConvBMP(L"{ColorConvertedBitmap "); + + cstrAttribute.Trim(); + INT cchFind = cstrAttribute.Find(cstrColConvBMP); + + if (cchFind == -1) + { + // + // The mark-up is the bitmap URI + // + cstrAttribute.Trim(); + m_bstrBitmapURI.Empty(); + m_bstrBitmapURI.Attach(cstrAttribute.AllocSysString()); + } + else + { + // + // The mark-up is specifying a profile associated with the image. + // Extract the path and set this in the profile manager. The markup takes + // the form "{ColorConvertedBitmap image.ext profile.icc}". + // + + // + // Delete leading string "{ColorConvertedBitmap " and the trailing "}" + // + cstrAttribute.Delete(0, cstrColConvBMP.GetLength()); + cstrAttribute.Delete(cstrAttribute.GetLength() - 1, 1); + cstrAttribute.Trim(); + + // + // Find the seperating space + // + cchFind = cstrAttribute.Find(L" "); + + // + // Construct the bitmap URI + // + m_bstrBitmapURI.Empty(); + m_bstrBitmapURI.Attach(cstrAttribute.Left(cchFind).AllocSysString()); + + // + // Delete the bitmap URI and space leaving the profile URI + // + cstrAttribute.Delete(0, cchFind+1); + + m_bstrSrcProfileURI.Empty(); + m_bstrSrcProfileURI.Attach(cstrAttribute.AllocSysString()); + } + } + catch (CXDException& e) + { + hr = e; + } + } + } + + if (FAILED(hr)) + { + throw CXDException(hr); + } +} + +/*++ + +Routine Name: + + CColorManagedImage::~CColorManagedImage + +Routine Description: + + Default destructor for the CColorManagedImage class + +Arguments: + + None + +Return Value: + + None + +--*/ +CColorManagedImage::~CColorManagedImage() +{ +} + +/*++ + +Routine Name: + + CColorManagedImage::WriteData + +Routine Description: + + This method handles the decoding of a bitmap, the colour + translation applied to the bitmap and the re-encoding of the bitmap + +Arguments: + + pStream - Pointer to a stream to write the resource out to + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CColorManagedImage::WriteData( + _In_ IPartBase* pResource, + _In_ IPrintWriteStream* pStream + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pResource, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pStream, E_POINTER))) + { + try + { + CComPtr pRead(NULL); + CComPtr pImagePart(NULL); + CComPtr pImageStream(NULL); + + // + // Load the bitmap into memory and create a stream to read the bitmap from + // + if (SUCCEEDED(hr = m_pFixedPage->GetPagePart(m_bstrBitmapURI, &pRead)) && + SUCCEEDED(hr = pRead.QueryInterface(&pImagePart)) && + SUCCEEDED(hr = pImagePart->GetStream(&pImageStream))) + { + BOOL bApplyTransform = FALSE; + CComPtr pInputImageStream(NULL); + + EWICPixelFormat eDstPixFormat = kWICPixelFormatDontCare; + UINT cDstWidth = 0; + UINT cDstHeight = 0; + DOUBLE dpiDstX = 0.0; + DOUBLE dpiDstY = 0.0; + + EProfileOption eProfileOption = RGB; + + // + // Set up the source and destination bitmaps so they are ready for use by TranslateBitmapBits + // + pInputImageStream.Attach(new(std::nothrow) CPrintReadStreamToIStream(pImageStream)); + if (SUCCEEDED(hr = CHECK_POINTER(pInputImageStream, E_OUTOFMEMORY)) && + SUCCEEDED(hr = m_srcBmp.Initialize(pInputImageStream)) && + SUCCEEDED(hr = m_srcBmp.GetSize(&cDstWidth, &cDstHeight)) && + SUCCEEDED(hr = m_srcBmp.GetResolution(&dpiDstX, &dpiDstY)) && + SUCCEEDED(hr = m_pProfManager->GetProfileOption(&eProfileOption))) + { + // + // The destination bitmap format can be one of: + // + // kWICPixelFormat128bppRGBFloat - scRGB output + // kWICPixelFormat128bppRGBAFloat - scRGB output with a source alpha channel + // kWICPixelFormat64bppCMYK - CMYK output + // kWICPixelFormat80bppCMYKAlpha - CMYK output with a source alpha channel + // + BOOL bScRGBOut = FALSE; + switch (eProfileOption) + { + case RGB: + { + eDstPixFormat = m_srcBmp.HasAlphaChannel() ? kWICPixelFormat128bppRGBAFloat : kWICPixelFormat128bppRGBFloat; + bScRGBOut = TRUE; + } + break; + + case CMYK: + { + eDstPixFormat = m_srcBmp.HasAlphaChannel() ? kWICPixelFormat40bppCMYKAlpha : kWICPixelFormat32bppCMYK; + } + break; + + default: + { + RIP("Unrecognised destination profile option.\n"); + + hr = E_FAIL; + } + break; + } + + if (SUCCEEDED(hr)) + { + // + // If the input is scRGB and the output is scRGB just pass through the bitmap + // Note: This should be optimised we do not write out a new bitmap but use the original + // + if (eDstPixFormat == m_srcBmp.GetPixelFormat() && + bScRGBOut) + { + m_dstBmp = m_srcBmp; + } + else if (SUCCEEDED(hr = m_dstBmp.Initialize(eDstPixFormat, cDstWidth, cDstHeight, dpiDstX, dpiDstY))) + { + bApplyTransform = TRUE; + } + } + } + + // + // Process the source and destination bitmaps a scanline at a time if the output image + // is still not set + // + if (SUCCEEDED(hr) && + bApplyTransform) + { + // + // Create scanline iterator objects from the source and destination bitmaps + // + CScanIterator srcIter(m_srcBmp, NULL); + CScanIterator dstIter(m_dstBmp, NULL); + + // + // Initialize the iterators, set the source profile and transform the scanlines + // + if (SUCCEEDED(hr = srcIter.Initialize(TRUE)) && + SUCCEEDED(hr = dstIter.Initialize(FALSE)) && + SUCCEEDED(hr = SetSrcProfile(&srcIter)) && + SUCCEEDED(hr = TransformScanLines(&srcIter, &dstIter))) + { + // + // CMYK output requires an embedded profile + // + CComBSTR bstrProfile; + if (eProfileOption == CMYK && + SUCCEEDED(hr = m_pProfManager->GetDstProfileName(&bstrProfile))) + { + hr = dstIter.SetProfile(bstrProfile); + } + } + + if (SUCCEEDED(hr)) + { + m_dstBmp = dstIter; + } + + // + // If there's a problem loading a suitable source profile, just pass + // the bitmap through unmodified + // + if (hr == HRESULT_FROM_WIN32(ERROR_PROFILE_NOT_FOUND)) + { + bApplyTransform = FALSE; + m_dstBmp = m_srcBmp; + hr = S_OK; + } + } + + if (SUCCEEDED(hr)) + { + // + // Create a write stream to accept the converted bitmap, fill from the output bitmap + // and write to the output stream (after ensuring the stream is pointing to the start). + // + CComPtr pOutputImageStream(NULL); + + LARGE_INTEGER cbMoveFromStart = {0}; + + PBYTE pBuff = new(std::nothrow) BYTE[CB_COPY_BUFFER]; + + if (SUCCEEDED(hr = CHECK_POINTER(pBuff, E_OUTOFMEMORY)) && + SUCCEEDED(hr = CreateStreamOnHGlobal(NULL, TRUE, &pOutputImageStream)) && + SUCCEEDED(hr = m_dstBmp.Write(GUID_ContainerFormatWmp, pOutputImageStream)) && + SUCCEEDED(hr = pOutputImageStream->Seek(cbMoveFromStart, STREAM_SEEK_SET, NULL))) + { + ULONG cbRead = 0; + ULONG cbWritten = 0; + + while (SUCCEEDED(hr) && + SUCCEEDED(hr = pOutputImageStream->Read(pBuff, CB_COPY_BUFFER, &cbRead)) && + cbRead > 0) + { + hr = pStream->WriteBytes(pBuff, cbRead, &cbWritten); + ASSERTMSG(cbRead == cbWritten, "Failed to write all data.\n"); + } + } + + if (pBuff != NULL) + { + delete[] pBuff; + pBuff = NULL; + } + } + + // + // Set the content type of the image part + // + CComQIPtr pImage = pResource; + if (SUCCEEDED(hr) && + SUCCEEDED(hr = CHECK_POINTER(pImage, E_NOINTERFACE))) + { + hr = pImage->SetImageContent(CComBSTR(L"image/vnd.ms-photo")); + } + + // + // If all is well mark the replaced bitmap and profile for deletion + // + if (SUCCEEDED(hr)) + { + (*m_pResDel)[m_bstrBitmapURI.m_str] = TRUE; + + if (m_bstrSrcProfileURI.Length() > 0) + { + (*m_pResDel)[m_bstrSrcProfileURI.m_str] = TRUE; + } + } + } + } + catch (CXDException& e) + { + hr = e; + } + catch (exception& DBG_ONLY(e)) + { + ERR(e.what()); + hr = E_FAIL; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CColorManagedImage::GetKeyName + +Routine Description: + + Method to obtain a unique key for the resource being handled + +Arguments: + + pbstrKeyName - Pointer to a string to hold the generated key + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CColorManagedImage::GetKeyName( + _Outptr_ BSTR* pbstrKeyName + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pbstrKeyName, E_POINTER))) + { + if (m_bstrBitmapURI.Length() > 0) + { + *pbstrKeyName = NULL; + + // + // The full URI to the bitmap resource concatenated with any associated + // profile is a suitable key + // + try + { + CStringXDW cstrKey(m_bstrBitmapURI); + cstrKey += m_bstrSrcProfileURI; + + *pbstrKeyName = cstrKey.AllocSysString(); + } + catch (CXDException& e) + { + hr = e; + } + } + else + { + hr = E_PENDING; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CColorManagedImage::GetResURI + +Routine Description: + + Method to obtain the URI of the resource being handled + +Arguments: + + pbstrResURI - Pointer to a string to hold the resource URI + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CColorManagedImage::GetResURI( + _Outptr_ BSTR* pbstrResURI + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pbstrResURI, E_POINTER))) + { + *pbstrResURI = NULL; + + if (m_bstrBitmapURI.Length() > 0) + { + try + { + // + // Create a URI from the original bitmap URI and the current tick count + // + CStringXDW cstrFileName(m_bstrBitmapURI); + CStringXDW cstrFileExt(PathFindExtension(cstrFileName)); + + INT indFileExt = cstrFileName.Find(cstrFileExt); + + if (indFileExt > -1) + { + cstrFileName.Delete(indFileExt, cstrFileExt.GetLength()); + } + + // + // Create a unique name for the bitmap for this print session + // + CStringXDW cstrURI; + cstrURI.Format(L"%s_%u.wdp", cstrFileName, GetUniqueNumber()); + + SysFreeString(*pbstrResURI); + *pbstrResURI = cstrURI.AllocSysString(); + } + catch (CXDException& e) + { + hr = e; + } + } + else + { + hr = E_PENDING; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CColorManagedImage::SetSrcProfile + +Routine Description: + + Method to set the source color profile given a particular source bitmap + +Arguments: + + pSrcBmp - Pointer to the source bitmap + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CColorManagedImage::SetSrcProfile( + _In_ CBmpConverter* pSrcBmp + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pSrcBmp, E_POINTER))) + { + // + // Update the source profile based on the source bitmap. The source profile + // is set according to the following rules: + // + // If the profile is specified in the ImageSource mark-up + // Use the profile in the container + // Else If the profile is embeded + // Use the embedded profile + // Else + // If the profile is RGB <= 16 bpc + // Use sRGB profile as source + // Else if the profile is RGB > 16 bpc + // Use scRGB profile as source + // Else if the profile is CMYK + // Use SWOP profile as source + // + if (m_bstrSrcProfileURI.Length() > 0) + { + // + // The mark-up references a profile in the XPS document - get the profile manager + // to extract it and set as the source profile + // + hr = m_pProfManager->SetSrcProfileFromContainer(m_bstrSrcProfileURI); + } + else if (pSrcBmp->HasColorProfile()) + { + IWICColorContext* pSrcContext = NULL; + + UINT cbBuffer = 0; + PBYTE pBuffer = NULL; + UINT cbActual = 0; + + // + // We have a profile embedded in the bitmap - extract and set as the source profile + // + if (SUCCEEDED(hr = pSrcBmp->GetColorContext(&pSrcContext)) && + SUCCEEDED(hr = pSrcContext->GetProfileBytes(cbBuffer, pBuffer, &cbActual))) + { + if (cbActual > 0) + { + pBuffer = new(std::nothrow) BYTE[cbActual]; + cbBuffer = cbActual; + + // + // The annotation on IWICColorContext::GetProfileBytes requires that the buffer + // be initialized. + // + + if (SUCCEEDED(hr = CHECK_POINTER(pBuffer, E_OUTOFMEMORY))) + { + ::memset(pBuffer, 0, cbBuffer); + } + + if (SUCCEEDED(hr) && + SUCCEEDED(hr = pSrcContext->GetProfileBytes(cbBuffer, pBuffer, &cbActual))) + { + // + // Set the source profile in the profile manager. Note: in this instance the profile name is + // no used to load the profile, merely to cache the profile. The bitmap URI uniquely idenitifies + // the bitmap and hence the embedded profile and is appropriate as a cache name + // + hr = m_pProfManager->SetSrcProfileFromBuffer(m_bstrBitmapURI, pBuffer, cbBuffer); + } + + if (pBuffer != NULL) + { + delete[] pBuffer; + pBuffer = NULL; + } + } + else + { + RIP("Zero length profile.\n"); + hr = E_FAIL; + } + } + } + else + { + // + // Deduce the source profile from the source bitmap format + // + switch (pSrcBmp->GetPixelFormat()) + { + case kWICPixelFormatDontCare: + case kWICPixelFormat1bppIndexed: + case kWICPixelFormat2bppIndexed: + case kWICPixelFormat4bppIndexed: + case kWICPixelFormat8bppIndexed: + case kWICPixelFormatBlackWhite: + case kWICPixelFormat2bppGray: + case kWICPixelFormat4bppGray: + case kWICPixelFormat8bppGray: + case kWICPixelFormat16bppBGR555: + case kWICPixelFormat16bppBGR565: + case kWICPixelFormat16bppGray: + case kWICPixelFormat24bppBGR: + case kWICPixelFormat24bppRGB: + case kWICPixelFormat32bppBGR: + case kWICPixelFormat32bppBGRA: + case kWICPixelFormat32bppPBGRA: + case kWICPixelFormat32bppBGR101010: + case kWICPixelFormat48bppRGB: + case kWICPixelFormat64bppRGBA: + case kWICPixelFormat64bppPRGBA: + { + hr = m_pProfManager->SetSrcProfileFromColDir(L"sRGB Color Space Profile.icm"); + } + break; + + case kWICPixelFormat48bppRGBFixedPoint: + case kWICPixelFormat96bppRGBFixedPoint: + case kWICPixelFormat128bppRGBAFloat: + case kWICPixelFormat128bppPRGBAFloat: + case kWICPixelFormat128bppRGBFloat: + case kWICPixelFormat64bppRGBAFixedPoint: + case kWICPixelFormat64bppRGBFixedPoint: + case kWICPixelFormat128bppRGBAFixedPoint: + case kWICPixelFormat128bppRGBFixedPoint: + case kWICPixelFormat64bppRGBAHalf: + case kWICPixelFormat64bppRGBHalf: + case kWICPixelFormat48bppRGBHalf: + case kWICPixelFormat32bppRGBE: + case kWICPixelFormat16bppGrayHalf: + case kWICPixelFormat32bppGrayFloat: + case kWICPixelFormat32bppGrayFixedPoint: + case kWICPixelFormat16bppGrayFixedPoint: + { + hr = m_pProfManager->SetSrcProfileFromColDir(L"xdwscRGB.icc"); + } + break; + + case kWICPixelFormat32bppCMYK: + case kWICPixelFormat64bppCMYK: + case kWICPixelFormat40bppCMYKAlpha: + case kWICPixelFormat80bppCMYKAlpha: + { + hr = m_pProfManager->SetSrcProfileFromColDir(L"xdCMYKPrinter.icc"); + } + break; + + default: + { + RIP("No acceptable default profile.\n"); + + hr = HRESULT_FROM_WIN32(ERROR_PROFILE_NOT_FOUND); + } + break; + } + } + } + + ERR_ON_HR(hr); + return hr; +} + + +/*++ + +Routine Name: + + CColorManagedImage::TransformScanLines + +Routine Description: + + Given source and destination scanline iterators, this method applies the + requiresite color transform + +Arguments: + + pSrcScans - Pointer to the source scanline iterator + pDstScans - Pointer to the destination scanline iterator + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CColorManagedImage::TransformScanLines( + _In_ CScanIterator* pSrcScans, + _In_ CScanIterator* pDstScans + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pSrcScans, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pDstScans, E_POINTER))) + { + try + { + // + // Apply the transform + // + HTRANSFORM hTransform = NULL; + BOOL bCanUseWCS = FALSE; + + if (SUCCEEDED(hr = m_pProfManager->GetColorTransform(&hTransform, &bCanUseWCS))) + { + PBYTE pDstData = NULL; + BMFORMAT bmSrcFormat; + UINT cSrcWidth = 0; + UINT cSrcHeight = 0; + UINT cbSrcStride = 0; + + PBYTE pSrcData = NULL; + BMFORMAT bmDstFormat; + UINT cDstWidth = 0; + UINT cDstHeight = 0; + UINT cbDstStride = 0; + + // + // While the source andd destination have scanlines remaining to process... + // + while (!pDstScans->Finished() && + !pSrcScans->Finished() && + SUCCEEDED(hr)) + { + // + // ...retrieve the scan buffers (these may have been processed to remove alpha data)... + // + if (SUCCEEDED(hr = pSrcScans->GetScanBuffer(&pSrcData, &bmSrcFormat, &cSrcWidth, &cSrcHeight, &cbSrcStride)) && + SUCCEEDED(hr = pDstScans->GetScanBuffer(&pDstData, &bmDstFormat, &cDstWidth, &cDstHeight, &cbDstStride))) + { + // + // ...translate the scanline data... + // + if (TranslateBitmapBits(hTransform, + pSrcData, + bmSrcFormat, + cSrcWidth, + cSrcHeight, + cbSrcStride, + pDstData, + bmDstFormat, + cbDstStride, + NULL, + 0)) + { + // + // ...and commit the data to the destination bitmap before incrementing to the next scanline. + // + hr = pDstScans->Commit(*pSrcScans); + (*pSrcScans)++; + (*pDstScans)++; + } + else + { + RIP("Translate bitmap bits failed.\n"); + hr = GetLastErrorAsHResult(); + } + } + } + } + } + catch (CXDException& e) + { + hr = e; + } + } + + ERR_ON_HR(hr); + return hr; +} + diff --git a/print/XPSDrvSmpl/src/filters/color/cmimg.h b/print/XPSDrvSmpl/src/filters/color/cmimg.h new file mode 100644 index 00000000..397c3678 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/color/cmimg.h @@ -0,0 +1,87 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + cmimg.h + +Abstract: + + Color management image definition. The CColorManagedImage class is responsible + for managing the image resources used in a container. This implements + the IResWriter interface so that the font can be added to the resource + cache. + +--*/ + +#pragma once + +#include "rescache.h" +#include "profman.h" +#include "scaniter.h" +#include "cmflt.h" + +class CColorManagedImage : public IResWriter +{ +public: + CColorManagedImage( + _In_ BSTR bstrResURI, + _In_ CProfileManager* pProfManager, + _In_ IFixedPage* pFixedPage, + _In_ ResDeleteMap* pResDel + ); + + ~CColorManagedImage(); + + HRESULT + WriteData( + _In_ IPartBase* pResource, + _In_ IPrintWriteStream* pStream + ); + + HRESULT + GetKeyName( + _Outptr_ BSTR* pbstrKeyName + ); + + HRESULT + GetResURI( + _Outptr_ BSTR* pbstrResURI + ); + +private: + HRESULT + SetSrcProfile( + _In_ CBmpConverter* pScanIter + ); + + HRESULT + TransformScanLines( + _In_ CScanIterator* pSrcScans, + _In_ CScanIterator* pDstScans + ); + +private: + CComBSTR m_bstrBitmapURI; + + CComBSTR m_bstrSrcProfileURI; + + CProfileManager* m_pProfManager; + + CBmpConverter m_srcBmp; + + CBmpConverter m_dstBmp; + + CComPtr m_pFixedPage; + + ResDeleteMap* m_pResDel; +}; + diff --git a/print/XPSDrvSmpl/src/filters/color/cmsax.cpp b/print/XPSDrvSmpl/src/filters/color/cmsax.cpp new file mode 100644 index 00000000..f5db86dd --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/color/cmsax.cpp @@ -0,0 +1,440 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + cmsax.cpp + +Abstract: + + Color managed image SAX handler implementation. The CCMSaxHandler class is responsible + for handling the XML markup in the container. + + Note regarding opacity masks: Ideally we would like to avoid color matching whilst + within an opacity mask element as only the alpha channel is of interest. This is + complicated however by the fact that the opacity mask resources my be re-used as + rendering resources. Ideally we would color match opacity mask elements only when + the resources are shared with other rendering operations. This is difficult to + achieve with SAX however as we do not know a priori if the resource is shared or + the resource is going to be shared. + Currently we are performing unnecessary color matching when an opacity mask is + encountered. We could alternatively ensure opacity mask resources are preserved and + other render sources are modified and written as new resources. The trade off is + reduced speed performance against added resource handling complexity and XPS + content bloat. This implementation takes the first option which trades processing time + against the amount of data written to the container and resource handling complexity. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdstring.h" +#include "cmsax.h" + +/*++ + +Routine Name: + + CCMSaxHandler::CCMSaxHandler + +Routine Description: + + Contructor for the color management filters SAX handler. + The constructor registers a writer for sending new markup out to and a color + converter object which handles any color conversion work for those markup + elements containing color data. + +Arguments: + + pWriter - Pointer to a write stream which receives markup + pConverter - Pointer to a color converter object which handles any + color conversion work for elements containing color data + +Return Value: + + None + Throws CXDException(HRESULT) on an error + +--*/ +CCMSaxHandler::CCMSaxHandler( + _In_ IPrintWriteStream* pWriter, + _In_ CBitmapColorConverter* pBmpConverter, + _In_ CColorRefConverter* pRefConverter, + _In_opt_ CResourceDictionaryConverter* pDictConverter + ) : + m_pWriter(pWriter), + m_bOpenTag(FALSE), + m_pBmpConv(pBmpConverter), + m_pRefConv(pRefConverter), + m_pDictConv(pDictConverter) +{ + ASSERTMSG(m_pWriter != NULL, "NULL writer passed to color SAX handler.\n"); + ASSERTMSG(m_pBmpConv != NULL, "NULL bitmap color converter passed to color SAX handler.\n"); + ASSERTMSG(m_pRefConv != NULL, "NULL color ref converter passed to color SAX handler.\n"); + + HRESULT hr = S_OK; + if (FAILED(hr = CHECK_POINTER(m_pWriter, E_POINTER)) || + FAILED(hr = CHECK_POINTER(m_pBmpConv, E_POINTER)) || + FAILED(hr = CHECK_POINTER(m_pRefConv, E_POINTER))) + { + throw CXDException(hr); + } +} + +/*++ + +Routine Name: + + CCMSaxHandler::~CCMSaxHandler + +Routine Description: + + Default destructor for the color management filters SAX handler + +Arguments: + + None + +Return Value: + + None + +--*/ +CCMSaxHandler::~CCMSaxHandler() +{ + m_bstrOpenElement.Empty(); +} + +/*++ + +Routine Name: + + CCMSaxHandler::startElement + +Routine Description: + + SAX handler method which handles each start element for the XML markup. + +Arguments: + + pwchQName - Pointer to a string containing the element name + cchQName - Count of the number of characters in the element name + pAttributes - Pointer to the attribute list for the supplied element + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT STDMETHODCALLTYPE +CCMSaxHandler::startElement( + CONST wchar_t*, + INT, + CONST wchar_t*, + INT, + _In_reads_(cchQName) CONST wchar_t* pwchQName, + _In_ INT cchQName, + _In_ ISAXAttributes* pAttributes + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pwchQName, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pAttributes, E_POINTER))) + { + if (cchQName < 1) + { + hr = E_INVALIDARG; + } + } + + CStringXDW cstrOut; + if (SUCCEEDED(hr)) + { + try + { + CComBSTR bstrElement(cchQName, pwchQName); + + // + // Check if we need to close an opened tag + // + if (m_bOpenTag) + { + cstrOut.Append(L">"); + } + + // + // Store the opened element name so we can handle nested elements + // + m_bstrOpenElement = bstrElement; + + // + // Create output element + // + cstrOut.Append(L"<"); + cstrOut.Append(bstrElement); + + // + // We opened a tag + // + m_bOpenTag = TRUE; + + // + // Find the number of attributes and enumerate over all of them + // + INT cAttributes = 0; + if (SUCCEEDED(hr = pAttributes->getLength(&cAttributes))) + { + for (INT cIndex = 0; cIndex < cAttributes; cIndex++) + { + PCWSTR pszAttUri = NULL; + INT cchAttUri = 0; + PCWSTR pszAttName = NULL; + INT cchAttName = 0; + PCWSTR pszAttQName = NULL; + INT cchAttQName = 0; + PCWSTR pszAttValue = NULL; + INT cchAttValue = 0; + + // + // Get the attribute data ready to write out + // + if (SUCCEEDED(hr = pAttributes->getName(cIndex, + &pszAttUri, + &cchAttUri, + &pszAttName, + &cchAttName, + &pszAttQName, + &cchAttQName))) + { + if (SUCCEEDED(pAttributes->getValue(cIndex, &pszAttValue, &cchAttValue))) + { + CComBSTR bstrAttName(cchAttQName, pszAttQName); + CComBSTR bstrAttValue(cchAttValue, pszAttValue); + + if (bstrElement == L"ResourceDictionary" && + bstrAttName == L"Source") + { + // + // Convert remote resource dictionary + // + if (SUCCEEDED(hr = CHECK_POINTER(m_pDictConv, E_FAIL))) + { + hr = m_pDictConv->Convert(&bstrAttValue); + } + } + else + { + // + // Find all color refs and image sources. + // + if (bstrAttName == L"Color" || + bstrAttName == L"Fill" || + bstrAttName == L"Stroke" ) + { + // + // Process the value passing the colorref + // + hr = m_pRefConv->Convert(&bstrAttValue); + } + else if (bstrAttName == L"ImageSource") + { + // + // Process the value passing the URI + // + hr = m_pBmpConv->Convert(&bstrAttValue); + } + } + + // + // Delimit attributes with a space + // + cstrOut.Append(L" "); + + // + // Reconstruct the attribute and write back to + // the fixed page + // + cstrOut.Append(bstrAttName); + cstrOut.Append(L"=\""); + + // + // If this is a UnicodeString we may need to escape entities + // + if (bstrAttName == L"UnicodeString") + { + hr = EscapeEntity(&bstrAttValue); + } + + cstrOut.Append(bstrAttValue); + cstrOut.Append(L"\""); + } + } + } + } + } + catch (CXDException& e) + { + hr = e; + } + } + + if (SUCCEEDED(hr)) + { + hr = WriteToPrintStream(&cstrOut, m_pWriter); + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CCMSaxHandler::endElement + +Routine Description: + + SAX handler method which handles each end element for the XML markup + +Arguments: + + pwchQName - Pointer to a string containing the element name + cchQName - Count of the number of characters in the element name + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT STDMETHODCALLTYPE +CCMSaxHandler::endElement( + CONST wchar_t*, + INT, + CONST wchar_t*, + INT, + _In_reads_(cchQName) CONST wchar_t* pwchQName, + _In_ INT cchQName + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pwchQName, E_POINTER))) + { + if (cchQName < 1) + { + hr = E_INVALIDARG; + } + } + + CStringXDW cstrClose; + if (SUCCEEDED(hr)) + { + try + { + CComBSTR bstrElement(cchQName, pwchQName); + + // + // If this is a root element with child nodes, the open + // element will not match the last startElement. In this case + // we need to add an appropriate closing tag + // + if (bstrElement == m_bstrOpenElement) + { + // + // Names match so just add a closing bracket + // + // We might have closed the tag when writing a new element + // + if (m_bOpenTag) + { + cstrClose.Append(L"/>"); + } + } + else + { + // + // Add a clossing tag + // + cstrClose.Append(L""); + } + } + catch (CXDException& e) + { + hr = e; + } + } + + if (SUCCEEDED(hr)) + { + hr = WriteToPrintStream(&cstrClose, m_pWriter); + } + + m_bOpenTag = FALSE; + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CCMSaxHandler::startDocument + +Routine Description: + + SAX handler method which handles the start document call to ensure + the xml version is correctly set + +Arguments: + + None + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT STDMETHODCALLTYPE +CCMSaxHandler::startDocument( + void + ) +{ + HRESULT hr = S_OK; + + try + { + if (SUCCEEDED(hr = CHECK_POINTER(m_pWriter, E_FAIL))) + { + CStringXDW cstrOut(L""); + hr = WriteToPrintStream(&cstrOut, m_pWriter); + } + } + catch (CXDException& e) + { + hr = e; + } + + ERR_ON_HR(hr); + return hr; +} + diff --git a/print/XPSDrvSmpl/src/filters/color/cmsax.h b/print/XPSDrvSmpl/src/filters/color/cmsax.h new file mode 100644 index 00000000..dc09f9d0 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/color/cmsax.h @@ -0,0 +1,80 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + cmsax.h + +Abstract: + + Color management sax handler definition. The color management SAX handler + is responsible for parsing the FixedPage mark-up for and vector objects + or bitmaps which contain color data and altering the mark-up where appropriate. + +--*/ + +#pragma once + +#include "saxhndlr.h" +#include "colconv.h" + +class CCMSaxHandler : public CSaxHandler +{ +public: + CCMSaxHandler( + _In_ IPrintWriteStream* pWriter, + _In_ CBitmapColorConverter* pBmpConverter, + _In_ CColorRefConverter* pRefConverter, + _In_opt_ CResourceDictionaryConverter* pDictConverter + ); + + virtual ~CCMSaxHandler(); + + virtual HRESULT STDMETHODCALLTYPE + startElement( + CONST wchar_t*, + INT, + CONST wchar_t*, + INT, + _In_reads_(cchQName) CONST wchar_t* pwchQName, + _In_ INT cchQName, + _In_ ISAXAttributes* pAttributes + ); + + virtual HRESULT STDMETHODCALLTYPE + endElement( + CONST wchar_t*, + INT, + CONST wchar_t*, + INT, + _In_reads_(cchQName) CONST wchar_t* pwchQName, + _In_ INT cchQName + ); + + HRESULT STDMETHODCALLTYPE + startDocument( + void + ); + +private: + CComPtr m_pWriter; + + CComBSTR m_bstrOpenElement; + + BOOL m_bOpenTag; + + CColorConverter* m_pBmpConv; + + CColorConverter* m_pRefConv; + + CColorConverter* m_pDictConv; +}; + diff --git a/print/XPSDrvSmpl/src/filters/color/colchan.cpp b/print/XPSDrvSmpl/src/filters/color/colchan.cpp new file mode 100644 index 00000000..2d98334f --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/color/colchan.cpp @@ -0,0 +1,1883 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + colchan.cpp + +Abstract: + + Color channel class implementation. The color channel class is responsible for maintaining + simple single color multiple channel data intialised from color references in the XPS markup. + It provides methods for intialization, access and conversion of the data. + + Note regarding color formats: The CColorChannelData class is only used in the filter for + processing color references in mark-up. As such we only ever see 8 bit per channel sRGB and + floating point scRGB and n-channel colors and we only ever need convert to 16 bpc for + down-level scRGB conversion. If the CColorChannelData is ever used when fixed point input + or other output types are required then these formats need support added (see E_NOTIMPL + return values). + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdexcept.h" +#include "colchan.h" + +#define MAX_CHANNEL_COUNT 9 // 1 alpha channel and 8 color channels +#define MAX_CHANNEL_SIZE sizeof(FLOAT) + +DWORD g_cbChannelType[] = { + sizeof(BYTE), // COLOR_BYTE + sizeof(WORD), // COLOR_WORD + sizeof(FLOAT), // COLOR_FLOAT + sizeof(WORD) // COLOR_S2DOT13FIXED +}; + + +/*++ + +Routine Name: + + CColorChannelData::CColorChannelData + +Routine Description: + + CColorChannelData default constructor + +Arguments: + + None + +Return Value: + + None + Throws an exception on failure. + +--*/ +CColorChannelData::CColorChannelData() : + m_cChannels(0), + m_channelType(COLOR_BYTE), + m_pChannelData(NULL), + m_cbChannelData(0), + m_dataType(sRGB) +{ + if (FAILED(AllocateChannelBuffers(&m_cbChannelData, &m_pChannelData))) + { + throw CXDException(E_OUTOFMEMORY); + } +} + +/*++ + +Routine Name: + + CColorChannelData::~CColorChannelData + +Routine Description: + + CColorChannelData destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CColorChannelData::~CColorChannelData() +{ + FreeChannelBuffers(); +} + +/*++ + +Routine Name: + + CColorChannelData::AddChannelData + +Routine Description: + + Template method for adding channel data. This allows any of the available color + channel data types to be added to the channel data buffer + +Arguments: + + channelValue - Value for the channel to be added + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +template +HRESULT +CColorChannelData::AddChannelData( + _In_ CONST _T& channelValue + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = ValidateDataSize<_T>())) + { + if (m_cChannels < MAX_CHANNEL_COUNT) + { + _T* pChannelData = reinterpret_cast<_T*>(m_pChannelData); + pChannelData[m_cChannels] = channelValue; + m_cChannels++; + } + else + { + hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CColorChannelData::GetChannelCount + +Routine Description: + + Retrieves the current number of channels defining the color. + +Arguments: + + pcChannels - Pointer to a variable that recieves the count of channels + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CColorChannelData::GetChannelCount( + _Out_ DWORD* pcChannels + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pcChannels, E_POINTER))) + { + *pcChannels = m_cChannels; + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CColorChannelData::GetChannelCountNoAlpha + +Routine Description: + + Retrieves the number of channels less the alpha channel if present + +Arguments: + + pcChannels - Pointer to a variable that recieves the count of non-alpha channels + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CColorChannelData::GetChannelCountNoAlpha( + _Out_ DWORD* pcChannels + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = GetChannelCount(pcChannels))) + { + if (HasAlpha()) + { + (*pcChannels)--; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CColorChannelData::GetChannelType + +Routine Description: + + Retrieves the COLORDATATYPE for the channel data + +Arguments: + + pChannelType - Pointer to a COLORDATATYPE variable that recieves the type + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CColorChannelData::GetChannelType( + _Out_ COLORDATATYPE* pChannelType + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pChannelType, E_POINTER))) + { + *pChannelType = m_channelType; + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CColorChannelData::ResetChannelType + +Routine Description: + + Resets the underlying channel data type to the requested type + +Arguments: + + channelType - The channel data type to reset to + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CColorChannelData::ResetChannelType( + _In_ CONST COLORDATATYPE& channelType + ) +{ + m_channelType = channelType; + m_cChannels = 0; + + return S_OK; +} + +/*++ + +Routine Name: + + CColorChannelData::GetChannelData + +Routine Description: + + Retrieves the buffer and count of bytes of the channel data + +Arguments: + + pcbDataSize - Pointer to variable that recieves the count of bytes in the buffer + ppData - Pointer to a BYTE pointer that recieves the buffer + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CColorChannelData::GetChannelData( + _Out_ DWORD* pcbDataSize, + _Out_ + _When_(*pcbDataSize > 0, _At_(*ppData, _Post_ _Readable_bytes_(*pcbDataSize))) + _When_(*pcbDataSize == 0, _At_(*ppData, _Post_ _Maybenull_)) + PVOID* ppData + ) +{ + HRESULT hr = S_OK; + + DWORD cbDataTypeSize = 0; + if (SUCCEEDED(hr = CHECK_POINTER(pcbDataSize, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(ppData, E_POINTER)) && + SUCCEEDED(hr = GetChannelSizeFromType(m_channelType, &cbDataTypeSize))) + { + *ppData = NULL; + *pcbDataSize = 0; + + if (m_cbChannelData >= m_cChannels * cbDataTypeSize) + { + if (m_cChannels > 0) + { + *pcbDataSize = m_cChannels * cbDataTypeSize; + *ppData = m_pChannelData; + } + } + else + { + hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CColorChannelData::GetChannelDataNoAlpha + +Routine Description: + + Retrieves the buffer and count of bytes of the channel data excluding the + alpha channel if present + +Arguments: + + pcbDataSize - Pointer to variable that recieves the count of bytes in the buffer + ppData - Pointer to a BYTE pointer that recieves the buffer + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CColorChannelData::GetChannelDataNoAlpha( + _Out_ DWORD* pcbDataSize, + _Out_ + _When_(*pcbDataSize > 0, _At_(*ppData, _Post_ _Readable_bytes_(*pcbDataSize))) + _When_(*pcbDataSize == 0, _At_(*ppData, _Post_ _Maybenull_)) + PVOID* ppData + ) +{ + HRESULT hr = S_OK; + + DWORD cbData = 0; + PBYTE pData = NULL; + + if (SUCCEEDED(hr = CHECK_POINTER(pcbDataSize, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(ppData, E_POINTER)) && + SUCCEEDED(hr = GetChannelData(&cbData, reinterpret_cast(&pData)))) + { + *pcbDataSize = cbData; + *ppData = pData; + + if (HasAlpha()) + { + DWORD cbChannelSize = 0; + if (SUCCEEDED(hr = GetChannelSizeFromType(m_channelType, &cbChannelSize))) + { + if (cbData >= cbChannelSize) + { + *pcbDataSize = cbData - cbChannelSize; + *ppData = pData + cbChannelSize; + } + else + { + hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); + } + } + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CColorChannelData::ClampChannelValues + +Routine Description: + + Template method that recieves the minimum and maximum value for a channel + and applies this to all channels defining the color + +Arguments: + + min - Minimum channel value + max - Maximum channel value + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +template +HRESULT +CColorChannelData::ClampChannelValues( + _In_ CONST _T& min, + _In_ CONST _T& max + ) +{ + HRESULT hr = S_OK; + + // + // Validate the data size against the current type + // + if (SUCCEEDED(hr = ValidateDataSize<_T>())) + { + _T* pData = reinterpret_cast<_T*>(m_pChannelData); + for (DWORD cChannel = 0; cChannel < m_cChannels; cChannel++, pData++) + { + if (*pData < min) + { + *pData = min; + } + else if (*pData > max) + { + *pData = max; + } + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CColorChannelData::InitializeChannelData + +Routine Description: + + Initializes the channel data according to the type, count of channels and a default value + +Arguments: + + channelType - The required channel data format + dataType - The required data type + cChannels - The count of channels defining the color + channelValue - The intial value for all channels + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +template +HRESULT +CColorChannelData::InitializeChannelData( + _In_ CONST COLORDATATYPE& channelType, + _In_ CONST EColorDataType& dataType, + _In_ CONST DWORD& cChannels, + _In_ CONST _T& channelValue + ) +{ + HRESULT hr = S_OK; + + // + // Validate the data size against the current type + // + if (SUCCEEDED(hr = ResetChannelType(channelType)) && + SUCCEEDED(hr = ValidateDataSize<_T>())) + { + if (cChannels <= MAX_CHANNEL_COUNT) + { + m_dataType = dataType; + m_cChannels = cChannels; + _T* pChannelData = reinterpret_cast<_T*>(m_pChannelData); + + for (DWORD cChannel = 0; cChannel < m_cChannels; cChannel++, pChannelData++) + { + *pChannelData = channelValue; + } + } + else + { + hr = E_INVALIDARG; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CColorChannelData::SetColorDataType + +Routine Description: + + Sets the color data type + +Arguments: + + dataType - The color data type + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CColorChannelData::SetColorDataType( + _In_ CONST EColorDataType& dataType + ) +{ + m_dataType = dataType; + + return S_OK; +} + +/*++ + +Routine Name: + + CColorChannelData::GetColorDataType + +Routine Description: + + Retrieves the current color data type + +Arguments: + + pDataType - Pointer to a variable to recieve the color data type + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CColorChannelData::GetColorDataType( + _Out_ EColorDataType* pDataType + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pDataType, E_POINTER))) + { + *pDataType = m_dataType; + } + + return S_OK; +} + +/*++ + +Routine Name: + + CColorChannelData::HasAlpha + +Routine Description: + + Indicates if the color channel data includes an alpha channel + +Arguments: + + None + +Return Value: + + TRUE - An alpha channel is present + FALSE - There is no alpha channel + +--*/ +BOOL +CColorChannelData::HasAlpha( + VOID + ) +{ + // + // If the source or destination is n-channel, or if either sRGB or scRGB have 4 channels, + // we have an alpha channel + // + return m_dataType == nChannel || m_cChannels == 4; +} + +/*++ + +Routine Name: + + CColorChannelData::GetAlphaChannelSize + +Routine Description: + + Retrieves the count of bytes of the alpha channel + +Arguments: + + pcbAlphaChannel - pointer to a variable that recieves the count of bytes of the alpha channel + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CColorChannelData::GetAlphaChannelSize( + _Out_ DWORD* pcbAlphaChan + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pcbAlphaChan, E_POINTER))) + { + *pcbAlphaChan = 0; + if (HasAlpha()) + { + hr = GetChannelSizeFromType(m_channelType, pcbAlphaChan); + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CColorChannelData::InitializeAlphaChannel + +Routine Description: + + Initialize the alpha channel based off a source color channel data object + +Arguments: + + pSrcChannelData - Pointer to a source color data channel object + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CColorChannelData::InitializeAlphaChannel( + _In_ CColorChannelData* pSrcChannelData + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pSrcChannelData, E_POINTER))) + { + if (HasAlpha()) + { + FLOAT alpha = 1.0f; + if (SUCCEEDED(hr) && + pSrcChannelData->HasAlpha() && + SUCCEEDED(hr = pSrcChannelData->GetAlphaAsFloat(&alpha))) + { + // + // Ensure alpha lies between 0.0 and 1.0 + // + if (alpha < 0.0) + { + alpha = 0.0; + } + else if (alpha > 1.0) + { + alpha = 1.0; + } + } + + switch (m_channelType) + { + case COLOR_BYTE: + { + *m_pChannelData = static_cast(alpha * kMaxByteAsFloat); + } + break; + + case COLOR_WORD: + { + *reinterpret_cast(m_pChannelData) = static_cast(alpha * kMaxWordAsFloat); + } + break; + + case COLOR_FLOAT: + { + *reinterpret_cast(m_pChannelData) = alpha; + } + break; + + case COLOR_S2DOT13FIXED: + { + hr = E_NOTIMPL; + } + break; + + default: + { + RIP("Unrecognised channel data format.\n"); + hr = E_FAIL; + } + break; + } + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CColorChannelData::GetColor + +Routine Description: + + Retrieves a COLOR object based of the channel data + +Arguments: + + pColor - Pointer to a color structure to be filled in + pType - Pointer to storage to accept the color type + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CColorChannelData::GetColor( + _Out_ PCOLOR pColor, + _Out_ COLORTYPE* pType + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pColor, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pType, E_POINTER))) + { + if (m_cChannels == 0) + { + hr = E_PENDING; + } + } + + DWORD cChannels = 0; + if (SUCCEEDED(hr) && + SUCCEEDED(hr = GetChannelCountNoAlpha(&cChannels))) + { + if (cChannels <= 4) + { + hr = ColorToWord(reinterpret_cast(pColor), static_cast(sizeof(COLOR))); + } + else if (cChannels <= 8) + { + hr = ColorToByte(reinterpret_cast(pColor), static_cast(sizeof(COLOR))); + } + else + { + hr = E_FAIL; + } + + if (SUCCEEDED(hr)) + { + if (m_dataType == sRGB || + m_dataType == scRGB) + { + *pType = COLOR_RGB; + } + else if (m_dataType == nChannel) + { + *pType = static_cast(cChannels + 3); + } + else + { + RIP("Unrecognised data type.\n"); + + hr = E_FAIL; + } + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CColorChannelData::SetColor + +Routine Description: + + Sets the channel data based on a COLOR structure + +Arguments: + + pColor - Pointer to a color structure to set the channel data from + type - The color type described by the color structure + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CColorChannelData::SetColor( + _In_ COLOR* pColor, + _In_ CONST COLORTYPE& type + ) +{ + HRESULT hr = S_OK; + + DWORD cChannels = 0; + DWORD cbData = 0; + PBYTE pData = NULL; + + if (SUCCEEDED(hr = CHECK_POINTER(pColor, E_POINTER)) && + SUCCEEDED(hr = GetChannelCountNoAlpha(&cChannels)) && + SUCCEEDED(hr = GetChannelDataNoAlpha(&cbData, reinterpret_cast(&pData)))) + { + DWORD cSrcChannels = 0; + + switch (type) + { + case COLOR_RGB: + { + if (m_dataType == sRGB || + m_dataType == scRGB) + { + cSrcChannels = 3; + } + else + { + hr = HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); + } + } + break; + + case COLOR_3_CHANNEL: + case COLOR_CMYK: + case COLOR_5_CHANNEL: + case COLOR_6_CHANNEL: + case COLOR_7_CHANNEL: + case COLOR_8_CHANNEL: + { + if (m_dataType == nChannel) + { + cSrcChannels = static_cast(type - 3); + } + else + { + hr = HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); + } + } + break; + + case COLOR_GRAY: + case COLOR_XYZ: + case COLOR_Yxy: + case COLOR_Lab: + case COLOR_NAMED: + { + hr = E_NOTIMPL; + } + break; + + default: + { + RIP("Unrecognised color type\n"); + hr = E_FAIL; + } + break; + } + + if (SUCCEEDED(hr)) + { + if (cChannels == cSrcChannels) + { + if (cSrcChannels <= 4) + { + hr = ColorFromWord(reinterpret_cast(pColor), sizeof(COLOR)); + } + else if (cSrcChannels <= 8) + { + hr = ColorFromByte(reinterpret_cast(pColor), sizeof(COLOR)); + } + else + { + RIP("Invalid channel count\n"); + hr = E_FAIL; + } + } + else + { + RIP("Miss-match between source channel count and current channel count\n"); + hr = E_FAIL; + } + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CColorChannelData::ColorToByte + +Routine Description: + + Converts the channel data to a 8 bpc COLOR type + +Arguments: + + pDstData - Pointer to the data to be set + cbDstData - Size of the destination buffer + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CColorChannelData::ColorToByte( + _Out_writes_bytes_(cbDstData) PBYTE pDstData, + _In_ CONST UINT cbDstData + ) +{ + HRESULT hr = S_OK; + + DWORD cChannels = 0; + DWORD cbData = 0; + PBYTE pData = NULL; + + if (SUCCEEDED(hr = CHECK_POINTER(pDstData, E_POINTER)) && + SUCCEEDED(hr = GetChannelCountNoAlpha(&cChannels)) && + SUCCEEDED(hr = GetChannelDataNoAlpha(&cbData, reinterpret_cast(&pData)))) + { + ZeroMemory(pDstData, cbDstData); + + if (cbDstData < cChannels) + { + hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); + } + } + + if (SUCCEEDED(hr) && + cbData == 0 && + cChannels != 0) + { + hr = E_UNEXPECTED; + } + + if (SUCCEEDED(hr)) + { + if (cbDstData > 0) + { + switch (m_channelType) + { + case COLOR_BYTE: + { + if (cbDstData >= cbData) + { + // + // Just copy all channels after alpha into the buffer + // + CopyMemory(pDstData, pData, cbData); + } + else + { + hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); + } + } + break; + + case COLOR_WORD: + { + if (cbDstData >= cChannels * sizeof(BYTE) && + cbData >= cChannels * sizeof(WORD)) + { + PWORD pSrcData = reinterpret_cast(pData); + + for (UINT cCurrChan = 0; + cCurrChan < cChannels; + cCurrChan++) + { + _Analysis_assume_(cCurrChan < cbDstData); + + pDstData[cCurrChan] = static_cast(MulDiv(pSrcData[cCurrChan], 0xFF, 0xFFFF)); + } + } + else + { + hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); + } + } + break; + + case COLOR_FLOAT: + { + // + // Make sure the float data runs between 0.0 and 1.0 for nChannel and sRGB and is + // truncated and scaled as follows for scRGB: + // + // 1. Truncate the input color to between -2.0 and +2.0 + // 2. Offset the value by +2.0 to put it into the 0.0 to 4.0 range + // 3. Scale the value down by 4.0 to put it into the range 0.0 to 1.0 + // 4. Set the 16 bit value according to the channel value from 0x00 + // for 0.0 to 0xFF for 1.0 + // + if (cbDstData >= cChannels * sizeof(BYTE) && + cbData >= cChannels * sizeof(FLOAT)) + { + PFLOAT pSrcData = reinterpret_cast(pData); + + if (m_dataType == scRGB) + { + for (UINT cCurrChan = 0; + cCurrChan < cChannels; + cCurrChan++) + { + _Analysis_assume_(cCurrChan < cbDstData); + + FLOAT channelValue = pSrcData[cCurrChan]; + channelValue = channelValue < -2.0f ? -2.0f : channelValue; + channelValue = channelValue > 2.0f ? 2.0f : channelValue; + channelValue += 2.0f; + channelValue /= 4.0f; + pDstData[cCurrChan] = static_cast(channelValue * kMaxByteAsFloat); + } + } + else + { + if (SUCCEEDED(hr = ClampChannelValues(0.0f, 1.0f))) + { + for (UINT cCurrChan = 0; + cCurrChan < cChannels; + cCurrChan++) + { + _Analysis_assume_(cCurrChan < cbDstData); + + pDstData[cCurrChan] = static_cast(pSrcData[cCurrChan] * kMaxByteAsFloat); + } + } + } + } + else + { + hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); + } + } + break; + + case COLOR_S2DOT13FIXED: + { + hr = E_NOTIMPL; + } + break; + + default: + { + RIP("Unrecognised color type\n"); + hr = E_FAIL; + } + break; + } + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CColorChannelData::ColorToWord + +Routine Description: + + Converts the channel data to a 16 bpc COLOR type + +Arguments: + + pDstData - Pointer to the data to be set + cbDstData - Size of the destination buffer + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CColorChannelData::ColorToWord( + _Out_writes_bytes_(cbDstData) PWORD pDstData, + _In_ CONST UINT cbDstData + ) +{ + HRESULT hr = S_OK; + + DWORD cChannels = 0; + DWORD cbData = 0; + PBYTE pData = NULL; + + if (SUCCEEDED(hr = CHECK_POINTER(pDstData, E_POINTER)) && + SUCCEEDED(hr = GetChannelCountNoAlpha(&cChannels)) && + SUCCEEDED(hr = GetChannelDataNoAlpha(&cbData, reinterpret_cast(&pData)))) + { + ZeroMemory(pDstData, cbDstData); + + if (cbDstData / sizeof(WORD) < cChannels) + { + hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); + } + } + + if (SUCCEEDED(hr) && + cbData == 0 && + cChannels != 0) + { + hr = E_UNEXPECTED; + } + + if (SUCCEEDED(hr)) + { + if (cbDstData > 0) + { + switch (m_channelType) + { + case COLOR_BYTE: + { + if (cbDstData >= cChannels * sizeof(WORD) && + cbData >= cChannels * sizeof(BYTE)) + { + for (UINT cCurrChan = 0; + cCurrChan < cChannels; + cCurrChan++) + { + _Analysis_assume_((cCurrChan + 1) * sizeof(WORD) <= cbDstData); + + pDstData[cCurrChan] = static_cast(MulDiv(pData[cCurrChan], 0xFFFF, 0xFF)); + } + } + else + { + hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); + } + } + break; + + case COLOR_WORD: + { + if (cbDstData - cbData > 0) + { + // + // Just copy all channels after alpha into the COLOR structure + // + CopyMemory(pDstData, pData, cbData); + } + else + { + hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); + } + } + break; + + case COLOR_FLOAT: + { + // + // Make sure the float data runs between 0.0 and 1.0 for nChannel and sRGB and is + // truncated and scaled as follows for scRGB: + // + // 1. Truncate the input color to between -2.0 and +2.0 + // 2. Offset the value by +2.0 to put it into the 0.0 to 4.0 range + // 3. Scale the value by 4.0 to put it into the range 0.0 to 1.0 + // 4. Set the 16 bit value according to the channel value from 0x0000 + // for 0.0 to 0xFFFF for 1.0 + // + if (cbDstData >= cChannels * sizeof(WORD) && + cbData >= cChannels * sizeof(FLOAT)) + { + PFLOAT pSrcData = reinterpret_cast(pData); + + if (m_dataType == scRGB) + { + for (UINT cCurrChan = 0; + cCurrChan < cChannels; + cCurrChan++) + { + _Analysis_assume_((cCurrChan + 1) * sizeof(WORD) <= cbDstData); + + FLOAT channelValue = pSrcData[cCurrChan]; + channelValue = channelValue < -2.0f ? -2.0f : channelValue; + channelValue = channelValue > 2.0f ? 2.0f : channelValue; + channelValue += 2.0f; + channelValue /= 4.0f; + pDstData[cCurrChan] = static_cast(channelValue * kMaxWordAsFloat); + } + } + else + { + if (SUCCEEDED(hr = ClampChannelValues(0.0f, 1.0f))) + { + for (UINT cCurrChan = 0; + cCurrChan < cChannels; + cCurrChan++) + { + _Analysis_assume_((cCurrChan + 1) * sizeof(WORD) <= cbDstData); + + pDstData[cCurrChan] = static_cast(pSrcData[cCurrChan] * kMaxWordAsFloat); + } + } + } + } + else + { + hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); + } + } + break; + + case COLOR_S2DOT13FIXED: + { + hr = E_NOTIMPL; + } + break; + + default: + { + RIP("Unrecognised color type\n"); + hr = E_FAIL; + } + break; + } + } + } + + ERR_ON_HR(hr); + return hr; +} + + +/*++ + +Routine Name: + + CColorChannelData::ColorFromByte + +Routine Description: + + Uses an 8 bpc COLOR structure to set the channel data + +Arguments: + + pSrcData - Pointer to the source COLOR data + cbSrcData - Size of the source buffer in bytes + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CColorChannelData::ColorFromByte( + _In_reads_bytes_(cbSrcData) PBYTE pSrcData, + _In_ CONST UINT& cbSrcData + ) +{ + HRESULT hr = S_OK; + + DWORD cChannels = 0; + DWORD cbData = 0; + PBYTE pData = NULL; + + if (SUCCEEDED(hr = CHECK_POINTER(pSrcData, E_POINTER)) && + SUCCEEDED(hr = GetChannelCountNoAlpha(&cChannels)) && + SUCCEEDED(hr = GetChannelDataNoAlpha(&cbData, reinterpret_cast(&pData)))) + { + if (cbData == 0 && + cChannels != 0) + { + hr = E_UNEXPECTED; + } + } + + if (SUCCEEDED(hr)) + { + ZeroMemory(pData, cbData); + + if (cbSrcData > 0) + { + switch (m_channelType) + { + case COLOR_BYTE: + { + if (cbData >= cChannels * sizeof(BYTE) && + cbSrcData >= cChannels * sizeof(BYTE)) + { + // + // Just copy src to dst + // + CopyMemory(pData, pSrcData, cChannels * sizeof(BYTE)); + } + else + { + hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); + } + } + break; + + case COLOR_WORD: + { + if (cbData >= cChannels * sizeof(WORD) && + cbSrcData >= cChannels * sizeof(BYTE)) + { + PWORD pDstData = reinterpret_cast(pData); + + for (UINT cCurrChan = 0; + cCurrChan < cChannels; + cCurrChan++) + { + _Analysis_assume_(cCurrChan < cbSrcData); + + pDstData[cCurrChan] = static_cast(MulDiv(pSrcData[cCurrChan], 0xFFFF, 0xFF)); + } + } + else + { + hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); + } + } + break; + + case COLOR_FLOAT: + { + // + // Make sure the float data is scaled to 0.0 and 1.0 for nChannel and sRGB and is + // scaled as follows for scRGB: + // + // 1. Convert the WORD value from 0x00 - 0xFF to 0.0f - 1.0f + // 1. Scale the value up by 4.0 to put it into the range 0.0 to 2.0 + // 2. Offset the value by -2.0 to put it into the -2.0 to 2.0 range + // + if (cbData >= cChannels * sizeof(FLOAT) && + cbSrcData >= cChannels * sizeof(BYTE)) + { + PFLOAT pDstData = reinterpret_cast(pData); + + if (m_dataType == scRGB) + { + for (UINT cCurrChan = 0; + cCurrChan < cChannels; + cCurrChan++) + { + _Analysis_assume_(cCurrChan < cbSrcData); + + pDstData[cCurrChan] = ((static_cast(pSrcData[cCurrChan])*4.0f)/kMaxByteAsFloat) - 2.0f; + } + } + else + { + for (UINT cCurrChan = 0; + cCurrChan < cChannels; + cCurrChan++) + { + _Analysis_assume_(cCurrChan < cbSrcData); + + pDstData[cCurrChan] = static_cast(pSrcData[cCurrChan])/kMaxByteAsFloat; + } + } + } + else + { + hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); + } + } + break; + + case COLOR_S2DOT13FIXED: + { + hr = E_NOTIMPL; + } + break; + + default: + { + RIP("Unrecognised color type\n"); + hr = E_FAIL; + } + break; + } + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CColorChannelData::ColorFromWord + +Routine Description: + + Uses an 16 bpc COLOR structure to set the channel data + +Arguments: + + pSrcData - Pointer to the source COLOR data + cbSrcData - Size of the source buffer in bytes + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CColorChannelData::ColorFromWord( + _In_reads_bytes_(cbSrcData) PWORD pSrcData, + _In_ CONST UINT& cbSrcData + ) +{ + HRESULT hr = S_OK; + + DWORD cChannels = 0; + DWORD cbData = 0; + PBYTE pData = NULL; + + if (SUCCEEDED(hr = CHECK_POINTER(pSrcData, E_POINTER)) && + SUCCEEDED(hr = GetChannelCountNoAlpha(&cChannels)) && + SUCCEEDED(hr = GetChannelDataNoAlpha(&cbData, reinterpret_cast(&pData)))) + { + if (cbData == 0 && + cChannels != 0) + { + hr = E_UNEXPECTED; + } + } + + if (SUCCEEDED(hr)) + { + ZeroMemory(pData, cbData); + + if (cbSrcData > 0) + { + switch (m_channelType) + { + case COLOR_BYTE: + { + if (cbData >= cChannels * sizeof(BYTE) && + cbSrcData >= cChannels * sizeof(WORD)) + { + for (UINT cCurrChan = 0; + cCurrChan < cChannels; + cCurrChan++) + { + _Analysis_assume_((cCurrChan + 1) * sizeof(WORD) < cbSrcData); + + pData[cCurrChan] = static_cast(MulDiv(pSrcData[cCurrChan], 0xFF, 0xFFFF)); + } + } + else + { + hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); + } + } + break; + + case COLOR_WORD: + { + if (cbData >= cChannels * sizeof(WORD) && + cbSrcData >= cChannels * sizeof(WORD)) + { + // + // Just copy src to dst + // + CopyMemory(pData, pSrcData, cChannels * sizeof(WORD)); + } + else + { + hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); + } + } + break; + + case COLOR_FLOAT: + { + // + // Make sure the float data is scaled to 0.0 and 1.0 for nChannel and sRGB and is + // scaled as follows for scRGB: + // + // 1. Convert the WORD value from 0x0000 - 0xFFFF to 0.0f - 1.0f + // 1. Scale the value up by 4.0 to put it into the range 0.0 to 2.0 + // 2. Offset the value by -2.0 to put it into the -2.0 to 2.0 range + // + if (cbData >= cChannels * sizeof(FLOAT) && + cbSrcData >= cChannels * sizeof(WORD)) + { + PFLOAT pDstData = reinterpret_cast(pData); + + if (m_dataType == scRGB) + { + for (UINT cCurrChan = 0; + cCurrChan < cChannels; + cCurrChan++) + { + _Analysis_assume_((cCurrChan + 1) * sizeof(WORD) < cbSrcData); + + pDstData[cCurrChan] = ((static_cast(pSrcData[cCurrChan])*4.0f)/kMaxWordAsFloat) - 2.0f; + } + } + else + { + for (UINT cCurrChan = 0; + cCurrChan < cChannels; + cCurrChan++) + { + _Analysis_assume_((cCurrChan + 1) * sizeof(WORD) < cbSrcData); + + pDstData[cCurrChan] = static_cast(pSrcData[cCurrChan])/kMaxWordAsFloat; + } + } + } + else + { + hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); + } + } + break; + + case COLOR_S2DOT13FIXED: + { + hr = E_NOTIMPL; + } + break; + + default: + { + RIP("Unrecognised color type\n"); + hr = E_FAIL; + } + break; + } + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CColorChannelData::GetChannelSizeFromType + +Routine Description: + + Retrieves the channel data size from the channel data type + +Arguments: + + channelType - The color channel data type + pcbChannelSize - Pointer to storage to recieve the channel data size + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CColorChannelData::GetChannelSizeFromType( + _In_ CONST COLORDATATYPE& channelType, + _Out_ DWORD* pcbChannelSize + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pcbChannelSize, E_POINTER))) + { + if (channelType < COLOR_BYTE || + channelType > COLOR_S2DOT13FIXED) + { + hr = E_INVALIDARG; + } + } + + if (SUCCEEDED(hr)) + { + *pcbChannelSize = g_cbChannelType[channelType - 1]; + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CColorChannelData::ValidateDataSize + +Routine Description: + + Template method that validates the data size given the current channel data type + +Arguments: + + None + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +template +HRESULT +CColorChannelData::ValidateDataSize( + VOID + ) +{ + HRESULT hr = S_OK; + + DWORD cbDataSize = 0; + if (SUCCEEDED(hr = GetChannelSizeFromType(m_channelType, &cbDataSize))) + { + // + // Make sure the data being added matches the data type in size + // + if (sizeof(_T) != cbDataSize) + { + hr = E_INVALIDARG; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CColorChannelData::AllocateChannelBuffers + +Routine Description: + + Allocates the channel data buffer + +Arguments: + + pcbBuffer - Pointer to variable that recieves the allocated buffer size + ppBuffer - Pointer to a pointer that recieves the buffer address + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CColorChannelData::AllocateChannelBuffers( + _Out_ UINT* pcbBuffer, + _Outptr_result_bytebuffer_(*pcbBuffer) _At_buffer_(*ppBuffer, _Iter_, *pcbBuffer, _Post_invalid_) + PBYTE* ppBuffer + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pcbBuffer, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(ppBuffer, E_POINTER))) + { + // + // Allocate a buffer for the channel data MAX_CHANNEL_COUNT x MAX_CHANNEL_SIZE + // This guarantees we have enough storage for the maximum n-channel support + // in WCS + // + *pcbBuffer = MAX_CHANNEL_COUNT*MAX_CHANNEL_SIZE; + *ppBuffer = new(std::nothrow) BYTE[*pcbBuffer]; + + if (*ppBuffer == NULL) + { + *pcbBuffer = 0; + hr = E_OUTOFMEMORY; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CColorChannelData::FreeChannelBuffers + +Routine Description: + + Releases channel buffer + +Arguments: + + None + +Return Value: + + None + +--*/ +VOID +CColorChannelData::FreeChannelBuffers( + VOID + ) +{ + if (m_pChannelData != NULL) + { + delete[] m_pChannelData; + m_pChannelData = NULL; + } + m_cbChannelData = 0; +} + +/*++ + +Routine Name: + + CColorChannelData::GetAlphaAsFloat + +Routine Description: + + Retrieves the alpha value of the channel data as a float + +Arguments: + + pAlpha - Pointer to a float that recieves the alpha value + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CColorChannelData::GetAlphaAsFloat( + _Out_ PFLOAT pAlpha + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pAlpha, E_POINTER))) + { + *pAlpha = 0.0f; + + if (HasAlpha()) + { + switch (m_channelType) + { + case COLOR_BYTE: + { + *pAlpha = static_cast(*m_pChannelData)/kMaxByteAsFloat; + } + break; + + case COLOR_WORD: + { + *pAlpha = static_cast(*reinterpret_cast(m_pChannelData))/kMaxWordAsFloat; + } + break; + + case COLOR_FLOAT: + { + *pAlpha = *reinterpret_cast(m_pChannelData); + } + break; + + case COLOR_S2DOT13FIXED: + { + hr = E_NOTIMPL; + } + break; + + default: + { + RIP("Unrecognised channel data format.\n"); + hr = E_FAIL; + } + break; + } + } + } + + ERR_ON_HR(hr); + return hr; +} + diff --git a/print/XPSDrvSmpl/src/filters/color/colchan.h b/print/XPSDrvSmpl/src/filters/color/colchan.h new file mode 100644 index 00000000..393261a8 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/color/colchan.h @@ -0,0 +1,289 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + colchan.h + +Abstract: + + Color channel class definition. The color channel class is responsible for maintaining + simple single color multiple channel data intialised from color references in the XPS markup. + It provides methods for intialization, access and conversion of the data. + +--*/ + +#pragma once + +enum EColorDataType +{ + sRGB = 0, + scRGB, + nChannel +}; + +class CColorChannelData +{ +public: + CColorChannelData(); + + ~CColorChannelData(); + + template + HRESULT + AddChannelData( + _In_ CONST _T& channelValue + ); + + HRESULT + GetChannelCount( + _Out_ DWORD* pcChannels + ); + + HRESULT + GetChannelCountNoAlpha( + _Out_ DWORD* pcChannels + ); + + HRESULT + GetChannelType( + _Out_ COLORDATATYPE* pChannelType + ); + + HRESULT + ResetChannelType( + _In_ CONST COLORDATATYPE& channelType + ); + + HRESULT + GetChannelData( + _Out_ DWORD* pcbDataSize, + _Out_ + _When_(*pcbDataSize > 0, _At_(*ppData, _Post_ _Readable_bytes_(*pcbDataSize))) + _When_(*pcbDataSize == 0, _At_(*ppData, _Post_ _Maybenull_)) + PVOID* ppData + ); + + HRESULT + GetChannelDataNoAlpha( + _Out_ DWORD* pcbDataSize, + _Out_ + _When_(*pcbDataSize > 0, _At_(*ppData, _Post_ _Readable_bytes_(*pcbDataSize))) + _When_(*pcbDataSize == 0, _At_(*ppData, _Post_ _Maybenull_)) + PVOID* ppData + ); + + template + HRESULT + ClampChannelValues( + _In_ CONST _T& min, + _In_ CONST _T& max + ); + + template + HRESULT + InitializeChannelData( + _In_ CONST COLORDATATYPE& channelType, + _In_ CONST EColorDataType& dataType, + _In_ CONST DWORD& cChannels, + _In_ CONST _T& channelValue + ); + + HRESULT + SetColorDataType( + _In_ CONST EColorDataType& dataType + ); + + HRESULT + GetColorDataType( + _Out_ EColorDataType* pDataType + ); + + BOOL + HasAlpha( + VOID + ); + + HRESULT + InitializeAlphaChannel( + _In_ CColorChannelData* pSrcChannelData + ); + + HRESULT + GetColor( + _Out_ PCOLOR pColor, + _Out_ COLORTYPE* pType + ); + + HRESULT + SetColor( + _In_ COLOR* pColor, + _In_ CONST COLORTYPE& type + ); + +private: + HRESULT + GetChannelSizeFromType( + _In_ CONST COLORDATATYPE& channelType, + _Out_ DWORD* pcbChannelSize + ); + + template + HRESULT + ValidateDataSize( + VOID + ); + + HRESULT + AllocateChannelBuffers( + _Out_ UINT* pcbBuffer, + _Outptr_result_bytebuffer_(*pcbBuffer) _At_buffer_(*ppBuffer, _Iter_, *pcbBuffer, _Post_invalid_) + PBYTE* ppBuffer + ); + + VOID + FreeChannelBuffers( + VOID + ); + + HRESULT + GetAlphaAsFloat( + _Out_ PFLOAT pAlpha + ); + + HRESULT + ColorToByte( + _Out_writes_bytes_(cbDstData) PBYTE pDstData, + _In_ CONST UINT cbDstData + ); + + HRESULT + ColorToWord( + _Out_writes_bytes_(cbDstData) PWORD pDstData, + _In_ CONST UINT cbDstData + ); + + HRESULT + ColorFromByte( + _In_reads_bytes_(cbSrcData) PBYTE pSrcData, + _In_ CONST UINT& cbSrcData + ); + + HRESULT + ColorFromWord( + _In_reads_bytes_(cbSrcData) PWORD pSrcData, + _In_ CONST UINT& cbSrcData + ); + + HRESULT + GetAlphaChannelSize( + _Out_ DWORD* pcbAlphaChan + ); + +private: + DWORD m_cChannels; + + COLORDATATYPE m_channelType; + + PBYTE m_pChannelData; + + UINT m_cbChannelData; + + EColorDataType m_dataType; +}; + +// +// Explicitly instantiate the template functions for BYTE, WORD and FLOAT +// +template +HRESULT +CColorChannelData::AddChannelData( + _In_ CONST BYTE& channelValue + ); + +template +HRESULT +CColorChannelData::ClampChannelValues( + _In_ CONST BYTE& min, + _In_ CONST BYTE& max + ); + +template +HRESULT +CColorChannelData::InitializeChannelData( + _In_ CONST COLORDATATYPE& channelType, + _In_ CONST EColorDataType& dataType, + _In_ CONST DWORD& cChannels, + _In_ CONST BYTE& channelValue + ); + +template +HRESULT +CColorChannelData::ValidateDataSize( + VOID + ); + +template +HRESULT +CColorChannelData::AddChannelData( + _In_ CONST WORD& channelValue + ); + +template +HRESULT +CColorChannelData::ClampChannelValues( + _In_ CONST WORD& min, + _In_ CONST WORD& max + ); + +template +HRESULT +CColorChannelData::InitializeChannelData( + _In_ CONST COLORDATATYPE& channelType, + _In_ CONST EColorDataType& dataType, + _In_ CONST DWORD& cChannels, + _In_ CONST WORD& channelValue + ); + +template +HRESULT +CColorChannelData::ValidateDataSize( + VOID + ); + +template +HRESULT +CColorChannelData::AddChannelData( + _In_ CONST FLOAT& channelValue + ); + +template +HRESULT +CColorChannelData::ClampChannelValues( + _In_ CONST FLOAT& min, + _In_ CONST FLOAT& max + ); + +template +HRESULT +CColorChannelData::InitializeChannelData( + _In_ CONST COLORDATATYPE& channelType, + _In_ CONST EColorDataType& dataType, + _In_ CONST DWORD& cChannels, + _In_ CONST FLOAT& channelValue + ); + +template +HRESULT +CColorChannelData::ValidateDataSize( + VOID + ); + diff --git a/print/XPSDrvSmpl/src/filters/color/colconv.cpp b/print/XPSDrvSmpl/src/filters/color/colconv.cpp new file mode 100644 index 00000000..13804f5e --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/color/colconv.cpp @@ -0,0 +1,1138 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + colconv.cpp + +Abstract: + + Color conversion manager implementation. The CColorConverter class is responsible + for coordinating the handling of the color conversion process. + + Note regarding transform caching: The color filter provides caching for the last + transform. This aids performance as quite some time can be consumed creating a + transform. The filter may however suffer if source content color profiles are rapidly + switched (e.g. alternating sRGB and scRGB mark-up). This could be mitigated by increasing + the number cached transforms beyond one. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdstring.h" +#include "xdexcept.h" +#include "colconv.h" +#include "cmimg.h" +#include "dictionary.h" + +using XDPrintSchema::PageSourceColorProfile::EProfileOption; +using XDPrintSchema::PageSourceColorProfile::RGB; +using XDPrintSchema::PageSourceColorProfile::CMYK; + +using XDPrintSchema::PageICMRenderingIntent::AbsoluteColorimetric; +using XDPrintSchema::PageICMRenderingIntent::RelativeColorimetric; +using XDPrintSchema::PageICMRenderingIntent::Photographs; +using XDPrintSchema::PageICMRenderingIntent::BusinessGraphics; + +COLORTYPE g_nChannelMap[] = { + COLOR_3_CHANNEL, + COLOR_CMYK, + COLOR_5_CHANNEL, + COLOR_6_CHANNEL, + COLOR_7_CHANNEL, + COLOR_8_CHANNEL +}; + +/*++ + +Routine Name: + + CColorConverter::CColorConverter + +Routine Description: + + Constructor for the base CColorConverter class. Provides common functionality + between the bitmap and color ref converter classes + +Arguments: + + pXpsConsumer - Pointer to the XPS consumer interface. Used to write out resources + pFixedPage - Pointer to the FixedPage interface. Resource cache uses this when writing + pResCache - Pointer to the resource cache. + pProfManager - Pointer to a profile manager for supplying a suitable color profile + +Return Value: + + None + Throws CXDException(HRESULT) on an error + +--*/ +CColorConverter::CColorConverter( + _In_ IXpsDocumentConsumer* pXpsConsumer, + _In_ IFixedPage* pFixedPage, + _In_ CFileResourceCache* pResCache, + _In_ CProfileManager* pProfManager, + _In_ ResDeleteMap* pResDel + ) : + m_pXpsConsumer(pXpsConsumer), + m_pFixedPage(pFixedPage), + m_pProfManager(pProfManager), + m_pResCache(pResCache), + m_pResDel(pResDel) +{ + HRESULT hr = S_OK; + + if (FAILED(hr = CHECK_POINTER(m_pXpsConsumer, E_POINTER)) || + FAILED(hr = CHECK_POINTER(m_pFixedPage, E_POINTER)) || + FAILED(hr = CHECK_POINTER(m_pProfManager, E_POINTER)) || + FAILED(hr = CHECK_POINTER(m_pResCache, E_POINTER)) || + FAILED(hr = CHECK_POINTER(m_pResDel, E_POINTER))) + { + throw CXDException(hr); + } +} + +/*++ + +Routine Name: + + CColorConverter::~CColorConverter + +Routine Description: + + Default destructor for the CColorConverter class + +Arguments: + + None + +Return Value: + + None + +--*/ +CColorConverter::~CColorConverter() +{ +} + +/*++ + +Routine Name: + + CBitmapColorConverter::CBitmapColorConverter + +Routine Description: + + Constructor for the CBitmapColorConverter class + +Arguments: + + pXpsConsumer - Pointer to the XPS consumer interface. Used to write out resources + pFixedPage - Pointer to the FixedPage interface. Resource cache uses this when writing + pResCache - Pointer to the resource cache. + pProfManager - Pointer to a profile manager for supplying a suitable color profile + +Return Value: + + None + Throws CXDException(HRESULT) on an error + +--*/ +CBitmapColorConverter::CBitmapColorConverter( + _In_ IXpsDocumentConsumer* pXpsConsumer, + _In_ IFixedPage* pFixedPage, + _In_ CFileResourceCache* pResCache, + _In_ CProfileManager* pProfManager, + _In_ ResDeleteMap* pResDel + ) : + CColorConverter(pXpsConsumer, pFixedPage, pResCache, pProfManager, pResDel) +{ +} + +/*++ + +Routine Name: + + CBitmapColorConverter::~CBitmapColorConverter + +Routine Description: + + Destructor for the CBitmapColorConverter class + +Arguments: + + None + +Return Value: + + None + +--*/ +CBitmapColorConverter::~CBitmapColorConverter() +{ +} + +/*++ + +Routine Name: + + CColorConverter::ConvertBitmap + +Routine Description: + + Method which performs the color conversion process to a bitmap resource and sets + the resource URI to contain the URI of the converted bitmap resource + +Arguments: + + pbstrBmpURI - Pointer to a string containing the bitmap resource path and name + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CBitmapColorConverter::Convert( + _Inout_ BSTR* pbstrBmpURI + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pbstrBmpURI, E_POINTER))) + { + try + { + // + // Create a color managed image object + // + CColorManagedImage bmpColManaged(*pbstrBmpURI, m_pProfManager, m_pFixedPage, m_pResDel); + + // + // Write out the cached bitmap and get a keyname for the written bitmap + // + CComBSTR bstrKey; + if (SUCCEEDED(hr = m_pResCache->WriteResource(m_pXpsConsumer, m_pFixedPage, &bmpColManaged)) && + SUCCEEDED(hr = bmpColManaged.GetKeyName(&bstrKey))) + { + hr = m_pResCache->GetURI(bstrKey, pbstrBmpURI); + + ASSERTMSG(SUCCEEDED(hr), "Failed to process image"); + } + } + catch (CXDException& e) + { + hr = e; + } + } + else + { + hr = E_POINTER; + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CColorRefConverter::CColorRefConverter + +Routine Description: + + Constructor for the base CColorRefConverter class which handles parsing and + conversion of a color string within XPS mark-up + +Arguments: + + pXpsConsumer - Pointer to the XPS consumer interface. Used to write out resources + pFixedPage - Pointer to the FixedPage interface. Resource cache uses this when writing + pResCache - Pointer to the resource cache. + pProfManager - Pointer to a profile manager for supplying a suitable color profile + +Return Value: + + None + Throws CXDException(HRESULT) on an error + +--*/ +CColorRefConverter::CColorRefConverter( + _In_ IXpsDocumentConsumer* pXpsConsumer, + _In_ IFixedPage* pFixedPage, + _In_ CFileResourceCache* pResCache, + _In_ CProfileManager* pProfManager, + _In_ ResDeleteMap* pResDel + ) : + CColorConverter(pXpsConsumer, pFixedPage, pResCache, pProfManager, pResDel) +{ +} + +/*++ + +Routine Name: + + CColorRefConverter::~CColorRefConverter + +Routine Description: + + Destructor for the CColorRefConverter class + +Arguments: + + None + +Return Value: + + None + +--*/ +CColorRefConverter::~CColorRefConverter() +{ +} + +/*++ + +Routine Name: + + CColorRefConverter::ConvertColor + +Routine Description: + + Method which performs the color conversion process to an XPS color ref element + +Arguments: + + pbstrColorRef - Pointer to a string containing the color data to be converted + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CColorRefConverter::Convert( + _Inout_ BSTR* pbstrColorRef + ) +{ + HRESULT hr = S_OK; + + BOOL bIsResourceReference = FALSE; + if (SUCCEEDED(hr = CHECK_POINTER(pbstrColorRef, E_POINTER)) && + SUCCEEDED(hr = ParseColorString(*pbstrColorRef, &m_srcData, &bIsResourceReference)) && + !bIsResourceReference) + { + // + // If the source and destination types are the same (e.g. scRGB in and scRGB out) + // we need go no further - simply return the existing string. This does not apply + // to nChannel as ContextColors specify their own profile and we cannot prove that + // this matches our output. The color space for sRGB and scRGB are implicit however. + // + EColorDataType srcType = sRGB; + EColorDataType dstType = sRGB; + if (SUCCEEDED(hr = InitDstChannels(&m_srcData, &m_dstData)) && + SUCCEEDED(hr = m_srcData.GetColorDataType(&srcType)) && + SUCCEEDED(hr = m_dstData.GetColorDataType(&dstType))) + { + if (dstType == nChannel || + dstType != srcType) + { + if (SUCCEEDED(hr = TransformColor(&m_srcData, &m_dstData))) + { + hr = CreateColorString(&m_dstData, pbstrColorRef); + } + } + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CColorRefConverter::InitDstChannels + +Routine Description: + + Initialise the destination color channel data based on the destination color + profile + +Arguments: + + pChannelDataDst - Pointer to a color channel data object to be intialised + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CColorRefConverter::InitDstChannels( + _In_ CColorChannelData* pChannelDataSrc, + _Inout_ CColorChannelData* pChannelDataDst + ) +{ + HRESULT hr = S_OK; + + EProfileOption profileType = RGB; + if (SUCCEEDED(hr = CHECK_POINTER(pChannelDataSrc, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pChannelDataDst, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(m_pProfManager, E_FAIL)) && + SUCCEEDED(hr = m_pProfManager->GetDstProfileType(&profileType))) + { + // + // Initialize the channel data based on the destination color profile + // settings: + // RGB = 3 channel with no src alpha + // 4 channel with src alpha + // CMYK = 5 channel (nChannel always has an alpha channel) + // + // The color type is based off the OS. XP does not have access to WCS + // and therefore floating point formats are converted to 16 bits per channel + // + // The conversion process for downlevel handling depends on the source format. + // If we are color matching for scRGB we convert the floating point value as + // follows: + // + // 1. Truncate the input color to between -2.0 and +2.0 + // 2. Offset the value by +2.0 to put it into the 0.0 to 4.0 range + // 3. Scale the value by 4.0 to put it into the range 0.0 to 1.0 + // 4. Set the 16 bit value according to the channel value from 0x0000 + // for 0.0 to 0xFFFF for 1.0 + // 5. Call TranslateColors passing the 16 bit value + // 6. Reverse steps 1 - 4 to retrieve the floating point value + // + // If we are color matching for context colors we apply the following conversion + // + // 1. Truncate the input color to between 0.0 and +1.0 + // 2. Set the 16 bit value according to the channel value from 0x0000 + // for 0.0 to 0xFFFF for 1.0 + // 3. Call TranslateColors passing the 16 bit value + // 4. Reverse steps 1 - 2 to retrieve the floating point value + // + // Note: We do not modify the gamma during the scRGB conversion process as this will + // be applied by WCS/ICM as the gamma is encapsulated by the relevant ICC + // profile. i.e. The gamma is maintained linear as that is what the transform + // is expecting. + // + COLORDATATYPE colorDataType = COLOR_FLOAT; + EColorDataType dataType = sRGB; + + DWORD cChannels = 0; + if (profileType == RGB) + { + dataType = scRGB; + cChannels = 3; + if (pChannelDataSrc->HasAlpha()) + { + cChannels++; + } + } + else if (profileType == CMYK) + { + dataType = nChannel; + cChannels = 5; + } + else + { + RIP("Unsupported color channel format\n"); + hr = E_FAIL; + } + + if (SUCCEEDED(hr) && + SUCCEEDED(hr = pChannelDataDst->InitializeChannelData(colorDataType, dataType, cChannels, 0.0f))) + { + hr = pChannelDataDst->InitializeAlphaChannel(pChannelDataSrc); + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CColorRefConverter::GetFloatChannelData + +Routine Description: + + Method which converts a comma delimited set of floating point values + defining color channels into floating point values in a list + +Arguments: + + szColorRef - The srting containing the comma seperated color values + pChannelData - Pointer to the color channels object + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CColorRefConverter::GetFloatChannelData( + _In_ LPCWSTR szColorRef, + _Inout_ CColorChannelData* pChannelData + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pChannelData, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(szColorRef, E_POINTER)) && + SUCCEEDED(hr = pChannelData->ResetChannelType(COLOR_FLOAT))) + { + try + { + CStringXDW cstrColorRef(szColorRef); + cstrColorRef.Trim(); + cstrColorRef.MakeLower(); + + INT cTokenIndex = 0; + INT cChars = cstrColorRef.GetLength(); + while (SUCCEEDED(hr) && + cTokenIndex < cChars && + cTokenIndex != -1) + { + CStringXDW cstrChannel(cstrColorRef.Tokenize(L",", cTokenIndex)); + hr = pChannelData->AddChannelData(static_cast(_wtof(cstrChannel))); + } + } + catch (CXDException& e) + { + hr = e; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CColorRefConverter::SetFloatChannelData + +Routine Description: + + Method which converts channel data object into a comma delimited set of + floating point values + +Arguments: + + pChannelData - Pointer to the color channel data + pcstrChannelData - Pointer to the color string to be populated + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CColorRefConverter::SetFloatChannelData( + _In_ CColorChannelData* pChannelData, + _Inout_ CStringXDW* pcstrChannelData + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pChannelData, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pcstrChannelData, E_POINTER))) + { + try + { + // + // Over all channels, write out comma seperated float values + // + DWORD cbData = 0; + PFLOAT pData = NULL; + DWORD cChanCount = 0; + if (SUCCEEDED(hr = pChannelData->GetChannelData(&cbData, reinterpret_cast(&pData))) && + SUCCEEDED(hr = pChannelData->GetChannelCount(&cChanCount))) + { + if (cChanCount == 0) + { + hr = E_FAIL; + } + + if (SUCCEEDED(hr) && + cbData >= cChanCount * sizeof(FLOAT)) + { + CStringXDW cstrChannel; + cstrChannel.Format(L"%f", pData[0]); + pcstrChannelData->Append(cstrChannel); + for (DWORD cChan = 1; cChan < cChanCount; cChan++) + { + cstrChannel.Format(L",%f", pData[cChan]); + pcstrChannelData->Append(cstrChannel); + } + } + else + { + hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); + } + } + } + catch (CXDException& e) + { + hr = e; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CColorRefConverter::ParseColorString + +Routine Description: + + Method which converts a XML formatted color string into useable color data + +Arguments: + + bstrColorRef - The color ref string to be parsed + pChannelData - Pointer to the color channel data object to be populated + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CColorRefConverter::ParseColorString( + _In_ BSTR bstrColorRef, + _Inout_ CColorChannelData* pChannelData, + _Out_ BOOL* pbIsResourceReference + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pChannelData, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pbIsResourceReference, E_POINTER))) + { + *pbIsResourceReference = FALSE; + + if (SysStringLen(bstrColorRef) <= 0) + { + hr = E_INVALIDARG; + } + } + + if (SUCCEEDED(hr)) + { + try + { + CStringXDW cstrColRef(bstrColorRef); + cstrColRef.Trim(); + + if (0 == cstrColRef.Find(L"sc#")) + { + // + // Strip the "sc#" prefix ready to parse the floating point channels + // + cstrColRef.Delete(0, 3); + + // + // Set the src profile to xdwscRGB.icc - this is an ICC profile with + // the system wcsRGB profile embedded so should work down-level + // Set the color data type and retrieve the channel data + // + if (SUCCEEDED(hr = m_pProfManager->SetSrcProfileFromColDir(L"xdwscRGB.icc")) && + SUCCEEDED(hr = pChannelData->ResetChannelType(COLOR_FLOAT)) && + SUCCEEDED(hr = pChannelData->SetColorDataType(scRGB))) + { + hr = GetFloatChannelData(cstrColRef, pChannelData); + } + } + else if (0 == cstrColRef.Find(L"ContextColor")) + { + // + // Context colors always have an associated profile - retrieve + // this and set it in the profile manager + // + cstrColRef.Delete(0, countof(L"ContextColor ")); + cstrColRef.Trim(); + CStringXDW cstrProfile(cstrColRef.Left(cstrColRef.Find(L" "))); + cstrColRef.Delete(0, cstrProfile.GetLength()); + + // + // Set the source profile ready to create the transform, retrieve the channel data + // and clamp between 0.0 and 1.0. + // + if (SUCCEEDED(hr = m_pProfManager->SetSrcProfileFromContainer(cstrProfile.GetBuffer())) && + SUCCEEDED(hr = pChannelData->ResetChannelType(COLOR_FLOAT)) && + SUCCEEDED(hr = pChannelData->SetColorDataType(nChannel)) && + SUCCEEDED(hr = GetFloatChannelData(cstrColRef, pChannelData)) && + SUCCEEDED(hr = pChannelData->ClampChannelValues(0.0f, 1.0f))) + { + // + // Mark the color profile for deletion + // + (*m_pResDel)[cstrProfile] = TRUE; + } + } + else if (0 == cstrColRef.Find(L"#")) + { + // + // Delete the # symbol so we are just left with the RGB values + // + cstrColRef.Delete(0, 1); + + // + // Set the source profile to sRGB rather than assume the default is set to + // sRGB. + // + if (SUCCEEDED(hr = m_pProfManager->SetSrcProfileFromColDir(L"sRGB Color Space Profile.icm")) && + SUCCEEDED(hr = pChannelData->ResetChannelType(COLOR_BYTE)) && + SUCCEEDED(hr = pChannelData->SetColorDataType(sRGB))) + { + while (SUCCEEDED(hr) && + cstrColRef.GetLength() > 0) + { + // + // Add the channel data + // + hr = pChannelData->AddChannelData(static_cast(wcstol(cstrColRef.Left(2), NULL, 16))); + + // + // Delete the channel from the color ref string + // + cstrColRef.Delete(0, 2); + } + } + } + else if (0 == cstrColRef.Find(L"{StaticResource")) + { + *pbIsResourceReference = TRUE; + } + else + { + // + // Unrecognised type + // + RIP("Unrecognised color syntax."); + hr = E_FAIL; + } + } + catch (CXDException& e) + { + hr = e; + } + catch (exception& DBG_ONLY(e)) + { + ERR(e.what()); + hr = E_FAIL; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CColorRefConverter::TransformColor + +Routine Description: + + Method which applies a color transform to a set of color data + +Arguments: + + pSrcData - Pointer to the source color channel data + pDstData - Pointer to the destination color channel data + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CColorRefConverter::TransformColor( + _In_ CColorChannelData* pSrcData, + _Inout_ CColorChannelData* pDstData + ) +{ + HRESULT hr = S_OK; + + HTRANSFORM hColorTrans = NULL; + + BOOL bUseWCS = FALSE; + + if (SUCCEEDED(hr = CHECK_POINTER(pSrcData, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pDstData, E_POINTER)) && + SUCCEEDED(hr = m_pProfManager->GetColorTransform(&hColorTrans, &bUseWCS))) + { + if (bUseWCS) + { + DWORD cSrcChan = 0; + DWORD cDstChan = 0; + + COLORDATATYPE srcDataType = COLOR_FLOAT; + COLORDATATYPE dstDataType = COLOR_FLOAT; + + DWORD cbSrcChan = 0; + DWORD cbDstChan = 0; + + PBYTE pSrcBuff = NULL; + PBYTE pDstBuff = NULL; + + if (SUCCEEDED(hr = CHECK_POINTER(hColorTrans, E_HANDLE)) && + SUCCEEDED(hr = pSrcData->GetChannelCountNoAlpha(&cSrcChan)) && + SUCCEEDED(hr = pSrcData->GetChannelType(&srcDataType)) && + SUCCEEDED(hr = pSrcData->GetChannelDataNoAlpha(&cbSrcChan, reinterpret_cast(&pSrcBuff))) && + SUCCEEDED(hr = pDstData->GetChannelCountNoAlpha(&cDstChan)) && + SUCCEEDED(hr = pDstData->GetChannelType(&dstDataType)) && + SUCCEEDED(hr = pDstData->GetChannelDataNoAlpha(&cbDstChan, reinterpret_cast(&pDstBuff)))) + { + if (cbDstChan > 0) + { + if (!WcsTranslateColorsXD(hColorTrans, + 1, + cSrcChan, + srcDataType, + cbSrcChan, + pSrcBuff, + cDstChan, + dstDataType, + cbDstChan, + pDstBuff)) + { + hr = GetLastErrorAsHResult(); + } + } + else + { + hr = E_FAIL; + } + } + } + else + { + COLOR srcColor; + COLOR dstColor; + + COLORTYPE srcType; + COLORTYPE dstType; + + if (SUCCEEDED(hr = pSrcData->GetColor(&srcColor, &srcType)) && + SUCCEEDED(hr = pDstData->GetColor(&dstColor, &dstType))) + { + if (TranslateColors(hColorTrans, + &srcColor, + 1, + srcType, + &dstColor, + dstType)) + { + hr = pDstData->SetColor(&dstColor, dstType); + } + else + { + hr = GetLastErrorAsHResult(); + } + } + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CColorRefConverter::CreateColorString + +Routine Description: + + Method which creates a XML formatted string descripting a transformed set of colors + +Arguments: + + pDstData - Pointer to destination color channel data + pbstrColorRef - Pointer to a string to contain the XML formatted color data + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CColorRefConverter::CreateColorString( + _In_ CColorChannelData* pDstData, + _Inout_ BSTR* pbstrColorRef + ) +{ + CComBSTR bstrTmpHolder; + + HRESULT hr = S_OK; + + EColorDataType colDataType = sRGB; + if (SUCCEEDED(hr = CHECK_POINTER(pDstData, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pbstrColorRef, E_POINTER)) && + SUCCEEDED(hr = pDstData->GetColorDataType(&colDataType))) + { + try + { + CStringXDW cstrChannelData; + + if (colDataType == scRGB) + { + // + // scRGB + // + cstrChannelData += L"sc#"; + hr = SetFloatChannelData(pDstData, &cstrChannelData); + } + else if (colDataType == nChannel) + { + // + // CMYK + // + cstrChannelData += L"ContextColor "; + + // + // Add the ICC profile and retrieve the URI + // + CComBSTR bstrKey; + CComBSTR bstrICCURI; + if (SUCCEEDED(hr = m_pResCache->WriteResource(m_pXpsConsumer, m_pFixedPage, m_pProfManager)) && + SUCCEEDED(hr = m_pProfManager->GetKeyName(&bstrKey)) && + SUCCEEDED(hr = m_pResCache->GetURI(bstrKey, &bstrICCURI))) + { + // + // Append the URI and a space + // + cstrChannelData += bstrICCURI; + cstrChannelData += L" "; + + hr = SetFloatChannelData(pDstData, &cstrChannelData); + } + } + else if (colDataType == sRGB) + { + // + // sRGB + // + cstrChannelData += L"#"; + + // + // Over all channels, write out hex byte values + // + DWORD cbData = 0; + PBYTE pData = NULL; + DWORD cChanCount = 0; + if (SUCCEEDED(hr = pDstData->GetChannelData(&cbData, reinterpret_cast(&pData))) && + SUCCEEDED(hr = pDstData->GetChannelCount(&cChanCount))) + { + if (cbData >= cChanCount * sizeof(BYTE)) + { + for (DWORD cChan = 0; cChan < cChanCount; cChan++) + { + _Analysis_assume_(cChan < cbData); + + CStringXDW cstrChannel; + cstrChannel.Format(L"%02x", pData[cChan]); + cstrChannelData.Append(cstrChannel); + } + } + else + { + hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); + } + } + } + else + { + RIP("Invalid color type\n"); + hr = E_FAIL; + } + + if (SUCCEEDED(hr)) + { + SysFreeString(*pbstrColorRef); + *pbstrColorRef = cstrChannelData.AllocSysString(); + } + } + catch (CXDException& e) + { + hr = e; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CResourceDictionaryConverter::CResourceDictionaryConverter + +Routine Description: + + CResourceDictionaryConverter constructir + +Arguments: + + pXpsConsumer - Pointer to the XPS consumer interface + pFixedPage - Pointer to the fixed page interface + pResCache - Pointer to the resource cache + pProfManager - Pointer to the color profile manager + pResDel - Pointer to the list of resources to delete from the page + pBmpConv - Pointer to the bitmap conversion class + pRefConv - Pointer to the color reference conversion class + +Return Value: + + None + Throws an exception on error. + +--*/ +CResourceDictionaryConverter::CResourceDictionaryConverter( + _In_ IXpsDocumentConsumer* pXpsConsumer, + _In_ IFixedPage* pFixedPage, + _In_ CFileResourceCache* pResCache, + _In_ CProfileManager* pProfManager, + _In_ ResDeleteMap* pResDel, + _In_ CBitmapColorConverter* pBmpConv, + _In_ CColorRefConverter* pRefConv + ) : + CColorConverter(pXpsConsumer, pFixedPage, pResCache, pProfManager, pResDel), + m_pBmpConv(pBmpConv), + m_pRefConv(pRefConv) +{ + if (m_pBmpConv == NULL || + m_pRefConv == NULL) + { + throw CXDException(E_POINTER); + } +} + +/*++ + +Routine Name: + + CResourceDictionaryConverter::~CResourceDictionaryConverter + +Routine Description: + + CResourceDictionaryConverter destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CResourceDictionaryConverter::~CResourceDictionaryConverter() +{ +} + +/*++ + +Routine Name: + + CResourceDictionaryConverter::Convert + +Routine Description: + + Applies color conversion on a remote resource dictionary. This is achieved + by creating a color SAX parser passing a stream based off the resource + +Arguments: + + pbstrDictionaryURI - The remote dictionary URI + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CResourceDictionaryConverter::Convert( + _Inout_ BSTR* pbstrDictionaryURI + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pbstrDictionaryURI, E_POINTER))) + { + try + { + CStringXDW cstrOriginalURI(*pbstrDictionaryURI); + + // + // Create a color managed dictionary object and pass to the cache manager + // + CRemoteDictionary newDictionary(m_pFixedPage, m_pBmpConv, m_pRefConv, *pbstrDictionaryURI); + + CComBSTR bstrKey; + if (SUCCEEDED(hr = m_pResCache->WriteResource(m_pXpsConsumer, m_pFixedPage, &newDictionary)) && + SUCCEEDED(hr = newDictionary.GetKeyName(&bstrKey)) && + SUCCEEDED(hr = m_pResCache->GetURI(bstrKey, pbstrDictionaryURI))) + { + (*m_pResDel)[cstrOriginalURI] = TRUE; + } + } + catch (CXDException& e) + { + hr = e; + } + catch (exception& DBG_ONLY(e)) + { + ERR(e.what()); + hr = E_FAIL; + } + } + + return hr; +} + diff --git a/print/XPSDrvSmpl/src/filters/color/colconv.h b/print/XPSDrvSmpl/src/filters/color/colconv.h new file mode 100644 index 00000000..a658df7f --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/color/colconv.h @@ -0,0 +1,167 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + colconv.h + +Abstract: + + Color conversion class definition. The CColorConverter class is responsible + for managing the color conversion process for vector objects and bitmaps. + +--*/ + +#pragma once + +#include "colchan.h" +#include "rescache.h" +#include "profman.h" +#include "wcsapiconv.h" +#include "cmflt.h" + +class CColorConverter +{ +public: + CColorConverter( + _In_ IXpsDocumentConsumer* pXpsConsumer, + _In_ IFixedPage* pFixedPage, + _In_ CFileResourceCache* pResCache, + _In_ CProfileManager* pProfManager, + _In_ ResDeleteMap* pResDel + ); + + virtual ~CColorConverter(); + + virtual HRESULT + Convert( + _Inout_ BSTR* pbstr + ) = 0; + +protected: + CComPtr m_pXpsConsumer; + + CComPtr m_pFixedPage; + + CProfileManager* m_pProfManager; + + CFileResourceCache* m_pResCache; + + ResDeleteMap* m_pResDel; +}; + +class CBitmapColorConverter : public CColorConverter +{ +public: + CBitmapColorConverter( + _In_ IXpsDocumentConsumer* pXpsConsumer, + _In_ IFixedPage* pFixedPage, + _In_ CFileResourceCache* pResCache, + _In_ CProfileManager* pProfManager, + _In_ ResDeleteMap* pResDel + ); + + virtual ~CBitmapColorConverter(); + + HRESULT + Convert( + _Inout_ BSTR* pbstrBmpURI + ); +}; + +class CColorRefConverter : public CColorConverter +{ +public: + CColorRefConverter( + _In_ IXpsDocumentConsumer* pXpsConsumer, + _In_ IFixedPage* pFixedPage, + _In_ CFileResourceCache* pResCache, + _In_ CProfileManager* pProfManager, + _In_ ResDeleteMap* pResDel + ); + + virtual ~CColorRefConverter(); + + HRESULT + Convert( + _Inout_ BSTR* pbstrColorRef + ); + +private: + HRESULT + InitDstChannels( + _In_ CColorChannelData* pChannelDataSrc, + _Inout_ CColorChannelData* pChannelDataDst + ); + + HRESULT + GetFloatChannelData( + _In_ LPCWSTR szColorRef, + _Inout_ CColorChannelData* pChannelData + ); + + HRESULT + SetFloatChannelData( + _In_ CColorChannelData* pChannelData, + _Inout_ CStringXDW* pcstrChannelData + ); + + HRESULT + ParseColorString( + _In_ BSTR bstrColorRef, + _Inout_ CColorChannelData* pChannelData, + _Out_ BOOL* pbIsResourceReference + ); + + HRESULT + TransformColor( + _In_ CColorChannelData* pSrcData, + _Inout_ CColorChannelData* pDstData + ); + + HRESULT + CreateColorString( + _In_ CColorChannelData* pDstData, + _Inout_ BSTR* pbstrColorRef + ); + +private: + CColorChannelData m_srcData; + + CColorChannelData m_dstData; +}; + +class CResourceDictionaryConverter : public CColorConverter +{ +public: + CResourceDictionaryConverter( + _In_ IXpsDocumentConsumer* pXpsConsumer, + _In_ IFixedPage* pFixedPage, + _In_ CFileResourceCache* pResCache, + _In_ CProfileManager* pProfManager, + _In_ ResDeleteMap* pResDel, + _In_ CBitmapColorConverter* pBmpConv, + _In_ CColorRefConverter* pRefConv + ); + + virtual ~CResourceDictionaryConverter(); + + HRESULT + Convert( + _Inout_ BSTR* pbstrDictionaryURI + ); + +private: + CBitmapColorConverter* m_pBmpConv; + + CColorRefConverter* m_pRefConv; +}; + diff --git a/print/XPSDrvSmpl/src/filters/color/dictionary.cpp b/print/XPSDrvSmpl/src/filters/color/dictionary.cpp new file mode 100644 index 00000000..5106aad7 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/color/dictionary.cpp @@ -0,0 +1,289 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + dict.cpp + +Abstract: + + Dictionary class implementation. The CRemoteDictionary class is responsible + for representing a single dictionay including managing any color + transforms in that dictionary and writing the dictionary out. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdstring.h" +#include "dictionary.h" +#include "cmsax.h" + +/*++ + +Routine Name: + + CRemoteDictionary::CRemoteDictionary + +Routine Description: + + Constructor for the CRemoteDictionary class which registers the URI to the resource + being represented and pointers to suitable color transformation objects + for use with color elements within that resource + +Arguments: + + bstrResURI - String containing the URI to the resource to be handled + pBmpConverter - Pointer to a bitmap color conversion object + pRefConverter - Pointer to a vector color conversion object + +Return Value: + + None + Throws CXDException(HRESULT) on an error + +--*/ +CRemoteDictionary::CRemoteDictionary( + _In_ IFixedPage* pFixedPage, + _In_ CBitmapColorConverter* pBmpConverter, + _In_ CColorRefConverter* pRefConverter, + _In_ BSTR bstrResURI + ) : + m_pFixedPage(pFixedPage), + m_pBmpConverter(pBmpConverter), + m_pRefConverter(pRefConverter), + m_bstrDictionaryURI(bstrResURI) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(m_pFixedPage, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(m_pRefConverter, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(m_pBmpConverter, E_POINTER))) + { + if (m_bstrDictionaryURI.Length() == 0) + { + hr = E_INVALIDARG; + } + } + + if (FAILED(hr)) + { + throw CXDException(hr); + } +} + +/*++ + +Routine Name: + + CRemoteDictionary::~CRemoteDictionary + +Routine Description: + + Destructor for the CRemoteDictionary class + +Arguments: + + None + +Return Value: + + None + +--*/ +CRemoteDictionary::~CRemoteDictionary() +{ +} + +/*++ + +Routine Name: + + CRemoteDictionary::WriteData + +Routine Description: + + This method handles the parsing of a new dictionary and + the writing out the new dictionary + +Arguments: + + pWriter - Pointer to a stream to write the resource out to + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CRemoteDictionary::WriteData( + _In_ IPartBase* pResource, + _In_ IPrintWriteStream* pWriter + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pResource, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pWriter, E_POINTER))) + { + try + { + CComPtr pRead(NULL); + CComPtr pResDictPart(NULL); + CComPtr pReader(NULL); + + if (SUCCEEDED(hr = m_pFixedPage->GetPagePart(m_bstrDictionaryURI, &pRead)) && + SUCCEEDED(hr = pRead->QueryInterface(&pResDictPart)) && + SUCCEEDED(hr = pResDictPart->GetStream(&pReader))) + { + // + // Create a SAX handler to parse the markup in the fixed page + // + CCMSaxHandler cmSaxHndlr(pWriter, m_pBmpConverter, m_pRefConverter, NULL); + + // + // Set-up the SAX reader and begin parsing the mark-up + // + CComPtr pSaxRdr(NULL); + + if (SUCCEEDED(hr = pSaxRdr.CoCreateInstance(CLSID_SAXXMLReader60)) && + SUCCEEDED(hr = pSaxRdr->putContentHandler(&cmSaxHndlr))) + { + CComPtr pReadStreamToSeq(NULL); + + pReadStreamToSeq.Attach(new(std::nothrow) pfp::PrintReadStreamToSeqStream(pReader)); + + if (SUCCEEDED(hr = CHECK_POINTER(pReadStreamToSeq, E_OUTOFMEMORY))) + { + hr = pSaxRdr->parse(CComVariant(static_cast(pReadStreamToSeq))); + } + } + } + } + catch (CXDException& e) + { + hr = e; + } + } + + ERR_ON_HR(hr); + return hr; +} + + +/*++ + +Routine Name: + + CRemoteDictionary::GetKeyName + +Routine Description: + + Method to obtain a unique key for the resource being handled + +Arguments: + + pbstrKeyName - Pointer to a string to hold the generated key + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CRemoteDictionary::GetKeyName( + _Outptr_ BSTR* pbstrKeyName + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pbstrKeyName, E_POINTER))) + { + if (m_bstrDictionaryURI.Length() > 0) + { + *pbstrKeyName = NULL; + + // + // The full URI to the resource is a suitable key + // + if (SUCCEEDED(hr = m_bstrDictionaryURI.CopyTo(pbstrKeyName)) && + !*pbstrKeyName) + { + hr = E_OUTOFMEMORY; + } + } + else + { + hr = E_PENDING; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CRemoteDictionary::GetResURI + +Routine Description: + + Method to obtain the URI of the resource being handled + +Arguments: + + pbstrResURI - Pointer to a string to hold the resource URI + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CRemoteDictionary::GetResURI( + _Outptr_ BSTR* pbstrResURI + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pbstrResURI, E_POINTER))) + { + *pbstrResURI = NULL; + + try + { + // + // Create a unique name for the dictionary for this print session + // + CStringXDW cstrURI; + cstrURI.Format(L"%s_%u.dict", m_bstrDictionaryURI, GetUniqueNumber()); + + *pbstrResURI = cstrURI.AllocSysString(); + } + catch (CXDException& e) + { + hr = e; + } + } + + ERR_ON_HR(hr); + return hr; +} + diff --git a/print/XPSDrvSmpl/src/filters/color/dictionary.h b/print/XPSDrvSmpl/src/filters/color/dictionary.h new file mode 100644 index 00000000..42e4e974 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/color/dictionary.h @@ -0,0 +1,65 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + dict.h + +Abstract: + + Dictionary class definition. The CRemoteDictionary class is responsible + for representing a single dictionay including managing any color + transforms in that dictionary and writing the dictionary out. + +--*/ + +#pragma once + +#include "colconv.h" + +class CRemoteDictionary : public IResWriter +{ +public: + CRemoteDictionary( + _In_ IFixedPage* pFixedPage, + _In_ CBitmapColorConverter* pBmpConverter, + _In_ CColorRefConverter* pRefConverter, + _In_ BSTR bstrResURI + ); + + ~CRemoteDictionary(); + + HRESULT + WriteData( + _In_ IPartBase* pResource, + _In_ IPrintWriteStream* pStream + ); + + HRESULT + GetKeyName( + _Outptr_ BSTR* pbstrKeyName + ); + + HRESULT + GetResURI( + _Outptr_ BSTR* pbstrResURI + ); + +private: + CComBSTR m_bstrDictionaryURI; + + CBitmapColorConverter* m_pBmpConverter; + + CColorRefConverter* m_pRefConverter; + + CComPtr m_pFixedPage; +}; + diff --git a/print/XPSDrvSmpl/src/filters/color/dllentry.cpp b/print/XPSDrvSmpl/src/filters/color/dllentry.cpp new file mode 100644 index 00000000..fff45c12 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/color/dllentry.cpp @@ -0,0 +1,145 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + dllentry.cpp + +Abstract: + + Implementation of the color management filter dllentry points. Dllmain only + stores the instance handle. DllGetClassObject calls on to a generic + get class factory template function. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdstring.h" +#include "clasfact.h" +#include "cmflt.h" +#include "xdexcept.h" +#include "xdstring.h" + +/*++ + +Routine Name: + + DllMain + +Routine Description: + + Entry point to the color management filter which is called when a new process is started + +Arguments: + + hInst - Handle to the DLL + wReason - Specifies a flag indicating why the DLL entry-point function is being called + +Return Value: + + TRUE + +--*/ +BOOL WINAPI +DllMain( + _In_ HINSTANCE hInst, + _In_ WORD wReason, + _In_opt_ LPVOID + ) +{ + switch (wReason) + { + case DLL_PROCESS_ATTACH: + { + g_hInstance = hInst; + } + break; + } + + return TRUE; +} + +/*++ + +Routine Name: + + DllCanUnloadNow + +Routine Description: + + Method which reports whether the DLL is in use to allow the caller to unload + the DLL safely + +Arguments: + + None + +Return Value: + + HRESULT + S_OK - Dll can unload + S_FALSE - Dll can't unload + +--*/ +STDAPI +DllCanUnloadNow() +{ + if (g_cServerLocks == 0) + { + return S_OK ; + } + else + { + return S_FALSE; + } +} + +/*++ + +Routine Name: + + DllGetClassObject + +Routine Description: + + Method to return the current class object + +Arguments: + + rclsid - CLSID that will associate the correct data and code + riid - Reference to the identifier of the interface that the caller is to use to communicate with the class object + ppv - Address of pointer variable that receives the interface pointer requested in riid + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + CLASS_E_CLASSNOTAVAILABLE - On unsupported class + +--*/ +STDAPI +DllGetClassObject( + _In_ REFCLSID rclsid, + _In_ REFIID riid, + _Outptr_ LPVOID FAR* ppv + ) +{ + // + // 21934A6D-EA30-480a-8DAD-C8045807F737 + // + CLSID colorCLSID = {0x21934A6D, 0xEA30, 0x480a, {0x8D, 0xAD, 0xC8, 0x04, 0x58, 0x07, 0xF7, 0x37}}; + + return GetFilterClassFactory(rclsid, riid, colorCLSID, ppv); +} + diff --git a/print/XPSDrvSmpl/src/filters/color/precompsrc.cpp b/print/XPSDrvSmpl/src/filters/color/precompsrc.cpp new file mode 100644 index 00000000..5944cf51 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/color/precompsrc.cpp @@ -0,0 +1 @@ +#include "precomp.h" \ No newline at end of file diff --git a/print/XPSDrvSmpl/src/filters/color/profile.cpp b/print/XPSDrvSmpl/src/filters/color/profile.cpp new file mode 100644 index 00000000..e3a8368c --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/color/profile.cpp @@ -0,0 +1,709 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + profile.cpp + +Abstract: + + Profile class implementation. The profile class is responsible for loading and maintaining + colo profile resources. The class provides methods for loading profiles from filename or + URI and is responsible for limited caching based off the file name and the (WCS)OpenProfile + options. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdstring.h" +#include "profile.h" +#include "wcsapiconv.h" + +DWORD g_tagWCSProfile = 'MS00'; + +/*++ + +Routine Name: + + CProfile::CProfile + +Routine Description: + + CProfile constructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CProfile::CProfile() : + m_hProfile(NULL), + m_dwDesiredAccess(PROFILE_READ), + m_dwShareMode(FILE_SHARE_READ), + m_dwCreationMode(OPEN_EXISTING), + m_dwWCSFlags(0) +{ +} + +/*++ + +Routine Name: + + CProfile::~CProfile + +Routine Description: + + CProfile destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CProfile::~CProfile() +{ + FreeProfile(); +} + +/*++ + +Routine Name: + + CProfile::SetProfile + +Routine Description: + + Sets the current profile from the fixed page using the specified resoure URI + +Arguments: + + pFP - Pointer to the fixed page interface + szURI - URI to the ICC profile to load + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CProfile::SetProfile( + _In_ IFixedPage* pFP, + _In_ LPCWSTR szURI + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pFP, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(szURI, E_POINTER))) + { + try + { + CStringXDW cstrKey; + + if (SUCCEEDED(hr = CreateProfileKey(szURI, NULL, NULL, &cstrKey)) && + (m_hProfile == NULL || + m_cstrProfileKey != cstrKey)) + { + FreeProfile(); + + // + // Get the read stream for the URI + // + CComPtr pPart(NULL); + CComPtr pProfilePart(NULL); + CComPtr pRead(NULL); + CComBSTR bstrProfileURI(szURI); + + ULONGLONG cbEnd = 0; + + // + // Get the profile part and a read stream. Seek to the end to find the + // size of the profile data + // + if (SUCCEEDED(hr = pFP->GetPagePart(bstrProfileURI, &pPart)) && + SUCCEEDED(hr = pPart.QueryInterface(&pProfilePart)) && + SUCCEEDED(hr = pProfilePart->GetStream(&pRead)) && + SUCCEEDED(hr = pRead->Seek(0, STREAM_SEEK_END, &cbEnd))) + { + // + // Allocate the buffer and copy + // + UINT cbProfileData = static_cast(cbEnd); + PBYTE pProfileData = new(std::nothrow) BYTE[cbProfileData]; + + ULONG cbRead; + BOOL bEOF = FALSE; + if (SUCCEEDED(hr = CHECK_POINTER(pProfileData, E_OUTOFMEMORY)) && + SUCCEEDED(hr = pRead->Seek(0, STREAM_SEEK_SET, &cbEnd)) && + SUCCEEDED(hr = pRead->ReadBytes(pProfileData, cbProfileData, &cbRead, &bEOF))) + { + if (cbProfileData != cbRead) + { + RIP("Failed to read all profile data\n"); + + hr = E_FAIL; + } + } + + // + // Create the transform from the buffer + // + if (SUCCEEDED(hr)) + { + PROFILE profile = { + PROFILE_MEMBUFFER, + pProfileData, + cbProfileData + }; + + if (SUCCEEDED(hr = OpenProfile(&profile, &m_hProfile))) + { + m_cstrProfileKey = cstrKey; + } + } + + if (pProfileData != NULL) + { + delete[] pProfileData; + pProfileData = NULL; + } + } + } + } + catch (CXDException& e) + { + hr = e; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CProfile::SetProfile + +Routine Description: + + Sets a profile from the specified file name + +Arguments: + + szFileName - File name of the profile to open + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CProfile::SetProfile( + _In_ LPCWSTR szFileName + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(szFileName, E_POINTER))) + { + try + { + CStringXDW cstrKey; + + if (SUCCEEDED(hr = CreateProfileKey(szFileName, NULL, NULL, &cstrKey)) && + (m_hProfile == NULL || + m_cstrProfileKey != cstrKey)) + { + FreeProfile(); + + CStringXDW profileFileName(szFileName); + PROFILE profile = { + PROFILE_FILENAME, + profileFileName.GetBuffer(), + profileFileName.GetLength() * sizeof(WCHAR) + }; + + if (SUCCEEDED(hr = OpenProfile(&profile, &m_hProfile))) + { + m_cstrProfileKey = cstrKey; + } + } + } + catch (CXDException& e) + { + hr = e; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CProfile::SetProfile + +Routine Description: + + Sets a color profile from memory + +Arguments: + + szProfile - Name of the profile. This is used for caching puproses + pBuffer - Buffer containing the profile data + cbBuffer - Size of the buffer + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CProfile::SetProfile( + _In_ LPWSTR szProfile, + _In_reads_bytes_(cbBuffer) PBYTE pBuffer, + _In_ UINT cbBuffer + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(szProfile, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pBuffer, E_POINTER))) + { + try + { + CStringXDW cstrKey; + + if (SUCCEEDED(hr = CreateProfileKey(szProfile, NULL, NULL, &cstrKey)) && + (m_hProfile == NULL || + m_cstrProfileKey != cstrKey)) + { + FreeProfile(); + + PROFILE profile = { + PROFILE_MEMBUFFER, + pBuffer, + cbBuffer + }; + + if (SUCCEEDED(hr = OpenProfile(&profile, &m_hProfile))) + { + m_cstrProfileKey = cstrKey; + } + } + } + catch (CXDException& e) + { + hr = e; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CProfile::GetProfileHandle + +Routine Description: + + Retrieves the current profile handle + +Arguments: + + phProfile - Pointer to a HPROFILE that accepts the current profile handle + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CProfile::GetProfileHandle( + _Out_ HPROFILE* phProfile + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(phProfile, E_POINTER))) + { + *phProfile = NULL; + if (SUCCEEDED(hr = CHECK_HANDLE(m_hProfile, E_PENDING))) + { + *phProfile = m_hProfile; + } + } + + ERR_ON_HR_EXC(hr, E_PENDING); + return hr; +} + +/*++ + +Routine Name: + + CProfile::IsWCSCompatible + +Routine Description: + + Checks if the current profile is suitable for use with WCS + +Arguments: + + pbWCSCompat - Pointer to BOOL the accepts the result + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CProfile::IsWCSCompatible( + _Out_ BOOL* pbWCSCompat + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pbWCSCompat, E_POINTER)) && + SUCCEEDED(hr = CHECK_HANDLE(m_hProfile, E_PENDING))) + { + // + // Assume true as the GetColorProfileHeader documentation states: "This function + // does not support Windows Color System (WCS) profiles CAMP, DMP, and GMMP.", therefore + // if the profile is loaded and it is not ICC (i.e. no header) it should be WCS compatible + // + *pbWCSCompat = TRUE; + + PROFILEHEADER profileHeader = {0}; + if (GetColorProfileHeader(m_hProfile, &profileHeader)) + { + if (profileHeader.phClass == CLASS_LINK || + profileHeader.phClass == CLASS_NAMED) + { + *pbWCSCompat = FALSE; + } + } + } + + ERR_ON_HR(hr); + return hr; +} + + +/*++ + +Routine Name: + + CProfile::GetProfileKey + +Routine Description: + + Retrieves a key identifying the current profile. This is composed of the profile name + and the options used to create the profile + +Arguments: + + pcstrProfileKey - Pointer to a CStringXDW object that recieves the key + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CProfile::GetProfileKey( + _Out_ CStringXDW* pcstrProfileKey + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pcstrProfileKey, E_POINTER))) + { + try + { + *pcstrProfileKey = m_cstrProfileKey; + } + catch (CXDException& e) + { + hr = e; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CProfile::operator== + +Routine Description: + + CProfile equality operator + +Arguments: + + cstrProfileKey - the key to compare against + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +BOOL +CProfile::operator==( + _In_ CONST CStringXDW& cstrProfileKey + ) CONST +{ + BOOL bEqual = TRUE; + + try + { + if (m_cstrProfileKey != cstrProfileKey) + { + bEqual = FALSE; + } + } + catch (CXDException&) + { + bEqual = FALSE; + } + + return bEqual; +} + +/*++ + +Routine Name: + + CProfile::operator!= + +Routine Description: + + CProfile inequality operator + +Arguments: + + cstrProfileKey - profile key to compare against + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +BOOL +CProfile::operator!=( + _In_ CONST CStringXDW& cstrProfileKey + ) CONST +{ + return !operator==(cstrProfileKey); +} + +/*++ + +Routine Name: + + CProfile::FreeProfile + +Routine Description: + + Frees the current profile + +Arguments: + + None + +Return Value: + + None + +--*/ +VOID +CProfile::FreeProfile( + VOID + ) +{ + try + { + m_cstrProfileKey.Empty(); + } + catch (CXDException&) + { + } + + if (m_hProfile != NULL) + { + CloseColorProfile(m_hProfile); + m_hProfile = NULL; + } +} + +/*++ + +Routine Name: + + CProfile::OpenProfile + +Routine Description: + + Opens the current profile based off the current OS. Vista uses WCSOpenProfile while + earlier Windows use OpenProfile + +Arguments: + + pProfile - Pointer to the profile structure used to open the profile + phProfile - Pointer to a HPROFILE to recieve the opened profile handle + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CProfile::OpenProfile( + _In_ PROFILE* pProfile, + _Out_ HPROFILE* phProfile + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pProfile, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(phProfile, E_POINTER))) + { + // + // Get a handle to the color profile using WCS in Vista or the XP API in earlier operating systems + // + if (IsVista()) + { + *phProfile = WcsOpenColorProfileXD(pProfile, NULL, NULL, m_dwDesiredAccess, m_dwShareMode, m_dwCreationMode, m_dwWCSFlags); + } + else + { + *phProfile = OpenColorProfile(pProfile, m_dwDesiredAccess, m_dwShareMode, m_dwCreationMode); + } + + if (FAILED(CHECK_POINTER(*phProfile, E_POINTER))) + { + hr = GetLastErrorAsHResult(); + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CProfile::CreateProfileKey + +Routine Description: + + Creates a profile key based on the possible profile names used to construct the + profile and the settings used to open the profile + +Arguments: + + + pszCDMP - Device model profile name + pszCAMP - Color adjustment model profile name + pszGMMP - Gamut model profile name + pcstrKey - Pointer to a CStringXDW that recieves the key + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CProfile::CreateProfileKey( + _In_ LPCWSTR pszCDMP, + _In_opt_ LPCWSTR pszCAMP, + _In_opt_ LPCWSTR pszGMMP, + _Out_ CStringXDW* pcstrKey + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pszCDMP, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pcstrKey, E_POINTER))) + { + try + { + pcstrKey->Empty(); + pcstrKey->Append(pszCDMP); + + if (pszCAMP != NULL) + { + pcstrKey->Append(pszCAMP); + } + + if (pszGMMP != NULL) + { + pcstrKey->Append(pszGMMP); + } + + CStringXDW cstrOpenOptions; + cstrOpenOptions.Format(L"%x%x%x%x", m_dwDesiredAccess, m_dwShareMode, m_dwCreationMode, m_dwWCSFlags); + + pcstrKey->Append(cstrOpenOptions); + pcstrKey->MakeLower(); + } + catch (CXDException& e) + { + hr = e; + } + } + + ERR_ON_HR(hr); + return hr; +} + diff --git a/print/XPSDrvSmpl/src/filters/color/profile.h b/print/XPSDrvSmpl/src/filters/color/profile.h new file mode 100644 index 00000000..46fa46fa --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/color/profile.h @@ -0,0 +1,124 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + profile.h + +Abstract: + + Profile class definition. The profile class is responsible for loading and maintaining + colo profile resources. The class provides methods for loading profiles from filename or + URI and is responsible for limited caching based off the file name and the (WCS)OpenProfile + options. + +--*/ + +#pragma once + +class CProfile +{ +public: + CProfile(); + + ~CProfile(); + + HRESULT + SetProfile( + _In_ IFixedPage* pFP, + _In_ LPCWSTR szURI + ); + + HRESULT + SetProfile( + _In_ LPCWSTR szURI + ); + + HRESULT + SetProfile( + _In_ LPWSTR szProfile, + _In_reads_bytes_(cbBuffer) PBYTE pBuffer, + _In_ UINT cbBuffer + ); + + HRESULT + GetProfileHandle( + _Out_ HPROFILE* phProfile + ); + + HRESULT + IsWCSCompatible( + _Out_ BOOL* pbWCSCompat + ); + + HRESULT + GetProfileKey( + _Out_ CStringXDW* pcstrProfileURI + ); + + BOOL + operator==( + _In_ CONST CStringXDW& cstrProfileKey + ) CONST; + + BOOL + operator!=( + _In_ CONST CStringXDW& cstrProfileKey + ) CONST; + +private: + HRESULT + CreateProfileBuffer( + VOID + ); + + VOID + FreeProfile( + VOID + ); + + HRESULT + OpenProfile( + _In_ PROFILE* pProfile, + _Out_ HPROFILE* phProfile + ); + + HRESULT + CreateProfileKey( + _In_ LPCWSTR pszCDMP, + _In_opt_ LPCWSTR pszCAMP, + _In_opt_ LPCWSTR pszGMMP, + _Out_ CStringXDW* pcstrKey + ); + +private: + HPROFILE m_hProfile; + + DWORD m_dwDesiredAccess; + + DWORD m_dwShareMode; + + DWORD m_dwCreationMode; + + DWORD m_dwWCSFlags; + + // + // We define a key for a profile as the URI(s) plus any options used when + // creating the profile. This allows anything that uses this profile in + // combination with other profiles to identify the constituents of the + // transform and hence cache that transform without needing to store the + // profile handles. + // + // Note: Do not cache against the handle as handles can be re-used + // + CStringXDW m_cstrProfileKey; +}; + diff --git a/print/XPSDrvSmpl/src/filters/color/profman.cpp b/print/XPSDrvSmpl/src/filters/color/profman.cpp new file mode 100644 index 00000000..8bd06284 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/color/profman.cpp @@ -0,0 +1,818 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + profman.cpp + +Abstract: + + Color profile class implementation. The CProfileManager class represents + a color profile and provides a transform from the system default profile + to the supplied profile. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdstring.h" +#include "xdexcept.h" +#include "profman.h" + +using XDPrintSchema::PageSourceColorProfile::PageSourceColorProfileData; +using XDPrintSchema::PageSourceColorProfile::EProfileOption; +using XDPrintSchema::PageSourceColorProfile::RGB; +using XDPrintSchema::PageSourceColorProfile::CMYK; + +using XDPrintSchema::PageICMRenderingIntent::PageICMRenderingIntentData; +using XDPrintSchema::PageICMRenderingIntent::AbsoluteColorimetric; +using XDPrintSchema::PageICMRenderingIntent::RelativeColorimetric; +using XDPrintSchema::PageICMRenderingIntent::Photographs; +using XDPrintSchema::PageICMRenderingIntent::BusinessGraphics; + + +/*++ + +Routine Name: + + CProfileManager::CProfileManager + +Routine Description: + + Constructor for the CProfileManager class which records internally the device name, + color profile structure, color intents data and initialises the CProfileManager + ready to supply suitable color transforms + +Arguments: + + pszDeviceName - Pointer to a string containing the device name + cmProfData - Structure containing color profile settings from the PrintTicket + cmIntData - Structure containing color intents settings from the PrintTicket + +Return Value: + + None + Throws CXDException(HRESULT) on an error + +--*/ +CProfileManager::CProfileManager( + _In_ LPCWSTR pszDeviceName, + _In_ PageSourceColorProfileData cmProfData, + _In_ PageICMRenderingIntentData cmIntData, + _In_ IFixedPage* pFP + ) : + m_strDeviceName(pszDeviceName), + m_cmProfData(cmProfData), + m_cmIntData(cmIntData), + m_pFixedPage(pFP) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pszDeviceName, E_POINTER)) || + SUCCEEDED(hr = CHECK_POINTER(m_pFixedPage, E_POINTER))) + { + if(m_strDeviceName.GetLength() <= 0) + { + hr = E_INVALIDARG; + } + } + + if (FAILED(hr)) + { + throw CXDException(E_INVALIDARG); + } +} + +/*++ + +Routine Name: + + CProfileManager::~CProfileManager + +Routine Description: + + Default destructor for the CProfileManager class which performs and clean up + +Arguments: + + None + +Return Value: + + None + +--*/ +CProfileManager::~CProfileManager() +{ +} + +/*++ + +Routine Name: + + CProfileManager::GetColorTransform + +Routine Description: + + Method which supplies a color transform based on the settings in the PrintTicket + +Arguments: + + phColorTrans - Pointer to a color transform handle which will contain + a transform based off the settings in the PrintTicket + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CProfileManager::GetColorTransform( + _Out_ HTRANSFORM* phColorTrans, + _Out_ BOOL* pbUseWCS + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pbUseWCS, E_POINTER)) && + SUCCEEDED(hr = CHECK_HANDLE(phColorTrans, E_POINTER)) && + SUCCEEDED(hr = m_dstProfile.SetProfile(m_cmProfData.cmProfileName))) + { + *pbUseWCS = IsVista(); + + try + { + // + // Construct and populate a profile list for the transform object + // + ProfileList profileList; + + // + // Check the source profile has been set. GetProfileHandle will return an error + // if it has not been. + // + HPROFILE hProfile = NULL; + if (SUCCEEDED(hr = m_srcProfile.GetProfileHandle(&hProfile))) + { + profileList.push_back(&m_srcProfile); + profileList.push_back(&m_dstProfile); + + // + // Map the PrintTicket intents option to the ICM option + // + DWORD intents = INTENT_ABSOLUTE_COLORIMETRIC; + switch (m_cmIntData.cmOption) + { + case AbsoluteColorimetric: + { + intents = INTENT_ABSOLUTE_COLORIMETRIC; + } + break; + + case RelativeColorimetric: + { + intents = INTENT_RELATIVE_COLORIMETRIC; + } + break; + + case Photographs: + { + intents = INTENT_PERCEPTUAL; + } + break; + + case BusinessGraphics: + default: + { + intents = INTENT_SATURATION; + } + break; + } + + DWORD flRender = BEST_MODE; + + // + // Check if the source and destination profiles are compatible with WCS + // + if (*pbUseWCS && + SUCCEEDED(hr = m_srcProfile.IsWCSCompatible(pbUseWCS))) + { + if (*pbUseWCS) + { + hr = m_dstProfile.IsWCSCompatible(pbUseWCS); + } + } + + if (SUCCEEDED(hr) && + *pbUseWCS) + { + // + // Everything is in place for using WCS + // + flRender |= WCS_ALWAYS; + } + + if (SUCCEEDED(hr) && + SUCCEEDED(hr = m_colorTrans.CreateTransform(&profileList, intents, flRender))) + { + hr = m_colorTrans.GetTransformHandle(phColorTrans); + } + } + } + catch (CXDException& e) + { + hr = e; + } + catch (exception& DBG_ONLY(e)) + { + ERR(e.what()); + hr = E_FAIL; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CProfileManager::GetDstProfileType + +Routine Description: + + Method to return the color profile type as read from the PrintTicket + +Arguments: + + pType - Pointer to the profile type to be filled in + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CProfileManager::GetDstProfileType( + _Out_ EProfileOption* pType + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pType, E_POINTER))) + { + *pType = m_cmProfData.cmProfile; + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CProfileManager::GetDstProfileName + +Routine Description: + + Method which returns the systems default colour profile name + +Arguments: + + pbstrProfileName - Pointer to string to hold the profile name + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CProfileManager::GetDstProfileName( + _Inout_ BSTR* pbstrProfileName + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pbstrProfileName, E_POINTER))) + { + try + { + CStringXDW cstrURI; + + if (m_cmProfData.cmProfile == RGB || + m_cmProfData.cmProfile == CMYK) + { + if (SUCCEEDED(hr = GetColDir(&cstrURI))) + { + cstrURI += L"\\"; + cstrURI += m_cmProfData.cmProfileName; + } + } + else + { + hr = E_NOTIMPL; + } + SysFreeString(*pbstrProfileName); + *pbstrProfileName = cstrURI.AllocSysString(); + } + catch (CXDException& e) + { + hr = e; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CProfileManager::SetSrcProfileFromContainer + +Routine Description: + + Method which sets the source colour profile from a profile within the + XPS container + +Arguments: + + pszProfileURI - Pointer to string holding the profile URI + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CProfileManager::SetSrcProfileFromContainer( + _In_ LPWSTR szProfileURI + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(szProfileURI, E_POINTER))) + { + hr = m_srcProfile.SetProfile(m_pFixedPage, szProfileURI); + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CProfileManager::SetSrcProfileFromColDir + +Routine Description: + + Method which sets the source colour profile from the color directory + +Arguments: + + pszProfile - Pointer to string holding the profile name + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CProfileManager::SetSrcProfileFromColDir( + _In_ LPWSTR szProfile + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(szProfile, E_POINTER))) + { + hr = SetProfileFromColDir(&m_srcProfile, szProfile); + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CProfileManager::SetSrcProfileFromBuffer + +Routine Description: + + Method which sets the source colour profile from a buffer + +Arguments: + + pszProfile - Pointer to string holding the profile name + pBuffer - Pointer to buffer holding the profile data + cbBuffer - Count of bytes in the profile buffer + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CProfileManager::SetSrcProfileFromBuffer( + _In_ LPWSTR szProfile, + _In_reads_bytes_(cbBuffer) PBYTE pBuffer, + _In_ UINT cbBuffer + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(szProfile, E_POINTER)) || + SUCCEEDED(hr = CHECK_POINTER(pBuffer, E_POINTER))) + { + hr = m_srcProfile.SetProfile(szProfile, pBuffer, cbBuffer); + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CProfileManager::GetProfileOption + +Routine Description: + + This method retrieves the profile option set in the PrintTicket + +Arguments: + + pProfileOption - Pointer to a profile option enumeration type to recieve the option + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CProfileManager::GetProfileOption( + _Out_ EProfileOption* pProfileOption + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pProfileOption, E_POINTER))) + { + *pProfileOption = m_cmProfData.cmProfile; + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CProfileManager::WriteData + +Routine Description: + + This method handles writing the destination profile to the container + +Arguments: + + pStream - Pointer to a stream to write the resource out to + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CProfileManager::WriteData( + _In_ IPartBase* pResource, + _In_ IPrintWriteStream* pStream + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pResource, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pStream, E_POINTER))) + { + HANDLE hFile = INVALID_HANDLE_VALUE; + + // + // Open the destination profile file from disk. We could use the + // handle however we do not know whether we will get the ICC or DMP. + // + CComBSTR bstrProfile; + if (SUCCEEDED(hr = GetDstProfileName(&bstrProfile))) + { + hFile = CreateFile(bstrProfile, + GENERIC_READ, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + + if (hFile == INVALID_HANDLE_VALUE) + { + hr = GetLastErrorAsHResult(); + } + } + + if (SUCCEEDED(hr)) + { + // + // Write profile data to stream + // + PBYTE pBuff = new(std::nothrow) BYTE[CB_COPY_BUFFER]; + hr = CHECK_POINTER(pBuff, E_OUTOFMEMORY); + + DWORD cbRead = 0; + + while (SUCCEEDED(hr)) + { + if (ReadFile(hFile, pBuff, CB_COPY_BUFFER, &cbRead, NULL)) + { + if (cbRead > 0) + { + ULONG cbWritten = 0; + hr = pStream->WriteBytes(reinterpret_cast(pBuff), cbRead, &cbWritten); + + if (cbRead != cbWritten) + { + RIP("Failed to write all profile data.\n"); + + hr = E_FAIL; + } + } + else + { + break; + } + } + else + { + hr = GetLastErrorAsHResult(); + } + } + + delete[] pBuff; + pBuff = NULL; + } + + if (hFile != INVALID_HANDLE_VALUE) + { + CloseHandle(hFile); + hFile = INVALID_HANDLE_VALUE; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CProfileManager::GetKeyName + +Routine Description: + + Method to obtain a unique key for the resource being handled + +Arguments: + + pbstrKeyName - Pointer to a string to hold the generated key + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CProfileManager::GetKeyName( + _Inout_ _At_(*pbstrKeyName, _Pre_maybenull_ _Post_valid_) BSTR* pbstrKeyName + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pbstrKeyName, E_POINTER))) + { + SysFreeString(*pbstrKeyName); + + if (SUCCEEDED(hr = m_cmProfData.cmProfileName.CopyTo(pbstrKeyName)) && + !*pbstrKeyName) + { + hr = E_OUTOFMEMORY; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CProfileManager::GetResURI + +Routine Description: + + Method to obtain the URI of the resource being handled + +Arguments: + + pbstrResURI - Pointer to a string to hold the resource URI + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CProfileManager::GetResURI( + _Outptr_ BSTR* pbstrResURI + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pbstrResURI, E_POINTER))) + { + try + { + CStringXDW cstrFileName(m_cmProfData.cmProfileName); + CStringXDW cstrFileExt(PathFindExtension(cstrFileName)); + + INT indFileExt = cstrFileName.Find(cstrFileExt); + + if (indFileExt > -1) + { + cstrFileName.Delete(indFileExt, cstrFileExt.GetLength()); + } + + // + // Create a unique name for the profile for this print session + // + CStringXDW cstrURI; + cstrURI.Format(L"/%s_%u%s", cstrFileName, GetUniqueNumber(), cstrFileExt); + + *pbstrResURI = cstrURI.AllocSysString(); + } + catch (CXDException& e) + { + hr = e; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CProfileManager::SetProfileFromColDir + +Routine Description: + + Set the named profile from the color directory. The method appends the specified + file name to the color directory path and instructs the profile class to open the + profile + +Arguments: + + pProfile - Pointer to the profile class that actually opens the profile + szProfile - The profile file name + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CProfileManager::SetProfileFromColDir( + _In_ CProfile* pProfile, + _In_ LPWSTR szProfile + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pProfile, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(szProfile, E_POINTER))) + { + try + { + CStringXDW cstrProfile; + + if (SUCCEEDED(hr = GetColDir(&cstrProfile))) + { + cstrProfile += L"\\"; + cstrProfile += szProfile; + + hr = pProfile->SetProfile(cstrProfile.GetBuffer()); + } + } + catch (CXDException& e) + { + hr = e; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CProfileManager::GetColDir + +Routine Description: + + Retrieves the color directory path + +Arguments: + + pcstrColDir - Pointer to a string class that accepts the color directory path + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CProfileManager::GetColDir( + _Out_ CStringXDW* pcstrColDir + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pcstrColDir, E_POINTER))) + { + try + { + pcstrColDir->Empty(); + DWORD cbColDir = 0; + if (!GetColorDirectory(NULL, NULL, &cbColDir)) + { + pcstrColDir->Preallocate(cbColDir/sizeof(WCHAR)); + if (!GetColorDirectory(NULL, pcstrColDir->GetBuffer(), &cbColDir)) + { + hr = GetLastErrorAsHResult(); + } + } + } + catch (CXDException& e) + { + hr = e; + } + } + + ERR_ON_HR(hr); + return hr; +} + diff --git a/print/XPSDrvSmpl/src/filters/color/profman.h b/print/XPSDrvSmpl/src/filters/color/profman.h new file mode 100644 index 00000000..4246a0c2 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/color/profman.h @@ -0,0 +1,126 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + profman.h + +Abstract: + + Color profile manager definition. The CProfileManager class is responsible + for managing the color profile set in the driver. + +--*/ + +#pragma once + +#include "cmprofiledata.h" +#include "cmintentsdata.h" +#include "rescache.h" +#include "transform.h" + +class CProfileManager : public IResWriter +{ +public: + CProfileManager( + _In_ LPCWSTR pszDeviceName, + _In_ XDPrintSchema::PageSourceColorProfile::PageSourceColorProfileData cmProfData, + _In_ XDPrintSchema::PageICMRenderingIntent::PageICMRenderingIntentData cmIntData, + _In_ IFixedPage* pFP + ); + + virtual ~CProfileManager(); + + HRESULT + GetColorTransform( + _Out_ HTRANSFORM* phColorTrans, + _Out_ BOOL* pbUseWCS + ); + + HRESULT + GetDstProfileType( + _Out_ XDPrintSchema::PageSourceColorProfile::EProfileOption* pType + ); + + HRESULT + GetDstProfileName( + _Inout_ BSTR* pbstrProfileName + ); + + HRESULT + SetSrcProfileFromContainer( + _In_ LPWSTR szProfileURI + ); + + HRESULT + SetSrcProfileFromColDir( + _In_ LPWSTR szProfile + ); + + HRESULT + SetSrcProfileFromBuffer( + _In_ LPWSTR szProfile, + _In_reads_bytes_(cbBuffer) PBYTE pBuffer, + _In_ UINT cbBuffer + ); + + HRESULT + GetProfileOption( + _Out_ XDPrintSchema::PageSourceColorProfile::EProfileOption* pProfileOption + ); + + // + // IResWriter interface + // + HRESULT + WriteData( + _In_ IPartBase* pResource, + _In_ IPrintWriteStream* pStream + ); + + HRESULT + GetKeyName( + _Inout_ _At_(*pbstrKeyName, _Pre_maybenull_ _Post_valid_) BSTR* pbstrKeyName + ); + + HRESULT + GetResURI( + _Outptr_ BSTR* pbstrResURI + ); + +private: + HRESULT + SetProfileFromColDir( + _In_ CProfile* pProfile, + _In_ LPWSTR szProfile + ); + + HRESULT + GetColDir( + _Out_ CStringXDW* pcstrColDir + ); + +private: + CStringXDW m_strDeviceName; + + XDPrintSchema::PageSourceColorProfile::PageSourceColorProfileData m_cmProfData; + + XDPrintSchema::PageICMRenderingIntent::PageICMRenderingIntentData m_cmIntData; + + CProfile m_srcProfile; + + CProfile m_dstProfile; + + CTransform m_colorTrans; + + CComPtr m_pFixedPage; +}; + diff --git a/print/XPSDrvSmpl/src/filters/color/scaniter.cpp b/print/XPSDrvSmpl/src/filters/color/scaniter.cpp new file mode 100644 index 00000000..541554ab --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/color/scaniter.cpp @@ -0,0 +1,604 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + scaniter.cpp + +Abstract: + + CScanIterator class implementation. The scan iterator class provides a convenient + interface for iterating over WIC data and retrieving scanline data approriate for + consumption in WCS/ICM. For example, the WIC pixel formats do not have alpha channel + positions that correspond with the WCS/ICM BMFORMAT types so this class is responsible + for presenting bitmap data without the alpha channel and for copying alpha data from + source to destination when scnaline changes are commited to the underlying WIC bitmap. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "xdexcept.h" +#include "globals.h" +#include "scaniter.h" + +/*++ + +Routine Name: + + CScanIterator::CScanIterator + +Routine Description: + + CScanIterator constructor + +Arguments: + + + bmpConv - Bitmap converter class encapsulating the underlying WIC bitmap + pRect - The rectangular area of the bitmap over which we want to iterate scanlines + +Return Value: + + None + Throws an exception on error. + +--*/ +CScanIterator::CScanIterator( + _In_ CONST CBmpConverter& bmpConv, + _In_opt_ WICRect* pRect + ) : + CBmpConverter(bmpConv), + m_bSrcLine(TRUE), + m_cbWICStride(0), + m_cWICWidth(0), + m_cWICHeight(0), + m_cbWICData(0), + m_pbWICData(NULL) +{ + HRESULT hr = S_OK; + + UINT cWidth = 0; + UINT cHeight = 0; + + if (SUCCEEDED(hr = CHECK_POINTER(m_pBitmap, E_POINTER)) && + SUCCEEDED(hr = m_pBitmap->GetSize(&cWidth, &cHeight))) + { + if (pRect == NULL) + { + // + // We want to iterate over the entire surface + // + m_rectTotal.X = 0; + m_rectTotal.Y = 0; + m_rectTotal.Width = static_cast(cWidth); + m_rectTotal.Height = static_cast(cHeight); + } + else + { + if (pRect->X >= 0 && + pRect->Y >= 0 && + pRect->Width <= static_cast(cWidth) && + pRect->Height <= static_cast(cHeight)) + { + m_rectTotal = *pRect; + } + else + { + hr = E_INVALIDARG; + } + } + } + + if (FAILED(hr)) + { + throw CXDException(hr); + } +} + +/*++ + +Routine Name: + + CScanIterator::~CScanIterator + +Routine Description: + + CScanIterator destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CScanIterator::~CScanIterator() +{ + UnlockSurface(); +} + +/*++ + +Routine Name: + + CScanIterator::Initialize + +Routine Description: + + Initialize the iterator. Here we are going to: + + 1. Convert to a suitable WIC format for processing + 2. Allocate an intermediate color buffer (if required) for processing + 3. Allocate an intermediate alpha buffer (if required) for processing + 4. Reset and lock the iterator rect ready for processing + +Arguments: + + bSrcLine - true if this is a source scanline (i.e. read only) + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CScanIterator::Initialize( + _In_ CONST BOOL& bSrcLine + ) +{ + HRESULT hr = S_OK; + m_bSrcLine = bSrcLine; + + // + // Look up the pixel format to convert to so that the bitmap is appropriate + // for consumption by WCS/ICM. + // + // Note: we are not dealing with the limitations of ICM downlevel. Downlevel + // we need to convert floating and fixed point values to values appropriate + // to ICM then back again before writing out so the underlying bitmap type is + // unmodified. + // + EWICPixelFormat eConversionFormat = kWICPixelFormatDontCare; + if (m_ePixelFormat > 0 && + m_ePixelFormat < kWICPixelFormatMax) + { + eConversionFormat = g_lutWICToBMFormat[m_ePixelFormat].m_pixFormTarget; + } + else + { + RIP("Unrecognised pixel format.\n"); + hr = E_FAIL; + } + + // + // Apply the conversion if required + // + BOOL bCanConvert = FALSE; + if (eConversionFormat != m_ePixelFormat && + SUCCEEDED(hr) && + SUCCEEDED(hr = Convert(eConversionFormat, &bCanConvert))) + { + if (!bCanConvert) + { + RIP("Cannot convert to target type.\n"); + hr = E_FAIL; + } + } + + // + // Set the current iteration data ready for processing + // + if (SUCCEEDED(hr)) + { + // + // Ensure the iterator is reset to the start of the area to be processed. This + // ensures that the current rect lock is valid so that we can initialise the + // first scanline to process + // + Reset(); + + // + // Initialise the WIC <-> BM scan line converter + // + if (SUCCEEDED(hr = m_currScan.Initialize(g_lutWICToBMFormat[m_ePixelFormat]))) + { + hr = SetCurrentIterationData(); + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CScanIterator::Reset + +Routine Description: + + Resets the current rect to the first scanline in the buffer. + +Arguments: + + None + +Return Value: + + None + +--*/ +VOID +CScanIterator::Reset( + VOID + ) +{ + m_rectCurrLock.X = m_rectTotal.X; + m_rectCurrLock.Y = m_rectTotal.Y; + m_rectCurrLock.Width = m_rectTotal.Width; + m_rectCurrLock.Height = 1; +} + +/*++ + +Routine Name: + + CScanIterator::operator++ + +Routine Description: + + Iterate to the next scan line. + +Arguments: + + None + +Return Value: + + Reference to this iterator + +--*/ +CScanIterator& +CScanIterator::operator++(INT) +{ + HRESULT hr = S_OK; + + m_rectCurrLock.Y++; + if (!Finished()) + { + if (FAILED(hr = SetCurrentIterationData())) + { + throw CXDException(hr); + } + } + + return *this; +} + +/*++ + +Routine Name: + + CScanIterator::GetScanBuffer + +Routine Description: + + Retrieves the scanline buffer appropriate for WCS/ICM consumption + +Arguments: + + ppData - Pointer to pointer that recieves the address of the data buffer + Note: the buffer is only valid for the lifetime of the CScanIterator object. + pBmFormat - Pointer to a BMFORMAT enumeration that recieves the format + pcWidth - Pointer to storage that recieves the pixel width + pcHeight - Pointer to storage that recieves the pixel height + pcbStride - Pointer to storage that recieves the stride + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CScanIterator::GetScanBuffer( + _Outptr_result_buffer_(*pcbStride) PBYTE* ppData, + _Out_ BMFORMAT* pBmFormat, + _Out_ UINT* pcWidth, + _Out_ UINT* pcHeight, + _Out_ UINT* pcbStride + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(ppData, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pBmFormat, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pcWidth, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pcHeight, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pcbStride, E_POINTER))) + { + *ppData = NULL; + *pcWidth = 0; + *pcHeight = 1; + *pcbStride = 0; + *pBmFormat = BM_RGBTRIPLETS; + + // + // Get the data from the WIC <-> BMFORMAT scanline converter + // + hr = m_currScan.GetData(ppData, pBmFormat, pcWidth, pcbStride); + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CScanIterator::Commit + +Routine Description: + + Commits the current color buffer to the surface if required and applies an optional alpha + channel passed in from a source iterator + +Arguments: + + alphaSource - Scan iterator instance with any potential alpha data to copy + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CScanIterator::Commit( + _In_ CONST CScanIterator& alphaSource + ) +{ + HRESULT hr = S_OK; + + COLORDATATYPE srcDataType = COLOR_BYTE; + COLORDATATYPE dstDataType = COLOR_BYTE; + + if (m_bSrcLine) + { + RIP("Cannot commit to readonly surface.\n"); + + hr = E_FAIL; + } + else if (alphaSource.m_ePixelFormat >= kWICPixelFormatMax || + alphaSource.m_ePixelFormat < kWICPixelFormatMin || + m_ePixelFormat >= kWICPixelFormatMax || + m_ePixelFormat < kWICPixelFormatMin) + { + RIP("Invalid pixel format.\n"); + + hr = E_FAIL; + } + else + { + srcDataType = g_lutWICToBMFormat[alphaSource.m_ePixelFormat].m_colDataType; + dstDataType = g_lutWICToBMFormat[m_ePixelFormat].m_colDataType; + + if (srcDataType > COLOR_S2DOT13FIXED || + srcDataType < COLOR_BYTE || + dstDataType > COLOR_S2DOT13FIXED || + dstDataType < COLOR_BYTE) + { + RIP("Invalid data type.\n"); + + hr = E_FAIL; + } + } + + if (SUCCEEDED(hr) && + alphaSource.HasAlphaChannel() && + HasAlphaChannel()) + { + // + // Convert and copy alpha data into destination + // + PBYTE pDst = m_pbWICData; + size_t cbDstChannel = g_lutColorDataSize[dstDataType]; + size_t cbDstAlphaOffset = g_lutWICToBMFormat[m_ePixelFormat].m_cAlphaOffset * cbDstChannel; + UINT cDstChannels = g_lutWICToBMFormat[m_ePixelFormat].m_cChannels; + + PBYTE pSrc = alphaSource.m_pbWICData; + size_t cbSrcChannel = g_lutColorDataSize[srcDataType]; + size_t cbSrcAlphaOffset = g_lutWICToBMFormat[alphaSource.m_ePixelFormat].m_cAlphaOffset * cbSrcChannel; + UINT cSrcChannels = g_lutWICToBMFormat[alphaSource.m_ePixelFormat].m_cChannels; + + if (m_cWICWidth * cDstChannels * cbDstChannel <= m_cbWICStride && + alphaSource.m_cWICWidth * cSrcChannels * cbSrcChannel <= alphaSource.m_cbWICStride) + { + // + // Move the source and destination to the first alpha channel + // + pDst += cbDstAlphaOffset; + pSrc += cbSrcAlphaOffset; + + // + // Call the appropriate convert copy function by casting the src pointer + // to the underlying data type + // + switch (srcDataType) + { + case COLOR_BYTE: + hr = ConvertCopyAlphaChannels(reinterpret_cast(pSrc), + m_cWICWidth, + cSrcChannels, + dstDataType, + pDst, + m_cWICWidth, + cDstChannels); + break; + + case COLOR_WORD: + hr = ConvertCopyAlphaChannels(reinterpret_cast(pSrc), + m_cWICWidth, + cSrcChannels, + dstDataType, + pDst, + m_cWICWidth, + cDstChannels); + break; + + case COLOR_FLOAT: + hr = ConvertCopyAlphaChannels(reinterpret_cast(pSrc), + m_cWICWidth, + cSrcChannels, + dstDataType, + pDst, + m_cWICWidth, + cDstChannels); + break; + + case COLOR_S2DOT13FIXED: + hr = ConvertCopyAlphaChannels(reinterpret_cast(pSrc), + m_cWICWidth, + cSrcChannels, + dstDataType, + pDst, + m_cWICWidth, + cDstChannels); + break; + + default: + { + RIP("Unrecognized source format.\n"); + + hr = E_FAIL; + } + break; + } + } + else + { + RIP("Insufficient buffer sizes.\n"); + + hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); + } + } + + // + // Commit the scanline + // + if (SUCCEEDED(hr)) + { + hr = m_currScan.Commit(m_pbWICData, m_cbWICStride); + } + + // + // Release the lock + // + UnlockSurface(); + + m_cbWICStride = 0; + m_cWICWidth = 0; + m_cWICHeight = 0; + m_cbWICData = 0; + m_pbWICData = NULL; + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CScanIterator::Finished + +Routine Description: + + We are done once all scanlines have been processed. + +Arguments: + + None + +Return Value: + + TRUE - We have iterated over all requested scanlines + FALSE - There are scanlines remaining + +--*/ +BOOL +CScanIterator::Finished( + VOID + ) +{ + return m_rectCurrLock.Y >= (m_rectTotal.Y + m_rectTotal.Height); +} + +/*++ + +Routine Name: + + CScanIterator::SetCurrentIterationData + +Routine Description: + + Sets up the current iteration data by locking the relevant area of the WIC bitmap + source and getting the WIC to BMFORMAT converter class to apply any conversion required + +Arguments: + + None + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CScanIterator::SetCurrentIterationData( + VOID + ) +{ + HRESULT hr = S_OK; + + m_cbWICStride = 0; + m_cWICWidth = 0; + m_cWICHeight = 0; + m_cbWICData = 0; + m_pbWICData = NULL; + + if (SUCCEEDED(hr = LockSurface(&m_rectCurrLock, + m_bSrcLine, + &m_cbWICStride, + &m_cWICWidth, + &m_cWICHeight, + &m_cbWICData, + &m_pbWICData)) && + SUCCEEDED(hr = CHECK_POINTER(m_pbWICData, E_FAIL))) + { + hr = m_currScan.SetData(m_bSrcLine, m_pbWICData, m_cbWICStride, m_cWICWidth); + } + + ERR_ON_HR(hr); + return hr; +} + diff --git a/print/XPSDrvSmpl/src/filters/color/scaniter.h b/print/XPSDrvSmpl/src/filters/color/scaniter.h new file mode 100644 index 00000000..de4b725e --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/color/scaniter.h @@ -0,0 +1,218 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + scaniter.h + +Abstract: + + CScanIterator class definition. The scan iterator class provides a convenient + interface for iterating over WIC data and retrieving scanline data approriate for + consumption in WCS/ICM. For example, the WIC pixel formats do not have alpha channel + positions that correspond with the WCS/ICM BMFORMAT types so this class is responsible + for presenting bitmap data without the alpha channel and for copying alpha data from + source to destination when scnaline changes are commited to the underlying WIC bitmap. + +--*/ + +#pragma once + +#include "bmpconv.h" +#include "wictobmscn.h" + +/* +Iterates through all scanlines in a bitmap creating a buffer appropriate +to color modification. These are: + + RGB channels (in that order) as byte, word, float or fixed - no alpha + CMYK channels (order as the source bitmap) as byte, word, float or fixed - no alpha + nChannel (order as the source bitmap) as byte - no alpha + +*/ +class CScanIterator : public CBmpConverter +{ +public: + CScanIterator( + _In_ CONST CBmpConverter& bmpConv, + _In_opt_ WICRect* pRect + ); + + virtual ~CScanIterator(); + + HRESULT + Initialize( + _In_ CONST BOOL& bReadOnly + ); + + VOID + Reset( + VOID + ); + + CScanIterator& + operator++( + INT + ); + + virtual HRESULT + GetScanBuffer( + _Outptr_result_buffer_(*pcbStride) PBYTE* ppData, + _Out_ BMFORMAT* pBmFormat, + _Out_ UINT* pcWidth, + _Out_ UINT* pcHeight, + _Out_ UINT* pcbStride + ); + + HRESULT + Commit( + _In_ CONST CScanIterator& cbAlphaBuffer + ); + + BOOL + Finished( + VOID + ); + +private: + HRESULT + SetCurrentIterationData( + VOID + ); + + template + HRESULT + ConvertCopyAlphaChannels( + _In_reads_(cSrcPix) _T* pSrc, + _In_ CONST UINT& cSrcPix, + _In_ CONST UINT& cSrcChan, + _Out_writes_(cDstPix) _U* pDst, + _In_ CONST UINT& cDstPix, + _In_ CONST UINT& cDstChan + ) + { + HRESULT hr = S_OK; + + if (cDstPix == cSrcPix) + { + for (UINT cCurPix = 0; + cCurPix < cDstPix; + cCurPix++, pSrc += cSrcChan, pDst += cDstChan) + { + ConvertCopy(*pDst, *pSrc); + } + } + else + { + hr = E_INVALIDARG; + } + + ERR_ON_HR(hr); + return hr; + } + + template + HRESULT + ConvertCopyAlphaChannels( + _In_reads_(cSrcPix) _T* pSrc, + _In_ CONST UINT& cSrcPix, + _In_ CONST UINT& cSrcChan, + _In_ CONST COLORDATATYPE& dstColType, + _When_(dstColType == COLOR_BYTE, _Out_writes_bytes_(cDstPix)) + _When_(dstColType == COLOR_WORD, _At_((PWORD)pDst, _Out_writes_(cDstPix))) + _When_(dstColType == COLOR_FLOAT, _At_((PFLOAT)pDst, _Out_writes_bytes_(cDstPix * sizeof(FLOAT)))) // Esp:1154 + _When_(dstColType == COLOR_S2DOT13FIXED, _At_((PS2DOT13FIXED)pDst, _Out_writes_(cDstPix))) + PBYTE pDst, + _In_ CONST UINT& cDstPix, + _In_ CONST UINT& cDstChan + ) + { + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pSrc, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pDst, E_POINTER))) + { + // + // Call the appropriate convert copy function by casting the dst pointer + // to the underlying data type + // + switch (dstColType) + { + case COLOR_BYTE: + hr = ConvertCopyAlphaChannels(reinterpret_cast<_T*>(pSrc), + cSrcPix, + cSrcChan, + reinterpret_cast(pDst), + cDstPix, + cDstChan); + break; + + case COLOR_WORD: + hr = ConvertCopyAlphaChannels(reinterpret_cast<_T*>(pSrc), + cSrcPix, + cSrcChan, + reinterpret_cast(pDst), + cDstPix, + cDstChan); + break; + + case COLOR_FLOAT: + hr = ConvertCopyAlphaChannels(reinterpret_cast<_T*>(pSrc), + cSrcPix, + cSrcChan, + reinterpret_cast(pDst), + cDstPix, + cDstChan); + break; + + case COLOR_S2DOT13FIXED: + hr = ConvertCopyAlphaChannels(reinterpret_cast<_T*>(pSrc), + cSrcPix, + cSrcChan, + reinterpret_cast(pDst), + cDstPix, + cDstChan); + break; + + default: + { + RIP("Unrecognized destination format.\n"); + + hr = E_INVALIDARG; + } + break; + } + } + + ERR_ON_HR(hr); + return hr; + } + +private: + WICRect m_rectTotal; + + WICRect m_rectCurrLock; + + BOOL m_bSrcLine; + + CWICToBMFormatScan m_currScan; + + UINT m_cbWICStride; + + UINT m_cWICWidth; + + UINT m_cWICHeight; + + UINT m_cbWICData; + + PBYTE m_pbWICData; +}; + diff --git a/print/XPSDrvSmpl/src/filters/color/transform.cpp b/print/XPSDrvSmpl/src/filters/color/transform.cpp new file mode 100644 index 00000000..adbf5b45 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/color/transform.cpp @@ -0,0 +1,666 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + transform.cpp + +Abstract: + + CTransform class implementation. This class creates and manages color transforms providing + limited caching functionality based off the source profile keys. + + This file also contains a utility class for handling profile lists. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdstring.h" +#include "xdexcept.h" +#include "transform.h" + +class CProfileList +{ +public: + /*++ + + Routine Name: + + CProfileList + + Routine Description: + + CProfileList constructor + + Arguments: + + pProfiles - pointer to a vector of profiles + + Return Value: + + None + Throws an exception on error. + + --*/ + CProfileList( + _In_ ProfileList* pProfiles + ) : + m_cProfiles(0), + m_phProfiles(NULL) + { + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pProfiles, E_POINTER))) + { + hr = CreateHandleBuffer(pProfiles); + } + + if (FAILED(hr)) + { + throw CXDException(hr); + } + } + + /*++ + + Routine Name: + + ~CProfileList + + Routine Description: + + CProfileList destructor + + Arguments: + + None + + Return Value: + + None + + --*/ + ~CProfileList() + { + FreeHandleBuffer(); + } + + /*++ + + Routine Name: + + GetProfileData + + Routine Description: + + Retrieves + + Arguments: + + pphProfiles - Pointer to pointer that recieves the address of an array of profile handles + Note: the buffer is only valid for the lifetime of the CProfileList object. + pcProfiles - Pointer to storage that recieves the count of profiles in the array + + Return Value: + + HRESULT + S_OK - On success + E_* - On error + + --*/ + HRESULT + GetProfileData( + _When_(*pcProfiles > 0, _Outptr_result_buffer_(*pcProfiles)) + _When_(*pcProfiles == 0, _Outptr_result_maybenull_) + HPROFILE** pphProfiles, + _Out_ DWORD* pcProfiles + ) + { + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pphProfiles, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pcProfiles, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(m_phProfiles, E_PENDING))) + { + *pphProfiles = 0; + *pcProfiles = 0; + + if (m_cProfiles > 0) + { + *pphProfiles = m_phProfiles; + *pcProfiles = m_cProfiles; + } + } + + ERR_ON_HR(hr); + return hr; + } + +private: + /*++ + + Routine Name: + + CreateHandleBuffer + + Routine Description: + + Creates the buffer that holds the profile handles + + Arguments: + + pProfiles - Pointer to the vector of CProfile objects that have the individual profile data + + Return Value: + + HRESULT + S_OK - On success + E_* - On error + + --*/ + HRESULT + CreateHandleBuffer( + _In_ ProfileList* pProfiles + ) + { + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pProfiles, E_POINTER))) + { + try + { + FreeHandleBuffer(); + + m_cProfiles = static_cast(pProfiles->size()); + if (m_cProfiles > 0) + { + m_phProfiles = new(std::nothrow) HPROFILE[m_cProfiles]; + + if (SUCCEEDED(hr = CHECK_POINTER(m_phProfiles, E_OUTOFMEMORY))) + { + ProfileList::iterator iterProfiles = pProfiles->begin(); + + for (UINT cProfile = 0; + SUCCEEDED(hr) && iterProfiles != pProfiles->end() && cProfile < m_cProfiles; + iterProfiles++, cProfile++) + { + hr = (*iterProfiles)->GetProfileHandle(&m_phProfiles[cProfile]); + } + } + } + } + catch (exception& DBG_ONLY(e)) + { + ERR(e.what()); + hr = E_FAIL; + } + } + + ERR_ON_HR(hr); + return hr; + } + + /*++ + + Routine Name: + + FreeHandleBuffer + + Routine Description: + + Frees up the profile handle buffer + + Arguments: + + None + + Return Value: + + None + + --*/ + VOID + FreeHandleBuffer( + VOID + ) + { + if (m_phProfiles != NULL) + { + delete[] m_phProfiles; + m_phProfiles = NULL; + } + + m_cProfiles = 0; + } + +private: + HPROFILE* m_phProfiles; + + DWORD m_cProfiles; +}; + +/*++ + +Routine Name: + + CTransform::CTransform + +Routine Description: + + CTransform constructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CTransform::CTransform() : + m_hColorTrans(NULL), + m_intents(INTENT_ABSOLUTE_COLORIMETRIC), + m_renderFlags(0), + m_pcstrProfileKeys(NULL), + m_cProfiles(0) +{ +} + +/*++ + +Routine Name: + + CTransform::~CTransform + +Routine Description: + + CTransform destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CTransform::~CTransform() +{ + FreeTransform(); +} + +/*++ + +Routine Name: + + CTransform::CreateTransform + +Routine Description: + + Creates the transform from a vector of CProfile objects + +Arguments: + + pProfiles - Pointer to the vector of CProfile objects that have the individual profile data + intent - Intent flags to be applied when creating transform + renderFlags - Render flags to be applied when creating transform + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CTransform::CreateTransform( + _In_ ProfileList* pProfiles, + _In_ CONST DWORD intent, + _In_ CONST DWORD renderFlags + ) +{ + HRESULT hr = S_OK; + + if (intent <= INTENT_ABSOLUTE_COLORIMETRIC) + { + BOOL bFreeTransform = FALSE; + + if (m_intents != intent) + { + m_intents = intent; + bFreeTransform = TRUE; + } + + if (m_renderFlags != renderFlags) + { + m_renderFlags = renderFlags; + bFreeTransform = TRUE; + } + + if (bFreeTransform) + { + FreeTransform(); + } + } + else + { + hr = E_INVALIDARG; + } + + BOOL bUpdate = FALSE; + + if (SUCCEEDED(hr) && + SUCCEEDED(hr = CHECK_POINTER(pProfiles, E_POINTER)) && + SUCCEEDED(hr = UpdateProfiles(pProfiles, &bUpdate))) + { + try + { + if (bUpdate) + { + HPROFILE* phProfiles = NULL; + DWORD cProfiles = 0; + CProfileList profileList(pProfiles); + + if (SUCCEEDED(hr = profileList.GetProfileData(&phProfiles, &cProfiles))) + { + m_hColorTrans = CreateMultiProfileTransform(phProfiles, + cProfiles, + &m_intents, + 1, + m_renderFlags, + INDEX_DONT_CARE); + + if (m_hColorTrans == NULL) + { + hr = GetLastErrorAsHResult(); + } + } + else + { + hr = E_INVALIDARG; + } + } + } + catch (exception& DBG_ONLY(e)) + { + ERR(e.what()); + hr = E_FAIL; + } + catch (CXDException& e) + { + hr = e; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CTransform::GetTransformHandle + +Routine Description: + + Retrieves the current transform handle + +Arguments: + + phTrans - Pointer to a HTRANSFORM that recieves the transform handle + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CTransform::GetTransformHandle( + _Out_ HTRANSFORM* phTrans + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(phTrans, E_POINTER))) + { + *phTrans = NULL; + + if (SUCCEEDED(hr = CHECK_HANDLE(m_hColorTrans, E_PENDING))) + { + *phTrans = m_hColorTrans; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CTransform::FreeTransform + +Routine Description: + + Free the current transform + +Arguments: + + None + +Return Value: + + None + +--*/ +VOID +CTransform::FreeTransform( + VOID + ) +{ + FreeProfileKeysBuffer(); + if (m_hColorTrans != NULL) + { + DeleteColorTransform(m_hColorTrans); + m_hColorTrans = NULL; + } +} + +/*++ + +Routine Name: + + CTransform::CreateProfileKeysBuffer + +Routine Description: + + Creates a buffer to recieve the keys to the profiles that compse the current + trnasform + +Arguments: + + cProfiles - the count of profiles that compose the transform + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CTransform::CreateProfileKeysBuffer( + _In_ CONST UINT& cProfiles + ) +{ + HRESULT hr = S_OK; + + FreeProfileKeysBuffer(); + + if (cProfiles > 0) + { + m_pcstrProfileKeys = new(std::nothrow) CStringXDW[cProfiles]; + if (SUCCEEDED(hr = CHECK_POINTER(m_pcstrProfileKeys, E_OUTOFMEMORY))) + { + m_cProfiles = cProfiles; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CTransform::FreeProfileKeysBuffer + +Routine Description: + + Frees the profile key buffer + +Arguments: + + None + +Return Value: + + None + +--*/ +VOID +CTransform::FreeProfileKeysBuffer( + VOID + ) +{ + if (m_pcstrProfileKeys != NULL) + { + delete[] m_pcstrProfileKeys; + m_pcstrProfileKeys = NULL; + } + + m_cProfiles = 0; +} + +/*++ + +Routine Name: + + CTransform::UpdateProfiles + +Routine Description: + + Updates the profile list and checks whether the transform needs to be generated + (i.e. is the current transform the same as the requested transform) + +Arguments: + + pProfiles - Pointer to the vector of CProfile objects that have the individual profile data + pbUpdate - Pointer to BOOL that recieves whether the transform requires updating + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CTransform::UpdateProfiles( + _In_ ProfileList* pProfiles, + _Out_ BOOL* pbUpdate + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pProfiles, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pbUpdate, E_POINTER))) + { + *pbUpdate = FALSE; + + try + { + // + // If we already have a transform, a list of profile keys and matching + // number of profiles, check our keys against the incoming list of profiles + // and note if we need to create a new transform + // + CStringXDW* pcstrProfileKeys = NULL; + if (m_hColorTrans != NULL && + m_pcstrProfileKeys != NULL && + m_cProfiles > 0 && + m_cProfiles == static_cast(pProfiles->size())) + { + pcstrProfileKeys = m_pcstrProfileKeys; + ProfileList::iterator iterProfiles = pProfiles->begin(); + + for (; + iterProfiles != pProfiles->end() && !*pbUpdate; + iterProfiles++) + { + if (*(*iterProfiles) != *pcstrProfileKeys++) + { + *pbUpdate = TRUE; + } + } + } + else + { + *pbUpdate = TRUE; + } + + if (*pbUpdate) + { + // + // We need to create a new transform. Free any current transform and cache the keys + // to the profiles that constitute the transform + // + FreeTransform(); + if (SUCCEEDED(hr = CreateProfileKeysBuffer(static_cast(pProfiles->size())))) + { + pcstrProfileKeys = m_pcstrProfileKeys; + ProfileList::iterator iterProfiles = pProfiles->begin(); + + for (; + SUCCEEDED(hr) && iterProfiles != pProfiles->end(); + iterProfiles++, pcstrProfileKeys++) + { + // + // If CreateProfileKeysBuffer succeeds, it fills + // in m_pcstrProfileKeys with pProfiles->size() + // elements. Hence the _Analysis_assume_. + // + _Analysis_assume_(pcstrProfileKeys != NULL); + hr = (*iterProfiles)->GetProfileKey(pcstrProfileKeys); + } + } + } + } + catch (exception& DBG_ONLY(e)) + { + ERR(e.what()); + hr = E_FAIL; + } + } + + ERR_ON_HR(hr); + return hr; +} + diff --git a/print/XPSDrvSmpl/src/filters/color/transform.h b/print/XPSDrvSmpl/src/filters/color/transform.h new file mode 100644 index 00000000..4d3034fd --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/color/transform.h @@ -0,0 +1,83 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + transform.h + +Abstract: + + CTransform class definition. This class creates and manages color transforms providing + limited caching functionality based off the source profile keys. + + +--*/ + +#pragma once + +#include "profile.h" + +typedef vector ProfileList; + +class CTransform +{ +public: + CTransform(); + + ~CTransform(); + + HRESULT + CreateTransform( + _In_ ProfileList* pProfiles, + _In_ CONST DWORD intent, + _In_ CONST DWORD renderFlags + ); + + HRESULT + GetTransformHandle( + _Out_ HTRANSFORM* phTrans + ); + + +private: + VOID + FreeTransform( + VOID + ); + + HRESULT + CreateProfileKeysBuffer( + _In_ CONST UINT& cProfiles + ); + + VOID + FreeProfileKeysBuffer( + VOID + ); + + HRESULT + UpdateProfiles( + _In_ ProfileList* pProfiles, + _Out_ BOOL* pbUpdate + ); + +private: + HTRANSFORM m_hColorTrans; + + DWORD m_intents; + + DWORD m_renderFlags; + + CStringXDW* m_pcstrProfileKeys; + + DWORD m_cProfiles; +}; + diff --git a/print/XPSDrvSmpl/src/filters/color/wcsapiconv.cpp b/print/XPSDrvSmpl/src/filters/color/wcsapiconv.cpp new file mode 100644 index 00000000..b53efb15 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/color/wcsapiconv.cpp @@ -0,0 +1,813 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + wcsapiconv.cpp + +Abstract: + + Implementation of the wrapper to the WCS API's + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "wcsapiconv.h" + +CWCSApiConv g_WCSApiConv; + +/*++ + +Routine Name: + + CWCSApiConv::CWCSApiConv + +Routine Description: + + CWCSApiConv class constructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CWCSApiConv::CWCSApiConv() +{ + m_dllHandle = LoadLibrary(L"mscms.dll"); + + // + // If running on Vista, record the proc address for each WCS API + // + if (m_dllHandle != NULL && + IsVista()) + { + m_WcsAssociateColorProfileWithDevice = GetProcAddress(m_dllHandle,"WcsAssociateColorProfileWithDevice"); + m_WcsDisassociateColorProfileFromDevice = GetProcAddress(m_dllHandle, "WcsDisassociateColorProfileFromDevice"); + m_WcsEnumColorProfilesSize = GetProcAddress(m_dllHandle, "WcsEnumColorProfilesSize"); + m_WcsGetDefaultColorProfileSize = GetProcAddress(m_dllHandle, "WcsGetDefaultColorProfileSize"); + m_WcsGetDefaultColorProfile = GetProcAddress(m_dllHandle, "WcsGetDefaultColorProfile"); + m_WcsSetDefaultColorProfile = GetProcAddress(m_dllHandle, "WcsSetDefaultColorProfile"); + m_WcsSetDefaultRenderingIntent = GetProcAddress(m_dllHandle, "WcsSetDefaultRenderingIntent"); + m_WcsGetUsePerUserProfiles = GetProcAddress(m_dllHandle, "WcsGetUsePerUserProfiles"); + m_WcsSetUsePerUserProfiles = GetProcAddress(m_dllHandle, "WcsSetUsePerUserProfiles"); + m_WcsTranslateColors = GetProcAddress(m_dllHandle, "WcsTranslateColors"); + m_WcsCheckColors = GetProcAddress(m_dllHandle, "WcsCheckColors"); + m_WcsOpenColorProfileA = GetProcAddress(m_dllHandle, "WcsOpenColorProfileA"); + m_WcsOpenColorProfileW = GetProcAddress(m_dllHandle, "WcsOpenColorProfileW"); + m_WcsCreateIccProfile = GetProcAddress(m_dllHandle, "WcsCreateIccProfile"); + + ASSERTMSG(m_WcsAssociateColorProfileWithDevice != NULL && + m_WcsDisassociateColorProfileFromDevice != NULL && + m_WcsEnumColorProfilesSize != NULL && + m_WcsGetDefaultColorProfileSize != NULL && + m_WcsGetDefaultColorProfile != NULL && + m_WcsSetDefaultColorProfile != NULL && + m_WcsSetDefaultRenderingIntent != NULL && + m_WcsGetUsePerUserProfiles != NULL && + m_WcsSetUsePerUserProfiles != NULL && + m_WcsTranslateColors != NULL && + m_WcsCheckColors != NULL && + m_WcsOpenColorProfileA != NULL && + m_WcsOpenColorProfileW != NULL && + m_WcsCreateIccProfile != NULL, + "Failed to load WCS APIs correctly.\n"); + } +} + +/*++ + +Routine Name: + + CWCSApiConv::~CWCSApiConv + +Routine Description: + + CWCSApiConv class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CWCSApiConv::~CWCSApiConv() +{ + FreeLibrary(m_dllHandle); +} + +/*++ + +Routine Name: + + CWCSApiConv::WcsAssociateColorProfileWithDevice + +Routine Description: + + +Arguments: + + scope - Profile management scope for this operation, which could be system wide or for current user. + + pProfileName - Points to the file name of the profile to associate. + + pDeviceName - Points to the name of the device to associate. + +Return Value: + + BOOL + If this function succeeds, the return value is TRUE. + +--*/ +BOOL +CWCSApiConv::WcsAssociateColorProfileWithDevice( + _In_ WCS_PROFILE_MANAGEMENT_SCOPE scope, + _In_ PCWSTR pProfileName, + _In_ PCWSTR pDeviceName + ) +{ + BOOL bResult = FALSE; + + if (m_WcsAssociateColorProfileWithDevice != NULL) + { + bResult = m_WcsAssociateColorProfileWithDevice.GetFunc()(scope, pProfileName, pDeviceName); + } + + return bResult; +} + +/*++ + +Routine Name: + + CWCSApiConv::WcsDisassociateColorProfileFromDevice + +Routine Description: + + +Arguments: + + scope - Profile management scope for this operation, which could be system wide or for current user. + + pProfileName - Pointer to the file name of the profile to disassociate. + + pDeviceName - Pointer to the name of the device to disassociate. + +Return Value: + + BOOL + If this function succeeds, the return value is TRUE. + +--*/ +BOOL +CWCSApiConv::WcsDisassociateColorProfileFromDevice( + _In_ WCS_PROFILE_MANAGEMENT_SCOPE scope, + _In_ PCWSTR pProfileName, + _In_ PCWSTR pDeviceName + ) +{ + BOOL bResult = FALSE; + + if (m_WcsDisassociateColorProfileFromDevice != NULL) + { + bResult = m_WcsDisassociateColorProfileFromDevice.GetFunc()(scope, pProfileName, pDeviceName); + } + + return bResult; +} + +/*++ + +Routine Name: + + CWCSApiConv::WcsEnumColorProfilesSize + +Routine Description: + + +Arguments: + + scope - management scope for this operation, which could be system wide or for current user. + + pEnumRecord - Pointer to the structure specifying the enumeration criteria. + + pdwSize - Returns the size in bytes required for the buffer to receive the set of profile names in WcsEnumColorProfiles. + +Return Value: + + BOOL + If this function succeeds, the return value is TRUE. + +--*/ +_Success_(return) +BOOL +#pragma warning(suppress: 6001 6101) // PREFast can't see through templated forwarder function call +CWCSApiConv::WcsEnumColorProfilesSize( + _In_ WCS_PROFILE_MANAGEMENT_SCOPE scope, + _In_ PENUMTYPEW pEnumRecord, + _Out_ PDWORD pdwSize + ) +{ + BOOL bResult = FALSE; + + if (m_WcsEnumColorProfilesSize != NULL) + { + bResult = m_WcsEnumColorProfilesSize.GetFunc()(scope, pEnumRecord, pdwSize); + } + + return bResult; +} + +/*++ + +Routine Name: + + CWCSApiConv::WcsGetDefaultColorProfileSize + +Routine Description: + + +Arguments: + + scope - Profile management scope for this operation, which could be system wide or for current user. + + pDeviceName - Pointer to the name of the device to get the default profile for. NULL implies device-independent default. + + cptColorProfileType - Specifies the color profile type value. + + cpstColorProfileSubType - Specifies the color profile subtype value. + + dwProfileID - Specifies the ID of the color space that the profile represents. + + pcbProfileName - the size in bytes for receiving the default profile in WcsGetDefaultColorProfile. + +Return Value: + + BOOL + If this function succeeds, the return value is TRUE. + +--*/ +_Success_(return) +BOOL +#pragma warning(suppress: 6001 6101) // PREFast can't see through templated forwarder function call +CWCSApiConv::WcsGetDefaultColorProfileSize( + _In_ WCS_PROFILE_MANAGEMENT_SCOPE scope, + _In_opt_ PCWSTR pDeviceName, + _In_ COLORPROFILETYPE cptColorProfileType, + _In_ COLORPROFILESUBTYPE cpstColorProfileSubType, + _In_ DWORD dwProfileID, + _Out_ PDWORD pcbProfileName + ) +{ + BOOL bResult = FALSE; + + if (m_WcsGetDefaultColorProfileSize != NULL) + { + bResult = m_WcsGetDefaultColorProfileSize.GetFunc()(scope, + pDeviceName, + cptColorProfileType, + cpstColorProfileSubType, + dwProfileID, + pcbProfileName); + } + + return bResult; +} + +/*++ + +Routine Name: + + CWCSApiConv::WcsGetDefaultColorProfile + +Routine Description: + + +Arguments: + + scope - Profile management scope for this operation, which could be system wide or for current user. + + pDeviceName - Pointer to the name of the device to get the default profile for. NULL implies device-independent default. + + cptColorProfileType - Specifies the color profile type value. + + cpstColorProfileSubType - Specifies the color profile subtype value. + + dwProfileID - Specifies the ID of the color space that the profile represents. + + cbProfileName - The size in bytes of the buffer pointed to by pProfileName. + + pProfileName - Pointer to the buffer in which the name of the profile is to be placed. + +Return Value: + + BOOL + If this function succeeds, the return value is TRUE. + +--*/ +#pragma warning(suppress: 6001 6054 6101) // PREFast can't see through templated forwarder function call +_Success_(return) +BOOL +CWCSApiConv::WcsGetDefaultColorProfile( + _In_ WCS_PROFILE_MANAGEMENT_SCOPE scope, + _In_opt_ PCWSTR pDeviceName, + _In_ COLORPROFILETYPE cptColorProfileType, + _In_ COLORPROFILESUBTYPE cpstColorProfileSubType, + _In_ DWORD dwProfileID, + _In_ DWORD cbProfileName, + _Out_writes_bytes_(cbProfileName) LPWSTR pProfileName + ) +{ + BOOL bResult = FALSE; + + if (m_WcsGetDefaultColorProfile != NULL) + { + bResult = m_WcsGetDefaultColorProfile.GetFunc()(scope, + pDeviceName, + cptColorProfileType, + cpstColorProfileSubType, + dwProfileID, + cbProfileName, + pProfileName); + } + + return bResult; +} + +/*++ + +Routine Name: + + CWCSApiConv::WcsSetDefaultColorProfile + +Routine Description: + + +Arguments: + + scope - Profile management scope for this operation, which could be system wide or for current user. + + pDeviceName - Pointer to the name of the device to set the default profile for. NULL implies device-independent default. + + cptColorProfileType - Specifies the color profile type value. + + cpstColorProfileSubType - Specifies the color profile subtype value. + + dwProfileID - Specifies the ID of the color space that the profile represents. + + pProfileName - Pointer to the buffer in which contains the name of the profile. + +Return Value: + + BOOL + If this function succeeds, the return value is TRUE. + +--*/ +BOOL +CWCSApiConv::WcsSetDefaultColorProfile( + _In_ WCS_PROFILE_MANAGEMENT_SCOPE scope, + _In_opt_ PCWSTR pDeviceName, + _In_ COLORPROFILETYPE cptColorProfileType, + _In_ COLORPROFILESUBTYPE cpstColorProfileSubType, + _In_ DWORD dwProfileID, + _In_opt_ LPCWSTR pProfileName + ) +{ + BOOL bResult = FALSE; + + if (m_WcsSetDefaultColorProfile != NULL) + { + bResult = m_WcsSetDefaultColorProfile.GetFunc()(scope, + pDeviceName, + cptColorProfileType, + cpstColorProfileSubType, + dwProfileID, + pProfileName); + } + + return bResult; +} + +/*++ + +Routine Name: + + CWCSApiConv::WcsSetDefaultRenderingIntent + +Routine Description: + + +Arguments: + + scope - management scope for this operation, which could be system wide or for current user. + + dwRenderingIntent - The rendering intent to set. + +Return Value: + + BOOL + If this function succeeds, the return value is TRUE. + +--*/ +BOOL +CWCSApiConv::WcsSetDefaultRenderingIntent( + _In_ WCS_PROFILE_MANAGEMENT_SCOPE scope, + _In_ DWORD dwRenderingIntent + ) +{ + BOOL bResult = FALSE; + + if (m_WcsSetDefaultRenderingIntent != NULL) + { + bResult = m_WcsSetDefaultRenderingIntent.GetFunc()(scope, dwRenderingIntent); + } + + return bResult; +} + +/*++ + +Routine Name: + + CWCSApiConv::WcsGetUsePerUserProfiles + +Routine Description: + + +Arguments: + + pDeviceName - The friendly name of the device. + + dwDeviceClass - The class of the device: CLASS_SCANNER for a capture device, + CLASS_MONITOR for a display device, or CLASS_PRINTER for a printer. + + pUsePerUserProfiles - Pointer to a location to receive the result. + This location receives TRUE if the user has chosen to use a + per-user profile association list for the specified device; otherwise FALSE. + +Return Value: + + BOOL + If this function succeeds, the return value is TRUE. + +--*/ +_Success_(return) +BOOL +#pragma warning(suppress: 6001 6101) // PREFast can't see through templated forwarder function call +CWCSApiConv::WcsGetUsePerUserProfiles( + _In_ LPCWSTR pDeviceName, + _In_ DWORD dwDeviceClass, + _Out_ PBOOL pUsePerUserProfiles + ) +{ + BOOL bResult = FALSE; + + if (m_WcsGetUsePerUserProfiles != NULL) + { + bResult = m_WcsGetUsePerUserProfiles.GetFunc()(pDeviceName, dwDeviceClass, pUsePerUserProfiles); + } + + return bResult; +} + +/*++ + +Routine Name: + + CWCSApiConv::WcsSetUsePerUserProfiles + +Routine Description: + + +Arguments: + + pDeviceName - The friendly name of the device. + + dwDeviceClass - The class of the device: CLASS_SCANNER for a capture device, + CLASS_MONITOR for a display device, or CLASS_PRINTER for a printer. + + usePerUserProfiles - TRUE is the user wishes to use a per-user profile association + list for the specified device; otherwise FALSE. + +Return Value: + + BOOL + If this function succeeds, the return value is TRUE. + +--*/ +BOOL +CWCSApiConv::WcsSetUsePerUserProfiles( + _In_ LPCWSTR pDeviceName, + _In_ DWORD dwDeviceClass, + _In_ BOOL usePerUserProfiles + ) +{ + BOOL bResult = FALSE; + + if (m_WcsSetUsePerUserProfiles != NULL) + { + bResult = m_WcsSetUsePerUserProfiles.GetFunc()(pDeviceName, dwDeviceClass, usePerUserProfiles); + } + + return bResult; +} + +/*++ + +Routine Name: + + CWCSApiConv::WcsTranslateColors + +Routine Description: + + +Arguments: + + hColorTransform - Identifies the WCS color transform to use. + + nColors - Contains the number of elements in the arrays pointed to by pInputData and pOutputData. + + nInputChannels - Contains the number of channels per element in the array pointed to by pInputData + + cdtInput - Specifies the input COLORDATATYPTE. + + cbInput - Contains buffer size of pInputData. + + pInputData - Pointer to array of input colors. + + nOutputChannels - Contains the number of channels per element in the array pointed to by pOutputData. + + cdtOutput - Specifies the output COLORDATATYPTE. + + cbOutput - Contains buffer size of pOutputData. + + pOutputData - Pointer to array of output colors. + +Return Value: + + BOOL + If this function succeeds, the return value is TRUE. + +--*/ +BOOL +CWCSApiConv::WcsTranslateColors( + _In_ HTRANSFORM hColorTransform, + _In_ DWORD nColors, + _In_ DWORD nInputChannels, + _In_ COLORDATATYPE cdtInput, + _In_ DWORD cbInput, + _In_reads_bytes_(cbInput) PVOID pInputData, + _In_ DWORD nOutputChannels, + _In_ COLORDATATYPE cdtOutput, + _In_ DWORD cbOutput, + _Out_writes_bytes_(cbOutput) PVOID pOutputData + ) +{ + BOOL bResult = FALSE; + + if (m_WcsTranslateColors != NULL) + { + bResult = m_WcsTranslateColors.GetFunc()(hColorTransform, + nColors, + nInputChannels, + cdtInput, + cbInput, + pInputData, + nOutputChannels, + cdtOutput, + cbOutput, + pOutputData); + } + + return bResult; +} + +/*++ + +Routine Name: + + CWCSApiConv::WCSCheckColors + +Routine Description: + + +Arguments: + + hColorTransform - Identifies the WCS color transform to use. + + nColors - Contains the number of elements in the arrays pointed to by pInputData and pResult. + + nInputChannels - Contains the number of channels per element in the array pointed to by pInputData + + cdtInput - Specifies the input COLORDATATYPTE. + + cbInput - Contains buffer size of pInputData. + + pInputData - Pointer to array of input colors. + + pResult - Pointer to array of nColor results of the test. + +Return Value: + + BOOL + If this function succeeds, the return value is TRUE. + +--*/ +BOOL +CWCSApiConv::WCSCheckColors( + _In_ HTRANSFORM hColorTransform, + _In_ DWORD nColors, + _In_ DWORD nInputChannels, + _In_ COLORDATATYPE cdtInput, + _In_ DWORD cbInput, + _In_reads_bytes_(cbInput) PVOID pInputData, + _Out_writes_bytes_(nColors)PBYTE pResult +) +{ + BOOL bResult = FALSE; + + if (m_WcsCheckColors != NULL) + { + bResult = m_WcsCheckColors.GetFunc()(hColorTransform, + nColors, + nInputChannels, + cdtInput, + cbInput, + pInputData, + pResult); + } + + return bResult; +} + +/*++ + +Routine Name: + + CWCSApiConv::WcsOpenColorProfileA + +Routine Description: + + +Arguments: + + pCDMPProfile - Pointer to a WCS DMP or an ICC color profile structure specifying the profile. + + pCAMPProfile - Pointer to a WCS CAMP color profile structure specifying the profile. + If this parameter is NULL, then the standard default CAMP is used. + + pGMMPProfile - Pointer to a WCS GMMP color profile structure specifying the profile. + If this parameter is NULL, then the standard default GMMP is used. + + dwDesireAccess - Specifies how to access the given profile. This parameter must take one the following constant values. + + dwShareMode - Specifies how the profile should be shared, if the profile is contained in a file. + A value of zero prevents the profile from being shared at all. + + dwCreationMode - Specifies which actions to take on the profile while opening it, if it is contained in a file. + + +Return Value: + + HPROFILE - Handle to the opened color profile + +--*/ +HPROFILE +CWCSApiConv::WcsOpenColorProfileA( + _In_ PPROFILE pCDMPProfile, + _In_opt_ PPROFILE pCAMPProfile, + _In_opt_ PPROFILE pGMMPProfile, + _In_ DWORD dwDesireAccess, + _In_ DWORD dwShareMode, + _In_ DWORD dwCreationMode, + _In_ DWORD dwFlags + ) +{ + HPROFILE hProfile = NULL; + + if (m_WcsOpenColorProfileA != NULL) + { + hProfile = m_WcsOpenColorProfileA.GetFunc()(pCDMPProfile, + pCAMPProfile, + pGMMPProfile, + dwDesireAccess, + dwShareMode, + dwCreationMode, + dwFlags); + } + + return hProfile; +} + +/*++ + +Routine Name: + + CWCSApiConv::WcsOpenColorProfileW + +Routine Description: + + +Arguments: + + pCDMPProfile - Pointer to a WCS DMP or an ICC color profile structure specifying the profile. + + pCAMPProfile - Pointer to a WCS CAMP color profile structure specifying the profile. + If this parameter is NULL, then the standard default CAMP is used. + + pGMMPProfile - Pointer to a WCS GMMP color profile structure specifying the profile. + If this parameter is NULL, then the standard default GMMP is used. + + dwDesireAccess - Specifies how to access the given profile. This parameter must take one the following constant values. + + dwShareMode - Specifies how the profile should be shared, if the profile is contained in a file. + A value of zero prevents the profile from being shared at all. + + dwCreationMode - Specifies which actions to take on the profile while opening it, if it is contained in a file. + + +Return Value: + + HPROFILE - Handle to the opened color profile + +--*/ +HPROFILE +CWCSApiConv::WcsOpenColorProfileW( + _In_ PPROFILE pCDMPProfile, + _In_opt_ PPROFILE pCAMPProfile, + _In_opt_ PPROFILE pGMMPProfile, + _In_ DWORD dwDesireAccess, + _In_ DWORD dwShareMode, + _In_ DWORD dwCreationMode, + _In_ DWORD dwFlags + ) +{ + HPROFILE hProfile = NULL; + + if (m_WcsOpenColorProfileW != NULL) + { + hProfile = m_WcsOpenColorProfileW.GetFunc()(pCDMPProfile, + pCAMPProfile, + pGMMPProfile, + dwDesireAccess, + dwShareMode, + dwCreationMode, + dwFlags); + } + + return hProfile; +} + +/*++ + +Routine Name: + + CWCSApiConv::WcsCreateIccProfile + +Routine Description: + + +Arguments: + + hWcsProfile - handle to a WCS profile which contains a combination + of a WCS DMP, and optionally a CAMP and/or GMMP. + + dwOptions - Options flag values from WCS_DEFAULT and WCS_ICCONLY + +Return Value: + + HPROFILE - Handle to the newly created color profile + +--*/ +HPROFILE +CWCSApiConv::WcsCreateIccProfile( + _In_ HPROFILE hWcsProfile, + _In_ DWORD dwOptions + ) +{ + HPROFILE hProfile = NULL; + + if (m_WcsCreateIccProfile != NULL) + { + hProfile = m_WcsCreateIccProfile.GetFunc()(hWcsProfile, dwOptions); + } + + return hProfile; +} + diff --git a/print/XPSDrvSmpl/src/filters/color/wcsapiconv.h b/print/XPSDrvSmpl/src/filters/color/wcsapiconv.h new file mode 100644 index 00000000..1e63cd6a --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/color/wcsapiconv.h @@ -0,0 +1,280 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + wcsapiconv.h + +Abstract: + + Provides a wrapper to the WCS API's + +--*/ + +#pragma once + +class CWCSApiConv; +extern CWCSApiConv g_WCSApiConv; + +typedef BOOL (CALLBACK* WCSASSOCIATECOLORPROFILEWITHDEVICE)(WCS_PROFILE_MANAGEMENT_SCOPE, PCWSTR, PCWSTR); +typedef BOOL (CALLBACK* WCSDISASSOCIATECOLORPROFILEFROMDEVICE)(WCS_PROFILE_MANAGEMENT_SCOPE, PCWSTR, PCWSTR); +typedef BOOL (CALLBACK* WCSENUMCOLORPROFILESSIZE)(WCS_PROFILE_MANAGEMENT_SCOPE, PENUMTYPEW, PDWORD); +typedef BOOL (CALLBACK* WCSGETDEFAULTCOLORPROFILESIZE)(WCS_PROFILE_MANAGEMENT_SCOPE, PCWSTR, COLORPROFILETYPE, COLORPROFILESUBTYPE, DWORD, PDWORD); +typedef BOOL (CALLBACK* WCSGETDEFAULTCOLORPROFILE)(WCS_PROFILE_MANAGEMENT_SCOPE, PCWSTR, COLORPROFILETYPE, COLORPROFILESUBTYPE, DWORD, DWORD, LPWSTR); +typedef BOOL (CALLBACK* WCSSETDEFAULTCOLORPROFILE)(WCS_PROFILE_MANAGEMENT_SCOPE, PCWSTR, COLORPROFILETYPE, COLORPROFILESUBTYPE, DWORD, LPCWSTR); +typedef BOOL (CALLBACK* WCSSETDEFAULTRENDERINGINTENT)(WCS_PROFILE_MANAGEMENT_SCOPE, DWORD); +typedef BOOL (CALLBACK* WCSGETUSEPERUSERPROFILES)(LPCWSTR, DWORD, PBOOL); +typedef BOOL (CALLBACK* WCSSETUSEPERUSERPROFILES)(LPCWSTR, DWORD, BOOL); +typedef BOOL (CALLBACK* WCSTRANSLATECOLORS)(HTRANSFORM, DWORD, DWORD, COLORDATATYPE, DWORD, PVOID, DWORD, COLORDATATYPE, DWORD, PVOID); +typedef BOOL (CALLBACK* WCSCHECKCOLORS)(HTRANSFORM, DWORD, DWORD, COLORDATATYPE, DWORD, PVOID, PBYTE); +typedef HPROFILE (CALLBACK* WCSOPENCOLORPROFILE)(PPROFILE, PPROFILE, PPROFILE, DWORD, DWORD, DWORD, DWORD); +typedef HPROFILE (CALLBACK* WCSCREATEICCPROFILE)(HPROFILE, DWORD); + +#define WcsAssociateColorProfileWithDeviceXD g_WCSApiConv.WcsAssociateColorProfileWithDevice +#define WcsDisassociateColorProfileFromDeviceXD g_WCSApiConv.WcsDisassociateColorProfileFromDevice +#define WcsEnumColorProfilesSizeXD g_WCSApiConv.WcsEnumColorProfilesSize +#define WcsGetDefaultColorProfileSizeXD g_WCSApiConv.WcsGetDefaultColorProfileSize +#define WcsGetDefaultColorProfileXD g_WCSApiConv.WcsGetDefaultColorProfile +#define WcsSetDefaultColorProfileXD g_WCSApiConv.WcsSetDefaultColorProfile +#define WcsSetDefaultRenderingIntentXD g_WCSApiConv.WcsSetDefaultRenderingIntent +#define WcsGetUsePerUserProfilesXD g_WCSApiConv.WcsGetUsePerUserProfiles +#define WcsSetUsePerUserProfilesXD g_WCSApiConv.WcsSetUsePerUserProfiles +#define WcsTranslateColorsXD g_WCSApiConv.WcsTranslateColors +#define WCSCheckColorsXD g_WCSApiConv.WCSCheckColors +#define WcsOpenColorProfileWXD g_WCSApiConv.WcsOpenColorProfileW +#define WcsOpenColorProfileAXD g_WCSApiConv.WcsOpenColorProfileA +#define WcsCreateIccProfileXD g_WCSApiConv.WcsCreateIccProfile + +#ifdef _UNICODE +#define WcsOpenColorProfileXD WcsOpenColorProfileWXD +#else +#define WcsOpenColorProfileXD WcsOpenColorProfileAXD +#endif + +template +class CEncodedFuncPtr +{ +public: + CEncodedFuncPtr() : + m_pFunc(NULL) + { + } + + ~CEncodedFuncPtr(){} + + CEncodedFuncPtr<_T>& + operator=( + _In_ FARPROC pFunc + ) + { + m_pFunc = EncodePointer(pFunc); + return *this; + } + + BOOL + operator==( + _In_opt_ PVOID pv + ) const + { + return m_pFunc == pv; + } + + BOOL + operator!=( + _In_opt_ PVOID pv + ) const + { + return !operator==(pv); + } + + _T + GetFunc( + VOID + ) + { + return reinterpret_cast<_T>(DecodePointer(m_pFunc)); + } + +private: + __field_encoded_pointer PVOID m_pFunc; +}; + +class CWCSApiConv +{ +public: + CWCSApiConv(); + + ~CWCSApiConv(); + + BOOL + WcsAssociateColorProfileWithDevice( + _In_ WCS_PROFILE_MANAGEMENT_SCOPE scope, + _In_ PCWSTR pProfileName, + _In_ PCWSTR pDeviceName + ); + + BOOL + WcsDisassociateColorProfileFromDevice( + _In_ WCS_PROFILE_MANAGEMENT_SCOPE scope, + _In_ PCWSTR pProfileName, + _In_ PCWSTR pDeviceName + ); + + _Success_(return) + BOOL + WcsEnumColorProfilesSize( + _In_ WCS_PROFILE_MANAGEMENT_SCOPE scope, + _In_ PENUMTYPEW pEnumRecord, + _Out_ PDWORD pdwSize + ); + + _Success_(return) + BOOL + WcsGetDefaultColorProfileSize( + _In_ WCS_PROFILE_MANAGEMENT_SCOPE scope, + _In_opt_ PCWSTR pDeviceName, + _In_ COLORPROFILETYPE cptColorProfileType, + _In_ COLORPROFILESUBTYPE cpstColorProfileSubType, + _In_ DWORD dwProfileID, + _Out_ PDWORD pcbProfileName + ); + + _Success_(return) + BOOL + WcsGetDefaultColorProfile( + _In_ WCS_PROFILE_MANAGEMENT_SCOPE scope, + _In_opt_ PCWSTR pDeviceName, + _In_ COLORPROFILETYPE cptColorProfileType, + _In_ COLORPROFILESUBTYPE cpstColorProfileSubType, + _In_ DWORD dwProfileID, + _In_ DWORD cbProfileName, + _Out_writes_bytes_(cbProfileName) LPWSTR pProfileName + ); + + BOOL + WcsSetDefaultColorProfile( + _In_ WCS_PROFILE_MANAGEMENT_SCOPE scope, + _In_opt_ PCWSTR pDeviceName, + _In_ COLORPROFILETYPE cptColorProfileType, + _In_ COLORPROFILESUBTYPE cpstColorProfileSubType, + _In_ DWORD dwProfileID, + _In_opt_ LPCWSTR pProfileName + ); + + BOOL + WcsSetDefaultRenderingIntent( + _In_ WCS_PROFILE_MANAGEMENT_SCOPE scope, + _In_ DWORD dwRenderingIntent + ); + + _Success_(return) + BOOL + WcsGetUsePerUserProfiles( + _In_ LPCWSTR pDeviceName, + _In_ DWORD dwDeviceClass, + _Out_ PBOOL pUsePerUserProfiles + ); + + BOOL + WcsSetUsePerUserProfiles( + _In_ LPCWSTR pDeviceName, + _In_ DWORD dwDeviceClass, + _In_ BOOL usePerUserProfiles + ); + + BOOL + WcsTranslateColors( + _In_ HTRANSFORM hColorTransform, + _In_ DWORD nColors, + _In_ DWORD nInputChannels, + _In_ COLORDATATYPE cdtInput, + _In_ DWORD cbInput, + _In_reads_bytes_(cbInput) PVOID pInputData, + _In_ DWORD nOutputChannels, + _In_ COLORDATATYPE cdtOutput, + _In_ DWORD cbOutput, + _Out_writes_bytes_(cbOutput)PVOID pOutputData + ); + + BOOL + WCSCheckColors( + _In_ HTRANSFORM hColorTransform, + _In_ DWORD nColors, + _In_ DWORD nInputChannels, + _In_ COLORDATATYPE cdtInput, + _In_ DWORD cbInput, + _In_reads_bytes_(cbInput) PVOID pInputData, + _Out_writes_bytes_(nColors)PBYTE pResult + ); + + HPROFILE WINAPI + WcsOpenColorProfileA( + _In_ PPROFILE pCDMPProfile, + _In_opt_ PPROFILE pCAMPProfile, + _In_opt_ PPROFILE pGMMPProfile, + _In_ DWORD dwDesireAccess, + _In_ DWORD dwShareMode, + _In_ DWORD dwCreationMode, + _In_ DWORD dwFlags + ); + + HPROFILE WINAPI + WcsOpenColorProfileW( + _In_ PPROFILE pCDMPProfile, + _In_opt_ PPROFILE pCAMPProfile, + _In_opt_ PPROFILE pGMMPProfile, + _In_ DWORD dwDesireAccess, + _In_ DWORD dwShareMode, + _In_ DWORD dwCreationMode, + _In_ DWORD dwFlags + ); + + HPROFILE + WcsCreateIccProfile( + _In_ HPROFILE hWcsProfile, + _In_ DWORD dwOptions + ); + +private: + HINSTANCE m_dllHandle; + + // + // WCS API + // + CEncodedFuncPtr m_WcsAssociateColorProfileWithDevice; + + CEncodedFuncPtr m_WcsDisassociateColorProfileFromDevice; + + CEncodedFuncPtr m_WcsEnumColorProfilesSize; + + CEncodedFuncPtr m_WcsGetDefaultColorProfileSize; + + CEncodedFuncPtr m_WcsGetDefaultColorProfile; + + CEncodedFuncPtr m_WcsSetDefaultColorProfile; + + CEncodedFuncPtr m_WcsSetDefaultRenderingIntent; + + CEncodedFuncPtr m_WcsGetUsePerUserProfiles; + + CEncodedFuncPtr m_WcsSetUsePerUserProfiles; + + CEncodedFuncPtr m_WcsTranslateColors; + + CEncodedFuncPtr m_WcsCheckColors; + + CEncodedFuncPtr m_WcsOpenColorProfileA; + + CEncodedFuncPtr m_WcsOpenColorProfileW; + + CEncodedFuncPtr m_WcsCreateIccProfile; +}; + diff --git a/print/XPSDrvSmpl/src/filters/color/wictobmscn.cpp b/print/XPSDrvSmpl/src/filters/color/wictobmscn.cpp new file mode 100644 index 00000000..ca6058aa --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/color/wictobmscn.cpp @@ -0,0 +1,751 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + wictobmscn.cpp + +Abstract: + + WIC pixel format to BMFORMAT conversion class implementation. This class provides methods + for converting between a source WIC scanline to a target destination BMFORMAT scanline. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "wictobmscn.h" + +/*++ + +Routine Name: + + CWICToBMFormatScan::CWICToBMFormatScan + +Routine Description: + + CWICToBMFormatScan constructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CWICToBMFormatScan::CWICToBMFormatScan() : + m_pScanBuffer(NULL), + m_cbScanBuffer(0), + m_cWidth(0), + m_pData(NULL), + m_cbData(0), + m_bInitialized(FALSE) +{ +} + +/*++ + +Routine Name: + + CWICToBMFormatScan::~CWICToBMFormatScan + +Routine Description: + + CWICToBMFormatScan destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CWICToBMFormatScan::~CWICToBMFormatScan() +{ + FreeScanBuffer(); +} + +/*++ + +Routine Name: + + CWICToBMFormatScan::Initialize + +Routine Description: + + Initializes the WIC to BMFORMAT transform data from the WICToBMFORMAT structure + +Arguments: + + WICToBM - Structure containing WIC pixel format to BMFORMAT conversion information + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CWICToBMFormatScan::Initialize( + _In_ CONST WICToBMFORMAT& WICToBM + ) +{ + HRESULT hr = S_OK; + + m_convData = WICToBM; + + if (m_convData.m_pixFormTarget <= kWICPixelFormatMin || + m_convData.m_pixFormTarget >= kWICPixelFormatMax || + m_convData.m_bmFormTarget < kICMPixelFormatMin || + m_convData.m_bmFormTarget >= kICMPixelFormatMax) + { + hr = E_INVALIDARG; + } + + if (SUCCEEDED(hr) && + !IsVista()) + { + // + // When processing color data down-level from Vista, we cannot use fixed or float + // BMFORMAT types. In these circumstances we need to convert to a 16 bpc equivalent, + // then back again. + // + if (m_convData.m_bmFormTarget == kBM_32b_scRGB || + m_convData.m_bmFormTarget == kBM_32b_scARGB || + m_convData.m_bmFormTarget == kBM_S2DOT13FIXED_scRGB || + m_convData.m_bmFormTarget == kBM_S2DOT13FIXED_scARGB) + { + m_convData.m_bNeedsScanBuffer = TRUE; + m_convData.m_bmFormTarget = kBM_16b_RGB; + } + } + + if (SUCCEEDED(hr)) + { + m_bInitialized = TRUE; + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CWICToBMFormatScan::SetData + +Routine Description: + + Set the current WIC data. This method takes the WIC scanline data and + applies any necessary conversion to achieve the required BMFORMAT + +Arguments: + + bIsSrc - Indicates if this is a source scanline (i.e. is the conversion required as the scanline is input) + pWicPxData - Pointer to the WIC data + cbWicPxData - Count of bytes in the WIC data buffer + cWidth - Count of pixels inthe scanline + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CWICToBMFormatScan::SetData( + _In_ CONST BOOL bIsSrc, + _In_reads_bytes_(cbWicPxData) PBYTE pWicPxData, + _In_ CONST UINT cbWicPxData, + _In_ CONST UINT cWidth + ) +{ + HRESULT hr = m_bInitialized ? S_OK : E_PENDING; + + COLORDATATYPE srcColType = COLOR_BYTE; + EICMPixelFormat eICMFormSrc = kBM_RGBTRIPLETS; + + COLORDATATYPE dstColType = COLOR_BYTE; + EICMPixelFormat eICMFormDst = kBM_RGBTRIPLETS; + + // + // Validate input + // + if (SUCCEEDED(hr) && + SUCCEEDED(hr = CHECK_POINTER(pWicPxData, E_POINTER))) + { + if (m_convData.m_pixFormTarget >= kWICPixelFormatMin && + m_convData.m_pixFormTarget < kWICPixelFormatMax) + { + // + // Set up the destination and source formats + // + eICMFormSrc = g_lutWICToBMFormat[m_convData.m_pixFormTarget].m_bmFormTarget; + srcColType = g_lutWICToBMFormat[m_convData.m_pixFormTarget].m_colDataType; + + if (m_convData.m_bmFormTarget < kICMPixelFormatMax && + m_convData.m_bmFormTarget >= kICMPixelFormatMin) + { + dstColType = g_lutBMFormatData[m_convData.m_bmFormTarget].m_colDataType; + eICMFormDst = m_convData.m_bmFormTarget; + } + else + { + hr = E_FAIL; + } + } + else + { + hr = E_FAIL; + } + } + + // + // Validate source and destination formats + // + if (SUCCEEDED(hr)) + { + if (eICMFormSrc < kICMPixelFormatMin || + eICMFormSrc >= kICMPixelFormatMax || + eICMFormDst < kICMPixelFormatMin || + eICMFormDst >= kICMPixelFormatMax) + { + RIP("Invalid pixel format.\n"); + + hr = E_FAIL; + } + else if (srcColType < COLOR_BYTE || + srcColType > COLOR_S2DOT13FIXED || + dstColType < COLOR_BYTE || + dstColType > COLOR_S2DOT13FIXED) + { + RIP("Invalid color data type.\n"); + + hr = E_FAIL; + } + } + + if (SUCCEEDED(hr)) + { + m_cWidth = cWidth; + if (m_convData.m_bNeedsScanBuffer) + { + // + // We need to convert in one way or another - create a buffer to + // hold the intermediate scanline data + // + if (SUCCEEDED(hr) && + SUCCEEDED(hr = CreateScanBuffer(m_cWidth, + g_lutColorDataSize[dstColType], + g_lutBMFormatData[eICMFormDst].m_cChannels))) + { + if (bIsSrc) + { + // + // We need to initialise the buffer from the WIC buffer passed in. Here we + // are doing one of two things: + // + // 1. Copying data directly as we have parity between the WIC and + // ICM pixel formats + // 2. Convert from the WIC format to the ICM format and copy. + // + + // + // Set up the source and destination pointers + // + PBYTE pSrc = pWicPxData; + UINT cSrcChannels = g_lutWICToBMFormat[m_convData.m_pixFormTarget].m_cChannels; + size_t cbSrcBytesPerPixel = g_lutColorDataSize[srcColType] * cSrcChannels; + + PBYTE pDst = m_pScanBuffer; + UINT cDstChannels = g_lutBMFormatData[eICMFormDst].m_cChannels; + size_t cbDstBytesPerPixel = g_lutColorDataSize[dstColType] * cDstChannels; + + PBYTE pSrcEnd = pSrc + cbWicPxData; + PBYTE pDstEnd = pDst + m_cbScanBuffer; + + if (dstColType == m_convData.m_colDataType) + { + while (pSrc < pSrcEnd && + pDst < pDstEnd) + { + if (pSrc + cbDstBytesPerPixel < pSrcEnd) + { + CopyMemory(pDst, pSrc, cbDstBytesPerPixel); + } + pSrc += cbSrcBytesPerPixel; + pDst += cbDstBytesPerPixel; + } + } + else + { + // + // We should only ever be required to convert from floating point and fixed point + // scRGB formats to 16 bpc RGB + // + if (eICMFormDst == kBM_16b_RGB && + (eICMFormSrc == kBM_32b_scRGB || + eICMFormSrc == kBM_32b_scARGB)) + { + FLOAT* pSrcData = reinterpret_cast(pSrc); + WORD* pDstData = reinterpret_cast(pDst); + + while (pSrcData <= reinterpret_cast(pSrcEnd) - cSrcChannels && + pDstData <= reinterpret_cast(pDstEnd) - cDstChannels) + { + for (UINT cChan = 0; + cChan < cDstChannels && cChan < cSrcChannels; + cChan++) + { + // + // Note: We are only converting from FLOAT and not applying gamma modification + // as the transform should account for this given the input scRGB ICC source profile. + // + if (pSrcData[cChan] <= -2.0f) + { + pDstData[cChan] = 0; + } + else if (pSrcData[cChan] >= 2.0f) + { + pDstData[cChan] = 0xFFFF; + } + else + { + pDstData[cChan] = static_cast(kMaxWordAsFloat * (pSrcData[cChan] + 2.0) / 4.0f); + } + } + + pSrcData += cSrcChannels; + pDstData += cDstChannels; + } + } + else if (eICMFormDst == kBM_16b_RGB && + (eICMFormSrc == kBM_S2DOT13FIXED_scRGB || + eICMFormSrc == kBM_S2DOT13FIXED_scARGB)) + { + WORD* pSrcData = reinterpret_cast(pSrc); + WORD* pDstData = reinterpret_cast(pDst); + + while (pSrcData <= reinterpret_cast(pSrcEnd) - cSrcChannels && + pDstData <= reinterpret_cast(pDstEnd) - cDstChannels) + { + for (UINT cChan = 0; + cChan < cDstChannels && cChan < cSrcChannels; + cChan++) + { + // + // Note: We are only converting from S2DOT13FIXED and not applying gamma modification + // as the transform should account for this given the input scRGB ICC source profile. + // + pDstData[cChan] = pSrcData[cChan] & kS2Dot13Neg ? pSrcData[cChan] ^ 0xFFFF : pSrcData[cChan] | kS2Dot13Neg; + } + + pSrcData += cSrcChannels; + pDstData += cDstChannels; + } + } + else + { + hr = E_NOTIMPL; + } + } + } + + // + // Set the out buffer pointer and size to the copy buffer + // + if (SUCCEEDED(hr)) + { + m_pData = m_pScanBuffer; + m_cbData = m_cbScanBuffer; + } + } + } + else + { + // + // Set the out buffer pointer and size to the WIC pixel data + // + m_pData = pWicPxData; + m_cbData = cbWicPxData; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CWICToBMFormatScan::Commit + +Routine Description: + + Commits the internal scanline data to the WIC data buffer + +Arguments: + + pWicPxData - Pointer to the WIC data + cbWicPxData - Count of bytes in the WIC data buffer + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CWICToBMFormatScan::Commit( + _In_reads_bytes_(cbWicPxData) PBYTE pWicPxData, + _In_ CONST UINT cbWicPxData + ) +{ + HRESULT hr = m_bInitialized ? S_OK : E_PENDING; + + COLORDATATYPE srcColType = COLOR_BYTE; + EICMPixelFormat eICMFormSrc = kBM_RGBTRIPLETS; + + COLORDATATYPE dstColType = COLOR_BYTE; + EICMPixelFormat eICMFormDst = kBM_RGBTRIPLETS; + + // + // Validate input + // + if (SUCCEEDED(hr) && + SUCCEEDED(hr = CHECK_POINTER(pWicPxData, E_POINTER))) + { + if (m_convData.m_pixFormTarget >= kWICPixelFormatMin && + m_convData.m_pixFormTarget < kWICPixelFormatMax) + { + // + // Set up the destination and source formats + // + eICMFormDst = g_lutWICToBMFormat[m_convData.m_pixFormTarget].m_bmFormTarget; + dstColType = g_lutWICToBMFormat[m_convData.m_pixFormTarget].m_colDataType; + + if (m_convData.m_bmFormTarget < kICMPixelFormatMax && + m_convData.m_bmFormTarget >= kICMPixelFormatMin) + { + eICMFormSrc = m_convData.m_bmFormTarget; + srcColType = g_lutBMFormatData[eICMFormSrc].m_colDataType; + } + else + { + hr = E_FAIL; + } + } + else + { + hr = E_FAIL; + } + } + + // + // Validate source and destination formats + // + if (SUCCEEDED(hr)) + { + if (eICMFormSrc < kICMPixelFormatMin || + eICMFormSrc >= kICMPixelFormatMax || + eICMFormDst < kICMPixelFormatMin || + eICMFormDst >= kICMPixelFormatMax) + { + RIP("Invalid pixel format.\n"); + + hr = E_FAIL; + } + else if (srcColType < COLOR_BYTE || + srcColType > COLOR_S2DOT13FIXED || + dstColType < COLOR_BYTE || + dstColType > COLOR_S2DOT13FIXED) + { + RIP("Invalid color data type.\n"); + + hr = E_FAIL; + } + } + + if (SUCCEEDED(hr)) + { + if (pWicPxData != m_pData) + { + // + // We need to convert the scan buffer and write back into the WIC buffer + // + PBYTE pDst = pWicPxData; + UINT cDstChannels = g_lutWICToBMFormat[m_convData.m_pixFormTarget].m_cChannels; + size_t cbDstBytesPerPixel = g_lutColorDataSize[dstColType] * cDstChannels; + + PBYTE pSrc = m_pScanBuffer; + UINT cSrcChannels = g_lutBMFormatData[eICMFormSrc].m_cChannels; + size_t cbSrcBytesPerPixel = g_lutColorDataSize[srcColType] * cSrcChannels; + + PBYTE pSrcEnd = pSrc + m_cbScanBuffer; + PBYTE pDstEnd = pDst + cbWicPxData; + + if (srcColType == m_convData.m_colDataType) + { + while (pSrc < pSrcEnd && + pDst < pDstEnd) + { + if (pDst + cbSrcBytesPerPixel < pDstEnd) + { + CopyMemory(pDst, pSrc, cbSrcBytesPerPixel); + } + + pSrc += cbSrcBytesPerPixel; + pDst += cbDstBytesPerPixel; + } + } + else + { + // + // We should only ever be required to convert from 16 bpc RGB to floating point + // and fixed point scRGB formats + // + if (eICMFormSrc == kBM_16b_RGB && + (eICMFormDst == kBM_32b_scRGB || + eICMFormDst == kBM_32b_scARGB)) + { + WORD* pSrcData = reinterpret_cast(pSrc); + FLOAT* pDstData = reinterpret_cast(pDst); + UINT cAlpha = eICMFormDst == kBM_32b_scARGB ? 1 : 0; + + while (pSrcData <= reinterpret_cast(pSrcEnd) - cSrcChannels && + pDstData <= reinterpret_cast(pDstEnd) - cDstChannels) + { + pDstData += cAlpha; + + for (UINT cChan = 0; + cChan < (cDstChannels - cAlpha) && cChan < cSrcChannels; + cChan++) + { + // + // Note: We are only converting to FLOAT and not applying gamma modification + // as the transform should account for this given the input scRGB ICC source profile. + // + pDstData[cChan] = (4.0f * static_cast(pSrcData[cChan]) / kMaxWordAsFloat) - 2.0f; + } + + pSrcData += cSrcChannels; + pDstData += cDstChannels - cAlpha; + } + } + else if (eICMFormSrc == kBM_16b_RGB && + (eICMFormDst == kBM_S2DOT13FIXED_scRGB || + eICMFormDst == kBM_S2DOT13FIXED_scARGB)) + { + WORD* pSrcData = reinterpret_cast(pSrc); + WORD* pDstData = reinterpret_cast(pDst); + UINT cAlpha = eICMFormDst == kBM_S2DOT13FIXED_scARGB ? 1 : 0; + + while (pSrcData <= reinterpret_cast(pSrcEnd) - cSrcChannels && + pDstData <= reinterpret_cast(pDstEnd) - cDstChannels) + { + pDstData += cAlpha; + + for (UINT cChan = 0; + cChan < (cDstChannels - cAlpha) && cChan < cSrcChannels; + cChan++) + { + // + // Note: We are only converting to S2DOT13FIXED and not applying gamma modification + // as the transform should account for this given the input scRGB ICC source profile. + // + pDstData[cChan] = pSrcData[cChan] & kS2Dot13Neg ? + pSrcData[cChan] ^ kS2Dot13Neg : pSrcData[cChan] ^ 0xFFFF; + } + + pSrcData += cSrcChannels; + pDstData += cDstChannels - cAlpha; + } + } + else + { + hr = E_NOTIMPL; + } + } + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CWICToBMFormatScan::GetData + +Routine Description: + + Retrieves the BMFORMAT buffer ready for processing + +Arguments: + + ppData - Pointer to a pointer that recieves the address of the data buffer. + Note: the buffer is only valid for the lifetime of the CWICToBMFormatScan object. + pBmFormat - Pointer to a BMFORMAT enum that recieves the type + pcWidth - Pointer to storage that recieves the pixel width + pcbStride - Pointer to storage that recieves the scanline stride + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CWICToBMFormatScan::GetData( + _Outptr_result_bytebuffer_(*pcbStride) PBYTE* ppData, + _Out_ BMFORMAT* pBmFormat, + _Out_ UINT* pcWidth, + _Out_ UINT* pcbStride + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(ppData, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pBmFormat, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pcWidth, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pcbStride, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(m_pData, E_PENDING))) + { + if (m_convData.m_bmFormTarget >= kICMPixelFormatMin && + m_convData.m_bmFormTarget < kICMPixelFormatMax) + { + *pBmFormat = g_lutBMFormatData[m_convData.m_bmFormTarget].m_bmFormat; + *pcWidth = m_cWidth; + *ppData = m_pData; + *pcbStride = static_cast(m_cbData); + } + else + { + hr = E_FAIL; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CWICToBMFormatScan::CreateScanBuffer + +Routine Description: + + Creates the intermediate scanline buffer + +Arguments: + + cWidth - Pixel width of the scanline + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CWICToBMFormatScan::CreateScanBuffer( + _In_ CONST UINT cWidth, + _In_ CONST SIZE_T cbDataType, + _In_ CONST UINT cChannels + ) +{ + HRESULT hr = S_OK; + + if (cWidth > MAX_PIXELWIDTH_COUNT || + cbDataType > MAX_COLDATATYPE_SIZE || + cChannels > MAX_COLCHANNEL_COUNT) + { + hr = E_INVALIDARG; + } + + size_t cbScanBuffer = 0; + + if (SUCCEEDED(hr)) + { + if (FAILED(SizeTMult(cWidth, cbDataType, &cbScanBuffer)) || + FAILED(SizeTMult(cbScanBuffer, cChannels, &cbScanBuffer))) + { + hr = HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW); + } + + } + + if (SUCCEEDED(hr)) + { + if (cbScanBuffer != m_cbScanBuffer) + { + FreeScanBuffer(); + m_pScanBuffer = new(std::nothrow) BYTE[cbScanBuffer]; + if (SUCCEEDED(hr = CHECK_POINTER(m_pScanBuffer, E_OUTOFMEMORY))) + { + m_cbScanBuffer = cbScanBuffer; + } + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CWICToBMFormatScan::FreeScanBuffer + +Routine Description: + + Free the intermediate scanline buffer + +Arguments: + + None + +Return Value: + + None + +--*/ +VOID +CWICToBMFormatScan::FreeScanBuffer( + VOID + ) +{ + if (m_pScanBuffer != NULL) + { + delete[] m_pScanBuffer; + m_pScanBuffer = NULL; + } + + m_cbScanBuffer = 0; +} + diff --git a/print/XPSDrvSmpl/src/filters/color/wictobmscn.h b/print/XPSDrvSmpl/src/filters/color/wictobmscn.h new file mode 100644 index 00000000..6ac780be --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/color/wictobmscn.h @@ -0,0 +1,88 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + wictobmscn.h + +Abstract: + + WIC pixel format to BMFORMAT conversion class implementation. This class provides methods + for converting between a source WIC scanline to a target destination BMFORMAT scanline. + +--*/ + +#pragma once + +#include "bmpdata.h" + +class CWICToBMFormatScan +{ +public: + CWICToBMFormatScan(); + + virtual ~CWICToBMFormatScan(); + + HRESULT + Initialize( + _In_ CONST WICToBMFORMAT& WICToBM + ); + + HRESULT + SetData( + _In_ CONST BOOL bIsSrc, + _In_reads_bytes_(cbWicPxData) PBYTE pWicPxData, + _In_ CONST UINT cbWicPxData, + _In_ CONST UINT cWidth + ); + + HRESULT + Commit( + _In_reads_bytes_(cbWicPxData) PBYTE pWicPxData, + _In_ CONST UINT cbWicPxData + ); + + HRESULT + GetData( + _Outptr_result_bytebuffer_(*pcbStride) PBYTE* ppData, + _Out_ BMFORMAT* pBmFormat, + _Out_ UINT* pcWidth, + _Out_ UINT* pcbStride + ); + +private: + HRESULT + CreateScanBuffer( + _In_ CONST UINT cWidth, + _In_ CONST SIZE_T cbDataType, + _In_ CONST UINT cChannels + ); + + VOID + FreeScanBuffer( + VOID + ); + +private: + WICToBMFORMAT m_convData; + + PBYTE m_pScanBuffer; + + size_t m_cbScanBuffer; + + UINT m_cWidth; + + PBYTE m_pData; + + size_t m_cbData; + + BOOL m_bInitialized; +}; diff --git a/print/XPSDrvSmpl/src/filters/common/clasfact.h b/print/XPSDrvSmpl/src/filters/common/clasfact.h new file mode 100644 index 00000000..409fc9bc --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/common/clasfact.h @@ -0,0 +1,202 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + clasfact.h + +Abstract: + + This file defines a template IClassFactory implementation + to be returned by each filter's DllGetClassObject() function. + + Also, a routine to return one of these class factories so that + this code does not need to be duplicated in every filter's + DllGetClassObject(). + +--*/ + +#pragma once + +#include "cunknown.h" +#include "globals.h" + +template +class CClassFactory : public CUnknown +{ +public: + // + // Constructor and Destruction + // + CClassFactory() : + CUnknown(IID_IClassFactory) + { } + + virtual ~CClassFactory() + { } + + // + // IClassFactory methods + // + virtual HRESULT STDMETHODCALLTYPE + CreateInstance( + _In_opt_ LPUNKNOWN pUnkOuter, + _In_ REFIID riid, + _Outptr_ PVOID* ppvObject + ) + { + HRESULT hr = S_OK; + + if (ppvObject == NULL) + { + hr = E_POINTER; + goto Exit; + } + *ppvObject = NULL; + + if (pUnkOuter == NULL) + { + // + // Create Filter + // + _T* pFilter = NULL; + + try + { + pFilter = new(std::nothrow) _T; + hr = CHECK_POINTER(pFilter, E_OUTOFMEMORY); + } + catch (CXDException& e) + { + if (pFilter != NULL) + { + delete pFilter; + pFilter = NULL; + } + + hr = e; + } + catch(...) + { + hr = E_FAIL; + } + + if (SUCCEEDED(hr)) + { + // + // Get the requested interface + // + hr = pFilter->QueryInterface(riid, ppvObject) ; + + // + // Release the IUnknown pointer. If QueryInterface failed + // the Release() call will clean up + // + pFilter->Release(); + } + } + else + { + // + // Cannot aggregate + // + hr = CLASS_E_NOAGGREGATION; + } + + Exit: + ERR_ON_HR(hr); + return hr; + } + + virtual HRESULT STDMETHODCALLTYPE + LockServer( + _In_ BOOL bLock + ) + { + if (bLock) + { + InterlockedIncrement(&g_cServerLocks); + } + else + { + InterlockedDecrement(&g_cServerLocks); + } + + return S_OK; + } +}; + +template +HRESULT +GetFilterClassFactory( + _In_ REFCLSID rclsid, + _In_ REFIID riid, + _In_ REFCLSID expectedclsid, + _Out_ VOID** ppv + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(ppv, E_POINTER))) + { + *ppv = NULL; + + // + // Make sure the appropriate class factory is being requested + // + if (rclsid == expectedclsid) + { + CClassFactory<_T>* pFactory = NULL; + + try + { + pFactory = new(std::nothrow) CClassFactory<_T>(); + hr = CHECK_POINTER(pFactory, E_OUTOFMEMORY); + } + catch (CXDException& e) + { + if (pFactory != NULL) + { + delete pFactory; + pFactory = NULL; + } + + hr = e; + } + catch (...) + { + hr = E_FAIL; + } + + if (SUCCEEDED(hr)) + { + // + // Get the requested interface. + // + hr = pFactory->QueryInterface(riid, ppv); + + // + // Release the IUnknown pointer. + // (If QueryInterface failed, component will delete itself.) + // + pFactory->Release(); + } + } + else + { + hr = CLASS_E_CLASSNOTAVAILABLE; + } + } + + ERR_ON_HR(hr); + return hr; +} + diff --git a/print/XPSDrvSmpl/src/filters/common/precompsrc.cpp b/print/XPSDrvSmpl/src/filters/common/precompsrc.cpp new file mode 100644 index 00000000..5944cf51 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/common/precompsrc.cpp @@ -0,0 +1 @@ +#include "precomp.h" \ No newline at end of file diff --git a/print/XPSDrvSmpl/src/filters/common/ptmanage.cpp b/print/XPSDrvSmpl/src/filters/common/ptmanage.cpp new file mode 100644 index 00000000..209c344a --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/common/ptmanage.cpp @@ -0,0 +1,1216 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + ptmanage.cpp + +Abstract: + + PrintTicket management class implementation. This class encapsulate + PrintTicket handling algorithm defined in the XPS Document specification. + It provides a simple set and get interace for to filters and handles + merging of tickets and the use of the Win32 PrintTicket provider API. + The algorithm for determining the PrintTicket applies as follows: + + 1. Validate and merge the PrintTicket from the FDS with the default + printicket converted from the property bag. + The resultant ticket will be the Job level ticket. + + 2. Validate and merge the PrintTicket from the current FD with the Job + level ticket from step 1. The resultant ticket will be the document + level ticket. + + 3. Validate and merge the PrintTicket from the current FP with the Doc + level ticket from step 2. The resultant ticket will be the page + level ticket. + + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdstring.h" +#include "ptmanage.h" +#include "streamcnv.h" + +/*++ + +Routine Name: + + CPTManager::CPTManager + +Routine Description: + + CPTManager class constructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CPTManager::CPTManager() : + m_pDefaultPT(NULL), + m_pJobPT(NULL), + m_pDocPT(NULL), + m_pPagePT(NULL), + m_hProvider(NULL), + m_hToken(INVALID_HANDLE_VALUE) +{ +} + +/*++ + +Routine Name: + + CPTManager::~CPTManager + +Routine Description: + + CPTManager class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CPTManager::~CPTManager() +{ + // + // Close the PT provider + // + CloseProvider(); +} + +/*++ + +Routine Name: + + CPTManager::Initialise + +Routine Description: + + This routine Initialises the PrintTicket manager with the default PrintTicket + and the device name. + +Arguments: + + pDefaultTicketStream - Pointer to the default user PrintTicket as an IStream + bstrPrinterName - The name of the printer + userToken - The user's security token + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPTManager::Initialise( + _In_ IPrintReadStream* pDefaultTicketStream, + _In_z_ BSTR bstrPrinterName, + _In_ HANDLE userToken + ) +{ + HRESULT hr = S_OK; + + m_hToken = userToken; + + // + // If the provider is already open close it + // + CloseProvider(); + + if (SUCCEEDED(hr = CHECK_POINTER(pDefaultTicketStream, E_POINTER))) + { + if (SysStringLen(bstrPrinterName) <= 0) + { + hr = E_INVALIDARG; + } + } + + // + // We need to impersonate the user who submitted the job + // in order to always have sufficient rights to call + // PTOpenProvider. + // + if (SUCCEEDED(hr)) + { + if (SetThreadToken(NULL, m_hToken)) + { + // + // Open the PT interface and initialise PrintTickets + // + if (SUCCEEDED(hr = PTOpenProvider(bstrPrinterName, 1, &m_hProvider))) + { + CComPtr pPTStream(NULL); + pPTStream.Attach(new(std::nothrow) CPrintReadStreamToIStream(pDefaultTicketStream)); + + if (SUCCEEDED(hr = CHECK_POINTER(pPTStream, E_OUTOFMEMORY))) + { + hr = InitialisePrintTickets(pPTStream); + } + } + + // + // Always revert back to the default security context + // + if (!SetThreadToken(NULL, NULL)) + { + // + // We couldn't revert the security context. The filter pipeline + // manager will clean up the thread when operation is complete, + // when it is determined that the security context was not + // reverted. Since there are no security implications with + // running this filter in an elevated context, we can + // continue to run. + // + } + } + else + { + hr = HRESULT_FROM_WIN32(GetLastError()); + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CPTManager::SetTicket + +Routine Description: + + This routine sets the Job level PrintTicket from the PrintTicket held in the + FixedDocumentSequence. If there is no PrintTicket associated with the FDS, the + default PrintTicket is used to set the Job level PrintTicket. + +Arguments: + + pFDS - Pointer to the FixedDocumentSequence interface + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPTManager::SetTicket( + _In_ CONST IFixedDocumentSequence* pFDS + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pFDS, E_POINTER))) + { + CComPtr pPTRef(NULL); + + // + // If a PrintTicket is available merge it at the job level + // + if (SUCCEEDED(hr = const_cast(pFDS)->GetPrintTicket(&pPTRef))) + { + hr = MergeTicket(kPTJobScope, pPTRef); + } + else if (hr == HRESULT_FROM_WIN32(ERROR_NOT_FOUND)) + { + // + // This indicates there is no print-ticket associated with + // the job. Free the tickets from this scope upward and + // reintialise the defaults + // + FreePrintTickets(kPTJobScope); + hr = UpdateDefaultPTs(kPTJobScope); + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CPTManager::SetTicket + +Routine Description: + + This routine sets the Socument level PrintTicket from the PrintTicket held in the + FixedDocument. If there is no PrintTicket associated with the FD, the + FixedDocumentSequence PrintTicket is used to set the Docuemnt level PrintTicket. + +Arguments: + + pFD - Pointer to the FixedDocument interface + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPTManager::SetTicket( + _In_ CONST IFixedDocument* pFD + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pFD, E_POINTER))) + { + CComPtr pPTRef(NULL); + + // + // If a PrintTicket is available merge it at the doc level + // + if (SUCCEEDED(hr) && + SUCCEEDED(hr = const_cast(pFD)->GetPrintTicket(&pPTRef))) + { + hr = MergeTicket(kPTDocumentScope, pPTRef); + } + else if (hr == HRESULT_FROM_WIN32(ERROR_NOT_FOUND)) + { + // + // This indicates there is no print-ticket associated with + // the job. Free the tickets from this scope upward and + // reintialise the defaults + // + FreePrintTickets(kPTDocumentScope); + hr = UpdateDefaultPTs(kPTDocumentScope); + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CPTManager::SetTicket + +Routine Description: + + This routine sets the Page level PrintTicket from the PrintTicket held in the + FixedPage. If there is no PrintTicket associated with the FP, the + FixedDocument PrintTicket is used to set the Page level PrintTicket. + +Arguments: + + pFP - Pointer to the FixedPage interface + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPTManager::SetTicket( + _In_ CONST IFixedPage* pFP + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pFP, E_POINTER))) + { + CComPtr pPTRef(NULL); + + // + // If a PrintTicket is available merge it at the page level + // + if (SUCCEEDED(hr) && + SUCCEEDED(hr = const_cast(pFP)->GetPrintTicket(&pPTRef))) + { + hr = MergeTicket(kPTPageScope, pPTRef); + } + else if (hr == HRESULT_FROM_WIN32(ERROR_NOT_FOUND)) + { + // + // This indicates there is no print-ticket associated with + // the job. Free the tickets from this scope upward and + // reintialise the defaults + // + FreePrintTickets(kPTPageScope); + hr = UpdateDefaultPTs(kPTPageScope); + } + } + + ERR_ON_HR(hr); + return hr; +} + + +/*++ + +Routine Name: + + CPTManager::SetTicket + +Routine Description: + + Sets the PrintTicket at the specified scope given a PrintTicket defined + as a DOM document + +Arguments: + + ptScope - The scope of the PrintTicket to be set + pPT - Pointer to an IXMLDOMDocument2 interface that contains the PrintTicket to be set + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPTManager::SetTicket( + _In_ CONST EPrintTicketScope ptScope, + _In_opt_ CONST IXMLDOMDocument2* pPT + ) +{ + HRESULT hr = S_OK; + + // + // Free the tickets from this scope upward and reintialise + // from the appropriate default. This ensures we are not + // using an old PrintTicket from the same scope + // + FreePrintTickets(ptScope); + + if (SUCCEEDED(hr = UpdateDefaultPTs(ptScope))) + { + if (pPT) + { + hr = MergeTicket(ptScope, pPT); + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CPTManager::GetTicket + +Routine Description: + + This routine retrieves the PrintTicket at the requested scope + +Arguments: + + ptScope - The scope of the PrintTicket to be retrieved + ppTicket - Pointer to an IXMLDOMDocument2 interface pointer that recieves the PrintTicket + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPTManager::GetTicket( + _In_ CONST EPrintTicketScope ptScope, + _Outptr_ IXMLDOMDocument2** ppTicket + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(ppTicket, E_POINTER)) && + SUCCEEDED(hr = UpdateDefaultPTs(ptScope))) + { + *ppTicket = NULL; + + switch (ptScope) + { + case kPTPageScope: + { + // + // Pointer should either be default or FP ticket but never NULL + // + ASSERTMSG(m_pPagePT != NULL, "NULL Page PrintTicket.\n"); + + if (SUCCEEDED(hr = CHECK_POINTER(m_pPagePT, E_PENDING))) + { + *ppTicket = m_pPagePT; + } + } + break; + + case kPTDocumentScope: + { + // + // Pointer should either be default or FD ticket but never NULL + // + ASSERTMSG(m_pDocPT != NULL, "NULL Document PrintTicket.\n"); + + if (SUCCEEDED(hr = CHECK_POINTER(m_pDocPT, E_PENDING))) + { + *ppTicket = m_pDocPT; + } + } + break; + + case kPTJobScope: + { + // + // Pointer should either be default or FDS ticket but never NULL + // + ASSERTMSG(m_pJobPT != NULL, "NULL Job PrintTicket.\n"); + + if (SUCCEEDED(hr = CHECK_POINTER(m_pJobPT, E_PENDING))) + { + *ppTicket = m_pJobPT; + } + } + break; + + default: + { + RIP("Unrecognised PT scope\n"); + + hr = E_INVALIDARG; + } + break; + } + + if (*ppTicket == NULL) + { + RIP("Failed to retrieve a valid PrintTicket\n"); + + hr = E_FAIL; + } + } + + ERR_ON_HR(hr); + return hr; +} + + +/*++ + +Routine Name: + + CPTManager::GetCapabilities + +Routine Description: + + This routine retrieves a PrintCapabilities document given a PrintTicket + +Arguments: + + pTicket - Pointer to the PrintTicket as a DOM document + pTicket - Pointer to a DOM document pointer that recieves the PrintCapabilities + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPTManager::GetCapabilities( + _In_ IXMLDOMDocument2* pTicket, + _Outptr_ IXMLDOMDocument2** ppCapabilities + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pTicket, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(ppCapabilities, E_POINTER))) + { + *ppCapabilities = NULL; + + CComBSTR bstrError; + CComPtr pPTIn(NULL); + CComPtr pPCOut(NULL); + CComPtr pCapabilitiesDoc(NULL); + + // + // Create the PrintCapabilities DOM document, retrieve the IStreams from the + // DOM documents and call the PT api to retrieve the capabilities document + // + if (SUCCEEDED(hr = pCapabilitiesDoc.CoCreateInstance(CLSID_DOMDocument60)) && + SUCCEEDED(hr = pTicket->QueryInterface(IID_IStream, reinterpret_cast(&pPTIn))) && + SUCCEEDED(hr = pCapabilitiesDoc->QueryInterface(IID_IStream, reinterpret_cast(&pPCOut)))) + { + if (SetThreadToken(NULL, m_hToken)) + { + if (SUCCEEDED(hr = PTGetPrintCapabilities(m_hProvider, pPTIn, pPCOut, &bstrError))) + { + LARGE_INTEGER cbMove = {0}; + if (SUCCEEDED(hr = pPCOut->Seek(cbMove, STREAM_SEEK_SET, NULL))) + { + *ppCapabilities = pCapabilitiesDoc.Detach(); + } + } + else + { + try + { + CStringXDA cstrError(bstrError); + ERR(cstrError.GetBuffer()); + } + catch (CXDException&) + { + } + } + + // + // Always revert back to the default security context + // + if (!SetThreadToken(NULL, NULL)) + { + // + // We couldn't revert the security context. The filter pipeline + // manager will clean up the thread when operation is complete, + // when it is determined that the security context was not + // reverted. Since there are no security implications with + // running this filter in an elevated context, we can + // continue to run. + // + } + } + else + { + hr = HRESULT_FROM_WIN32(GetLastError()); + + // + // If SetThreadToken fails, GetLastError will return an error + // + _Analysis_assume_(FAILED(hr)); + } + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CPTManager::InitialisePrintTickets + +Routine Description: + + This routine intialises the PrintTickets at the default, job, document and page scope + using an IStream containing the default PrintTicket mark-up + +Arguments: + + pDefaultPTStream - Pointer to an IStream interface that contains the default PrintTicket data + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPTManager::InitialisePrintTickets( + _In_ IStream* pDefaultPTStream + ) +{ + ASSERTMSG(m_hProvider != NULL, "NULL PrintTicket provider interface detected.\n"); + + HRESULT hr = S_OK; + + // + // Make sure all print tickets are released + // + m_pDefaultPT = NULL; + m_pJobPT = NULL; + m_pDocPT = NULL; + m_pPagePT = NULL; + + if (SUCCEEDED(hr = CHECK_POINTER(pDefaultPTStream, E_POINTER))) + { + // + // Create the DOM documents for default PT + // + hr = SetPTFromStream(pDefaultPTStream, &m_pDefaultPT); + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CPTManager::SetPTFromDOMDoc + +Routine Description: + + This routine copies one DOM document representation of the PrintTicket to another + +Arguments: + + pPTDOMDoc - Pointer to the source PrintTicket as a DOM document + ppDomDoc - Pointer to an IXMLDOMDOcument pointer that recieves the copied PrintTicket + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPTManager::SetPTFromDOMDoc( + _In_ IXMLDOMDocument2* pPTDOMDoc, + _Outptr_ IXMLDOMDocument2** ppDomDoc + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pPTDOMDoc, E_POINTER))) + { + // + // Get the IStream from the DOM doc and pass to SetPTFromStream + // + CComPtr pStream(NULL); + if (SUCCEEDED(hr = pPTDOMDoc->QueryInterface(IID_IStream, reinterpret_cast(&pStream)))) + { + hr = SetPTFromStream(pStream, ppDomDoc); + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CPTManager::SetPTFromStream + +Routine Description: + + This routine copies an IStream representation of the PrintTicket to a DOM document + +Arguments: + + pPTStream - Pointer to the source PrintTicket as an IStream + ppDomDoc - Pointer to an IXMLDOMDOcument pointer that recieves the copied PrintTicket + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPTManager::SetPTFromStream( + _In_ IStream* pPTStream, + _Outptr_ IXMLDOMDocument2** ppDomDoc + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pPTStream, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(ppDomDoc, E_POINTER))) + { + *ppDomDoc = NULL; + + LARGE_INTEGER cbMoveFromStart = {0}; + CComPtr pDOMDoc(NULL); + VARIANT_BOOL fLoaded = VARIANT_FALSE; + + // + // Create the DOM document instance, seek to the start of the + // PT stream and load into the dom document + // + if (SUCCEEDED(hr = pDOMDoc.CoCreateInstance(CLSID_DOMDocument60)) && + SUCCEEDED(hr = pPTStream->Seek(cbMoveFromStart, STREAM_SEEK_SET, NULL)) && + SUCCEEDED(hr = pDOMDoc->load(CComVariant(pPTStream), &fLoaded))) + { + if (fLoaded == VARIANT_TRUE) + { + // + // Assign the outgoing element pointer - detach from CComPtr to release ownership + // + *ppDomDoc = pDOMDoc.Detach(); + } + else + { + hr = E_FAIL; + } + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CPTManager::MergeTicket + +Routine Description: + + This routine merges a PrintTicket (supplied as a IPartPrintTicket pointer) into + the DOM representation of the PrintTicket at the requested scope + +Arguments: + + ptScope - The scope at which the PrintTicket is to be merged + pPTRef - Pointer to an IPartPrintTicket interface containing the PrintTicket to be merged + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPTManager::MergeTicket( + _In_ CONST EPrintTicketScope ptScope, + _In_ CONST IPartPrintTicket* pPTRef + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pPTRef, E_POINTER))) + { + // + // Create a DOM document from the PT ref stream + // + CComPtr pNewPT(NULL); + CComPtr pRead(NULL); + + if (SUCCEEDED(hr = pNewPT.CoCreateInstance(CLSID_DOMDocument60)) && + SUCCEEDED(hr = const_cast(pPTRef)->GetStream(&pRead))) + { + CComPtr pReadStreamToSeq(NULL); + VARIANT_BOOL fLoaded = VARIANT_FALSE; + + pReadStreamToSeq.Attach(new(std::nothrow) pfp::PrintReadStreamToSeqStream(pRead)); + + if (SUCCEEDED(hr = CHECK_POINTER(pReadStreamToSeq, E_OUTOFMEMORY)) && + SUCCEEDED(hr = pNewPT->load(CComVariant(pReadStreamToSeq), &fLoaded))) + { + if (fLoaded == VARIANT_TRUE) + { + hr = MergeTicket(ptScope, pNewPT); + } + else + { + hr = E_FAIL; + } + } + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CPTManager::MergeTicket + +Routine Description: + + This routine merges a PrintTicket (supplied as a IXMLDOMDocument2 pointer) into + the DOM representation of the PrintTicket at the requested scope + +Arguments: + + ptScope - The scope at which the PrintTicket is to be merged + pPT - Pointer to an IXMLDOMDocument2 interface containing the PrintTicket to be merged + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPTManager::MergeTicket( + _In_ CONST EPrintTicketScope ptScope, + _In_ CONST IXMLDOMDocument2* pPT + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pPT, E_POINTER))) + { + CComPtr pPTLevelUp(NULL); + CComPtr pResult(NULL); + + switch (ptScope) + { + case kPTJobScope: + { + pPTLevelUp = m_pDefaultPT; + } + break; + + case kPTDocumentScope: + { + pPTLevelUp = m_pJobPT; + } + break; + + case kPTPageScope: + { + pPTLevelUp = m_pDocPT; + } + break; + + default: + { + RIP("Unrecognised PT scope\n"); + + hr = E_INVALIDARG; + } + break; + } + + ASSERTMSG(pPTLevelUp != NULL, "PrintTicket at the level up has not been set (check part handler is attempting to)\n"); + + if (SUCCEEDED(hr) && + SUCCEEDED(hr = CHECK_POINTER(pPTLevelUp, E_PENDING)) && + SUCCEEDED(hr = GetMergedTicket(ptScope, pPT, pPTLevelUp, &pResult))) + { + switch (ptScope) + { + case kPTJobScope: + { + m_pJobPT = pResult; + } + break; + + case kPTDocumentScope: + { + m_pDocPT = pResult; + } + break; + + case kPTPageScope: + { + m_pPagePT = pResult; + } + break; + } + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CPTManager::GetMergedTicket + +Routine Description: + + This routine retrieves a merged PrintTicket at the requested scope given the base + and delta PrintTickets as IXMLDOMDocument2 interface pointers + +Arguments: + + ptScope - The scope at which the merge should take place + pDelta - The delta PrintTicket as an IXMLDOMDocument2 pointer + pBase - The base PrintTicket as an IXMLDOMDocument2 pointer + ppResult - The resulting PrintTicket after the merge has completed + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPTManager::GetMergedTicket( + _In_ CONST EPrintTicketScope ptScope, + _In_ CONST IXMLDOMDocument2* pDelta, + _In_ IXMLDOMDocument2* pBase, + _Outptr_ IXMLDOMDocument2** ppResult + ) +{ + ASSERTMSG(pDelta != NULL, "NULL PT reference part passed.\n"); + ASSERTMSG(pBase != NULL, "NULL base PT passed.\n"); + ASSERTMSG(ppResult != NULL, "NULL out PT passed.\n"); + + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_HANDLE(m_hProvider, E_PENDING)) && + SUCCEEDED(hr = CHECK_POINTER(ppResult, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pDelta, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pBase, E_POINTER))) + { + *ppResult = NULL; + } + + CComPtr pResultStream(NULL); + CComPtr pBaseStream(NULL); + CComPtr pDeltaStream(NULL); + + CComPtr pNewPT(NULL); + + // + // Create a new DOM doc based off the result ticket and + // assign to the resultant DOM doc + // + try + { + CComBSTR bstrErrorMessage; + + if (SUCCEEDED(hr) && + SUCCEEDED(hr = CreateStreamOnHGlobal(NULL, TRUE, &pResultStream)) && + SUCCEEDED(hr = pBase->QueryInterface(IID_IStream, reinterpret_cast(&pBaseStream))) && + SUCCEEDED(hr = const_cast(pDelta)->QueryInterface(IID_IStream, reinterpret_cast(&pDeltaStream)))) + { + if (SetThreadToken(NULL, m_hToken)) + { + if (SUCCEEDED(hr = PTMergeAndValidatePrintTicket(m_hProvider, + pBaseStream, + pDeltaStream, + ptScope, + pResultStream, + &bstrErrorMessage))) + { + if (SUCCEEDED(hr = SetPTFromStream(pResultStream, &pNewPT))) + { + // + // Assign the outgoing element pointer - detach from CComPtr to release ownership + // + *ppResult = pNewPT.Detach(); + } + } + else + { + CStringXDA cstrMessage; + CStringXDA cstrError(bstrErrorMessage); + cstrMessage.Format("PTMergeAndValidatePrintTicket failed with message: %s\n", cstrError); + + ERR(cstrMessage.GetBuffer()); + } + + // + // Always revert back to the default security context + // + if (!SetThreadToken(NULL, NULL)) + { + // + // We couldn't revert the security context. The filter pipeline + // manager will clean up the thread when operation is complete, + // when it is determined that the security context was not + // reverted. Since there are no security implications with + // running this filter in an elevated context, we can + // continue to run. + // + } + } + else + { + hr = HRESULT_FROM_WIN32(GetLastError()); + + // + // If SetThreadToken fails, GetLastError will return an error + // + _Analysis_assume_(FAILED(hr)); + } + } + } + catch (CXDException& e) + { + hr = e; + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CPTManager::CloseProvider + +Routine Description: + + This routine closes the PrintTicket provider + +Arguments: + + None + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPTManager::CloseProvider( + VOID + ) +{ + HRESULT hr = S_OK; + + if (m_hProvider != NULL) + { + hr = PTCloseProvider(m_hProvider); + m_hProvider = NULL; + } + + return hr; +} + +/*++ + +Routine Name: + + CPTManager::UpdateDefaultPTs + +Routine Description: + + This routine updates the default PrintTicket at a given scope. This routine updates + the Job PrintTicket with the default, the Document with the Job and the Page with the + Document if they are not set and are within the requested scope. + +Arguments: + + ptScope - The scope of the PrintTicket to update + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPTManager::UpdateDefaultPTs( + _In_ CONST EPrintTicketScope ptScope + ) +{ + HRESULT hr = S_OK; + + // + // We need at least the default ticket in place + // + ASSERTMSG(m_pDefaultPT != NULL, "The default PrintTicket is not correctly set\n"); + + if (SUCCEEDED(hr = CHECK_POINTER(m_pDefaultPT, E_PENDING))) + { + if (ptScope <= kPTJobScope && + m_pJobPT == NULL) + { + hr = SetPTFromDOMDoc(m_pDefaultPT, &m_pJobPT); + } + + if (SUCCEEDED(hr) && + ptScope <= kPTDocumentScope && + m_pDocPT == NULL) + { + hr = SetPTFromDOMDoc(m_pJobPT, &m_pDocPT); + } + + if (SUCCEEDED(hr) && + ptScope == kPTPageScope && + m_pPagePT == NULL) + { + hr = SetPTFromDOMDoc(m_pDocPT, &m_pPagePT); + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CPTManager::FreePrintTickets + +Routine Description: + + This routine releases the PrintTicket at a given scope and all PrintTickets + that depend on it. + +Arguments: + + ptScope - The scope from which the PrintTickets should be released + +Return Value: + + None + +--*/ +VOID +CPTManager::FreePrintTickets( + _In_ CONST EPrintTicketScope ptScope + ) +{ + if (ptScope >= kPTPageScope) + { + m_pPagePT = NULL; + } + + if (ptScope >= kPTDocumentScope) + { + m_pDocPT = NULL; + } + + if (ptScope >= kPTJobScope) + { + m_pJobPT = NULL; + } +} + diff --git a/print/XPSDrvSmpl/src/filters/common/ptmanage.h b/print/XPSDrvSmpl/src/filters/common/ptmanage.h new file mode 100644 index 00000000..1c1e3f67 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/common/ptmanage.h @@ -0,0 +1,153 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + ptmanage.cpp + +Abstract: + + PrintTicket management class definition. This class encapsulate + PrintTicket handling algorithm defined in the XPS Document specification. + It provides a simple set and get interace for to filters and handles + merging of tickets and the use of the Win32 PrintTicket provider API. + The algorithm for determining the PrintTicket applies as follows: + + 1. Validate and merge the PrintTicket from the FDS with the default + printicket converted from the default devmode in the property bag. + The resultant ticket will be the Job level ticket. + + 2. Validate and merge the PrintTicket from the current FD with the Job + level ticket from step 1. The resultant ticket will be the document + level ticket. + + 3. Validate and merge the PrintTicket from the current FP with the Doc + level ticket from step 2. The resultant ticket will be the page + level ticket. + +--*/ + +#pragma once + +class CPTManager +{ +public: + CPTManager(); + + virtual ~CPTManager(); + + HRESULT + Initialise( + _In_ IPrintReadStream* pDefaultTicketStream, + _In_z_ BSTR bstrPrinterName, + _In_ HANDLE userToken + ); + + HRESULT + SetTicket( + _In_ CONST IFixedDocumentSequence* pFDS + ); + + HRESULT + SetTicket( + _In_ CONST IFixedDocument* pFD + ); + + HRESULT + SetTicket( + _In_ CONST IFixedPage* pFP + ); + + HRESULT + SetTicket( + _In_ CONST EPrintTicketScope ptScope, + _In_opt_ CONST IXMLDOMDocument2* pPT + ); + + HRESULT + GetTicket( + _In_ CONST EPrintTicketScope ptScope, + _Outptr_ IXMLDOMDocument2** ppTicket + ); + + HRESULT + GetCapabilities( + _In_ IXMLDOMDocument2* pTicket, + _Outptr_ IXMLDOMDocument2** ppCapabilities + ); + +private: + HRESULT + InitialisePrintTickets( + _In_ IStream* pDefaultPTStream + ); + + HRESULT + SetPTFromDOMDoc( + _In_ IXMLDOMDocument2* pPTDOMDoc, + _Outptr_ IXMLDOMDocument2** ppDomDoc + ); + + HRESULT + SetPTFromStream( + _In_ IStream* pPTStream, + _Outptr_ IXMLDOMDocument2** ppDomDoc + ); + + HRESULT + MergeTicket( + _In_ CONST EPrintTicketScope ptScope, + _In_ CONST IPartPrintTicket* pPTRef + ); + + HRESULT + MergeTicket( + _In_ CONST EPrintTicketScope ptScope, + _In_ CONST IXMLDOMDocument2* pPT + ); + + HRESULT + GetMergedTicket( + _In_ CONST EPrintTicketScope ptScope, + _In_ CONST IXMLDOMDocument2* pDelta, + _In_ IXMLDOMDocument2* pBase, + _Outptr_ IXMLDOMDocument2** ppResult + ); + + HRESULT + CloseProvider( + VOID + ); + + HRESULT + UpdateDefaultPTs( + _In_ CONST EPrintTicketScope ptScope + ); + + VOID + FreePrintTickets( + _In_ CONST EPrintTicketScope ptScope + ); + +private: + CComPtr m_pDefaultPT; + + CComPtr m_pJobPT; + + CComPtr m_pDocPT; + + CComPtr m_pPagePT; + + HPTPROVIDER m_hProvider; + + HANDLE m_hToken; +}; + diff --git a/print/XPSDrvSmpl/src/filters/common/rescache.cpp b/print/XPSDrvSmpl/src/filters/common/rescache.cpp new file mode 100644 index 00000000..32b206e2 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/common/rescache.cpp @@ -0,0 +1,309 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + rescache.cpp + +Abstract: + + File resource cache implementation. Filters that need to add resources + may be required to add the same resource to numerous pages in a job. To + prevent the same resource being sent repeatedly, the file resource cache + class implements an interface that filters can use to add resources + without needing to keep track of whether they have been sent. For specific + filter functionality, a class should be created that implements a resource + writer interface. This should be able to write the resource to a stream. The + filter can then add this class to the the resource cache and it will take + care of writing the resource via the IResWriter::WriteData method if it has + not already been written. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdexcept.h" +#include "rescache.h" + +/*++ + +Routine Name: + + CFileResourceCache::CFileResourceCache + +Routine Description: + + CFileResourceCache class constructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CFileResourceCache::CFileResourceCache() +{ +} + +/*++ + +Routine Name: + + CFileResourceCache::~CFileResourceCache + +Routine Description: + + CFileResourceCache class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CFileResourceCache::~CFileResourceCache() +{ +} + +/*++ + +Routine Name: + + CFileResourceCache::WriteResource + +Routine Description: + + This template function writes a resource to a fixed page. The type + of resource is supplied as an argument to the template. The resource + data is written via the IResWriter interface passed to the method. + +Arguments: + + pXpsConsumer - The XPS consumer to create the new resource part + pFixedPage - The FixedPage to send the resource to + pResWriter - The resource writer (hides the resource type behind a generic write interface) + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +template +HRESULT +CFileResourceCache::WriteResource( + _In_ IXpsDocumentConsumer* pXpsConsumer, + _In_ IFixedPage* pFixedPage, + _In_ IResWriter* pResWriter + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pXpsConsumer, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pFixedPage, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pResWriter, E_POINTER))) + { + CComBSTR bstrKeyName; + CComBSTR bstrURI; + + // + // Check if the resource has already been written + // + if (SUCCEEDED(hr = pResWriter->GetKeyName(&bstrKeyName)) && + SUCCEEDED(hr = pResWriter->GetResURI(&bstrURI))) + { + if (!Cached(bstrKeyName)) + { + // + // The resource is not cached: + // 1. Create the resource part + // 2. Write data to part + // 3. Cache URI and new part against the resource name + // + CComPtr<_T> pRes(NULL); + CComPtr pWrite(NULL); + + if (SUCCEEDED(hr = pXpsConsumer->GetNewEmptyPart(bstrURI, + __uuidof(_T), + reinterpret_cast(&pRes), + &pWrite))) + { + hr = pResWriter->WriteData(pRes, pWrite); + + pWrite->Close(); + + try + { + CComPtr pPartBase(NULL); + if (SUCCEEDED(hr) && + SUCCEEDED(hr = pRes.QueryInterface(&pPartBase))) + { + m_resMap[CComBSTR(bstrKeyName)].first = bstrURI; + m_resMap[CComBSTR(bstrKeyName)].second = pPartBase; + } + } + catch (exception& DBG_ONLY(e)) + { + ERR(e.what()); + hr = E_FAIL; + } + } + } + + // + // Set the resource so relationships are updated + // + try + { + if (SUCCEEDED(hr)) + { + hr = pFixedPage->SetPagePart(m_resMap[CComBSTR(bstrKeyName)].second); + } + } + catch (exception& DBG_ONLY(e)) + { + ERR(e.what()); + hr = E_FAIL; + } + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CFileResourceCache::GetURI + +Routine Description: + + This routine retrieves the URI to a given resource + +Arguments: + + bstrResNameIn - The name of the resource for which the URI is required + pbstrURI - Pointer to a BSTR that recieves the resource URI + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CFileResourceCache::GetURI( + _In_z_ BSTR bstrResNameIn, + _Outptr_ BSTR* pbstrURI + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pbstrURI, E_POINTER))) + { + if (SysStringLen(bstrResNameIn) == 0) + { + hr = E_INVALIDARG; + } + } + + if (SUCCEEDED(hr)) + { + try + { + CComBSTR bstrResName(bstrResNameIn); + CComBSTR uri(m_resMap[bstrResName].first); + + if (uri.Length() > 0) + { + if (SUCCEEDED(hr = uri.CopyTo(pbstrURI)) && + !*pbstrURI) + { + hr = E_OUTOFMEMORY; + } + } + else + { + *pbstrURI = NULL; + hr = E_FAIL; + } + } + catch (exception& DBG_ONLY(e)) + { + ERR(e.what()); + hr = E_FAIL; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CFileResourceCache::Cached + +Routine Description: + + This routine checks if a resource has been cached + +Arguments: + + bstrResNameIn - The name (key) of the resource + +Return Value: + + BOOL + TRUE - The resource is in the cache + FALSE - The resource is not in the cache + +--*/ +BOOL +CFileResourceCache::Cached( + _In_z_ BSTR bstrResNameIn + ) +{ + BOOL bCached = FALSE; + + try + { + CComBSTR bstrResName(bstrResNameIn); + ResCache::const_iterator resMapIter = m_resMap.begin(); + + for (;resMapIter != m_resMap.end() && !bCached; resMapIter++) + { + if (resMapIter->first == bstrResName) + { + bCached = TRUE; + } + } + } + catch (exception& DBG_ONLY(e)) + { + ERR(e.what()); + } + + return bCached; +} + diff --git a/print/XPSDrvSmpl/src/filters/common/rescache.h b/print/XPSDrvSmpl/src/filters/common/rescache.h new file mode 100644 index 00000000..554e6352 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/common/rescache.h @@ -0,0 +1,132 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + rescache.h + +Abstract: + + File resource cache defintion and resource writer interface defintion. + Filters that need to add resources may be required to add the same resource + to numerous pages in a job. To prevent the same resource being sent + repeatedly, the file resource cache class implements an interface that + filters can use to add resources without needing to keep track of whether + they have been sent. For specific filter functionality, a class should be + created that implements a resource writer interface. This should be able to + write the resource to a stream. The filter can then add this class to the + the resource cache and it will take care of writing the resource via the + IResWriter::WriteData method if it has not already been written. + +--*/ + +#pragma once + +// +// The resource cache needs to map a unique name against the URI used +// and the part that was added. This allows us to retrieve the URI to +// write to the mark-up and also the part to set to the page/doc/docseq +// part. +// +typedef pair > URIPartPair; +typedef map ResCache; + +class IResWriter +{ +public: + IResWriter(){} + + virtual ~IResWriter(){} + + virtual HRESULT + WriteData( + _In_ IPartBase* pResource, + _In_ IPrintWriteStream* pWriter + ) = 0; + + virtual HRESULT + GetKeyName( + _Outptr_ BSTR* pbstrKeyName + ) = 0; + + virtual HRESULT + GetResURI( + _Outptr_ BSTR* pbstrResURI + ) = 0; + +}; + +class CFileResourceCache +{ +public: + CFileResourceCache(); + + virtual ~CFileResourceCache(); + + HRESULT + GetURI( + _In_z_ BSTR bstrResName, + _Outptr_ BSTR* pbstrURI + ); + + template + HRESULT + WriteResource( + _In_ IXpsDocumentConsumer* pXpsConsumer, + _In_ IFixedPage* pFixedPage, + _In_ IResWriter* pResWriter + ); + +protected: + BOOL + Cached( + _In_z_ BSTR bstrResName + ); + +private: + ResCache m_resMap; +}; + +// +// Explicitly instantiate the IPartFont, IPartImage and IPartColorProfile WriteResource template functions +// +template +HRESULT +CFileResourceCache::WriteResource( + _In_ IXpsDocumentConsumer* pXpsConsumer, + _In_ IFixedPage* pFixedPage, + _In_ IResWriter* pResWriter + ); + +template +HRESULT +CFileResourceCache::WriteResource( + _In_ IXpsDocumentConsumer* pXpsConsumer, + _In_ IFixedPage* pFixedPage, + _In_ IResWriter* pResWriter + ); + +template +HRESULT +CFileResourceCache::WriteResource( + _In_ IXpsDocumentConsumer* pXpsConsumer, + _In_ IFixedPage* pFixedPage, + _In_ IResWriter* pResWriter + ); + +template +HRESULT +CFileResourceCache::WriteResource( + _In_ IXpsDocumentConsumer* pXpsConsumer, + _In_ IFixedPage* pFixedPage, + _In_ IResWriter* pResWriter + ); + diff --git a/print/XPSDrvSmpl/src/filters/common/rescpy.cpp b/print/XPSDrvSmpl/src/filters/common/rescpy.cpp new file mode 100644 index 00000000..2f56349c --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/common/rescpy.cpp @@ -0,0 +1,132 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + rescpy.cpp + +Abstract: + + Page resource copy class implementation. This class stores resources + from one page and copies them to a destination. This is required when + copying page markup into a new page - without doing so any resources + referenced in the source page are lost. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "rescpy.h" + +/*++ + +Routine Name: + + CResourceCopier::CResourceCopier + +Routine Description: + + CResourceCopier class constructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CResourceCopier::CResourceCopier() +{ +} + +/*++ + +Routine Name: + + CResourceCopier::~CResourceCopier + +Routine Description: + + CResourceCopier class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CResourceCopier::~CResourceCopier() +{ +} + +/*++ + +Routine Name: + + CResourceCopier::CopyPageResources + +Routine Description: + + This routine takes a source page and copies all resources to a destination page. + This is required when a filter copies mark-up to a new FixedPage part else the + resources for the mark-up will be lost. + +Arguments: + + pFPSrc - Pointer to the source IFixedPage interface + pFPDst - Pointer to the destination IFixedPage interface + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CResourceCopier::CopyPageResources( + _In_ CONST IFixedPage* pFPSrc, + _Inout_ IFixedPage* pFPDst + ) +{ + HRESULT hr = S_OK; + CComPtr pXpsPartIt(NULL); + + if (SUCCEEDED(hr = CHECK_POINTER(pFPSrc, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pFPDst, E_POINTER)) && + SUCCEEDED(hr = const_cast(pFPSrc)->GetXpsPartIterator(&pXpsPartIt))) + { + pXpsPartIt->Reset(); + while (!pXpsPartIt->IsDone() && + SUCCEEDED(hr)) + { + CComBSTR bstrPartURI; + CComPtr pXPSPart(NULL); + + if (SUCCEEDED(hr = pXpsPartIt->Current(&bstrPartURI, &pXPSPart))) + { + hr = pFPDst->SetPagePart(pXPSPart); + + pXpsPartIt->Next(); + } + } + } + + ERR_ON_HR(hr); + return hr; +} + diff --git a/print/XPSDrvSmpl/src/filters/common/rescpy.h b/print/XPSDrvSmpl/src/filters/common/rescpy.h new file mode 100644 index 00000000..27dde831 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/common/rescpy.h @@ -0,0 +1,40 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + rescpy.h + +Abstract: + + Page resource copy class definition. This class stores resources + from one page and copies them to a destination. This is required when + copying page markup into a new page - without doing so any resources + referenced in the source page are lost. + +--*/ + +#pragma once + +class CResourceCopier +{ +public: + CResourceCopier(); + + virtual ~CResourceCopier(); + + HRESULT + CopyPageResources( + _In_ CONST IFixedPage* pFPSrc, + _Inout_ IFixedPage* pFPDst + ); +}; + diff --git a/print/XPSDrvSmpl/src/filters/common/saxhndlr.cpp b/print/XPSDrvSmpl/src/filters/common/saxhndlr.cpp new file mode 100644 index 00000000..bca931a5 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/common/saxhndlr.cpp @@ -0,0 +1,586 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + saxhndlr.cpp + +Abstract: + + Default sax handler implementation. Provides default implementations + for the ISAXContentHandler. This allows derived classes to only need + to implement the methods that are required. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdstring.h" +#include "xdexcept.h" +#include "saxhndlr.h" +#include "widetoutf8.h" + +/*++ + +Routine Name: + + CSaxHandler::CSaxHandler + +Routine Description: + + CSaxHandler class constructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CSaxHandler::CSaxHandler() : + CUnknown(IID_ISAXContentHandler) +{ +} + +/*++ + +Routine Name: + + CSaxHandler::~CSaxHandler + +Routine Description: + + CSaxHandler class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CSaxHandler::~CSaxHandler() +{ +} + +/*++ + +Routine Name: + + CSaxHandler::putDocumentLocator + +Routine Description: + + This routine is the default implementation for ISAXContentHandler::putDocumentLocator + +Arguments: + + Unused + +Return Value: + + HRESULT + S_OK - Always succeeds + +--*/ +HRESULT STDMETHODCALLTYPE +CSaxHandler::putDocumentLocator( + ISAXLocator * + ) +{ + return S_OK; +} + +/*++ + +Routine Name: + + CSaxHandler::startDocument + +Routine Description: + + This routine is the default implementation for ISAXContentHandler::startDocument + +Arguments: + + Unused + +Return Value: + + HRESULT + S_OK - Always succeeds + +--*/ +HRESULT STDMETHODCALLTYPE +CSaxHandler::startDocument( + void + ) +{ + return S_OK; +} + +/*++ + +Routine Name: + + CSaxHandler::endDocument + +Routine Description: + + This routine is the default implementation for ISAXContentHandler::endDocument + +Arguments: + + Unused + +Return Value: + + HRESULT + S_OK - Always succeeds + +--*/ +HRESULT STDMETHODCALLTYPE +CSaxHandler::endDocument( + void + ) +{ + return S_OK; +} + +/*++ + +Routine Name: + + CSaxHandler::startPrefixMapping + +Routine Description: + + This routine is the default implementation for ISAXContentHandler::startPrefixMapping + +Arguments: + + Unused + +Return Value: + + HRESULT + S_OK - Always succeeds + +--*/ +HRESULT STDMETHODCALLTYPE +CSaxHandler::startPrefixMapping( + CONST wchar_t*, + INT, + CONST wchar_t*, + INT + ) +{ + return S_OK; +} + +/*++ + +Routine Name: + + CSaxHandler::endPrefixMapping + +Routine Description: + + This routine is the default implementation for ISAXContentHandler::endPrefixMapping + +Arguments: + + Unused + +Return Value: + + HRESULT + S_OK - Always succeeds + +--*/ +HRESULT STDMETHODCALLTYPE +CSaxHandler::endPrefixMapping( + CONST wchar_t*, + INT + ) +{ + return S_OK; +} + +/*++ + +Routine Name: + + CSaxHandler::startElement + +Routine Description: + + This routine is the default implementation for ISAXContentHandler::startElement + +Arguments: + + Unused + +Return Value: + + HRESULT + S_OK - Always succeeds + +--*/ +HRESULT STDMETHODCALLTYPE +CSaxHandler::startElement( + CONST wchar_t*, + INT, + CONST wchar_t*, + INT, + CONST wchar_t*, + INT, + _In_ ISAXAttributes* + ) +{ + return S_OK; +} + +/*++ + +Routine Name: + + CSaxHandler::endElement + +Routine Description: + + This routine is the default implementation for ISAXContentHandler::endElement + +Arguments: + + Unused + +Return Value: + + HRESULT + S_OK - Always succeeds + +--*/ +HRESULT STDMETHODCALLTYPE +CSaxHandler::endElement( + CONST wchar_t*, + INT, + CONST wchar_t*, + INT, + CONST wchar_t*, + INT + ) +{ + return S_OK; +} + +/*++ + +Routine Name: + + CSaxHandler::characters + +Routine Description: + + This routine is the default implementation for ISAXContentHandler::characters + +Arguments: + + Unused + +Return Value: + + HRESULT + S_OK - Always succeeds + +--*/ +HRESULT STDMETHODCALLTYPE +CSaxHandler::characters( + CONST wchar_t*, + INT + ) +{ + return S_OK; +} + +/*++ + +Routine Name: + + CSaxHandler::ignorableWhitespace + +Routine Description: + + This routine is the default implementation for ISAXContentHandler::ignorableWhitespace + +Arguments: + + Unused + +Return Value: + + HRESULT + S_OK - Always succeeds + +--*/ +HRESULT STDMETHODCALLTYPE +CSaxHandler::ignorableWhitespace( + CONST wchar_t*, + INT + ) +{ + return S_OK; +} + +/*++ + +Routine Name: + + CSaxHandler::processingInstruction + +Routine Description: + + This routine is the default implementation for ISAXContentHandler::processingInstruction + +Arguments: + + Unused + +Return Value: + + HRESULT + S_OK - Always succeeds + +--*/ +HRESULT STDMETHODCALLTYPE +CSaxHandler::processingInstruction( + CONST wchar_t*, + INT, + CONST wchar_t*, + INT + ) +{ + return S_OK; +} + +/*++ + +Routine Name: + + CSaxHandler::skippedEntity + +Routine Description: + + This routine is the default implementation for ISAXContentHandler::skippedEntity + +Arguments: + + Unused + +Return Value: + + HRESULT + S_OK - Always succeeds + +--*/ +HRESULT STDMETHODCALLTYPE +CSaxHandler::skippedEntity( + CONST wchar_t*, + INT + ) +{ + return S_OK; +} + +/*++ + +Routine Name: + + CSaxHandler::WriteToPrintStream + +Routine Description: + + This routine converts a CStringXDW buffer to UTF-8 string to be + written to the write stream provided. This overload handles accepts + an IPrintWriteStream to write the data out. + +Arguments: + + pcstrOut - Pointer to the Atl CStringXDW containing the mark-up to be written + pWriter - Pointer to the print write stream to write to + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CSaxHandler::WriteToPrintStream( + _In_ CStringXDW* pcstrOut, + _In_ IPrintWriteStream* pWriter + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pcstrOut, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pWriter, E_POINTER))) + { + ULONG cbWritten = 0; + PVOID pData = NULL; + ULONG cbData = 0; + + try + { + CWideToUTF8 wideToUTF8(pcstrOut); + + if (SUCCEEDED(hr = wideToUTF8.GetBuffer(&pData, &cbData))) + { + hr = pWriter->WriteBytes(pData, cbData, &cbWritten); + } + } + catch (CXDException& e) + { + hr = e; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CSaxHandler::WriteToPrintStream + +Routine Description: + + This routine converts a CStringXDW buffer to UTF-8 string to be + written to the write stream provided. This overload handles accepts + an ISequentialStream to write the data out. + +Arguments: + + pcstrOut - Pointer to the Atl CStringXDW containing the mark-up to be written + pWriter - Pointer to the print write stream to write to + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CSaxHandler::WriteToPrintStream( + _In_ CStringXDW* pcstrOut, + _In_ ISequentialStream* pWriter + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pcstrOut, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pWriter, E_POINTER))) + { + ULONG cbWritten = 0; + PVOID pData = NULL; + ULONG cbData = 0; + + try + { + CWideToUTF8 wideToUTF8(pcstrOut); + + if (SUCCEEDED(hr = wideToUTF8.GetBuffer(&pData, &cbData))) + { + hr = pWriter->Write(pData, cbData, &cbWritten); + } + } + catch (CXDException& e) + { + hr = e; + } + } + + ERR_ON_HR(hr); + return hr; +} + + + +/*++ + +Routine Name: + + CSaxHandler::EscapeEntity + +Routine Description: + + The UnicodeString mark-up could contain characters that need to be escaped (the + SAX handler is passed the characters and not the original escapes). + The list of characters which need to be escaped are defined in the XML standard + and may change in future revisions. + This routine takes a BSTR and replaces all instances of these characters with + their escaped versions. + +Arguments: + + pStr - Pointer to the BSTR to be converted + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CSaxHandler::EscapeEntity( + _Inout_ BSTR* pStr + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pStr, E_POINTER))) + { + try + { + if (SysStringLen(*pStr) > 0) + { + CStringXDW cstrStr(*pStr); + + cstrStr.Replace(L"&", L"&"); + cstrStr.Replace(L"<", L"<"); + cstrStr.Replace(L">", L">"); + cstrStr.Replace(L"\"", L"""); + cstrStr.Replace(L"'", L"'"); + + SysFreeString(*pStr); + *pStr = cstrStr.AllocSysString(); + } + } + catch (CXDException& e) + { + hr = e; + } + } + + ERR_ON_HR(hr); + return hr; +} + diff --git a/print/XPSDrvSmpl/src/filters/common/saxhndlr.h b/print/XPSDrvSmpl/src/filters/common/saxhndlr.h new file mode 100644 index 00000000..33b142e1 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/common/saxhndlr.h @@ -0,0 +1,129 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + saxhndlr.h + +Abstract: + + Default sax handler definition. Provides default implementations + for the ISAXContentHandler. This allows derived classes to only need + to implement the methods that are required. + +--*/ + +#pragma once + +#include "CUnknown.h" + +class CSaxHandler : public CUnknown +{ +public: + CSaxHandler(); + + virtual ~CSaxHandler(); + + virtual HRESULT STDMETHODCALLTYPE + putDocumentLocator( + ISAXLocator * + ); + + virtual HRESULT STDMETHODCALLTYPE + startDocument( + void + ); + + virtual HRESULT STDMETHODCALLTYPE + endDocument( + void + ); + + virtual HRESULT STDMETHODCALLTYPE + startPrefixMapping( + CONST wchar_t*, + INT, + CONST wchar_t*, + INT + ); + + virtual HRESULT STDMETHODCALLTYPE + endPrefixMapping( + CONST wchar_t*, + INT + ); + + virtual HRESULT STDMETHODCALLTYPE + startElement( + CONST wchar_t*, + INT, + CONST wchar_t*, + INT, + CONST wchar_t*, + INT, + _In_ ISAXAttributes* + ); + + virtual HRESULT STDMETHODCALLTYPE + endElement( + CONST wchar_t*, + INT, + CONST wchar_t*, + INT, + CONST wchar_t*, + INT + ); + + virtual HRESULT STDMETHODCALLTYPE + characters( + CONST wchar_t*, + INT + ); + + virtual HRESULT STDMETHODCALLTYPE + ignorableWhitespace( + CONST wchar_t*, + INT + ); + + virtual HRESULT STDMETHODCALLTYPE + processingInstruction( + CONST wchar_t*, + INT, + CONST wchar_t*, + INT + ); + + virtual HRESULT STDMETHODCALLTYPE + skippedEntity( + CONST wchar_t*, + INT + ); + +protected: + HRESULT + WriteToPrintStream( + _In_ CStringXDW* pcstrOut, + _In_ IPrintWriteStream* pWriter + ); + + HRESULT + WriteToPrintStream( + _In_ CStringXDW* pcstrOut, + _In_ ISequentialStream* pWriter + ); + + HRESULT + EscapeEntity( + _Inout_ BSTR* pStr + ); +}; + diff --git a/print/XPSDrvSmpl/src/filters/common/widetoutf8.cpp b/print/XPSDrvSmpl/src/filters/common/widetoutf8.cpp new file mode 100644 index 00000000..39a207a5 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/common/widetoutf8.cpp @@ -0,0 +1,199 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + widetoutf8.cpp + +Abstract: + + The CWideToUTF8 class converts a Unicode character string into the UTF-8 code page format. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdstring.h" +#include "widetoutf8.h" + +/*++ + +Routine Name: + + CWideToUTF8::CWideToUTF8 + +Routine Description: + + CWideToUTF8 class constructor + +Arguments: + + pcstrWide - Unicode string to be converted to UTF8. + +Return Value: + + None + Throws CXDException(HRESULT) on an error + +--*/ +CWideToUTF8::CWideToUTF8( + CStringXDW* pcstrWide + ) : + m_pcstrWide(pcstrWide), + m_pMultiByte(NULL) +{ + HRESULT hr = CHECK_POINTER(m_pcstrWide, E_POINTER); + + if (FAILED(hr)) + { + throw CXDException(hr); + } +} + +/*++ + +Routine Name: + + CWideToUTF8::~CWideToUTF8 + +Routine Description: + + CWideToUTF8 class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CWideToUTF8::~CWideToUTF8() +{ + FreeBuffer(); +} + +/*++ + +Routine Name: + + CWideToUTF8::GetBuffer + +Routine Description: + + This method retrieves a pointer to the UTF8 converted character buffer for the CWideToUTF8 object. + +Arguments: + + ppBuffer - pointer to a pointer to the buffer. + pcbBuffer - size of the buffer that was returned. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CWideToUTF8::GetBuffer( + _Outptr_ PVOID* ppBuffer, + _Out_ ULONG* pcbBuffer + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(ppBuffer, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pcbBuffer, E_POINTER))) + { + FreeBuffer(); + + try + { + INT cbMultiByte = WideCharToMultiByte(CP_UTF8, + 0, + m_pcstrWide->GetBuffer(), + m_pcstrWide->GetLength(), + NULL, + 0, + NULL, + NULL); + + if (cbMultiByte > 0) + { + m_pMultiByte = new(std::nothrow) CHAR[cbMultiByte]; + + if (SUCCEEDED(hr = CHECK_POINTER(m_pMultiByte, E_OUTOFMEMORY))) + { + if (WideCharToMultiByte(CP_UTF8, + 0, + m_pcstrWide->GetBuffer(), + m_pcstrWide->GetLength(), + m_pMultiByte, + cbMultiByte, + NULL, + NULL) > 0) + { + *ppBuffer = m_pMultiByte; + *pcbBuffer = cbMultiByte; + } + else + { + hr = E_FAIL; + } + } + } + else + { + hr = E_FAIL; + } + } + catch (CXDException& e) + { + hr = e; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CWideToUTF8::FreeBuffer + +Routine Description: + + Releases the memory that was allocated for the string buffer during a call to CWideToUTF8::GetBuffer. + +Arguments: + + None + +Return Value: + + None + +--*/ +VOID +CWideToUTF8::FreeBuffer() +{ + if (m_pMultiByte != NULL) + { + delete[] m_pMultiByte; + m_pMultiByte = NULL; + } +} + diff --git a/print/XPSDrvSmpl/src/filters/common/widetoutf8.h b/print/XPSDrvSmpl/src/filters/common/widetoutf8.h new file mode 100644 index 00000000..9bae001a --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/common/widetoutf8.h @@ -0,0 +1,48 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + widetoutf8.h + +Abstract: + + The CWideToUTF8 class converts a Unicode character string into the UTF-8 code page format. + +--*/ + +#pragma once + +class CWideToUTF8 +{ +public: + CWideToUTF8( + CStringXDW* pcstrWide + ); + + virtual ~CWideToUTF8(); + + HRESULT + GetBuffer( + _Outptr_ PVOID* ppBuffer, + _Out_ ULONG* pcbBuffer + ); + +private: + VOID + FreeBuffer(); + +private: + CStringXDW* m_pcstrWide; + + PSTR m_pMultiByte; +}; + diff --git a/print/XPSDrvSmpl/src/filters/common/xdfltcmn.vcxproj b/print/XPSDrvSmpl/src/filters/common/xdfltcmn.vcxproj new file mode 100644 index 00000000..aa44d047 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/common/xdfltcmn.vcxproj @@ -0,0 +1,326 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {DDC3CDA6-A188-4A21-A321-37E8A044EC22} + $(MSBuildProjectName) + false + true + Debug + Win32 + {6F603421-7288-4EC6-94EF-3DEF8C069604} + + + + Windows10 + False + Desktop + + WindowsApplicationForDrivers10.0 + StaticLibrary + + + Windows10 + True + Desktop + + WindowsApplicationForDrivers10.0 + StaticLibrary + + + Windows10 + False + Desktop + + WindowsApplicationForDrivers10.0 + StaticLibrary + + + Windows10 + True + Desktop + + WindowsApplicationForDrivers10.0 + StaticLibrary + + + + $(IntDir) + + + + + + + + + + + + + + + + + %(AdditionalIncludeDirectories);..\xdcont + + + %(AdditionalIncludeDirectories);..\xdcont + + + %(AdditionalIncludeDirectories);..\xdcont + + + + + %(AdditionalIncludeDirectories);..\xdcont + + + %(AdditionalIncludeDirectories);..\xdcont + + + %(AdditionalIncludeDirectories);..\xdcont + + + + + %(AdditionalIncludeDirectories);..\xdcont + + + %(AdditionalIncludeDirectories);..\xdcont + + + %(AdditionalIncludeDirectories);..\xdcont + + + + + %(AdditionalIncludeDirectories);..\xdcont + + + %(AdditionalIncludeDirectories);..\xdcont + + + %(AdditionalIncludeDirectories);..\xdcont + + + + xdfltcmn + + + xdfltcmn + + + xdfltcmn + + + xdfltcmn + + + + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + MultiThreaded + MultiThreadedDebug + true + Level4 + Sync + + + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + %(AdditionalDependencies);uuid.lib;WIAGUID.lib;msxml6.lib;Kernel32.lib;ole32.lib;oleaut32.lib;prntvpt.lib;winspool.lib;gdi32.lib;gdiplus.lib;shlwapi.lib;Advapi32.lib;user32.lib;.\..\..\debug\$(IntDir)\xdsdbg.lib;.\..\..\common\$(IntDir)\xdsmplcmn.lib;.\..\..\filters\common\$(IntDir)\xdfltcmn.lib + + + + + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + MultiThreaded + MultiThreadedDebug + true + Level4 + Sync + + + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + %(AdditionalDependencies);uuid.lib;WIAGUID.lib;msxml6.lib;Kernel32.lib;ole32.lib;oleaut32.lib;prntvpt.lib;winspool.lib;gdi32.lib;gdiplus.lib;shlwapi.lib;Advapi32.lib;user32.lib;.\..\..\debug\$(IntDir)\xdsdbg.lib;.\..\..\common\$(IntDir)\xdsmplcmn.lib;.\..\..\filters\common\$(IntDir)\xdfltcmn.lib + + + + + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + MultiThreaded + MultiThreadedDebug + true + Level4 + Sync + + + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + %(AdditionalDependencies);uuid.lib;WIAGUID.lib;msxml6.lib;Kernel32.lib;ole32.lib;oleaut32.lib;prntvpt.lib;winspool.lib;gdi32.lib;gdiplus.lib;shlwapi.lib;Advapi32.lib;user32.lib;.\..\..\debug\$(IntDir)\xdsdbg.lib;.\..\..\common\$(IntDir)\xdsmplcmn.lib;.\..\..\filters\common\$(IntDir)\xdfltcmn.lib + + + + + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + MultiThreaded + MultiThreadedDebug + true + Level4 + Sync + + + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + %(AdditionalDependencies);uuid.lib;WIAGUID.lib;msxml6.lib;Kernel32.lib;ole32.lib;oleaut32.lib;prntvpt.lib;winspool.lib;gdi32.lib;gdiplus.lib;shlwapi.lib;Advapi32.lib;user32.lib;.\..\..\debug\$(IntDir)\xdsdbg.lib;.\..\..\common\$(IntDir)\xdsmplcmn.lib;.\..\..\filters\common\$(IntDir)\xdfltcmn.lib + + + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + + + ..;%(AdditionalIncludeDirectories) + precomp.h + Create + $(IntDir)\precomp.h.pch + + + ..;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ..;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ..;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ..;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ..;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ..;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ..;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ..;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/print/XPSDrvSmpl/src/filters/common/xdfltcmn.vcxproj.Filters b/print/XPSDrvSmpl/src/filters/common/xdfltcmn.vcxproj.Filters new file mode 100644 index 00000000..b1a98d47 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/common/xdfltcmn.vcxproj.Filters @@ -0,0 +1,46 @@ + + + + + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* + {5AE8E0BE-9490-4B67-8D0D-F1CE31744D4F} + + + h;hpp;hxx;hm;inl;inc;xsd + {C415BB35-3B6A-474A-94EB-62A11CC60EFD} + + + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml + {D121133F-D487-4B70-AD04-C77945981F69} + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/print/XPSDrvSmpl/src/filters/common/xdrchflt.cpp b/print/XPSDrvSmpl/src/filters/common/xdrchflt.cpp new file mode 100644 index 00000000..6fa2b0ed --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/common/xdrchflt.cpp @@ -0,0 +1,508 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + xdrchflt.cpp + +Abstract: + + Base Xps filter implementation. The CXDXpsFilter provides common filter + functionality for Xps filters. It provides default handlers for part + handlers that set print tickets appropriately through the PrintTicket + manager class. This allows derived classes to implement only the part + handlers that they require (for example, the watermark filter is only + interested in the fixed page, and leaves all other parts to be handled + by this class). The class implements IPrintPipelineFilter::StartOperation + which is responsible for retrieving parts from the Xps provider and + dispatching them to the relevant part handler. It is also responsible for + intialising the Xps provider and consumer. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdrchflt.h" + +/*++ + +Routine Name: + + CXDXpsFilter::CXDXpsFilter + +Routine Description: + + CXDXpsFilter class constructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CXDXpsFilter::CXDXpsFilter() : + m_pXDReader(NULL), + m_pXDWriter(NULL) +{ + VERBOSE("Constructing Xps filter\n"); +} + +/*++ + +Routine Name: + + CXDXpsFilter::~CXDXpsFilter + +Routine Description: + + CXDXpsFilter class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CXDXpsFilter::~CXDXpsFilter() +{ + VERBOSE("Destroying Xps filter\n"); +} + +/*++ + +Routine Name: + + CXDXpsFilter::StartOperation + +Routine Description: + + This is the XPS Doxument interface implementation of IPrintPipelineFilter::StartOperation + shared by all XPS Document filters + +Arguments: + + None + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CXDXpsFilter::StartOperation( + VOID + ) +{ + VERBOSE("Starting filter operation.\n"); + + HRESULT hr = S_OK; + BOOL bDoCoUninitialize = FALSE; + + if (SUCCEEDED(hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED))) + { + bDoCoUninitialize = TRUE; + } + + if (SUCCEEDED(hr) && + SUCCEEDED(hr = InitialiseXDIO()) && + SUCCEEDED(hr = InitializePrintTicketManager())) + { + CComPtr pUnk(NULL); + + while (SUCCEEDED(hr) && + SUCCEEDED(hr = m_pXDReader->GetXpsPart(&pUnk)) && + pUnk != NULL && + !m_bFilterFinished) + { + CComPtr pXD(NULL); + CComPtr pFDS(NULL); + CComPtr pFD(NULL); + CComPtr pFP(NULL); + + // + // Query interface to find the part type and pass to the + // appropriate part handler + // + if (SUCCEEDED(pUnk.QueryInterface(&pXD))) + { + hr = ProcessPart(pXD); + } + else if (SUCCEEDED(pUnk.QueryInterface(&pFDS))) + { + hr = ProcessPart(pFDS); + } + else if (SUCCEEDED(pUnk.QueryInterface(&pFD))) + { + hr = ProcessPart(pFD); + } + else if (SUCCEEDED(pUnk.QueryInterface(&pFP))) + { + hr = ProcessPart(pFP); + } + else + { + // + // Unrecognised part - send as unknown. + // + hr = m_pXDWriter->SendXpsUnknown(pUnk); + } + + // + // Must call release since pUnk is declared outside of the while loop + // + pUnk.Release(); + } + + if (SUCCEEDED(hr)) + { + // + // Call finalize letting derived classes know we have + // processed all parts + // + hr = Finalize(); + } + + // + // Close the xps package consumer + // + m_pXDWriter->CloseSender(); + } + + // + // If the filter failed make sure we shutdown the pipeline + // + if (FAILED(hr)) + { + if (m_bFilterFinished) + { + // + // Filter is already closing down so report S_OK + // + hr = S_OK; + } + else + { + // + // Request the pipeline manager shutdown the filter + // + ERR("Requesting filter shutdown\n"); + RequestShutdown(hr); + } + } + + // + // Let the filter pipe manager know the filter is finished + // + if (bDoCoUninitialize) + { + CoUninitialize(); + } + + FilterFinished(); + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CXDXpsFilter::ProcessPart + +Routine Description: + + This routine is the default XPS document part handler + +Arguments: + + pXD - Pointer to the IXPSDocument interface + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CXDXpsFilter::ProcessPart( + _Inout_ IXpsDocument* pXD + ) +{ + VERBOSE("Processing XPS Document part with default handler\n"); + + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pXD, E_POINTER))) + { + hr = m_pXDWriter->SendXpsDocument(pXD); + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CXDXpsFilter::ProcessPart + +Routine Description: + + This routine is the default fixed document sequence part handler + +Arguments: + + pFDS - Pointer to the IFixedDocumentSequence interface + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CXDXpsFilter::ProcessPart( + _Inout_ IFixedDocumentSequence* pFDS + ) +{ + VERBOSE("Processing Fixed Document Sequence part with default handler\n"); + + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pFDS, E_POINTER))) + { + // + // Default handler: Set the PT and send the doc sequence + // + if (SUCCEEDED(hr = m_ptManager.SetTicket(pFDS))) + { + hr = m_pXDWriter->SendFixedDocumentSequence(pFDS); + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CXDXpsFilter::ProcessPart + +Routine Description: + + This routine is the default fixed document part handler + +Arguments: + + pFD - Pointer to the IFixedDocument interface + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CXDXpsFilter::ProcessPart( + _Inout_ IFixedDocument* pFD + ) +{ + VERBOSE("Processing Fixed Document part with default handler\n"); + + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pFD, E_POINTER))) + { + // + // Default handler: Set the PT and send the doc + // + if (SUCCEEDED(hr = m_ptManager.SetTicket(pFD))) + { + hr = m_pXDWriter->SendFixedDocument(pFD); + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CXDXpsFilter::ProcessPart + +Routine Description: + + This routine is the default fixed page handler + +Arguments: + + pFP - Pointer to the IFixedPage interface + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CXDXpsFilter::ProcessPart( + _Inout_ IFixedPage* pFP + ) +{ + VERBOSE("Processing Fixed Page part with default handler\n"); + + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pFP, E_POINTER))) + { + // + // Default handler: No ticket required, just send the page + // + hr = m_pXDWriter->SendFixedPage(pFP); + } + + ERR_ON_HR(hr); + return hr; +} + + +/*++ + +Routine Name: + + CXDXpsFilter::Finalize + +Routine Description: + + This method is the default finalize method called when all parts in the XPS document + have been processed + +Arguments: + + None + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CXDXpsFilter::Finalize( + VOID + ) +{ + return S_OK; +} + +/*++ + +Routine Name: + + CXDXpsFilter::InitialiseXDIO + +Routine Description: + + This routine initialises the XPS producer and consumer interfaces used by + all XPS document filters + +Arguments: + + None + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CXDXpsFilter::InitialiseXDIO( + VOID + ) +{ + VERBOSE("Retrieving Xps producer and consumer.\n"); + + HRESULT hr = S_OK; + + // + // Ensure the produver and consumer are released + // + m_pXDReader = NULL; + m_pXDWriter = NULL; + + if (SUCCEEDED(hr = CHECK_POINTER(m_pInterFltrComm, E_PENDING))) + { + // + // Get the producer and consumer from the filter communicator + // + if (SUCCEEDED(hr = m_pInterFltrComm->RequestReader(reinterpret_cast(&m_pXDReader)))) + { + hr = m_pInterFltrComm->RequestWriter(reinterpret_cast(&m_pXDWriter)); + } + + // + // If anything went wrong, ensure the produver and consumer are released + // + if (FAILED(hr)) + { + m_pXDReader = NULL; + m_pXDWriter = NULL; + } + } + + // + // Check interface is as expected. If not then it is likely that + // the wrong GUID has been defined in the filter configuration file + // + if (SUCCEEDED(hr)) + { + CComPtr pReaderCheck(NULL); + CComPtr pWriterCheck(NULL); + + if (FAILED(m_pXDReader.QueryInterface(&pReaderCheck)) || + FAILED(m_pXDWriter.QueryInterface(&pWriterCheck))) + { + RIP("Invalid reader and writer defined - check GUIDs in the filter configuration file\n"); + + // + // Request the pipeline manager shutsdown the filter + // + hr = E_FAIL; + RequestShutdown(hr); + } + } + + ERR_ON_HR(hr); + return hr; +} + diff --git a/print/XPSDrvSmpl/src/filters/common/xdrchflt.h b/print/XPSDrvSmpl/src/filters/common/xdrchflt.h new file mode 100644 index 00000000..eeb6e4c9 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/common/xdrchflt.h @@ -0,0 +1,86 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + xdrchflt.h + +Abstract: + + Base Xps filter definition. The CXDXpsFilter provides common filter + functionality for Xps filters. It provides default handlers for part + handlers that set print tickets appropriately through the PrintTicket + manager class. This allows derived classes to implement only the part + handlers that they require (for example, the watermark filter is only + interested in the fixed page, and leaves all other parts to be handled + by this class). The class implements IPrintPipelineFilter::StartOperation + which is responsible for retrieving parts from the Xps provider and + dispatching them to the relevant part handler. It is also responsible for + intialising the Xps provider and consumer. + +--*/ + +#pragma once + +#include "xdsmplflt.h" +#include "rescache.h" + +class CXDXpsFilter : public CXDSmplFilter +{ +public: + CXDXpsFilter(); + + virtual ~CXDXpsFilter(); + +protected: + virtual HRESULT STDMETHODCALLTYPE + StartOperation( + VOID + ); + + virtual HRESULT + ProcessPart( + _Inout_ IXpsDocument* pXD + ); + + virtual HRESULT + ProcessPart( + _Inout_ IFixedDocumentSequence* pFDS + ); + + virtual HRESULT + ProcessPart( + _Inout_ IFixedDocument* pFD + ); + + virtual HRESULT + ProcessPart( + _Inout_ IFixedPage* pFP + ); + + virtual HRESULT + Finalize( + VOID + ); + + virtual HRESULT + InitialiseXDIO( + VOID + ); + +protected: + CComPtr m_pXDReader; + + CComPtr m_pXDWriter; + + CFileResourceCache m_resCache; +}; + diff --git a/print/XPSDrvSmpl/src/filters/common/xdsmplflt.cpp b/print/XPSDrvSmpl/src/filters/common/xdsmplflt.cpp new file mode 100644 index 00000000..cce45ac6 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/common/xdsmplflt.cpp @@ -0,0 +1,319 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + xdsmplflt.cpp + +Abstract: + + Base filter class for stream and Xps filters. This class implements + the IPrintPipelineFilter methods common to both Xps and stream filters. + +Known Issues: + + Request shutdown does not pass an IImgErrorInfo pointer + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdsmplflt.h" + +/*++ + +Routine Name: + + CXDSmplFilter::CXDSmplFilter + +Routine Description: + + CXDSmplFilter class constructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CXDSmplFilter::CXDSmplFilter() : + CUnknown(IID_IPrintPipelineFilter), + m_bFilterFinished(FALSE) +{ + VERBOSE("Constructing filter\n"); +} + + +/*++ + +Routine Name: + + CXDSmplFilter::~CXDSmplFilter + +Routine Description: + + CXDSmplFilter class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CXDSmplFilter::~CXDSmplFilter() +{ + VERBOSE("Destroying filter\n"); + + // + // Make sure FilterFinished() is called + // + FilterFinished(); +} + +/*++ + +Routine Name: + + CXDSmplFilter::InitializeFilter + +Routine Description: + + This is the IPrintPipelineFilter::InitializeFilter implementation used + by all XPS document interface filters. This is called by the print filter + pipeline manager before IPrintPipelineFilter::StartOperation. + +Arguments: + + pIInterFilterCommunicator - Pointer to the inter filter communicator + pIPropertyBag - Pointer to the property bag + pIPipelineControl - Pointer to the pipeline control interface + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CXDSmplFilter::InitializeFilter( + _In_ IInterFilterCommunicator* pIInterFilterCommunicator, + _In_ IPrintPipelinePropertyBag* pIPropertyBag, + _In_ IPrintPipelineManagerControl* pIPipelineControl + ) +{ + VERBOSE("Initializing filter\n"); + + HRESULT hr = S_OK; + + if (FAILED(hr = CHECK_POINTER(pIInterFilterCommunicator, E_POINTER)) || + FAILED(hr = CHECK_POINTER(pIPropertyBag, E_POINTER)) || + FAILED(hr = CHECK_POINTER(pIPipelineControl, E_POINTER))) + { + RequestShutdown(hr); + } + else + { + m_pPrintPipeManager = pIPipelineControl; + m_pInterFltrComm = pIInterFilterCommunicator; + m_pPrintPropertyBag = pIPropertyBag; + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CXDSmplFilter::ShutdownOperation + +Routine Description: + + This is the IPrintPipelineFilter::ShutdownOperation implementation used + by all XPS document interface filters. This is called by the print filter + pipeline manager when the filter is complete or an error forces the + pipeline to be shutdown + +Arguments: + + None + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CXDSmplFilter::ShutdownOperation( + VOID + ) +{ + VERBOSE("Shutting down filter\n"); + + FilterFinished(); + return S_OK; +} + +/*++ + +Routine Name: + + CXDSmplFilter::FilterFinished + +Routine Description: + + This routine is called when the filter is finished. Filter finished should + only be called once so this routine protects against multiple calls from the + same filter. + +Arguments: + + None + +Return Value: + + None + +--*/ +VOID +CXDSmplFilter::FilterFinished( + VOID + ) +{ + if (!m_bFilterFinished) + { + VERBOSE("Finishing filter\n"); + + if (m_pPrintPipeManager != NULL) + { + m_pPrintPipeManager->FilterFinished(); + m_bFilterFinished = TRUE; + } + } +} + +/*++ + +Routine Name: + + CXDSmplFilter::RequestShutdown + +Routine Description: + + This routine lets derived classes request the filter to shutdown + without having to know about the pipeline manager explicitly + +Arguments: + + hr - The HRESULT value to be passed to the pipeline managers RequestShutdown method. + +Return Value: + + None + +--*/ +VOID +CXDSmplFilter::RequestShutdown( + _In_ HRESULT hr + ) +{ + VERBOSE("Requesting shutdown\n"); + + if (m_pPrintPipeManager != NULL) + { +#pragma prefast(suppress:__WARNING_INVALID_PARAM_VALUE_1, "MSDN requires that pReason be NULL.") + m_pPrintPipeManager->RequestShutdown(hr, NULL); + } +} + +/*++ + +Routine Name: + + CXDSmplFilter::InitializePrintTicketManager + +Routine Description: + + This routine initializes the PrintTicket manager with the default devmode + +Arguments: + + None + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CXDSmplFilter::InitializePrintTicketManager( + VOID + ) +{ + ASSERTMSG(m_pPrintPropertyBag != NULL, "NULL property bag pointer\n"); + + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(m_pPrintPropertyBag, E_PENDING))) + { + // + // Get the printer name and user PrintTicket from the property bag + // + CComVariant varName; + CComVariant varPTReadStreamFactory; + + // + // Avoid CComVariant if getting the XPS_FP_USER_TOKEN property. + // Please refer to http://go.microsoft.com/fwlink/?LinkID=255534 for detailed information. + // + VARIANT varUserToken; + VariantInit(&varUserToken); + + if (SUCCEEDED(hr = m_pPrintPropertyBag->GetProperty(XPS_FP_USER_PRINT_TICKET, &varPTReadStreamFactory)) && + SUCCEEDED(hr = m_pPrintPropertyBag->GetProperty(XPS_FP_PRINTER_NAME, &varName)) && + SUCCEEDED(hr = m_pPrintPropertyBag->GetProperty(XPS_FP_USER_TOKEN, &varUserToken))) + { + // + // Retrieve the PrintReadStream for the user PrintTicket + // + CComPtr pUnk(varPTReadStreamFactory.punkVal); + CComPtr pPrintReadStreamFactory(NULL); + CComPtr pPrintReadStream(NULL); + if (SUCCEEDED(hr = pUnk.QueryInterface(&pPrintReadStreamFactory)) && + SUCCEEDED(hr = pPrintReadStreamFactory->GetStream(&pPrintReadStream))) + { + // + // Initialise the PT manager with the user PrintTicket and device name + // + hr = m_ptManager.Initialise(pPrintReadStream, varName.bstrVal, varUserToken.byref); + } + } + + VariantClear(&varUserToken); + } + + ERR_ON_HR(hr); + return hr; +} + diff --git a/print/XPSDrvSmpl/src/filters/common/xdsmplflt.h b/print/XPSDrvSmpl/src/filters/common/xdsmplflt.h new file mode 100644 index 00000000..b4903b4e --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/common/xdsmplflt.h @@ -0,0 +1,77 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + xdsmplflt.h + +Abstract: + + Base filter class for stream and Xps filters. This class implements + the IPrintPipelineFilter methods common to both Xps and stream filters. + +--*/ + +#pragma once + +#include "cunknown.h" +#include "ptmanage.h" + +class CXDSmplFilter : public CUnknown +{ +public: + CXDSmplFilter(); + + virtual ~CXDSmplFilter(); + + // + // IImgPipelineFilter methods + // + virtual HRESULT STDMETHODCALLTYPE + InitializeFilter( + _In_ IInterFilterCommunicator* pINegotiation, + _In_ IPrintPipelinePropertyBag* pIPropertyBag, + _In_ IPrintPipelineManagerControl* pIPipelineControl + ); + + virtual HRESULT STDMETHODCALLTYPE + ShutdownOperation( + VOID + ); + +protected: + VOID + FilterFinished( + VOID + ); + + VOID + RequestShutdown( + _In_ HRESULT hr + ); + + HRESULT + InitializePrintTicketManager( + VOID + ); + +protected: + CComPtr m_pInterFltrComm; + + CComPtr m_pPrintPipeManager; + + CComPtr m_pPrintPropertyBag; + + CPTManager m_ptManager; + + BOOL m_bFilterFinished; +}; + diff --git a/print/XPSDrvSmpl/src/filters/common/xdstrmflt.cpp b/print/XPSDrvSmpl/src/filters/common/xdstrmflt.cpp new file mode 100644 index 00000000..da8d6a5e --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/common/xdstrmflt.cpp @@ -0,0 +1,351 @@ +/*++ + +Copyright (C) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + xdstrmflt.cpp + +Abstract: + + Base stream filter implementation. This provides stream interface specific + functionality general to all filters that use the stream interface to process + fixed pages. The class is responsible copying data from reader to writer in the + absence of the PK archive handling module, for a default fixed page processing + function (filters should implement their own to manipulate fixed page markup) + and for initialising the stream reader and writer. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdstrmflt.h" + +/*++ + +Routine Name: + + CXDStreamFilter::CXDStreamFilter + +Routine Description: + + CXDStreamFilter class constructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CXDStreamFilter::CXDStreamFilter() : + m_pStreamReader(NULL), + m_pStreamWriter(NULL) +{ + VERBOSE("Constructing stream filter\n"); +} + +/*++ + +Routine Name: + + CXDStreamFilter::~CXDStreamFilter + +Routine Description: + + CXDStreamFilter clsas destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CXDStreamFilter::~CXDStreamFilter() +{ + VERBOSE("Destroying stream filter\n"); +} + +/*++ + +Routine Name: + + CXDStreamFilter::StartOperation + +Routine Description: + + This is the stream interface implementation of IPrintPipelineFilter::StartOperation + shared by all stream interface filters + +Arguments: + + None + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT STDMETHODCALLTYPE +CXDStreamFilter::StartOperation( + VOID + ) +{ + VERBOSE("Starting stream filter operation.\n"); + + HRESULT hr = S_OK; + BOOL bDoCoUninitialize = FALSE; + + if (SUCCEEDED(hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED))) + { + bDoCoUninitialize = TRUE; + } + + if (SUCCEEDED(hr) && + SUCCEEDED(hr = InitialiseStreamIO()) && + SUCCEEDED(hr = InitializePrintTicketManager())) + { + try + { + CXPSProcessor* pXpsProcessor = new(std::nothrow) CXPSProcessor(m_pStreamReader, m_pStreamWriter, this, m_pPrintPropertyBag, &m_ptManager); + + if (SUCCEEDED(hr = CHECK_POINTER(pXpsProcessor, E_OUTOFMEMORY))) + { + hr = pXpsProcessor->Start(); + } + + if (pXpsProcessor != NULL) + { + delete pXpsProcessor; + pXpsProcessor = NULL; + } + } + catch (CXDException& e) + { + hr = e; + } + catch (...) + { + hr = E_FAIL; + } + + if (hr == E_NOINTERFACE) + { + // + // The PK archive handler is missing - just pass the data on + // + + if (SUCCEEDED(hr = CHECK_POINTER(m_pStreamReader, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(m_pStreamWriter, E_POINTER))) + { + ULONG cbRead = 0; + BOOL bEOF = FALSE; + + PBYTE pBuff = new(std::nothrow) BYTE[CB_COPY_BUFFER]; + + if (SUCCEEDED(hr = CHECK_POINTER(pBuff, E_OUTOFMEMORY))) + { + do + { + if (SUCCEEDED(hr = m_pStreamReader->ReadBytes(pBuff, CB_COPY_BUFFER, &cbRead, &bEOF))) + { + ULONG cbWritten = 0; + hr = m_pStreamWriter->WriteBytes(pBuff, cbRead, &cbWritten); + } + } + while (SUCCEEDED(hr) && + !bEOF && + cbRead > 0); + + delete[] pBuff; + pBuff = NULL; + } + } + } + } + + if (m_pStreamWriter) + { + m_pStreamWriter->Close(); + } + + // + // If the filter failed make sure we shutdown the pipeline + // + if (FAILED(hr)) + { + if (m_bFilterFinished) + { + // + // Filter is already closing down so report S_OK + // + hr = S_OK; + } + else + { + // + // Request the pipeline manager shutdown the filter + // + ERR("Requesting filter shutdown\n"); + RequestShutdown(hr); + } + } + + // + // Let the filter pipe manager know the filter is finished + // + if (bDoCoUninitialize) + { + CoUninitialize(); + } + + FilterFinished(); + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CXDStreamFilter::ProcessFixedPage + +Routine Description: + + This routine is the default implemenation of the fixed page processor called by + the XPS processor object. + +Arguments: + + pFPPT - Pointer to the fixed page PrintTicket + pPageReadStream - Pointer to the page read stream + pPageWriteStream - Pointer to the page write stream + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CXDStreamFilter::ProcessFixedPage( + _In_ IXMLDOMDocument2* pFPPT, + _In_ ISequentialStream* pPageReadStream, + _In_ ISequentialStream* pPageWriteStream + ) +{ + VERBOSE("Processing stream fixed page with default handler\n"); + + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pFPPT, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pPageReadStream, E_POINTER))) + { + hr = CHECK_POINTER(pPageWriteStream, E_POINTER); + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CXDStreamFilter::InitialiseStreamIO + +Routine Description: + + This routine initialises the print stream read and write interfaces used by + all stream filters + +Arguments: + + None + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CXDStreamFilter::InitialiseStreamIO( + VOID + ) +{ + VERBOSE("Retrieving stream reader and writer.\n"); + + HRESULT hr = S_OK; + + // + // Make sure the reader and writer are released + // + m_pStreamReader = NULL; + m_pStreamWriter = NULL; + + if (SUCCEEDED(hr = CHECK_POINTER(m_pInterFltrComm, E_PENDING))) + { + // + // Get the reader and writer from the filter communicator + // + if (SUCCEEDED(hr = m_pInterFltrComm->RequestReader(reinterpret_cast(&m_pStreamReader)))) + { + hr = m_pInterFltrComm->RequestWriter(reinterpret_cast(&m_pStreamWriter)); + } + + // + // If anything went wrong, make sure the reader and writer + // have been released + // + if (FAILED(hr)) + { + m_pStreamReader = NULL; + m_pStreamWriter = NULL; + } + } + + // + // Check interface is as expected. If not then it is likely that + // the wrong GUID has been defined in the filter configuration file + // + if (SUCCEEDED(hr)) + { + CComPtr pReaderCheck(NULL); + CComPtr pWriterCheck(NULL); + + if (FAILED(m_pStreamReader.QueryInterface(&pReaderCheck)) || + FAILED(m_pStreamWriter.QueryInterface(&pWriterCheck))) + { + RIP("Invalid reader and writer defined - check GUIDs in the filter configuration file\n"); + + // + // Request the pipeline manager shutsdown the filter + // + hr = E_FAIL; + RequestShutdown(hr); + } + } + + ERR_ON_HR(hr); + return hr; +} + diff --git a/print/XPSDrvSmpl/src/filters/common/xdstrmflt.h b/print/XPSDrvSmpl/src/filters/common/xdstrmflt.h new file mode 100644 index 00000000..64489672 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/common/xdstrmflt.h @@ -0,0 +1,63 @@ +/*++ + +Copyright (C) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + xdstrmflt.h + +Abstract: + + Base stream filter definition. This provides stream interface specific + functionality general to all filters that use the stream interface to process + fixed pages. The class is responsible copying data from reader to writer in the + absence of the PK archive handling module, for a default fixed page processing + function (filters should implement their own to manipulate fixed page markup) + and for initialising the stream reader and writer. + +--*/ + +#pragma once + +#include "xdsmplflt.h" +#include "ptmanage.h" +#include "xpsproc.h" + +class CXDStreamFilter : public CXDSmplFilter, public IFixedPageProcessor +{ +public: + CXDStreamFilter(); + + virtual ~CXDStreamFilter(); + +protected: + virtual HRESULT STDMETHODCALLTYPE + StartOperation( + VOID + ); + + virtual HRESULT + ProcessFixedPage( + _In_ IXMLDOMDocument2* pFPPT, + _In_ ISequentialStream* pPageReadStream, + _In_ ISequentialStream* pPageWriteStream + ); + + HRESULT + InitialiseStreamIO( + VOID + ); + +protected: + CComPtr m_pStreamReader; + + CComPtr m_pStreamWriter; +}; + diff --git a/print/XPSDrvSmpl/src/filters/nup/dllentry.cpp b/print/XPSDrvSmpl/src/filters/nup/dllentry.cpp new file mode 100644 index 00000000..271afaaa --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/nup/dllentry.cpp @@ -0,0 +1,144 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + dllentry.cpp + +Abstract: + + Implementation of the NUp filter dllentry points. Dllmain only + stores the instance handle. DllGetClassObject calls on to a generic + get class factory template function. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "clasfact.h" +#include "nupflt.h" +#include "xdexcept.h" + +/*++ + +Routine Name: + + DllMain + +Routine Description: + + Entry point to the NUp filter which is called when a new process is started + +Arguments: + + hInst - Handle to the DLL + wReason - Specifies a flag indicating why the DLL entry-point function is being called + +Return Value: + + TRUE + +--*/ +BOOL WINAPI +DllMain( + _In_ HINSTANCE hInst, + _In_ WORD wReason, + _In_opt_ LPVOID + ) +{ + switch (wReason) + { + case DLL_PROCESS_ATTACH: + { + g_hInstance = hInst; + } + break; + } + + return TRUE; +} + + +/*++ + +Routine Name: + + DllCanUnloadNow + +Routine Description: + + Method which reports whether the DLL is in use to allow the caller to unload + the DLL safely + +Arguments: + + None + +Return Value: + + HRESULT + S_OK - Dll can unload + S_FALSE - Dll can't unload + +--*/ +STDAPI +DllCanUnloadNow() +{ + if (g_cServerLocks == 0) + { + return S_OK ; + } + else + { + return S_FALSE; + } +} + +/*++ + +Routine Name: + + DllGetClassObject + +Routine Description: + + Method to return the current class object + +Arguments: + + rclsid - CLSID that will associate the correct data and code + riid - Reference to the identifier of the interface that the caller is to use to communicate with the class object + ppv - Address of pointer variable that receives the interface pointer requested in riid + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + CLASS_E_CLASSNOTAVAILABLE - On unsupported class + +--*/ +STDAPI +DllGetClassObject( + _In_ REFCLSID rclsid, + _In_ REFIID riid, + _Outptr_ LPVOID FAR* ppv + ) +{ + // + // 6B105794-3140-40ca-A94F-624AE00AC9E8 + // + CLSID nupCLSID = {0x6B105794, 0x3140, 0x40ca, {0xA9, 0x4F, 0x62, 0x4A, 0xE0, 0x0A, 0xC9, 0xE8}}; + + return GetFilterClassFactory(rclsid, riid, nupCLSID, ppv); +} + diff --git a/print/XPSDrvSmpl/src/filters/nup/nupflt.cpp b/print/XPSDrvSmpl/src/filters/nup/nupflt.cpp new file mode 100644 index 00000000..b226ecc7 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/nup/nupflt.cpp @@ -0,0 +1,476 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + nupflt.cpp + +Abstract: + + NUp filter implementation. This class derives from the Xps filter class + and implements the necessary part handlers to support NUp printing. The + NUp filter is responsible for applying page transformations appropriate + to the NUp option selected. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "nupflt.h" +#include "nupsax.h" +#include "nupthndlr.h" +#include "bkpthndlr.h" +#include "psizepthndlr.h" +#include "porientpthndlr.h" + + +using XDPrintSchema::NUp::NUpData; + +using XDPrintSchema::Binding::BindingData; + +using XDPrintSchema::PageMediaSize::PageMediaSizeData; + +using XDPrintSchema::PageOrientation::PageOrientationData; + +/*++ + +Routine Name: + + CNUpFilter::CNUpFilter + +Routine Description: + + Default constructor for the nup filter which ensures GDI plus is correctly running + and initialises the CNUpFilter variables to sensible defaults + +Arguments: + + None + +Return Value: + + None + +--*/ +CNUpFilter::CNUpFilter() : + m_bSendAllDocs(TRUE), + m_pNUpPage(NULL), + m_nupScope(CNUpPTProperties::None) +{ + ASSERTMSG(m_gdiPlus.GetGDIPlusStartStatus() == Ok, "GDI plus is not correctly initialized.\n"); +} + +/*++ + +Routine Name: + + CNUpFilter::~CNUpFilter + +Routine Description: + + Default destructor for the color management filter + +Arguments: + + None + +Return Value: + + None + +--*/ +CNUpFilter::~CNUpFilter() +{ + DeleteNUpPage(); +} + +/*++ + +Routine Name: + + CNUpFilter::ProcessPart + +Routine Description: + + Method for processing each fixed document sequence part in a container + +Arguments: + + pFDS - Pointer to the fixed document sequence to process + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CNUpFilter::ProcessPart( + _Inout_ IFixedDocumentSequence* pFDS + ) +{ + VERBOSE("Processing Fixed Document Sequence part with NUpFilter handler\n"); + + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pFDS, E_POINTER))) + { + // + // Get the PT manager to return the correct ticket. + // + IXMLDOMDocument2* pPT = NULL; + if (SUCCEEDED(hr = m_ptManager.SetTicket(pFDS)) && + SUCCEEDED(hr = m_ptManager.GetTicket(kPTJobScope, &pPT))) + { + hr = CreateNUpPage(pPT); + } + } + + if (SUCCEEDED(hr)) + { + hr = m_pXDWriter->SendFixedDocumentSequence(pFDS); + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CNUpFilter::ProcessPart + +Routine Description: + + Method for processing each fixed document part in a container + +Arguments: + + pFD - Pointer to the fixed document to process + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CNUpFilter::ProcessPart( + _Inout_ IFixedDocument* pFD + ) +{ + VERBOSE("Processing Fixed Document part with NUpFilter handler\n"); + + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pFD, E_POINTER)) && + SUCCEEDED(hr = m_ptManager.SetTicket(pFD))) + { + // + // If we are in a JobNUpAllDocumentsContiguously session we want to maintain the current + // JobNUpAllDocumentsContiguously settings so keep the current NUp page object + // + if (m_nupScope != CNUpPTProperties::Job) + { + // + // Get the PT manager to return the correct ticket. + // + IXMLDOMDocument2* pPT = NULL; + if (SUCCEEDED(hr = m_ptManager.GetTicket(kPTDocumentScope, &pPT))) + { + hr = CreateNUpPage(pPT); + } + } + } + + if (SUCCEEDED(hr) && + m_bSendAllDocs) + { + hr = m_pXDWriter->SendFixedDocument(pFD); + + // + // If we are JobNUpAllDocumentsContiguously we only ever send one doc - now we have + // sent the first document we can test to see if we need to + // send all of them + // + if (m_nupScope == CNUpPTProperties::Job) + { + m_bSendAllDocs = FALSE; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CNUpFilter::ProcessPart + +Routine Description: + + Method for processing each fixed page part in a container + +Arguments: + + pFP - Pointer to the fixed page to process + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CNUpFilter::ProcessPart( + _Inout_ IFixedPage* pFP + ) +{ + VERBOSE("Processing Fixed Page part with NUpFilter handler\n"); + + ASSERTMSG(m_pXDWriter != NULL, "NULL consumer pointer\n"); + + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pFP, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(m_pXDWriter, E_PENDING))) + { + if (m_pNUpPage != NULL) + { + // + // Add this pages contents to our NUp page + // + hr = m_pNUpPage->AddPageContent(m_pXDWriter, pFP); + } + else + { + // + // Just write out the fixed page + // + hr = m_pXDWriter->SendFixedPage(pFP); + } + } + + ERR_ON_HR(hr); + return hr; +} + + +/*++ + +Routine Name: + + CNUpFilter::Finalize + +Routine Description: + + Method to close any pages which are still open as the last action of the filter + +Arguments: + + None + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CNUpFilter::Finalize( + VOID + ) +{ + ASSERTMSG(m_pXDWriter != NULL, "NULL consumer pointer\n"); + + HRESULT hr = S_OK; + + if (m_pNUpPage != NULL) + { + // + // Close any open pages - we are done + // + hr = m_pNUpPage->ClosePage(m_pXDWriter); + DeleteNUpPage(); + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CNUpFilter::DeleteNUpPage + +Routine Description: + + Method to delete the current CNUpPage object + +Arguments: + + None + +Return Value: + + None + +--*/ +VOID +CNUpFilter::DeleteNUpPage( + VOID + ) +{ + if (m_pNUpPage != NULL) + { + delete m_pNUpPage; + m_pNUpPage = NULL; + } +} + +/*++ + +Routine Name: + + CNUpFilter::CreateNUpPage + +Routine Description: + + Method to create a new nup page based on the settings specified in the PrintTicket + +Arguments: + + pPT - Pointer to the PrintTicket containing the nup driver settings + +Return Value: + + HRESULT + S_OK - On success + S_FALSE - When not enabled in the PT + E_* - On error + +--*/ +HRESULT +CNUpFilter::CreateNUpPage( + _In_ IXMLDOMDocument2* pPT + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pPT, E_POINTER))) + { + + try + { + // + // Retrieve the NUp, Booklet, PageMediaSize and PageOrientation data from the PT + // + NUpData nUpData; + BindingData bindingData; + PageMediaSizeData pageMediaSizeData; + PageOrientationData pageOrientData; + + CNUpPTHandler nUpPTHandler(pPT); + CBookPTHandler bkPTHandler(pPT); + CPageSizePTHandler pageSizePTHandler(pPT); + CPageOrientationPTHandler pageOrientPTHandler(pPT); + + // + // Try the booklet data first + // + if (FAILED(hr = bkPTHandler.GetData(&bindingData))) + { + // + // If booklet is not present try NUp settings + // + if (hr == E_ELEMENT_NOT_FOUND) + { + hr = nUpPTHandler.GetData(&nUpData); + } + } + + if (SUCCEEDED(hr) && + SUCCEEDED(hr = pageSizePTHandler.GetData(&pageMediaSizeData)) && + SUCCEEDED(hr = pageOrientPTHandler.GetData(&pageOrientData))) + { + CNUpPTProperties nUpProps(nUpData, bindingData, pageMediaSizeData, pageOrientData); + + UINT cNUp = 1; + if (SUCCEEDED(hr = nUpProps.GetScope(&m_nupScope)) && + SUCCEEDED(hr = nUpProps.GetCount(&cNUp)) && + m_nupScope != CNUpPTProperties::None && + cNUp > 1) + { + if (m_pNUpPage == NULL) + { + // + // Create a new NUp page + // + m_pNUpPage = new(std::nothrow) CNUpPage(&nUpProps, &m_resCopier); + + hr = CHECK_POINTER(m_pNUpPage, E_OUTOFMEMORY); + } + else if (m_nupScope == CNUpPTProperties::Document) + { + // + // Second or subsequent Document NUp session - close the page and set + // the new properties + // + if (SUCCEEDED(hr = m_pNUpPage->ClosePage(m_pXDWriter))) + { + hr = m_pNUpPage->SetProperties(&nUpProps); + } + } + } + else + { + // + // NUp is not set - Fail the request so the page is closed and deleted + // + hr = E_ELEMENT_NOT_FOUND; + } + } + } + catch (CXDException& e) + { + hr = e; + } + } + + if (hr == E_ELEMENT_NOT_FOUND) + { + // + // The relevant features are not present in the print ticket or contain unsupported values. + // Close and delete the NUp page if it is currently open and do not propogate the fail status. + // + hr = S_FALSE; + + if (m_pNUpPage != NULL) + { + hr = m_pNUpPage->ClosePage(m_pXDWriter); + } + + DeleteNUpPage(); + } + + ERR_ON_HR(hr); + return hr; +} + diff --git a/print/XPSDrvSmpl/src/filters/nup/nupflt.h b/print/XPSDrvSmpl/src/filters/nup/nupflt.h new file mode 100644 index 00000000..814d8021 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/nup/nupflt.h @@ -0,0 +1,88 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + nupflt.h + +Abstract: + + NUp filter definition. This class derives from the Xps filter + class and implements the necessary part handlers to support booklet + printing. The nup filter is responsible for applyinh page transofmations + appropriate to the NUp option selected. + +Known Issues: + + The filter uses PageMediaSize and not PageImageableSize to calculate the + canvas bounds + + The filter does not yet handle booklet offsets (gutter etc.) + +--*/ + +#pragma once + +#include "xdrchflt.h" +#include "nuppage.h" +#include "gdip.h" + +class CNUpFilter : public CXDXpsFilter +{ +public: + CNUpFilter(); + + virtual ~CNUpFilter(); + +private: + + virtual HRESULT + ProcessPart( + _Inout_ IFixedDocumentSequence* pFDS + ); + + virtual HRESULT + ProcessPart( + _Inout_ IFixedDocument* pFD + ); + + virtual HRESULT + ProcessPart( + _Inout_ IFixedPage* pFP + ); + + HRESULT + Finalize( + VOID + ); + + VOID + DeleteNUpPage( + VOID + ); + + HRESULT + CreateNUpPage( + _In_ IXMLDOMDocument2* pPT + ); + +protected: + GDIPlus m_gdiPlus; + + CNUpPage* m_pNUpPage; + + BOOL m_bSendAllDocs; + + CNUpPTProperties::ENUpScope m_nupScope; + + CResourceCopier m_resCopier; +}; + diff --git a/print/XPSDrvSmpl/src/filters/nup/nupflt.rc b/print/XPSDrvSmpl/src/filters/nup/nupflt.rc new file mode 100644 index 00000000..f88d267c --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/nup/nupflt.rc @@ -0,0 +1,43 @@ +// +// Copyright (c) 2005 Microsoft Corporation +// +// All rights reserved. +// +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +// PARTICULAR PURPOSE. +// +// File Name: +// +// nupflt.rc +// +// Abstract: +// +// NUp filter resource file. +// +// + +#include +#include + +#define VER_FILETYPE VFT_DLL +#define VER_FILESUBTYPE VFT2_UNKNOWN +#define VER_FILEDESCRIPTION_STR "XPSDrv Sample NUp Filter" +#define VER_INTERNALNAME_STR "PrintFeatureFilters" + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#endif // English (U.S.) resources + +///////////////////////////////////////////////////////////////////////////// + +#include "common.ver" + diff --git a/print/XPSDrvSmpl/src/filters/nup/nuppage.cpp b/print/XPSDrvSmpl/src/filters/nup/nuppage.cpp new file mode 100644 index 00000000..f814d21a --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/nup/nuppage.cpp @@ -0,0 +1,581 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + nuppage.cpp + +Abstract: + + NUp page implementation. This class is responsible for maintaining + the current NUp page. The public interface defines methods for adding + fixed page content and closing the current page. When a page is added, + the class uses a SAX handler to strip the FixedPage tags from the + source page, apply a canvas with a transformation and add it to the + current NUp page. When the page is full it is closed and sent and a new + NUp page is created. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdstring.h" +#include "nuppage.h" +#include "nupsax.h" +#include "widetoutf8.h" + +static CONST PCWSTR pszOpenFPTag = L""; + +/*++ + +Routine Name: + + CNUpPage::CNUpPage + +Routine Description: + + Constructor for the CNUpPage class which initialises itself to sensible values + and creates a new page transformation + +Arguments: + + pNUpProps - Pointer to class containing nup settings from the PrintTicket + pResCopier - Pointer to page resource copy class used for copying markup between pages + +Return Value: + + None + Throws CXDException(HRESULT) on an error + +--*/ +CNUpPage::CNUpPage( + _In_ CNUpPTProperties* pNUpProps, + _In_ CResourceCopier* pResCopier + ) : + m_pNUpProps(NULL), + m_pNUpTransform(NULL), + m_pWriter(NULL), + m_pFixedPage(NULL), + m_cCurrPageIndex(0), + m_cNUp(1), + m_pResCopier(pResCopier) +{ + HRESULT hr = S_OK; + ASSERTMSG(m_pResCopier != NULL, "Invalid resource copier\n"); + + if (SUCCEEDED(hr = CHECK_POINTER(pNUpProps, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pResCopier, E_POINTER))) + { + try + { + m_pNUpProps = new(std::nothrow) CNUpPTProperties(*pNUpProps); + + if (SUCCEEDED(hr = CHECK_POINTER(m_pNUpProps, E_OUTOFMEMORY))) + { + m_pNUpTransform = new(std::nothrow) CNUpTransform(m_pNUpProps); + + hr = CHECK_POINTER(m_pNUpTransform, E_OUTOFMEMORY); + } + + if (SUCCEEDED(hr)) + { + hr = m_pNUpProps->GetCount(&m_cNUp); + } + } + catch (CXDException& e) + { + hr = e; + } + } + + if (FAILED(hr)) + { + if (m_pNUpProps != NULL) + { + delete m_pNUpProps; + m_pNUpProps = NULL; + } + + if (m_pNUpTransform != NULL) + { + delete m_pNUpTransform; + m_pNUpTransform = NULL; + } + + throw CXDException(hr); + } +} + +/*++ + +Routine Name: + + CNUpPage::~CNUpPage + +Routine Description: + + Default destructor for the CNUpPage class + +Arguments: + + None + +Return Value: + + None + +--*/ +CNUpPage::~CNUpPage() +{ + DeleteProperties(); + DeleteTransform(); + + ASSERTMSG(m_pWriter == NULL, "Destroying NUp page with open page writer\n"); + ASSERTMSG(m_pFixedPage == NULL, "Destroying NUp page with open fixed page\n"); +} + +/*++ + +Routine Name: + + CNUpPage::AddPageContent + +Routine Description: + + Method to write out fixed page with a transformation matrix + +Arguments: + + pWriter - Pointer to a writer which the transformed fixed page will be sent to + pFP - Pointer to the fixed page to be transformed and written out + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CNUpPage::AddPageContent( + _In_ IXpsDocumentConsumer* pWriter, + _In_ IFixedPage* pFP + ) +{ + ASSERTMSG(m_pNUpTransform != NULL, "NULL transform object\n"); + ASSERTMSG(m_pNUpProps != NULL, "NULL NUp properties object\n"); + + HRESULT hr = S_OK; + + SizeF sizePage; + if (SUCCEEDED(hr = CHECK_POINTER(pWriter, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pFP, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(m_pNUpProps, E_PENDING)) && + SUCCEEDED(hr = CHECK_POINTER(m_pNUpTransform, E_PENDING)) && + SUCCEEDED(hr = m_pNUpProps->GetPageSize(&sizePage)) && + m_pFixedPage == NULL) + { + hr = CreateNewPage(pWriter, sizePage); + } + + if (SUCCEEDED(hr)) + { + // + // Create a SAX reader to parse the mark-up write out the page + // content + // + CComPtr pSaxRdr(NULL); + if (SUCCEEDED(hr) && + SUCCEEDED(hr = pSaxRdr.CoCreateInstance(CLSID_SAXXMLReader60))) + { + try + { + m_pNUpTransform->SetCurrentPage(m_cCurrPageIndex); + + // + // Create our NUp sax handler + // + CNUpSaxHandler nupSaxHndlr(m_pWriter, m_pResCopier, m_pNUpTransform); + + // + // Set-up the SAX reader and begin parsing the mark-up + // + CComPtr pReader(NULL); + if (SUCCEEDED(hr = pSaxRdr->putContentHandler(&nupSaxHndlr)) && + SUCCEEDED(hr = pFP->GetStream(&pReader))) + { + CComPtr pReadStreamToSeq(NULL); + + pReadStreamToSeq.Attach(new(std::nothrow) pfp::PrintReadStreamToSeqStream(pReader)); + + if (SUCCEEDED(hr = CHECK_POINTER(pReadStreamToSeq, E_OUTOFMEMORY))) + { + hr = pSaxRdr->parse(CComVariant(static_cast(pReadStreamToSeq))); + } + } + } + catch (CXDException& e) + { + hr = e; + } + } + + // + // Copy resources + // + if (SUCCEEDED(hr) && + SUCCEEDED(hr = CHECK_POINTER(m_pResCopier, E_PENDING))) + { + hr = m_pResCopier->CopyPageResources(pFP, m_pFixedPage); + } + + m_cCurrPageIndex++; + } + + if (SUCCEEDED(hr)) + { + // + // Check if we need to close the page + // + if (m_cCurrPageIndex == m_cNUp) + { + hr = ClosePage(pWriter); + m_cCurrPageIndex = 0; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CNUpPage::ClosePage + +Routine Description: + + Method to close an open fixed page including the addition of any required markup + +Arguments: + + pWriter - Pointer to a writer which receives the closing markup + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CNUpPage::ClosePage( + _In_ IXpsDocumentConsumer* pWriter + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pWriter, E_POINTER))) + { + // + // Add closing page mark-up, close the current page writer + // + if (m_pWriter != NULL) + { + try + { + CStringXDW cstrCloseFP(L""); + hr = WriteToPrintStream(&cstrCloseFP, m_pWriter); + } + catch (CXDException& e) + { + hr = e; + } + + ASSERTMSG(SUCCEEDED(hr), "Failed to write fixed page closing tag\n"); + + m_pWriter->Close(); + } + + // + // Send the current page + // + if (m_pFixedPage != NULL) + { + hr = pWriter->SendFixedPage(m_pFixedPage); + } + + ASSERTMSG(SUCCEEDED(hr), "Failed to send page\n"); + } + + // + // Release the writer and the fixed page + // + m_pWriter = NULL; + m_pFixedPage = NULL; + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CNUpPage::SetProperties + +Routine Description: + + Method to set the nup properties at a start of a new run of pages + +Arguments: + + pNUpProps - Pointer to an object containing nup settings from the PrintTicket + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CNUpPage::SetProperties( + _In_ CNUpPTProperties* pNUpProps + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pNUpProps, E_POINTER))) + { + DeleteProperties(); + DeleteTransform(); + + m_pNUpProps = new(std::nothrow) CNUpPTProperties(*pNUpProps); + + if (SUCCEEDED(hr = CHECK_POINTER(m_pNUpProps, E_OUTOFMEMORY))) + { + m_pNUpTransform = new(std::nothrow) CNUpTransform(m_pNUpProps); + + if (SUCCEEDED(hr = CHECK_POINTER(m_pNUpTransform, E_OUTOFMEMORY))) + { + hr = m_pNUpProps->GetCount(&m_cNUp); + m_cCurrPageIndex = 0; + } + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CNUpPage::CreateNewPage + +Routine Description: + + Method to create a new fixed page to contain the original pages as canvas' + +Arguments: + + pWriter - Pointer to a writer which the new fixed page will be sent to + sizePage - Size of the new page + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CNUpPage::CreateNewPage( + _In_ IXpsDocumentConsumer* pWriter, + _In_ SizeF sizePage + ) +{ + HRESULT hr = S_OK; + + CComBSTR bstrPageURI; + + if (SUCCEEDED(hr = CHECK_POINTER(pWriter, E_POINTER))) + { + // + // Create a unique page URI + // + try + { + // + // Create a unique name for the NUp page for this print session + // + CStringXDW cstrPageURI; + cstrPageURI.Format(L"/NUpPage_%u.xml", GetUniqueNumber()); + bstrPageURI.Empty(); + bstrPageURI.Attach(cstrPageURI.AllocSysString()); + } + catch (CXDException& e) + { + hr = e; + } + } + + // + // Close any open pages, create the new page and retrieve the page writer + // + if (SUCCEEDED(hr) && + SUCCEEDED(hr = ClosePage(pWriter)) && + SUCCEEDED(hr = pWriter->GetNewEmptyPart(bstrPageURI, + __uuidof(IFixedPage), + reinterpret_cast(&m_pFixedPage), + &m_pWriter))) + { + // + // Construct the opening FixedPage tag + // + try + { + CStringXDW cstrOpenFP; + cstrOpenFP.Format(pszOpenFPTag, sizePage.Width, sizePage.Height); + hr = WriteToPrintStream(&cstrOpenFP, m_pWriter); + } + catch (CXDException& e) + { + hr = e; + } + + ASSERTMSG(SUCCEEDED(hr), "Failed to write fixed page opening tag\n"); + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CNUpPage::DeleteProperties + +Routine Description: + + Method to delete the current nup properties object + +Arguments: + + None + +Return Value: + + None + +--*/ +VOID +CNUpPage::DeleteProperties( + VOID + ) +{ + if (m_pNUpProps != NULL) + { + delete m_pNUpProps; + m_pNUpProps = NULL; + } +} + +/*++ + +Routine Name: + + CNUpPage::DeleteTransform + +Routine Description: + + Method to delete the current nup transform object + +Arguments: + + None + +Return Value: + + None + +--*/ +VOID +CNUpPage::DeleteTransform( + VOID + ) +{ + delete m_pNUpTransform; + m_pNUpTransform = NULL; +} + + +/*++ + +Routine Name: + + CNUpPage::WriteToPrintStream + +Routine Description: + + This routine converts a CStringXDW buffer to UTF-8 string to be + written to the write stream provided + +Arguments: + + pcstrOut - Pointer to the Atl CStringXDW containing the mark-up to be written + pWriter - Pointer to the print write stream to write to + +Return Value: + + HRESULT + S_OK - Always succeeds + +--*/ +HRESULT +CNUpPage::WriteToPrintStream( + _In_ CStringXDW* pcstrOut, + _In_ IPrintWriteStream* pWriter + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pcstrOut, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pWriter, E_POINTER))) + { + ULONG cbWritten = 0; + PVOID pData = NULL; + ULONG cbData = 0; + + try + { + CWideToUTF8 wideToUTF8(pcstrOut); + + if (SUCCEEDED(hr = wideToUTF8.GetBuffer(&pData, &cbData))) + { + hr = pWriter->WriteBytes(pData, cbData, &cbWritten); + } + } + catch (CXDException& e) + { + hr = e; + } + } + + ERR_ON_HR(hr); + return hr; +} + diff --git a/print/XPSDrvSmpl/src/filters/nup/nuppage.h b/print/XPSDrvSmpl/src/filters/nup/nuppage.h new file mode 100644 index 00000000..545c5114 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/nup/nuppage.h @@ -0,0 +1,107 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + nuppage.h + +Abstract: + + NUp page definition. This class is responsible for maintaining + the current NUp page. The public interface defines methods for adding + fixed page content and closing the current page. When a page is added, + the class uses a SAX handler to strip the FixedPage tags from the + source page, apply a canvas with a transformation and add it to the + current NUp page. When the page is full it is closed and sent and a new + NUp page is created. + +--*/ + +#pragma once + +#include "rescpy.h" +#include "xdstring.h" +#include "nupxform.h" + +class CNUpPage +{ +public: + CNUpPage( + _In_ CNUpPTProperties* pNUpProps, + _In_ CResourceCopier* pResCopier + ); + + virtual ~CNUpPage(); + + HRESULT + AddPageContent( + _In_ IXpsDocumentConsumer* pWriter, + _In_ IFixedPage* pFP + ); + + HRESULT + ClosePage( + _In_ IXpsDocumentConsumer* pWriter + ); + + HRESULT + SetProperties( + _In_ CNUpPTProperties* pNUpProps + ); + +private: + HRESULT + CreateNewPage( + _In_ IXpsDocumentConsumer* pWriter, + _In_ SizeF sizePage + ); + + HRESULT + CopyResources( + _In_ IFixedPage* pFPSrc, + _Inout_ IFixedPage* pFPDst + ); + + VOID + DeleteProperties( + VOID + ); + + VOID + DeleteTransform( + VOID + ); + + HRESULT + WriteToPrintStream( + _In_ CStringXDW* pcstrOut, + _In_ IPrintWriteStream* pWriter + ); + +private: + CComPtr m_pWriter; + + CComPtr m_pFixedPage; + + // + // Current page index (i.e. 0 - 5 for 6 Up) + // + UINT m_cCurrPageIndex; + + UINT m_cNUp; + + CNUpTransform* m_pNUpTransform; + + CNUpPTProperties* m_pNUpProps; + + CResourceCopier* m_pResCopier; +}; + diff --git a/print/XPSDrvSmpl/src/filters/nup/nupsax.cpp b/print/XPSDrvSmpl/src/filters/nup/nupsax.cpp new file mode 100644 index 00000000..830f6928 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/nup/nupsax.cpp @@ -0,0 +1,522 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + nupsax.xpp + +Abstract: + + NUp SAX handler implementation. The class derives from the default SAX handler + and implements only the necessary SAX APIs to process the mark-up. The + handler is responsible for copying page mark-up to a writer, removing + the fixed page opening and closing tags. It is also responsible for + identifying resources that need to be copied from the source page to + the NUp page. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdstring.h" +#include "nupsax.h" + +// +// We will need to preserve namespaces defined by the source fixed page into each canvas, +// e.g. xmlns:x="http://schemas.microsoft.com/xps/2005/06/resourcedictionary-key". To do +// this we will create and populate a vector of namespaces to add to the canvas wrappning +// the source fixed page. +// +typedef pair AttribValuePair; +typedef vector NamespaceVector; + +/*++ + +Routine Name: + + CNUpSaxHandler::CNUpSaxHandler + +Routine Description: + + Contructor for the nup filters SAX handler which registers + internally the writer for sending new markup out to and a + resource copier which copies markup between pages + +Arguments: + + pWriter - Pointer to a write stream which receives markup + pResCopier - Pointer to a resource markup copier object which + copies markup between pages + +Return Value: + + None + Throws CXDException(HRESULT) on an error + +--*/ +CNUpSaxHandler::CNUpSaxHandler( + _In_ IPrintWriteStream* pWriter, + _In_ CResourceCopier* pResCopier, + _In_ CNUpTransform* pNUpTransform + ) : + m_pWriter(pWriter), + m_bOpenTag(FALSE), + m_pResCopier(pResCopier), + m_pNUpTransform(pNUpTransform) +{ + ASSERTMSG(m_pWriter != NULL, "NULL writer passed to NUp SAX handler.\n"); + ASSERTMSG(m_pResCopier != NULL, "NULL resource copier passed to NUp SAX handler.\n"); + ASSERTMSG(m_pNUpTransform != NULL, "NULL NUp Transform object passed to NUp SAX handler.\n"); + + HRESULT hr = S_OK; + if (FAILED(hr = CHECK_POINTER(m_pWriter, E_PENDING)) || + FAILED(hr = CHECK_POINTER(m_pResCopier, E_PENDING)) || + FAILED(hr = CHECK_POINTER(m_pNUpTransform, E_PENDING))) + { + throw CXDException(hr); + } +} + +/*++ + +Routine Name: + + CNUpSaxHandler::~CNUpSaxHandler + +Routine Description: + + Default destructor for the nup filters SAX handler + +Arguments: + + None + +Return Value: + + None + +--*/ +CNUpSaxHandler::~CNUpSaxHandler() +{ + m_bstrOpenElement.Empty(); +} + +/*++ + +Routine Name: + + CNUpSaxHandler::startElement + +Routine Description: + + SAX handler method which handles each start element for the XML markup + +Arguments: + + pwchQName - Pointer to a string containing the element name + cchQName - Count of the number of characters in the element name + pAttributes - Pointer to the attribute list for the supplied element + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT STDMETHODCALLTYPE +CNUpSaxHandler::startElement( + CONST wchar_t*, + INT, + CONST wchar_t*, + INT, + _In_reads_(cchQName) CONST wchar_t* pwchQName, + _In_ INT cchQName, + _In_ ISAXAttributes* pAttributes + ) +{ + HRESULT hr = S_OK; + CStringXDW cstrOut; + + // + // If this is the fixed page we need the width and height retrieved + // + BOOL bIsFixedPage = FALSE; + + try + { + CComBSTR bstrElement(cchQName, pwchQName); + + bIsFixedPage = (bstrElement == L"FixedPage"); + + // + // The resource dictionary is now canvas wide + // + if (bstrElement == L"FixedPage.Resources") + { + bstrElement = L"Canvas.Resources"; + } + + // + // Check if we need to close an opened tag + // + if (m_bOpenTag) + { + cstrOut.Append(L">"); + } + + // + // Store the opened element name so we can handle nested elements + // + m_bstrOpenElement = bstrElement; + } + catch (CXDException& e) + { + hr = e; + } + + if (SUCCEEDED(hr)) + { + // + // If this is the fixed page we do not write the tag + // + if (!bIsFixedPage) + { + // + // Write out element + // + try + { + cstrOut.Append(L"<"); + cstrOut.Append(m_bstrOpenElement); + } + catch (CXDException& e) + { + hr = e; + } + + // + // We opened a tag + // + m_bOpenTag = TRUE; + } + + SizeF sizePage(0.0f, 0.0f); + + // + // Record additional namespaces defined by the fixed page + // + NamespaceVector fpNamespaces; + + // + // Find the number of attributes and enumerate over all of them + // + INT cAttributes = 0; + if (SUCCEEDED(hr) && + SUCCEEDED(hr = pAttributes->getLength(&cAttributes))) + { + for (INT cIndex = 0; cIndex < cAttributes && SUCCEEDED(hr); cIndex++) + { + PCWSTR pszAttUri = NULL; + INT cchAttUri = 0; + PCWSTR pszAttName = NULL; + INT cchAttName = 0; + PCWSTR pszAttQName = NULL; + INT cchAttQName = 0; + PCWSTR pszAttValue = NULL; + INT cchAttValue = 0; + + // + // Get the attribute data ready to write out + // + if (SUCCEEDED(hr = pAttributes->getName(cIndex, + &pszAttUri, + &cchAttUri, + &pszAttName, + &cchAttName, + &pszAttQName, + &cchAttQName))) + { + if (SUCCEEDED(pAttributes->getValue(cIndex, &pszAttValue, &cchAttValue))) + { + try + { + CComBSTR bstrAttName(cchAttQName, pszAttQName); + CComBSTR bstrAttValue(cchAttValue, pszAttValue); + + if (bIsFixedPage) + { + // + // Extract the page Width and Height values + // + CStringXDW cstrAttName(bstrAttName); + if (cstrAttName == L"Width") + { + sizePage.Width = static_cast(_wtof(bstrAttValue)); + + if (sizePage.Width < 1.f) + { + // + // According to the Xps Specification, + // FixedPage Width must be >= 1.0 + // + hr = E_FAIL; + } + } + else if (cstrAttName == L"Height") + { + sizePage.Height = static_cast(_wtof(bstrAttValue)); + + if (sizePage.Height < 1.f) + { + // + // According to the Xps Specification, + // FixedPage Height must be >= 1.0 + // + hr = E_FAIL; + } + } + else if (cstrAttName.Find(L"xmlns:") == 0) + { + // + // We have an additional namespace - add to the vector to be applied to the canvas element + // + fpNamespaces.push_back(AttribValuePair(cstrAttName, CStringXDW(bstrAttValue))); + } + } + else + { + // + // Delimit attributes with a space + // + cstrOut.Append(L" "); + + // + // Reconstruct the attribute and write back to + // the fixed page + // + cstrOut.Append(bstrAttName); + cstrOut.Append(L"=\""); + + // + // If this is a UnicodeString we may need to escape entities + // + if (bstrAttName == L"UnicodeString") + { + hr = EscapeEntity(&bstrAttValue); + } + + cstrOut.Append(bstrAttValue); + cstrOut.Append(L"\""); + } + } + catch (CXDException& e) + { + hr = e; + } + catch (exception& DBG_ONLY(e)) + { + ERR(e.what()); + hr = E_FAIL; + } + } + } + } + } + + if (SUCCEEDED(hr) && + bIsFixedPage) + { + // + // Write the canvas out + // + try + { + // + // Get the page transform for the current page + // + CComBSTR bstrMatrix; + Matrix matrixTransform; + + if (SUCCEEDED(hr = m_pNUpTransform->GetPageTransform(sizePage, &matrixTransform)) && + SUCCEEDED(hr = m_pNUpTransform->MatrixToXML(&matrixTransform, &bstrMatrix))) + { + + // + // Create a clipping region which is the size of the logical page + // + CStringXDW strClip; + + strClip.Format(L"M 0,0 L %.2f,0 L %.2f,%.2f L 0, %.2f Z", + sizePage.Width, + sizePage.Width, + sizePage.Height, + sizePage.Height); + + cstrOut.Format(L""; + } + } + catch (CXDException& e) + { + hr = e; + } + catch (exception& DBG_ONLY(e)) + { + ERR(e.what()); + hr = E_FAIL; + } + + ASSERTMSG(SUCCEEDED(hr), "Failed to write canvas\n"); + } + + if (SUCCEEDED(hr)) + { + hr = WriteToPrintStream(&cstrOut, m_pWriter); + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CNUpSaxHandler::endElement + +Routine Description: + + SAX handler method which handles each end element for the XML markup + +Arguments: + + pwchQName - Pointer to a string containing the element name + cchQName - Count of the number of characters in the element name + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT STDMETHODCALLTYPE +CNUpSaxHandler::endElement( + CONST wchar_t*, + INT, + CONST wchar_t*, + INT, + _In_reads_(cchQName) CONST wchar_t* pwchQName, + _In_ INT cchQName + ) +{ + HRESULT hr = S_OK; + CStringXDW cstrClose; + BOOL bCloseTag = FALSE; + + try + { + CComBSTR bstrElement(cchQName, pwchQName); + + // + // The resource dictionary is now canvas wide + // + if (bstrElement == L"FixedPage.Resources") + { + bstrElement = L"Canvas.Resources"; + } + + // + // Ignore close fixed page tag + // + if (bstrElement != L"FixedPage") + { + bCloseTag = TRUE; + + // + // If this is a root element with child nodes, the open + // element will not match the last startElement. In this case + // we need to add an appropriate closing tag + // + if (bstrElement == m_bstrOpenElement && !!m_bOpenTag) + { + // + // Names match so just add a closing bracket + // + // We might have closed the tag when writing the watermark XML + // + cstrClose.Append(L"/>"); + } + else + { + // + // Add a closing tag + // + cstrClose.Append(L""); + } + + m_bOpenTag = FALSE; + } + else + { + // + // Close the canvas + // + try + { + bCloseTag = TRUE; + cstrClose.Append(L""); + } + catch (CXDException& e) + { + hr = e; + } + + ASSERTMSG(SUCCEEDED(hr), "Failed to write canvas\n"); + } + } + catch (CXDException& e) + { + hr = e; + } + + if (SUCCEEDED(hr) && + bCloseTag) + { + hr = WriteToPrintStream(&cstrClose, m_pWriter); + } + + ERR_ON_HR(hr); + return hr; +} + diff --git a/print/XPSDrvSmpl/src/filters/nup/nupsax.h b/print/XPSDrvSmpl/src/filters/nup/nupsax.h new file mode 100644 index 00000000..8b78cfd8 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/nup/nupsax.h @@ -0,0 +1,76 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + nupsax.h + +Abstract: + + NUp SAX handler definition. The class derives from the default SAX handler + and implements only the necessary SAX APIs to process the mark-up. The + handler is responsible for copying page mark-up to a writer, removing + the fixed page opening and closing tags. It is also responsible for + identifying resources that need to be copied from the source page to + the NUp page. + +--*/ + +#pragma once + +#include "saxhndlr.h" +#include "rescpy.h" +#include "nupxform.h" + +class CNUpSaxHandler : public CSaxHandler +{ +public: + CNUpSaxHandler( + _In_ IPrintWriteStream* pWriter, + _In_ CResourceCopier* pResCopier, + _In_ CNUpTransform* pNUpTransform + ); + + virtual ~CNUpSaxHandler(); + + virtual HRESULT STDMETHODCALLTYPE + startElement( + CONST wchar_t*, + INT, + CONST wchar_t*, + INT, + _In_reads_(cchQName) CONST wchar_t* pwchQName, + _In_ INT cchQName, + _In_ ISAXAttributes* pAttributes + ); + + virtual HRESULT STDMETHODCALLTYPE + endElement( + CONST wchar_t*, + INT, + CONST wchar_t*, + INT, + _In_reads_(cchQName) CONST wchar_t* pwchQName, + _In_ INT cchQName + ); + +private: + CComPtr m_pWriter; + + CComBSTR m_bstrOpenElement; + + BOOL m_bOpenTag; + + CResourceCopier* m_pResCopier; + + CNUpTransform* m_pNUpTransform; +}; + diff --git a/print/XPSDrvSmpl/src/filters/nup/nuptprps.cpp b/print/XPSDrvSmpl/src/filters/nup/nuptprps.cpp new file mode 100644 index 00000000..0783f0ce --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/nup/nuptprps.cpp @@ -0,0 +1,449 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + nuptprps.cpp + +Abstract: + + NUp properties class implementation. The NUp properties class is + responsible for interpreting NUp, Binding, PageMediaSize and + PageOrientation data for the NUp filter. Binding data is required + as the NUp filter is responsible for applying two up for booklet + processing. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "nuptprps.h" + +using XDPrintSchema::NUp::NUpData; +using XDPrintSchema::NUp::JobNUpAllDocumentsContiguously; + +using XDPrintSchema::NUp::PresentationDirection::ENUpDirectionOption; +using XDPrintSchema::NUp::PresentationDirection::LeftBottom; +using XDPrintSchema::NUp::PresentationDirection::TopLeft; +using XDPrintSchema::NUp::PresentationDirection::BottomLeft; +using XDPrintSchema::NUp::PresentationDirection::RightBottom; + +using XDPrintSchema::Binding::BindingData; +using XDPrintSchema::Binding::EBindingOption; +using XDPrintSchema::Binding::None; +using XDPrintSchema::Binding::BindLeft; +using XDPrintSchema::Binding::BindRight; +using XDPrintSchema::Binding::BindTop; +using XDPrintSchema::Binding::BindBottom; +using XDPrintSchema::Binding::JobBindAllDocuments; +using XDPrintSchema::Binding::EdgeStitchLeft; +using XDPrintSchema::Binding::EdgeStitchRight; +using XDPrintSchema::Binding::EdgeStitchTop; +using XDPrintSchema::Binding::EdgeStitchBottom; + +using XDPrintSchema::PageMediaSize::PageMediaSizeData; + +using XDPrintSchema::PageOrientation::PageOrientationData; +using XDPrintSchema::PageOrientation::EOrientationOption; + +/*++ + +Routine Name: + + CNUpPTProperties::CNUpPTProperties + +Routine Description: + + Constructor for the CNUpPTProperties class which + initialises members to sensible default values + +Arguments: + + nupData - Structure containing nup settings from the PrintTicket + bindingData - Structure containing nup binding settings from the PrintTicket + pageMediaSizeData - Structure containing nup page media size settings from the PrintTicket + pageOrientData - Structure containing nup page orientation settings from the PrintTicket + +Return Value: + + None + +--*/ +CNUpPTProperties::CNUpPTProperties( + _In_ CONST NUpData& nupData, + _In_ CONST BindingData& bindingData, + _In_ CONST PageMediaSizeData& pageMediaSizeData, + _In_ CONST PageOrientationData& pageOrientData + ) : + m_nupData(nupData), + m_bindingData(bindingData), + m_pageMediaSizeData(pageMediaSizeData), + m_pageOrientData(pageOrientData) +{ +} + +/*++ + +Routine Name: + + CNUpPTProperties::~CNUpPTProperties + +Routine Description: + + Default destructor for the CNUpPTProperties class + +Arguments: + + None + +Return Value: + + None + +--*/ +CNUpPTProperties::~CNUpPTProperties() +{ +} + +/*++ + +Routine Name: + + CNUpPTProperties::GetCount + +Routine Description: + + Method to get the nup count. For booklet printing this will always be set to two + +Arguments: + + pcNUpPages - Integer value which will contain the nup count + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CNUpPTProperties::GetCount( + _Out_ UINT* pcNUpPages + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pcNUpPages, E_POINTER))) + { + *pcNUpPages = m_nupData.cNUp; + + if (m_bindingData.bindOption != XDPrintSchema::Binding::None) + { + *pcNUpPages = 2; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CNUpPTProperties::GetPresentationDirection + +Routine Description: + + Method to get the nup presentation direction + +Arguments: + + pPresentationDirection - Enumeration value which is set to the current + presentation direction + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CNUpPTProperties::GetPresentationDirection( + _Out_ ENUpDirectionOption* pPresentationDirection + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pPresentationDirection, E_POINTER))) + { + *pPresentationDirection = m_nupData.nUpPresentDir; + + if (m_bindingData.bindOption != XDPrintSchema::Binding::None) + { + hr = PresentDirFromBindOption(pPresentationDirection); + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CNUpPTProperties::GetScope + +Routine Description: + + Method to get the nup scope which can be either + document wide or job wide. + +Arguments: + + pNUpScope - Enumeration value which will be set to the + current scope of nup. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CNUpPTProperties::GetScope( + _In_ ENUpScope* pNUpScope + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pNUpScope, E_POINTER))) + { + *pNUpScope = CNUpPTProperties::None; + + if (m_bindingData.bindOption != XDPrintSchema::Binding::None) + { + *pNUpScope = m_bindingData.bindFeature == JobBindAllDocuments ? Job : Document; + } + else if (m_nupData.cNUp > 1) + { + *pNUpScope = m_nupData.nUpFeature == JobNUpAllDocumentsContiguously ? Job : Document; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CNUpPTProperties::GetPageSize + +Routine Description: + + Method to get the nup page media size + +Arguments: + + pSizePage - Value which will be set to the nup page media size + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CNUpPTProperties::GetPageSize( + _Out_ SizeF* pSizePage + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pSizePage, E_POINTER))) + { + // + // Convert microns to 96th of an inch. + // + pSizePage->Width = static_cast(m_pageMediaSizeData.pageWidth)/k96thInchAsMicrons; + pSizePage->Height = static_cast(m_pageMediaSizeData.pageHeight)/k96thInchAsMicrons; + + if (pSizePage->Width <= 0.0f || + pSizePage->Height <= 0.0f) + { + // + // The page media size is incorrect + // + ERR("Could not acquire a valid media page size\n"); + + hr = E_FAIL; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CNUpPTProperties::GetPageOrientation + +Routine Description: + + Method to get the nup page orientation which can be either landscape or portrait + +Arguments: + + pPageOrientation - Enumeration value which will be set to either landscape or portrait + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CNUpPTProperties::GetPageOrientation( + _In_ EOrientationOption* pPageOrientation + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pPageOrientation, E_POINTER))) + { + *pPageOrientation = m_pageOrientData.orientation; + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CNUpPTProperties::PresentDirFromBindOption + +Routine Description: + + Method to obtain a presentation direction from the current binding setting + +Arguments: + + pPresentationDirection - Enumeration value which will be set to a presentation direction + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CNUpPTProperties::PresentDirFromBindOption( + _Out_ ENUpDirectionOption* pPresentationDirection + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pPresentationDirection, E_POINTER))) + { + switch (m_bindingData.bindOption) + { + case BindRight: + case EdgeStitchRight: + { + *pPresentationDirection = LeftBottom; + } + break; + + case BindBottom: + case EdgeStitchBottom: + { + // + // Vertical direction takes precidence over horizontal direction + // + *pPresentationDirection = TopLeft; + } + break; + + case BindTop: + case EdgeStitchTop: + { + // + // Vertical direction takes precidence over horizontal direction + // + *pPresentationDirection = BottomLeft; + } + break; + + // + // Everything else is RightBottom + // + default: + { + *pPresentationDirection = RightBottom; + } + break; + } + } + + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CNUpPTProperties::GetBindingOption + +Routine Description: + + Method to obtain the binding direction + +Arguments: + + pBindingOption - Enumeration value which will be set to a binding direction + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CNUpPTProperties::GetBindingOption( + _Out_ EBindingOption* pBindingOption + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pBindingOption, E_POINTER))) + { + *pBindingOption = m_bindingData.bindOption; + } + + ERR_ON_HR(hr); + return hr; +} diff --git a/print/XPSDrvSmpl/src/filters/nup/nuptprps.h b/print/XPSDrvSmpl/src/filters/nup/nuptprps.h new file mode 100644 index 00000000..2d53082a --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/nup/nuptprps.h @@ -0,0 +1,97 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + nuptprps.cpp + +Abstract: + + NUp properties class definition. The NUp properties class is + responsible for holding and controling NUp properties. + +--*/ + +#pragma once + +#include "nupdata.h" +#include "bkdata.h" +#include "psizedata.h" +#include "porientdata.h" + +class CNUpPTProperties +{ +public: + enum ENUpScope + { + None = 0, + Job, + Document + }; + +public: + CNUpPTProperties( + _In_ CONST XDPrintSchema::NUp::NUpData& nupData, + _In_ CONST XDPrintSchema::Binding::BindingData& bindingData, + _In_ CONST XDPrintSchema::PageMediaSize::PageMediaSizeData& pageMediaSizeData, + _In_ CONST XDPrintSchema::PageOrientation::PageOrientationData& pageOrientData + ); + + virtual ~CNUpPTProperties(); + + HRESULT + GetCount( + _Out_ UINT* pcNUpPages + ); + + HRESULT + GetPresentationDirection( + _Out_ XDPrintSchema::NUp::PresentationDirection::ENUpDirectionOption* pPresentationDirection + ); + + HRESULT + GetScope( + _In_ ENUpScope* pNUpScope + ); + + HRESULT + GetPageSize( + _Out_ SizeF* pSizePage + ); + + HRESULT + GetPageOrientation( + _In_ XDPrintSchema::PageOrientation::EOrientationOption* pPageOrientation + ); + + HRESULT + GetBindingOption( + _Out_ XDPrintSchema::Binding::EBindingOption* pBindingOption + ); + +private: + CNUpPTProperties& operator = (CONST CNUpPTProperties&); + + HRESULT + PresentDirFromBindOption( + _Out_ XDPrintSchema::NUp::PresentationDirection::ENUpDirectionOption* pPresentationDirection + ); + +private: + CONST XDPrintSchema::NUp::NUpData m_nupData; + + CONST XDPrintSchema::Binding::BindingData m_bindingData; + + CONST XDPrintSchema::PageMediaSize::PageMediaSizeData m_pageMediaSizeData; + + CONST XDPrintSchema::PageOrientation::PageOrientationData m_pageOrientData; +}; + diff --git a/print/XPSDrvSmpl/src/filters/nup/nupxform.cpp b/print/XPSDrvSmpl/src/filters/nup/nupxform.cpp new file mode 100644 index 00000000..a79ff819 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/nup/nupxform.cpp @@ -0,0 +1,623 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + nupxform.cpp + +Abstract: + + NUp transform implementation. The NUp transform class is responsible + for calculating the appropriate matrix transform for a given page in + an NUp sequence. + +Known Issues: + + The NUp implementation does not yet account for reverse orientations + (ReverseLandscape and ReversePortrait). + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdstring.h" +#include "xdexcept.h" +#include "nupxform.h" + +using XDPrintSchema::NUp::NUpData; +using XDPrintSchema::NUp::JobNUpAllDocumentsContiguously; + +using XDPrintSchema::NUp::PresentationDirection::ENUpDirectionOption; +using XDPrintSchema::NUp::PresentationDirection::ENUpDirectionOptionMin; +using XDPrintSchema::NUp::PresentationDirection::RightBottom; +using XDPrintSchema::NUp::PresentationDirection::BottomRight; +using XDPrintSchema::NUp::PresentationDirection::LeftBottom; +using XDPrintSchema::NUp::PresentationDirection::BottomLeft; +using XDPrintSchema::NUp::PresentationDirection::RightTop; +using XDPrintSchema::NUp::PresentationDirection::TopRight; +using XDPrintSchema::NUp::PresentationDirection::LeftTop; +using XDPrintSchema::NUp::PresentationDirection::TopLeft; +using XDPrintSchema::NUp::PresentationDirection::ENUpDirectionOptionMax; + +using XDPrintSchema::Binding::EBindingOption; +using XDPrintSchema::Binding::None; +using XDPrintSchema::Binding::BindTop; +using XDPrintSchema::Binding::BindBottom; + +using XDPrintSchema::PageOrientation::EOrientationOption; +using XDPrintSchema::PageOrientation::Landscape; +using XDPrintSchema::PageOrientation::ReverseLandscape; +using XDPrintSchema::PageOrientation::Portrait; + +static CONST REAL kLetterWidth96thsInch = 816.0f; +static CONST REAL kLetterHeight96thsInch = 1056.0f; + +/*++ + +Routine Name: + + CNUpTransform::CNUpTransform + +Routine Description: + + Constructor for the CNUpTransform class which initialises members + to sensible values based on the supplied PrintTicket object + +Arguments: + + pNUpPTProps - PrintTicket properties object used for initialising the + CNUpTransform object + +Return Value: + + None + Throws CXDException(HRESULT) on an error + +--*/ +CNUpTransform::CNUpTransform( + _In_ CNUpPTProperties* pNUpPTProps + ) : + m_bRotatePage(FALSE), + m_cCurrPageIndex(0) +{ + ASSERTMSG(pNUpPTProps != NULL, "NULL PrintTicket passed to page transform handler\n"); + + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pNUpPTProps, E_POINTER))) + { + if (SUCCEEDED(hr) && + FAILED(hr = pNUpPTProps->GetCount(&m_CanvasCount))) + { + m_CanvasCount = 1; + ERR("Failed to retrieve NUp count\n"); + } + + if (SUCCEEDED(hr) && + FAILED(hr = pNUpPTProps->GetPresentationDirection(&m_NUpPresentDirection))) + { + m_NUpPresentDirection = RightBottom; + ERR("Failed to retrieve NUp order\n"); + } + + if (SUCCEEDED(hr) && + FAILED(hr = pNUpPTProps->GetPageSize(&m_sizeTargetPage))) + { + m_sizeTargetPage.Width = kLetterWidth96thsInch; + m_sizeTargetPage.Height = kLetterHeight96thsInch; + ERR("Failed to retrieve target page size\n"); + } + + EOrientationOption pgOrient = Portrait; + if (SUCCEEDED(hr) && + FAILED(hr = pNUpPTProps->GetPageOrientation(&pgOrient))) + { + ERR("Failed to retrieve target page orientation\n"); + } + + // + // Initialise canvas count + // + switch (m_CanvasCount) + { + case 1: + { + m_CanvasXCount = 1; + m_CanvasYCount = 1; + } + break; + + case 2: + { + m_CanvasXCount = 1; + m_CanvasYCount = 2; + m_bRotatePage = TRUE; + + // + // Booklet printing is treated as a special case of 2Up. + // Unlike regular 2Up which always rotates pages, booklet + // only requires pages to be rotated when binding left to right + // or right to left. + // + EBindingOption bindingOption; + if(SUCCEEDED(hr = pNUpPTProps->GetBindingOption(&bindingOption))) + { + if(bindingOption == BindBottom || + bindingOption == BindTop) + { + m_bRotatePage = FALSE; + } + + if (pgOrient == Landscape) + { + m_CanvasXCount = 2; + m_CanvasYCount = 1; + } + } + } + break; + + case 4: + { + m_CanvasXCount = 2; + m_CanvasYCount = 2; + } + break; + + case 6: + { + m_CanvasXCount = 2; + m_CanvasYCount = 3; + m_bRotatePage = TRUE; + } + break; + + case 8: + { + m_CanvasXCount = 2; + m_CanvasYCount = 4; + m_bRotatePage = TRUE; + } + break; + + case 9: + { + m_CanvasXCount = 3; + m_CanvasYCount = 3; + } + break; + + case 16: + { + m_CanvasXCount = 4; + m_CanvasYCount = 4; + } + break; + + default: + { + m_CanvasXCount = 1; + m_CanvasYCount = 1; + } + break; + } + + if (pgOrient == Landscape || + pgOrient == ReverseLandscape) + { + INT countSwap = m_CanvasXCount; + m_CanvasXCount = m_CanvasYCount; + m_CanvasYCount = countSwap; + } + } + + if (SUCCEEDED(hr)) + { + hr = InitTransformMap(); + } + + if (FAILED(hr)) + { + throw CXDException(hr); + } +} + + +/*++ + +Routine Name: + + CNUpTransform::~CNUpTransform + +Routine Description: + + Default destructor for the CNUpTransform class + +Arguments: + + None + +Return Value: + + None + +--*/ +CNUpTransform::~CNUpTransform() +{ +} + +/*++ + +Routine Name: + + CNUpTransform::SetCurrentPage + +Routine Description: + + Sets the page member of the object + +Arguments: + + cPage - Current page count around the nup page count. + +Return Value: + + None + +--*/ +VOID +CNUpTransform::SetCurrentPage( + _In_ UINT cPage + ) +{ + m_cCurrPageIndex = cPage; +} + +/*++ + +Routine Name: + + CNUpTransform::GetPageTransform + +Routine Description: + + Method for obtaining a page transformation matrix based on the count of the + current canvas and the dimensions of the source and target pages + +Arguments: + + sizePage - Size of the source page being transformed + pTransform - Pointer to the resulting transformation matrix + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CNUpTransform::GetPageTransform( + _In_ SizeF sizePage, + _Out_ Matrix* pTransform + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pTransform, E_POINTER))) + { + SizeF sizeCanvas(m_sizeTargetPage.Width / m_CanvasXCount, m_sizeTargetPage.Height / m_CanvasYCount); + PointF canvasCentre(sizeCanvas.Width/2.0f, sizeCanvas.Height/2.0f); + PointF pageCentre(sizePage.Width/2.0f, sizePage.Height/2.0f); + + REAL scaleX = 1.0f; + REAL scaleY = 1.0f; + if (m_bRotatePage) + { + // + // Calculate the dimension scale accounting for page rotation + // + scaleX = sizeCanvas.Width / sizePage.Height; + scaleY = sizeCanvas.Height / sizePage.Width; + + // + // Apply the rotation + // + pTransform->Rotate(90.0f, MatrixOrderAppend); + } + else + { + // + // Calculate the dimension scale + // + scaleX = sizeCanvas.Width / sizePage.Width; + scaleY = sizeCanvas.Height / sizePage.Height; + } + + // + // The minimum scale of x and y gurantees both + // dimensions fit the target + // + REAL scale = min(scaleX, scaleY); + + // + // Apply the scaling factor + // + pTransform->Scale(scale, scale, MatrixOrderAppend); + + // + // Find the new page centre + // + pTransform->TransformPoints(&pageCentre, 1); + + // + // Apply a translate to the canvas + // + UINT cPage = 0; + BOOL bDone = FALSE; + + for (UINT cIndexY = 0; cIndexY < m_CanvasYCount && !bDone; cIndexY++) + { + for (UINT cIndexX = 0; cIndexX < m_CanvasXCount && !bDone; cIndexX++) + { + if (m_pageNumVect[cPage] == m_cCurrPageIndex) + { + // + // Offset multipliers from loop indices + // + REAL yMult = static_cast(cIndexY); + REAL xMult = static_cast(cIndexX); + + // + // Use a matrix to find the centre of the translated canvas + // + Matrix canvasXForm; + + // + // Translate canvas to destination + // + canvasXForm.Translate(sizeCanvas.Width * xMult, sizeCanvas.Height * yMult, MatrixOrderAppend); + + // + // Apply the canvas transform to the canvas centre + // + canvasXForm.TransformPoints(&canvasCentre, 1); + + bDone = TRUE; + } + cPage++; + } + } + + // + // Calculate the offset of the centre of page to the centre + // of the canvas and apply the translation + // + PointF offset(canvasCentre - pageCentre); + pTransform->Translate(offset.X, offset.Y, MatrixOrderAppend); + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CNUpTransform::MatrixToXML + +Routine Description: + + Method to create xml markup representing a transformation matrix + +Arguments: + + pMatrix - Pointer to a transformation matrix to convert to markup + pbstrMatrixXForm - Pointer to a string to contain the matrix markup + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CNUpTransform::MatrixToXML( + _In_ CONST Matrix* pMatrix, + _Outptr_ BSTR* pbstrMatrixXForm + ) +{ + // + // Construct the matric mark-up from a GDI+ matrix + // + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pbstrMatrixXForm, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pMatrix, E_POINTER))) + { + *pbstrMatrixXForm = NULL; + REAL matElems[6]; + + if (Ok == pMatrix->GetElements(matElems)) + { + CStringXDW cstrMatrix; + + try + { + cstrMatrix.Format(L"%.2f,%.2f,%.2f,%.2f,%.2f,%.2f", + matElems[0], + matElems[1], + matElems[2], + matElems[3], + matElems[4], + matElems[5]); + + *pbstrMatrixXForm = cstrMatrix.AllocSysString(); + } + catch (CXDException& e) + { + hr = e; + } + } + else + { + *pbstrMatrixXForm = NULL; + hr = E_FAIL; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CNUpTransform::InitTransformMap + +Routine Description: + + Method to initialise the map of transforms which depends + on the nup page count and presentation direction + +Arguments: + + None + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CNUpTransform::InitTransformMap( + VOID + ) +{ + HRESULT hr = S_OK; + + // + // Populate the map of page numbers. + // The transforms are calculated left to right, top to bottom on + // the physical page so rather than special case each presentation + // order, we simply apply the same transform in the same order but + // to a different ordering of pages + // + try + { + // + // Certain NUp page counts cause a rotation to be applied to the page. + // When this occurs, the presentation order should also be rotated. + // + ENUpDirectionOption rotatedOrder[ENUpDirectionOptionMax] = { + BottomLeft, + LeftBottom, + TopLeft, + LeftTop, + BottomRight, + RightBottom, + TopRight, + RightTop + }; + + if (m_bRotatePage) + { + if (m_NUpPresentDirection >= ENUpDirectionOptionMin && + m_NUpPresentDirection < ENUpDirectionOptionMax) + { + m_NUpPresentDirection = rotatedOrder[m_NUpPresentDirection]; + } + else + { + ERR("Invalid presentation direction.\n"); + + hr = E_FAIL; + } + } + + if (SUCCEEDED(hr)) + { + m_pageNumVect.clear(); + for (UINT cIndexY = 0; cIndexY < m_CanvasYCount; cIndexY++) + { + for (UINT cIndexX = 0; cIndexX < m_CanvasXCount; cIndexX++) + { + switch (m_NUpPresentDirection) + { + case RightTop: + { + m_pageNumVect.push_back((m_CanvasXCount * (m_CanvasYCount-1)) - (m_CanvasXCount * cIndexY) + cIndexX); + } + break; + + case LeftBottom: + { + m_pageNumVect.push_back(cIndexY * m_CanvasXCount + (m_CanvasXCount - cIndexX) - 1); + } + break; + + case LeftTop: + { + m_pageNumVect.push_back((m_CanvasXCount * m_CanvasYCount) - cIndexX - (cIndexY*m_CanvasXCount) - 1); + } + break; + + case BottomRight: + { + m_pageNumVect.push_back(m_CanvasYCount * cIndexX + cIndexY); + } + break; + + case TopRight: + { + m_pageNumVect.push_back((m_CanvasYCount - 1 - cIndexY) + (cIndexX * m_CanvasYCount)); + } + break; + + case BottomLeft: + { + m_pageNumVect.push_back(m_CanvasYCount * (m_CanvasXCount - 1 - cIndexX) + cIndexY); + } + break; + + case TopLeft: + { + m_pageNumVect.push_back(((m_CanvasXCount-cIndexX) * m_CanvasYCount) - 1 - cIndexY); + } + break; + + case RightBottom: + default: + { + m_pageNumVect.push_back(cIndexY * m_CanvasXCount + cIndexX); + } + break; + } + } + } + } + } + catch (exception& DBG_ONLY(e)) + { + ERR(e.what()); + hr = E_FAIL; + } + + ERR_ON_HR(hr); + return hr; +} + diff --git a/print/XPSDrvSmpl/src/filters/nup/nupxform.h b/print/XPSDrvSmpl/src/filters/nup/nupxform.h new file mode 100644 index 00000000..a752730f --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/nup/nupxform.h @@ -0,0 +1,101 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + nupxform.h + +Abstract: + + NUp transform definition. The NUp transform class is responsible + for calculating the appropriate matrix transform for a given page in + an NUp sequence. + +--*/ + +#pragma once + +#include "nuptprps.h" + +class CNUpTransform +{ +public: + CNUpTransform( + _In_ CNUpPTProperties* pNUpPTProps + ); + + virtual ~CNUpTransform(); + + VOID + SetCurrentPage( + _In_ UINT cPage + ); + + HRESULT + GetPageTransform( + _In_ SizeF sizePage, + _Out_ Matrix* pTransform + ); + + HRESULT + MatrixToXML( + _In_ CONST Matrix* pMatrix, + _Outptr_ BSTR* pbstrMatrixXForm + ); + +private: + HRESULT + InitTransformMap( + VOID + ); + +private: + // + // Nup count + // + UINT m_CanvasCount; + + // + // Current Nup index + // + UINT m_cCurrPageIndex; + + // + // Presentation order + // + XDPrintSchema::NUp::PresentationDirection::ENUpDirectionOption m_NUpPresentDirection; + + // + // Target page size + // + SizeF m_sizeTargetPage; + + // + // Nup count across + // + UINT m_CanvasXCount; + + // + // Nup count down + // + UINT m_CanvasYCount; + + // + // Vector of page maps + // + vector m_pageNumVect; + + // + // We need to handle page rotation for 2, 6 and 8 up + // + BOOL m_bRotatePage; +}; + diff --git a/print/XPSDrvSmpl/src/filters/nup/precompsrc.cpp b/print/XPSDrvSmpl/src/filters/nup/precompsrc.cpp new file mode 100644 index 00000000..5944cf51 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/nup/precompsrc.cpp @@ -0,0 +1 @@ +#include "precomp.h" \ No newline at end of file diff --git a/print/XPSDrvSmpl/src/filters/nup/xdnup.def b/print/XPSDrvSmpl/src/filters/nup/xdnup.def new file mode 100644 index 00000000..349aaaa6 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/nup/xdnup.def @@ -0,0 +1,26 @@ +; +; Copyright (c) 2005 Microsoft Corporation +; +; All rights reserved. +; +; THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +; ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +; THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +; PARTICULAR PURPOSE. +; +; File Name: +; +; xdnup.def +; +; Abstract: +; +; NUp filter module definition file +; + +LIBRARY XDNup + +EXPORTS + DllMain + DllCanUnloadNow PRIVATE + DllGetClassObject PRIVATE + diff --git a/print/XPSDrvSmpl/src/filters/nup/xdnup.vcxproj b/print/XPSDrvSmpl/src/filters/nup/xdnup.vcxproj new file mode 100644 index 00000000..8be08f78 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/nup/xdnup.vcxproj @@ -0,0 +1,317 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {06548B4B-6104-4F36-8BAA-127D23F73CD4} + $(MSBuildProjectName) + false + true + Debug + Win32 + {A8424516-5DB1-4D7C-9199-604456506188} + + + + Windows10 + False + Desktop + + WindowsApplicationForDrivers10.0 + DynamicLibrary + + + Windows10 + True + Desktop + + WindowsApplicationForDrivers10.0 + DynamicLibrary + + + Windows10 + False + Desktop + + WindowsApplicationForDrivers10.0 + DynamicLibrary + + + Windows10 + True + Desktop + + WindowsApplicationForDrivers10.0 + DynamicLibrary + + + + $(IntDir) + + + + + + + + + + + + + + + + xdnup + + + xdnup + + + xdnup + + + xdnup + + + + _DllMainCRTStartup@12 + _DllMainCRTStartup + + + + + _DllMainCRTStartup@12 + _DllMainCRTStartup + + + + + _DllMainCRTStartup@12 + _DllMainCRTStartup + + + + + _DllMainCRTStartup@12 + _DllMainCRTStartup + + + + + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + MultiThreaded + MultiThreadedDebug + true + Level4 + Sync + + + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + %(AdditionalDependencies);uuid.lib;WIAGUID.lib;msxml6.lib;Kernel32.lib;ole32.lib;oleaut32.lib;prntvpt.lib;winspool.lib;gdi32.lib;gdiplus.lib;shlwapi.lib;Advapi32.lib;user32.lib;.\..\..\debug\$(IntDir)\xdsdbg.lib;.\..\..\common\$(IntDir)\xdsmplcmn.lib;.\..\..\filters\common\$(IntDir)\xdfltcmn.lib + + + + + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + MultiThreaded + MultiThreadedDebug + true + Level4 + Sync + + + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + %(AdditionalDependencies);uuid.lib;WIAGUID.lib;msxml6.lib;Kernel32.lib;ole32.lib;oleaut32.lib;prntvpt.lib;winspool.lib;gdi32.lib;gdiplus.lib;shlwapi.lib;Advapi32.lib;user32.lib;.\..\..\debug\$(IntDir)\xdsdbg.lib;.\..\..\common\$(IntDir)\xdsmplcmn.lib;.\..\..\filters\common\$(IntDir)\xdfltcmn.lib + + + + + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + MultiThreaded + MultiThreadedDebug + true + Level4 + Sync + + + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + %(AdditionalDependencies);uuid.lib;WIAGUID.lib;msxml6.lib;Kernel32.lib;ole32.lib;oleaut32.lib;prntvpt.lib;winspool.lib;gdi32.lib;gdiplus.lib;shlwapi.lib;Advapi32.lib;user32.lib;.\..\..\debug\$(IntDir)\xdsdbg.lib;.\..\..\common\$(IntDir)\xdsmplcmn.lib;.\..\..\filters\common\$(IntDir)\xdfltcmn.lib + + + + + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + MultiThreaded + MultiThreadedDebug + true + Level4 + Sync + + + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + %(AdditionalDependencies);uuid.lib;WIAGUID.lib;msxml6.lib;Kernel32.lib;ole32.lib;oleaut32.lib;prntvpt.lib;winspool.lib;gdi32.lib;gdiplus.lib;shlwapi.lib;Advapi32.lib;user32.lib;.\..\..\debug\$(IntDir)\xdsdbg.lib;.\..\..\common\$(IntDir)\xdsmplcmn.lib;.\..\..\filters\common\$(IntDir)\xdfltcmn.lib + + + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + + + ..;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ..;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ..;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ..;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ..;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ..;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + + + + xdnup.def + + + + + xdnup.def + + + + + xdnup.def + + + + + xdnup.def + + + + + ..;%(AdditionalIncludeDirectories) + precomp.h + Create + $(IntDir)\precomp.h.pch + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/print/XPSDrvSmpl/src/filters/nup/xdnup.vcxproj.Filters b/print/XPSDrvSmpl/src/filters/nup/xdnup.vcxproj.Filters new file mode 100644 index 00000000..83b4f180 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/nup/xdnup.vcxproj.Filters @@ -0,0 +1,48 @@ + + + + + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* + {BE7F4E72-895A-4B10-AED0-F7E2DA352886} + + + h;hpp;hxx;hm;inl;inc;xsd + {8B40F3CB-A605-4B5A-847F-9AAF83A28B5E} + + + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml + {577EA8D3-BCBF-4CCC-9F9F-73F6A6E3D3DF} + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Resource Files + + + \ No newline at end of file diff --git a/print/XPSDrvSmpl/src/filters/precomp.h b/print/XPSDrvSmpl/src/filters/precomp.h new file mode 100644 index 00000000..640660ec --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/precomp.h @@ -0,0 +1,107 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + precomp.h + +Abstract: + + Precompiled header for all filters + +--*/ + +#pragma once + +// +// Annotate this as a usermode driver for static analysis +// +#include +_Analysis_mode_(_Analysis_code_type_user_driver_) + +// +// Standard Annotation Language include +// +#include + +// +// Windows includes +// +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif // WIN32_LEAN_AND_MEAN +#include +#include + +// +// COM includes +// +#include +#include + +// +// Standard library includes +// +#include +#include +#pragma warning(push) +#pragma warning(disable : 4018) +#include +#pragma warning(pop) +#include +#include + +// +// ATL Includes +// +#include + +// +// GDIPlus includes +// +#include + +// +// MSXML includes +// +#include + +// +// Filter pipeline includes +// +#include +#include +#include +#include + +// +// WCS Includes +// +#include + +// +// Windows Imaging Component +// +#include + +// +// Commonly used namespaces +// +using namespace std; +using namespace Gdiplus; + +// +// String safe includes - included last to prevent build warnings +// +#include + +#include "common.ver" + diff --git a/print/XPSDrvSmpl/src/filters/scaling/dllentry.cpp b/print/XPSDrvSmpl/src/filters/scaling/dllentry.cpp new file mode 100644 index 00000000..7ae94af8 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/scaling/dllentry.cpp @@ -0,0 +1,144 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + dllentry.cpp + +Abstract: + + Implementation of the page scaling filter dllentry points. Dllmain only + stores the instance handle. DllGetClassObject calls on to a generic + get class factory template function. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "clasfact.h" +#include "scaleflt.h" +#include "xdexcept.h" + +/*++ + +Routine Name: + + DllMain + +Routine Description: + + Entry point to the page scaling filter which is called when a new process is started + +Arguments: + + hInst - Handle to the DLL module. + wReason - Indicates why the DLL entry-point function is being called. + +Return Value: + + TRUE + +--*/ +BOOL WINAPI +DllMain( + _In_ HINSTANCE hInst, + _In_ WORD wReason, + _In_opt_ LPVOID + ) +{ + switch (wReason) + { + case DLL_PROCESS_ATTACH: + { + g_hInstance = hInst; + } + break; + } + + return TRUE; +} + +/*++ + +Routine Name: + + DllCanUnloadNow + +Routine Description: + + Determines whether the DLL is in use. + If not, the caller can unload the DLL from memory. + +Arguments: + + None + +Return Value: + + HRESULT + S_OK - Dll can unload + S_FALSE - Dll can't unload + +--*/ +STDAPI +DllCanUnloadNow() +{ + if (g_cServerLocks == 0) + { + return S_OK ; + } + else + { + return S_FALSE; + } +} + +/*++ + +Routine Name: + + DllGetClassObject + +Routine Description: + + Retrieves the class object for the DLL. + Called from within the CoGetClassObject function. + +Arguments: + + rclsid - CLSID that will associate the correct data and code. + riid - Reference to the identifier of the interface that the caller is to use to communicate with the class object. + ppv - Address of pointer variable that receives the interface pointer requested in riid. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + CLASS_E_CLASSNOTAVAILABLE - On unsupported class + +--*/ +STDAPI +DllGetClassObject( + _In_ REFCLSID rclsid, + _In_ REFIID riid, + _Outptr_ LPVOID FAR* ppv + ) +{ + // + // 976EDCE4-274E-482a-9773-12453BE3E7F1 + // + CLSID scalingCLSID = {0x976EDCE4, 0x274E, 0x482a, {0x97, 0x73, 0x12, 0x45, 0x3B, 0xE3, 0xE7, 0xF1}}; + + return GetFilterClassFactory(rclsid, riid, scalingCLSID, ppv); +} + diff --git a/print/XPSDrvSmpl/src/filters/scaling/pagescale.cpp b/print/XPSDrvSmpl/src/filters/scaling/pagescale.cpp new file mode 100644 index 00000000..44e0d5d3 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/scaling/pagescale.cpp @@ -0,0 +1,761 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + pagescale.cpp + +Abstract: + + Page Scaling class implementation. The Page Scaling class provides + functionality required to perform page Scaling. This includes methods for converting a GDI matrix object + into the appropriate XPS matrix mark-up and intialising the matrix according to + the Page Scaling options. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdstring.h" +#include "pagescale.h" + +using XDPrintSchema::PageScaling::EScaleOption; +using XDPrintSchema::PageScaling::Custom; +using XDPrintSchema::PageScaling::CustomSquare; +using XDPrintSchema::PageScaling::FitBleedToImageable; +using XDPrintSchema::PageScaling::FitContentToImageable; +using XDPrintSchema::PageScaling::FitMediaToImageable; +using XDPrintSchema::PageScaling::FitMediaToMedia; + +using XDPrintSchema::PageScaling::OffsetAlignment::EScaleOffsetOption; +using XDPrintSchema::PageScaling::OffsetAlignment::BottomCenter; +using XDPrintSchema::PageScaling::OffsetAlignment::BottomLeft; +using XDPrintSchema::PageScaling::OffsetAlignment::BottomRight; +using XDPrintSchema::PageScaling::OffsetAlignment::Center; +using XDPrintSchema::PageScaling::OffsetAlignment::LeftCenter; +using XDPrintSchema::PageScaling::OffsetAlignment::RightCenter; +using XDPrintSchema::PageScaling::OffsetAlignment::TopCenter; +using XDPrintSchema::PageScaling::OffsetAlignment::TopLeft; +using XDPrintSchema::PageScaling::OffsetAlignment::TopRight; + +/*++ + +Routine Name: + + CPageScaling::CPageScaling + +Routine Description: + + CPageScaling class constructor + +Arguments: + + pgscProps - Reference to the page scaling PrintTicket properties. + +Return Value: + + None + +--*/ +CPageScaling::CPageScaling( + _In_ CONST CPGSCPTProperties& pgscProps + ) : + m_pageDimensions(0.0f, 0.0f), + m_PGSCProps(pgscProps), + m_bAddCanvas(FALSE), + m_contentBox(0.0f, 0.0f, 0.0f, 0.0f), + m_bleedBox(0.0f, 0.0f, 0.0f, 0.0f) +{ +} + +/*++ + +Routine Name: + + CPageScaling::~CPageScaling + +Routine Description: + + CPageScaling class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CPageScaling::~CPageScaling() +{ +} + +/*++ + +Routine Name: + + CPageScaling::GetFixedPageWidth + +Routine Description: + + Creates a string containing the page width in 1/96 Inch + (Not applicable to Custom Scaling options). + +Arguments: + + pbstrWidth - Address of a pointer that will be modified to point to a string + that is filled out with the fixed page width. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPageScaling::GetFixedPageWidth( + _Outptr_ BSTR* pbstrWidth + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pbstrWidth, E_POINTER))) + { + try + { + SizeF targetPage; + if (SUCCEEDED(hr = m_PGSCProps.GetPageSize(&targetPage))) + { + CStringXDW cstrValue; + cstrValue.Format(L"%.2f", targetPage.Width); + *pbstrWidth = cstrValue.AllocSysString(); + } + } + catch (CXDException& e) + { + hr = e; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CPageScaling::GetFixedPageHeight + +Routine Description: + + Creates a string containing the page height in 1/96 Inch + (Not applicable to Custom Scaling options). + +Arguments: + + pbstrHeight - Address of a pointer that will be modified to point to a string + that is filled out with the fixed page height. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPageScaling::GetFixedPageHeight( + _Outptr_ BSTR* pbstrHeight + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pbstrHeight, E_POINTER))) + { + try + { + SizeF targetPage; + if (SUCCEEDED(hr = m_PGSCProps.GetPageSize(&targetPage))) + { + CStringXDW cstrValue; + cstrValue.Format(L"%.2f", targetPage.Height); + *pbstrHeight = cstrValue.AllocSysString(); + } + } + catch (CXDException& e) + { + hr = e; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CPageScaling::MatrixToXML + +Routine Description: + + Creates a string representation of a Matrix class object. + The string is suitable for use in XPS markup with the 'RenderTransform' keyword. + +Arguments: + + pMatrix - Pointer to a Matrix class object. + pbstrMatrixXForm - Address of a pointer that will be modified to point to a string + that is filled out with the matrix. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPageScaling::MatrixToXML( + _In_ CONST Matrix* pMatrix, + _Outptr_ BSTR* pbstrMatrixXForm + ) +{ + // + // Construct the matric mark-up from a GDI+ matrix + // + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pbstrMatrixXForm, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pMatrix, E_POINTER))) + { + REAL matElems[6]; + if (Ok == pMatrix->GetElements(matElems)) + { + try + { + CStringXDW cstrMatrix; + cstrMatrix.Format(L"%.2f,%.2f,%.2f,%.2f,%.2f,%.2f", + matElems[0], + matElems[1], + matElems[2], + matElems[3], + matElems[4], + matElems[5]); + + *pbstrMatrixXForm = cstrMatrix.AllocSysString(); + } + catch (CXDException& e) + { + hr = e; + } + } + else + { + *pbstrMatrixXForm = NULL; + hr = E_FAIL; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CPageScaling::SetPageDimensions + +Routine Description: + + Used to set the XPS page width and height in the page scaling interface. + +Arguments: + + width - Width of the XPS fixed page in 1/96 Inch. + height - Height of the XPS fixed page in 1/96 Inch. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPageScaling::SetPageDimensions( + _In_ CONST REAL width, + _In_ CONST REAL height + ) +{ + m_pageDimensions.Width = width; + m_pageDimensions.Height = height; + + return S_OK; +} + +/*++ + +Routine Name: + + CPageScaling::SetBleedBox + +Routine Description: + + Used to set the XPS BleedBox in the page scaling interface. + +Arguments: + + pBleedBox - pointer to a rectangle defining the BleedBox of the XPS page in 1/96 Inch. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPageScaling::SetBleedBox( + _In_ RectF* pBleedBox + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pBleedBox, E_POINTER))) + { + m_bleedBox = *pBleedBox; + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CPageScaling::SetContentBox + +Routine Description: + + Used to set the XPS ContentBox in the page scaling interface. + +Arguments: + + pContentBox - pointer to a rectangle defining the ContentBox of the XPS page in 1/96 Inch. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPageScaling::SetContentBox( + _In_ RectF* pContentBox + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pContentBox, E_POINTER))) + { + m_contentBox = *pContentBox; + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CPageScaling::CalculateMatrix + +Routine Description: + + Calculates a matrix transform from the current page scaling properties. + +Arguments: + + pMatrix - Pointer to a Matrix class object that is modified to reflect the current transform. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPageScaling::CalculateMatrix( + _Inout_ Matrix* pMatrix + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pMatrix, E_POINTER))) + { + REAL xScale = 1.0f; + REAL yScale = 1.0f; + REAL widthOffset = 0.0f; + REAL heightOffset = 0.0f; + + EScaleOption pgscOption; + + if (SUCCEEDED(hr = m_PGSCProps.GetOption(&pgscOption))) + { + switch (pgscOption) + { + case Custom: + case CustomSquare: + { + // + // The PrintTicket property handler for Custom and CustomSquare + // already handle mapping of x and y. + // + if (SUCCEEDED(hr = m_PGSCProps.GetWidthScale(&xScale)) && + SUCCEEDED(hr = m_PGSCProps.GetHeightScale(&yScale)) && + SUCCEEDED(hr = m_PGSCProps.GetWidthOffset(&widthOffset))) + { + hr = m_PGSCProps.GetHeightOffset(&heightOffset); + } + } + break; + + case FitBleedToImageable: // ImageableSize <- BleedBox + case FitContentToImageable: // ImageableSize <- ContentBox + case FitMediaToImageable: // ImageableSize <- FixedPage + case FitMediaToMedia: // Mediasize <- FixedPage + { + EScaleOffsetOption offsetOption; + + if (SUCCEEDED(hr = m_PGSCProps.GetOffsetOption(&offsetOption))) + { + RectF targetPage; + RectF sourcePage; + + switch (pgscOption) + { + case FitBleedToImageable: + { + m_PGSCProps.GetImageableRect(&targetPage); + + sourcePage = m_bleedBox; + } + break; + case FitContentToImageable: + { + m_PGSCProps.GetImageableRect(&targetPage); + + sourcePage = m_contentBox; + } + break; + case FitMediaToImageable: + { + m_PGSCProps.GetImageableRect(&targetPage); + + sourcePage = RectF(0, 0, m_pageDimensions.Width, m_pageDimensions.Height); + } + break; + case FitMediaToMedia: + { + SizeF pageSize; + m_PGSCProps.GetPageSize(&pageSize); + targetPage = RectF(0, 0, pageSize.Width, pageSize.Height); + + sourcePage = RectF(0, 0, m_pageDimensions.Width, m_pageDimensions.Height); + } + break; + } + + // + // Calculate scaling factors + // + xScale = static_cast(targetPage.Width / sourcePage.Width); + yScale = static_cast(targetPage.Height / sourcePage.Height); + + // + // Best Fit, always maintain aspect ratio + // Select the smallest of the two scale factors, + // This will ensure that the image always fits on the page. + // + if (xScale < yScale) + { + yScale = xScale; + } + else + { + xScale = yScale; + } + + // + // Calculate the offset to meet the offset alignment setting + // + RectF scaledPage(xScale*sourcePage.X, yScale*sourcePage.Y, xScale*sourcePage.Width, yScale*sourcePage.Height); + switch (offsetOption) + { + case BottomCenter: + { + widthOffset = (targetPage.X + (targetPage.Width/2.0f)) - (scaledPage.X + (scaledPage.Width/2.0f)); + heightOffset = (targetPage.Y + targetPage.Height) - (scaledPage.Y + scaledPage.Height); + } + break; + case BottomLeft: + { + widthOffset = targetPage.X - scaledPage.X; + heightOffset = targetPage.Y + targetPage.Height - (scaledPage.Y + scaledPage.Height); + } + break; + case BottomRight: + { + widthOffset = (targetPage.X + targetPage.Width) - (scaledPage.X + scaledPage.Width); + heightOffset = (targetPage.Y + targetPage.Height) - (scaledPage.Y + scaledPage.Height); + } + break; + case Center: + { + widthOffset = (targetPage.X + (targetPage.Width/2.0f)) - (scaledPage.X + (scaledPage.Width/2.0f)); + heightOffset = (targetPage.Y + (targetPage.Height/2.0f)) - (scaledPage.Y + (scaledPage.Height/2.0f)); + } + break; + case LeftCenter: + { + widthOffset = targetPage.X - scaledPage.X; + heightOffset = (targetPage.Y + (targetPage.Height/2.0f)) - (scaledPage.Y + (scaledPage.Height/2.0f)); + } + break; + case RightCenter: + { + widthOffset = (targetPage.X + targetPage.Width) - (scaledPage.X + scaledPage.Width); + heightOffset = (targetPage.Y + (targetPage.Height/2.0f)) - (scaledPage.Y + (scaledPage.Height/2.0f)); + } + break; + case TopCenter: + { + widthOffset = (targetPage.X + (targetPage.Width/2.0f)) - (scaledPage.X + (scaledPage.Width/2.0f)); + heightOffset = targetPage.Y - scaledPage.Y; + } + break; + default: + case TopLeft: + { + // + // Default Top Left + // + widthOffset = targetPage.X - scaledPage.X; + heightOffset = targetPage.Y - scaledPage.Y; + } + break; + case TopRight: + { + widthOffset = (targetPage.X + targetPage.Width) - (scaledPage.X + scaledPage.Width); + heightOffset = targetPage.Y - scaledPage.Y; + } + break; + } + } + } + break; + + default: + { + // + // No Scaling required. + // + } + break; + } + } + + // + // Apply the transforms to the matrix + // + Status gdiPlusStatus = pMatrix->Scale(xScale, yScale, MatrixOrderAppend); + + if (gdiPlusStatus == Ok) + { + gdiPlusStatus = pMatrix->Translate(widthOffset, heightOffset, MatrixOrderAppend); + } + + if (gdiPlusStatus != Ok) + { + hr = GetGDIStatusErrorAsHResult(gdiPlusStatus); + } + } + + ERR_ON_HR(hr); + return hr; +} + + +/*++ + +Routine Name: + + CPageScaling::CreateTransform + +Routine Description: + + Creates a string representation of the current page scaling matrix. + The string is suitable for use in XPS markup with the 'RenderTransform' keyword. + +Arguments: + + pbstrMatrixXForm - Address of a pointer that will be modified to point to a string + that is filled out with the matrix. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPageScaling::CreateTransform( + _Outptr_ BSTR* pbstrMatrixXForm + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pbstrMatrixXForm, E_POINTER))) + { + *pbstrMatrixXForm = NULL; + + // + // Start with the identity matrix + // + + Matrix xForm; + + if (SUCCEEDED(hr = CalculateMatrix(&xForm))) + { + // + // Retrieve the matrix string + // + hr = MatrixToXML(&xForm, pbstrMatrixXForm); + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CPageScaling::GetOpenTagXML + +Routine Description: + + Creates a string that contains the open tag XPS markup required to + scale the page content. Page Scaling is achieved by wrapping the page content + in a canvas and applying a RenderTransform which reflects the current page scaling properties. + +Arguments: + + pbstrXML - Address of a pointer that will be modified to point to a string + that is filled out with the page scaling close tag XPS markup. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPageScaling::GetOpenTagXML( + _Outptr_ BSTR* pbstrXML + ) +{ + HRESULT hr = S_OK; + + // + // Create the Canvas with Render Transform + // + try + { + CComBSTR bstrMatrixXForm; + + if (SUCCEEDED(hr = CreateTransform(&bstrMatrixXForm))) + { + CStringXDW cstrCanvas; + cstrCanvas.Format(L"\n"); + *pbstrXML = cstrCanvas.AllocSysString(); + } + catch (CXDException& e) + { + hr = e; + } + } + + ERR_ON_HR(hr); + return hr; +} + diff --git a/print/XPSDrvSmpl/src/filters/scaling/pagescale.h b/print/XPSDrvSmpl/src/filters/scaling/pagescale.h new file mode 100644 index 00000000..51f9be89 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/scaling/pagescale.h @@ -0,0 +1,107 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + scalepage.h + +Abstract: + + Page Scaling class implementation. The Page Scaling class provides + functionality required to generate the XPS markup to perform page scaling. + This includes methods for converting a GDI matrix object + into the appropriate XPS matrix mark-up and intialising the matrix according to + the Page Scaling options. + +--*/ + +#pragma once + +#include "pgscptprop.h" + +class CPageScaling +{ +public: + CPageScaling( + _In_ CONST CPGSCPTProperties& psProps + ); + + virtual ~CPageScaling(); + + HRESULT + GetFixedPageWidth( + _Outptr_ BSTR* pbstrWidth + ); + + HRESULT + GetFixedPageHeight( + _Outptr_ BSTR* pbstrHeight + ); + + HRESULT + GetOpenTagXML( + _Outptr_ BSTR* pbstrXML + ); + + HRESULT + GetCloseTagXML( + _Outptr_ BSTR* pbstrXML + ); + + HRESULT + SetPageDimensions( + _In_ CONST REAL width, + _In_ CONST REAL height + ); + + HRESULT + SetBleedBox( + _In_ RectF* pBleedBox + ); + + HRESULT + SetContentBox( + _In_ RectF* pContentBox + ); + +private: + HRESULT + CreateTransform( + _Outptr_ BSTR* pbstrMatrixXForm + ); + + HRESULT + CalculateMatrix( + _Inout_ Matrix* pMatrix + ); + + HRESULT + MatrixToXML( + _In_ CONST Matrix* pMatrix, + _Outptr_ BSTR* pbstrMatrixXForm + ); + +private: + CComPtr m_pDOMDoc; + + CComPtr m_pCanvasElem; + + CPGSCPTProperties m_PGSCProps; + + RectF m_bleedBox; + + RectF m_contentBox; + + SizeF m_pageDimensions; + + BOOL m_bAddCanvas; +}; + diff --git a/print/XPSDrvSmpl/src/filters/scaling/pgscptprop.cpp b/print/XPSDrvSmpl/src/filters/scaling/pgscptprop.cpp new file mode 100644 index 00000000..9f771658 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/scaling/pgscptprop.cpp @@ -0,0 +1,478 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + pgscptprop.cpp + +Abstract: + + Page Scaling properties class implementation. The Page Scaling properties class + is responsible for holding and controling Page Scaling properties. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "pgscptprop.h" + +using XDPrintSchema::PageScaling::PageScalingData; +using XDPrintSchema::PageScaling::EScaleOption; +using XDPrintSchema::PageScaling::OffsetAlignment::EScaleOffsetOption; + +using XDPrintSchema::PageOrientation::PageOrientationData; +using XDPrintSchema::PageOrientation::Landscape; +using XDPrintSchema::PageOrientation::ReverseLandscape; + +using XDPrintSchema::PageMediaSize::PageMediaSizeData; + +using XDPrintSchema::PageImageableSize::PageImageableData; + +/*++ + +Routine Name: + + CPGSCPTProperties::CPGSCPTProperties + +Routine Description: + + CPGSCPTProperties class constructor + +Arguments: + + pgscData - reference to the Page Scaling data. + pSizeData - reference to the Page Size data. + pImageableData - reference to the Page Imageable Size data. + +Return Value: + + None + +--*/ +CPGSCPTProperties::CPGSCPTProperties( + _In_ CONST PageScalingData& pgscData, + _In_ CONST PageMediaSizeData& pSizeData, + _In_ CONST PageImageableData& pImageableData, + _In_ CONST PageOrientationData& pageOrientData + ) : + m_pgscData(pgscData), + m_pageMediaSizeData(pSizeData), + m_pageImageableData(pImageableData), + m_pageOrientData(pageOrientData) +{ +} + +/*++ + +Routine Name: + + CPGSCPTProperties::~CPGSCPTProperties + +Routine Description: + + CPGSCPTProperties class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CPGSCPTProperties::~CPGSCPTProperties() +{ +} + +/*++ + +Routine Name: + + CPGSCPTProperties::GetOption + +Routine Description: + + Used to obtain the current page scaling option. + +Arguments: + + pOption - Pointer to the page scaling option to filled out. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPGSCPTProperties::GetOption( + _Out_ EScaleOption* pOption + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pOption, E_POINTER))) + { + *pOption = m_pgscData.pgscOption; + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CPGSCPTProperties::GetOffsetOption + +Routine Description: + + Used to obtain the current page scaling offset option. + +Arguments: + + pOffsetOption - Pointer to the page scaling offset option to filled out. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPGSCPTProperties::GetOffsetOption( + _Out_ EScaleOffsetOption* pOffsetOption + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pOffsetOption, E_POINTER))) + { + *pOffsetOption = m_pgscData.offsetOption; + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CPGSCPTProperties::GetWidthOffset + +Routine Description: + + Used to obtain the current width offset (Only applies to the custom scaling options). + Units are in 1/96 Inch. + +Arguments: + + pWidthOffset - Pointer to the width offset data to be filled out. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPGSCPTProperties::GetWidthOffset( + _Out_ REAL* pWidthOffset + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pWidthOffset, E_POINTER))) + { + *pWidthOffset = static_cast(m_pgscData.offWidth)/k96thInchAsMicrons; + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CPGSCPTProperties::GetHeightOffset + +Routine Description: + + Used to obtain the current height offset (Only applies to the custom scaling options). + Units are in 1/96 Inch. + +Arguments: + + pHeightOffset - Pointer to the height offset data to be filled out. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPGSCPTProperties::GetHeightOffset( + _Out_ REAL* pHeightOffset + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pHeightOffset, E_POINTER))) + { + *pHeightOffset = static_cast(m_pgscData.offHeight)/k96thInchAsMicrons; + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CPGSCPTProperties::GetWidthScale + +Routine Description: + + Used to obtain the current width scale percentage + (Only applies to the custom scaling options). + +Arguments: + + pWidthScale - Pointer to the width scale data to be filled out. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPGSCPTProperties::GetWidthScale( + _Out_ REAL* pWidthScale + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pWidthScale, E_POINTER))) + { + *pWidthScale = static_cast(m_pgscData.scaleWidth)/100.00f; + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CPGSCPTProperties::GetHeightScale + +Routine Description: + + Used to obtain the current height scale percentage + (Only applies to the custom scaling options). + +Arguments: + + pHeightScale - Pointer to the height scale data to be filled out. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPGSCPTProperties::GetHeightScale( + _Out_ REAL* pHeightScale + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pHeightScale, E_POINTER))) + { + *pHeightScale = static_cast(m_pgscData.scaleHeight)/100.00f; + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CPGSCPTProperties::GetPageSize + +Routine Description: + + Used to obtain the current page size. Units are in 1/96 Inch. + + Note: This returns the page dimensions accounting for the orientation and media size + expressed by the PrintTicket as PageOrientation and PageMediaSize. The PageMediaSize + expresses the dimensions using the convention that the page is oriented as portrait. + To get the dimensions for scaling we need to swap width for height when in landscape + so that we can scale the FixedPage content appropriately. + +Arguments: + + pSizePage - Pointer to the page size data to be filled out. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPGSCPTProperties::GetPageSize( + _Out_ SizeF* pSizePage + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pSizePage, E_POINTER))) + { + // + // Convert microns to 96th of an inch + // + pSizePage->Width = static_cast(m_pageMediaSizeData.pageWidth)/k96thInchAsMicrons; + pSizePage->Height = static_cast(m_pageMediaSizeData.pageHeight)/k96thInchAsMicrons; + + // + // Swap dimensions if the orientation is a landscape orientation + // + if (m_pageOrientData.orientation == Landscape || + m_pageOrientData.orientation == ReverseLandscape) + { + REAL sizeSwap = pSizePage->Width; + pSizePage->Width = pSizePage->Height; + pSizePage->Height = sizeSwap; + } + + if (pSizePage->Width <= 0.0f || + pSizePage->Height <= 0.0f) + { + // + // The page media size is incorrect + // + ERR("Could not acquire a valid media page size\n"); + + hr = E_FAIL; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CPGSCPTProperties::GetImageableRect + +Routine Description: + + Used to obtain the current page imageable area and offset. + Units are in 1/96 Inch. + +Arguments: + + pImageableRect - Pointer to the page imageable data to be filled out. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPGSCPTProperties::GetImageableRect( + _Out_ RectF* pImageableRect + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pImageableRect, E_POINTER))) + { + pImageableRect->X = 0; + pImageableRect->Y = 0; + pImageableRect->Width = 0; + pImageableRect->Height = 0; + + // + // Get the size of the area - convert microns to 96th of an inch + // + SizeF sizeImage; + if (m_pageImageableData.imageableSizeWidth > 0 && + m_pageImageableData.imageableSizeHeight > 0) + { + sizeImage.Width = static_cast(m_pageImageableData.imageableSizeWidth)/k96thInchAsMicrons; + sizeImage.Height = static_cast(m_pageImageableData.imageableSizeHeight)/k96thInchAsMicrons; + } + else + { + // + // Page imageable size was not set - use the page media size + // + sizeImage.Width = static_cast(m_pageMediaSizeData.pageWidth)/k96thInchAsMicrons; + sizeImage.Height = static_cast(m_pageMediaSizeData.pageHeight)/k96thInchAsMicrons; + } + + // + // Get the offset of the area - convert microns to 96th of an inch + // + PointF offsetImage(static_cast(m_pageImageableData.originWidth)/k96thInchAsMicrons, + static_cast(m_pageImageableData.originHeight)/k96thInchAsMicrons); + + // + // Swap dimensions if the orientation is a landscape orientation + // + if (m_pageOrientData.orientation == Landscape || + m_pageOrientData.orientation == ReverseLandscape) + { + pImageableRect->Width = sizeImage.Height; + pImageableRect->Height = sizeImage.Width; + + pImageableRect->X = offsetImage.Y; + pImageableRect->Y = offsetImage.X; + } + else + { + pImageableRect->Width = sizeImage.Width; + pImageableRect->Height = sizeImage.Height; + + pImageableRect->X = offsetImage.X; + pImageableRect->Y = offsetImage.Y; + } + } + + ERR_ON_HR(hr); + return hr; +} + diff --git a/print/XPSDrvSmpl/src/filters/scaling/pgscptprop.h b/print/XPSDrvSmpl/src/filters/scaling/pgscptprop.h new file mode 100644 index 00000000..99cb5328 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/scaling/pgscptprop.h @@ -0,0 +1,91 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + pgscptprop.h + +Abstract: + + Page Scaling properties class definition. The Page Scaling properties class + is responsible for holding and controling Page Scaling properties. + +--*/ + +#pragma once + +#include "pgscdata.h" +#include "psizedata.h" +#include "pimagedata.h" +#include "porientdata.h" + +class CPGSCPTProperties +{ +public: + CPGSCPTProperties( + _In_ CONST XDPrintSchema::PageScaling::PageScalingData& pgscData, + _In_ CONST XDPrintSchema::PageMediaSize::PageMediaSizeData& psizeData, + _In_ CONST XDPrintSchema::PageImageableSize::PageImageableData& pimageableData, + _In_ CONST XDPrintSchema::PageOrientation::PageOrientationData& pageOrientData + ); + + virtual ~CPGSCPTProperties(); + + HRESULT + GetOption( + _Out_ XDPrintSchema::PageScaling::EScaleOption* pScaleOption + ); + + HRESULT + GetWidthOffset( + _Out_ REAL* pWidthOffset + ); + + HRESULT + GetHeightOffset( + _Out_ REAL* pHeightOffset + ); + + HRESULT + GetWidthScale( + _Out_ REAL* pWidthScale + ); + + HRESULT + GetHeightScale( + _Out_ REAL* pHeightScale + ); + + HRESULT + GetOffsetOption( + _Out_ XDPrintSchema::PageScaling::OffsetAlignment::EScaleOffsetOption* pOffsetOption + ); + + HRESULT + GetPageSize( + _Out_ SizeF* pSizePage + ); + + HRESULT + GetImageableRect( + _Out_ RectF* pImageableRect + ); + +protected: + XDPrintSchema::PageScaling::PageScalingData m_pgscData; + + XDPrintSchema::PageMediaSize::PageMediaSizeData m_pageMediaSizeData; + + XDPrintSchema::PageImageableSize::PageImageableData m_pageImageableData; + + XDPrintSchema::PageOrientation::PageOrientationData m_pageOrientData; +}; + diff --git a/print/XPSDrvSmpl/src/filters/scaling/precompsrc.cpp b/print/XPSDrvSmpl/src/filters/scaling/precompsrc.cpp new file mode 100644 index 00000000..5944cf51 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/scaling/precompsrc.cpp @@ -0,0 +1 @@ +#include "precomp.h" \ No newline at end of file diff --git a/print/XPSDrvSmpl/src/filters/scaling/scaleflt.cpp b/print/XPSDrvSmpl/src/filters/scaling/scaleflt.cpp new file mode 100644 index 00000000..1827a9a2 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/scaling/scaleflt.cpp @@ -0,0 +1,253 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + scaleflt.cpp + +Abstract: + + Page Scaling filter implementation. This class derives from the Xps filter + class and implements the necessary part handlers to support Page Scaling + printing. The Page Scaling filter is responsible for modifying the XPS document + to add the appropriate mark-up onto pages to achieve scaling. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "scaleflt.h" +#include "pagescale.h" +#include "scalesax.h" +#include "psizepthndlr.h" +#include "pimagepthndlr.h" +#include "pgscpthndlr.h" +#include "porientpthndlr.h" + +using XDPrintSchema::PageScaling::PageScalingData; +using XDPrintSchema::PageMediaSize::PageMediaSizeData; +using XDPrintSchema::PageImageableSize::PageImageableData; +using XDPrintSchema::PageOrientation::PageOrientationData; + +/*++ + +Routine Name: + + CPageScalingFilter::CPageScalingFilter + +Routine Description: + + CPageScalingFilter class constructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CPageScalingFilter::CPageScalingFilter() +{ + ASSERTMSG(m_gdiPlus.GetGDIPlusStartStatus() == Ok, "GDI plus is not correctly initialized.\n"); +} + +/*++ + +Routine Name: + + CPageScalingFilter::~CPageScalingFilter + +Routine Description: + + CPageScalingFilter class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CPageScalingFilter::~CPageScalingFilter() +{ +} + +/*++ + +Routine Name: + + CPageScalingFilter::ProcessFixedPage + +Routine Description: + + This method processes the XPS content of a page applying + any scaling required according to information in the PrintTicket. + The result is written out to a new XPS document. + +Arguments: + + pPrintTicket - Pointer to the XML PrintTicket Document that is associated with the page. + pPageReadStream - Pointer to the input stream interface for the XPS Page. + pPageWriteStream - Pointer to the output stream interface for the XPS Page. + +Return Value: + + HRESULT + S_OK - On success + HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED) - When the fixed page is not to be modified + E_* - On error + +--*/ +HRESULT +CPageScalingFilter::ProcessFixedPage( + _In_ IXMLDOMDocument2* pFPPT, + _In_ ISequentialStream* pPageReadStream, + _In_ ISequentialStream* pPageWriteStream + ) +{ + VERBOSE("Processing stream fixed page with page scaling handler\n"); + + HRESULT hr = S_OK; + + CPageScaling* pPageScaling = NULL; + CComPtr pSaxRdr(NULL); + CComPtr pPrintCapabilities(NULL); + + if (SUCCEEDED(hr = m_ptManager.GetCapabilities(pFPPT, &pPrintCapabilities)) && + SUCCEEDED(hr = CHECK_POINTER(pFPPT, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pPageReadStream, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pPageWriteStream, E_POINTER)) && + SUCCEEDED(hr = GetPageScaling(pFPPT, pPrintCapabilities, &pPageScaling)) && + SUCCEEDED(hr = pSaxRdr.CoCreateInstance(CLSID_SAXXMLReader60))) + { + // + // Set-up the SAX reader and begin parsing the mark-up + // + CScaleSaxHandler scaleSaxHndlr(pPageWriteStream, pPageScaling); + + if (SUCCEEDED(hr = pSaxRdr->putContentHandler(&scaleSaxHndlr))) + { + hr = pSaxRdr->parse(CComVariant(pPageReadStream)); + } + } + else if (hr == E_ELEMENT_NOT_FOUND) + { + // + // No Page Scaling was found in the PrintTicket - return error not supported so + // the xps container sends the unmodified data + // + hr = HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); + } + + // + // Clean up the Page Scaling if it was successfully created + // + if (pPageScaling != NULL) + { + delete pPageScaling; + pPageScaling = NULL; + } + + ERR_ON_HR_EXC(hr, HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED)); + return hr; +} + +/*++ + +Routine Name: + + CPageScalingFilter::GetPageScaling + +Routine Description: + + Creates and initialises an instance of the Page Scaling Interface + using the information in the PrintTicket provided. + +Arguments: + + pPrintTicket - Pointer to an XML PrintTicket Document. + pPrintCapabilities - Pointer to an XML PrintCapabilities Document. + ppPageScaling - Address of pointer that receives the Page Scaling Interface. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPageScalingFilter::GetPageScaling( + _In_ IXMLDOMDocument2* pPrintTicket, + _In_ IXMLDOMDocument2* pPrintCapabilities, + _Outptr_ CPageScaling** ppPageScaling + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(ppPageScaling, E_POINTER))) + { + *ppPageScaling = NULL; + + try + { + CPageScalingPTHandler pgscPTHandler(pPrintTicket); + CPageImageablePCHandler imagePCHandler(pPrintCapabilities); + CPageSizePTHandler sizePTHandler(pPrintTicket); + CPageOrientationPTHandler orientPTHandler(pPrintTicket); + + PageScalingData pgscData; + PageMediaSizeData sizeData; + PageImageableData imageData; + PageOrientationData orientData; + + if (SUCCEEDED(hr = pgscPTHandler.GetData(&pgscData)) && + SUCCEEDED(hr = sizePTHandler.GetData(&sizeData)) && + SUCCEEDED(hr = orientPTHandler.GetData(&orientData))) + { + hr = imagePCHandler.GetData(&imageData); + + // + // The imageable area property in a PrintTicket is an optional requirement. + // + if (hr == E_ELEMENT_NOT_FOUND) + { + hr = S_OK; + } + + if (SUCCEEDED(hr)) + { + CPGSCPTProperties pgscProperties(pgscData, sizeData, imageData, orientData); + + *ppPageScaling = new(std::nothrow) CPageScaling(pgscProperties); + + if (*ppPageScaling == NULL) + { + hr = E_OUTOFMEMORY; + } + } + } + } + catch (CXDException& e) + { + hr = e; + } + } + + ERR_ON_HR_EXC(hr, E_ELEMENT_NOT_FOUND); + return hr; +} + diff --git a/print/XPSDrvSmpl/src/filters/scaling/scaleflt.h b/print/XPSDrvSmpl/src/filters/scaling/scaleflt.h new file mode 100644 index 00000000..2e8307c0 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/scaling/scaleflt.h @@ -0,0 +1,56 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + scaleflt.h + +Abstract: + + Page Scaling filter defnition. This class derives from the Xps filter + class and implements the necessary part handlers to support Page Scaling. + The Page Scaling filter is responsible for adding mark-up to + the XPS document to allow scaling of pages. + +--*/ + +#pragma once + +#include "xdstrmflt.h" +#include "pagescale.h" +#include "gdip.h" + +class CPageScalingFilter : public CXDStreamFilter +{ +public: + CPageScalingFilter(); + + virtual ~CPageScalingFilter(); + + virtual HRESULT + ProcessFixedPage( + _In_ IXMLDOMDocument2* pFPPT, + _In_ ISequentialStream* pPageReadStream, + _In_ ISequentialStream* pPageWriteStream + ); + +private: + HRESULT + GetPageScaling( + _In_ IXMLDOMDocument2* pPrintTicket, + _In_ IXMLDOMDocument2* pPrintCapabilities, + _Outptr_ CPageScaling** ppPageScaling + ); + +private: + GDIPlus m_gdiPlus; +}; + diff --git a/print/XPSDrvSmpl/src/filters/scaling/scaleflt.rc b/print/XPSDrvSmpl/src/filters/scaling/scaleflt.rc new file mode 100644 index 00000000..677e6c0a --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/scaling/scaleflt.rc @@ -0,0 +1,43 @@ +// +// Copyright (c) 2005 Microsoft Corporation +// +// All rights reserved. +// +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +// PARTICULAR PURPOSE. +// +// File Name: +// +// scaleflt.rc +// +// Abstract: +// +// Page Scaling filter resource file. +// +// + +#include +#include + +#define VER_FILETYPE VFT_DLL +#define VER_FILESUBTYPE VFT2_UNKNOWN +#define VER_FILEDESCRIPTION_STR "XPSDrv Sample Scaling Filter" +#define VER_INTERNALNAME_STR "PrintFeatureFilters" + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#endif // English (U.S.) resources + +///////////////////////////////////////////////////////////////////////////// + +#include "common.ver" + diff --git a/print/XPSDrvSmpl/src/filters/scaling/scalesax.cpp b/print/XPSDrvSmpl/src/filters/scaling/scalesax.cpp new file mode 100644 index 00000000..43219976 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/scaling/scalesax.cpp @@ -0,0 +1,591 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + scalesax.xpp + +Abstract: + + Page Scaling SAX handler implementation. The class derives from the default SAX handler + and implements only the necessary SAX APIs to process the mark-up. The + handler is responsible for copying page mark-up to a writer, removing + the fixed page opening and closing tags. + +Known Issues: + + Need to check if all resources are required resources are being added to the + resource copying class. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdstring.h" +#include "scalesax.h" + +/*++ + +Routine Name: + + CScaleSaxHandler::CScaleSaxHandler + +Routine Description: + + CScaleSaxHandler class constructor + +Arguments: + + pWriter - Pointer to the output stream interface for the XPS page markup. + pPageScaling - Pointer to the Page Scaling Interface. + +Return Value: + + None + Throws CXDException(HRESULT) on an error + +--*/ +CScaleSaxHandler::CScaleSaxHandler( + _In_ ISequentialStream* pWriter, + _In_ CPageScaling* pPageScaling + ) : + m_pWriter(pWriter), + m_pPageScaling(pPageScaling), + m_bOpenTag(FALSE) +{ + ASSERTMSG(m_pWriter != NULL, "NULL writer passed to page scaling SAX handler.\n"); + ASSERTMSG(m_pPageScaling != NULL, "NULL page scaling class passed to page scaling SAX handler.\n"); + + HRESULT hr = S_OK; + if (FAILED(hr = CHECK_POINTER(m_pWriter, E_POINTER)) || + FAILED(hr = CHECK_POINTER(m_pPageScaling, E_POINTER))) + { + throw CXDException(hr); + } +} + +/*++ + +Routine Name: + + CScaleSaxHandler::~CScaleSaxHandler + +Routine Description: + + CScaleSaxHandler class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CScaleSaxHandler::~CScaleSaxHandler() +{ + m_bstrOpenElement.Empty(); +} + +/*++ + +Routine Name: + + CScaleSaxHandler::startElement + +Routine Description: + + Receives notification of the beginning of an XML element in the XPS page. + The page scaling filter parses each element, applies any changes + and writes out the resultant XPS markup. + +Arguments: + + pwchQName - The XML 1.0 qualified name (QName), with prefix, or an empty string + (if QNames are not available). + cchQName - The length of the QName. + pAttributes - The attributes attached to the element. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT STDMETHODCALLTYPE +CScaleSaxHandler::startElement( + CONST wchar_t*, + INT, + CONST wchar_t*, + INT, + _In_reads_(cchQName) CONST wchar_t* pwchQName, + _In_ INT cchQName, + _In_ ISAXAttributes* pAttributes + ) +{ + HRESULT hr = S_OK; + CStringXDW cstrOut; + + // + // If this is the fixed page we need the width and height retrieved + // + BOOL bIsFixedPage = FALSE; + + try + { + CComBSTR bstrElement(cchQName, pwchQName); + + bIsFixedPage = (bstrElement == L"FixedPage"); + + // + // Check if we need to close an opened tag + // + if (m_bOpenTag) + { + cstrOut.Append(L">\n"); + } + + // + // Store the opened element name so we can handle nested elements + // + m_bstrOpenElement = bstrElement; + } + catch (CXDException& e) + { + hr = e; + } + + if (SUCCEEDED(hr)) + { + // + // Write out element + // + try + { + cstrOut.Append(L"<"); + cstrOut.Append(m_bstrOpenElement); + } + catch (CXDException& e) + { + hr = e; + } + + // + // We opened a tag + // + m_bOpenTag = TRUE; + + REAL widthPage(0.0f); + REAL heightPage(0.0f); + RectF bleedBox(0.0f, 0.0f, 0.0f, 0.0f); + RectF contentBox(0.0f, 0.0f, 0.0f, 0.0f); + + BOOL bBleedBoxSet = FALSE; + BOOL bContentBoxSet = FALSE; + + // + // Find the number of attributes and enumerate over all of them + // + INT cAttributes = 0; + if (SUCCEEDED(hr) && + SUCCEEDED(hr = pAttributes->getLength(&cAttributes))) + { + for (INT cIndex = 0; cIndex < cAttributes && SUCCEEDED(hr); cIndex++) + { + PCWSTR pszAttUri = NULL; + INT cchAttUri = 0; + PCWSTR pszAttName = NULL; + INT cchAttName = 0; + PCWSTR pszAttQName = NULL; + INT cchAttQName = 0; + PCWSTR pszAttValue = NULL; + INT cchAttValue = 0; + + // + // Get the attribute data ready to write out + // + if (SUCCEEDED(hr = pAttributes->getName(cIndex, + &pszAttUri, + &cchAttUri, + &pszAttName, + &cchAttName, + &pszAttQName, + &cchAttQName))) + { + if (SUCCEEDED(pAttributes->getValue(cIndex, &pszAttValue, &cchAttValue))) + { + try + { + CComBSTR bstrAttName(cchAttQName, pszAttQName); + CComBSTR bstrAttValue(cchAttValue, pszAttValue); + + // + // If this is the fixed page we want to retrieve the + // dimensions of the fixed page - take the opportunity + // to do so now while we parse the attributes + // + if (bIsFixedPage) + { + if (bstrAttName == L"Width") + { + widthPage = static_cast(_wtof(bstrAttValue)); + } + else if (bstrAttName == L"Height") + { + heightPage = static_cast(_wtof(bstrAttValue)); + } + else if (bstrAttName == L"ContentBox") + { + CStringXDW str( bstrAttValue ); + CStringXDW resToken; + INT curPos= 0; + bContentBoxSet = TRUE; + + resToken = str.Tokenize(L",",curPos); + + if (resToken != L"") + { + contentBox.X = static_cast(_wtof(resToken)); + } + + resToken = str.Tokenize(L",",curPos); + + if (resToken != L"") + { + contentBox.Y = static_cast(_wtof(resToken)); + } + + resToken = str.Tokenize(L",",curPos); + + if (resToken != L"") + { + contentBox.Width = static_cast(_wtof(resToken)); + } + + resToken = str.Tokenize(L",",curPos); + + if (resToken != L"") + { + contentBox.Height = static_cast(_wtof(resToken)); + } + } + else if (bstrAttName == L"BleedBox") + { + CStringXDW str( bstrAttValue ); + CStringXDW resToken; + INT curPos= 0; + bBleedBoxSet = TRUE; + + resToken = str.Tokenize(L",",curPos); + + if (resToken != "") + { + bleedBox.X = static_cast(_wtof(resToken)); + } + + resToken = str.Tokenize(L",",curPos); + + if (resToken != "") + { + bleedBox.Y = static_cast(_wtof(resToken)); + } + + resToken = str.Tokenize(L",",curPos); + + if (resToken != "") + { + bleedBox.Width = static_cast(_wtof(resToken)); + } + + resToken = str.Tokenize(L",",curPos); + + if (resToken != "") + { + bleedBox.Height = static_cast(_wtof(resToken)); + } + } + } + + // + // As we are applying scaling we need to remove the bleedBox and contentBox + // + if (bstrAttName != L"BleedBox" && + bstrAttName != L"ContentBox") + { + // + // Replace the Width and Height aValues with the target papersize + // + if (bstrAttName == L"Width") + { + CComBSTR bstrWidthValue; + if (SUCCEEDED(hr = m_pPageScaling->GetFixedPageWidth(&bstrWidthValue))) + { + if (bstrWidthValue.Length() > 0) + { + bstrAttValue = bstrWidthValue; + } + } + } + else if (bstrAttName == L"Height") + { + CComBSTR bstrHeightValue; + if (SUCCEEDED(hr = m_pPageScaling->GetFixedPageHeight(&bstrHeightValue))) + { + if (bstrHeightValue.Length() > 0) + { + bstrAttValue = bstrHeightValue; + } + } + } + + if (SUCCEEDED(hr)) + { + // + // Delimit attributes with a space + // + cstrOut.Append(L" "); + + // + // Reconstruct the attribute and write back to + // the fixed page + // + cstrOut.Append(bstrAttName); + cstrOut.Append(L"=\""); + + // + // If this is a UnicodeString we may need to escape entities + // + if (bstrAttName == L"UnicodeString") + { + hr = EscapeEntity(&bstrAttValue); + } + + cstrOut.Append(bstrAttValue); + cstrOut.Append(L"\""); + } + } + } + catch (CXDException& e) + { + hr = e; + } + } + } + } + } + + // + // If bleedbox hasn't been set, set it to the page dimensions + // + if (bBleedBoxSet == FALSE) + { + bleedBox.Width = widthPage; + bleedBox.Height = heightPage; + } + + // + // If contentbox hasn't been set, set it to the page dimensions + // + if (bContentBoxSet == FALSE) + { + contentBox.Width = widthPage; + contentBox.Height = heightPage; + } + + if (SUCCEEDED(hr = m_pPageScaling->SetPageDimensions(widthPage, heightPage)) && + SUCCEEDED(hr = m_pPageScaling->SetBleedBox(&bleedBox)) && + SUCCEEDED(hr = m_pPageScaling->SetContentBox(&contentBox))) + { + if (bIsFixedPage) + { + try + { + // + // Close the fixed page tag + // + cstrOut.Append(L">"); + + // + // Create and retrieve the markup for the Canvas + // + CComBSTR bstrCanvasText; + if (SUCCEEDED(hr = m_pPageScaling->GetOpenTagXML(&bstrCanvasText))) + { + // + // Insert the mark-up by writing after the opening fixed page + // remembering to close the tag first + // + cstrOut.Append(bstrCanvasText); + } + } + catch (CXDException& e) + { + hr = e; + } + } + } + + if (SUCCEEDED(hr)) + { + hr = WriteToPrintStream(&cstrOut, m_pWriter); + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CScaleSaxHandler::endElement + +Routine Description: + + Receives notification of the end of an XML element in the XPS page. + The page scaling filter parses each element, applies any changes + and writes out the resultant XPS markup. + + A corresponding startElement method is invoked for every endElement method, even when the element is empty. + +Arguments: + + pwchQName - The XML 1.0 qualified name (QName), with prefix, or an empty string + (if QNames are not available). + cchQName - The length of the QName. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT STDMETHODCALLTYPE +CScaleSaxHandler::endElement( + CONST wchar_t*, + INT, + CONST wchar_t*, + INT, + _In_reads_(cchQName) CONST wchar_t* pwchQName, + _In_ INT cchQName + ) +{ + HRESULT hr = S_OK; + CStringXDW cstrClose; + BOOL bIsFixedPage = FALSE; + + try + { + CComBSTR bstrElement(cchQName, pwchQName); + + bIsFixedPage = (bstrElement == L"FixedPage"); + + // + // If this is a root element with child nodes, the open + // element will not match the last startElement. In this case + // we need to add an appropriate closing tag + // + if (bstrElement == m_bstrOpenElement) + { + // + // Names match so just add a closing bracket + // + if (m_bOpenTag) + { + cstrClose.Append(L"/>\n"); + } + } + else + { + // + // Close Canvas if previously opened. + // + if (bIsFixedPage) + { + // + // Insert the closing canvas mark-up before closing the fixed page + // + CComBSTR bstrCloseCanvasText; + if (SUCCEEDED(hr = m_pPageScaling->GetCloseTagXML(&bstrCloseCanvasText))) + { + cstrClose.Append(bstrCloseCanvasText); + } + } + + // + // Add a full closing tag + // + cstrClose.Append(L"\n"); + } + + m_bOpenTag = FALSE; + } + catch (CXDException& e) + { + hr = e; + } + + if (SUCCEEDED(hr)) + { + hr = WriteToPrintStream(&cstrClose, m_pWriter); + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CScaleSaxHandler::startDocument + +Routine Description: + + This method writes out the header markup for the XPS page. + +Arguments: + + None + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT STDMETHODCALLTYPE +CScaleSaxHandler::startDocument() +{ + HRESULT hr = S_OK; + + try + { + CStringXDW cstrXMLVersion(L""); + hr = WriteToPrintStream(&cstrXMLVersion, m_pWriter); + } + catch (CXDException& e) + { + hr = e; + } + + ERR_ON_HR(hr); + return hr; +} + diff --git a/print/XPSDrvSmpl/src/filters/scaling/scalesax.h b/print/XPSDrvSmpl/src/filters/scaling/scalesax.h new file mode 100644 index 00000000..2e10e971 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/scaling/scalesax.h @@ -0,0 +1,75 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + scalesax.h + +Abstract: + + Page Scaling SAX handler definition. The class derives from the default SAX handler + and implements only the necessary SAX APIs to process the mark-up. The + handler is responsible for copying page mark-up to a writer, removing + the fixed page opening and closing tags. + +--*/ + +#pragma once + +#include "saxhndlr.h" +#include "pagescale.h" + +class CScaleSaxHandler : public CSaxHandler +{ +public: + CScaleSaxHandler( + _In_ ISequentialStream* pWriter, + _In_ CPageScaling* pPageScaling + ); + + virtual ~CScaleSaxHandler(); + + virtual HRESULT STDMETHODCALLTYPE + startDocument( + void + ); + + virtual HRESULT STDMETHODCALLTYPE + startElement( + CONST wchar_t*, + INT, + CONST wchar_t*, + INT, + _In_reads_(cchQName) CONST wchar_t* pwchQName, + _In_ INT cchQName, + _In_ ISAXAttributes* pAttributes + ); + + virtual HRESULT STDMETHODCALLTYPE + endElement( + CONST wchar_t*, + INT, + CONST wchar_t*, + INT, + _In_reads_(cchQName) CONST wchar_t* pwchQName, + _In_ INT cchQName + ); + +private: + CComPtr m_pWriter; + + CComBSTR m_bstrOpenElement; + + BOOL m_bOpenTag; + + CPageScaling* m_pPageScaling; +}; + diff --git a/print/XPSDrvSmpl/src/filters/scaling/xdscale.def b/print/XPSDrvSmpl/src/filters/scaling/xdscale.def new file mode 100644 index 00000000..82d0a024 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/scaling/xdscale.def @@ -0,0 +1,26 @@ +; +; Copyright (c) 2005 Microsoft Corporation +; +; All rights reserved. +; +; THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +; ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +; THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +; PARTICULAR PURPOSE. +; +; File Name: +; +; xdscale.def +; +; Abstract: +; +; Page Scaling filter module definition file +; + +LIBRARY XDScale + +EXPORTS + DllMain + DllCanUnloadNow PRIVATE + DllGetClassObject PRIVATE + diff --git a/print/XPSDrvSmpl/src/filters/scaling/xdscale.vcxproj b/print/XPSDrvSmpl/src/filters/scaling/xdscale.vcxproj new file mode 100644 index 00000000..223908a0 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/scaling/xdscale.vcxproj @@ -0,0 +1,327 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {268439B8-E924-47E4-BFE9-01DED439AFFE} + $(MSBuildProjectName) + false + true + Debug + Win32 + {48DA3138-F4A4-4566-8485-21ABE98B0187} + + + + Windows10 + False + Desktop + + WindowsApplicationForDrivers10.0 + DynamicLibrary + + + Windows10 + True + Desktop + + WindowsApplicationForDrivers10.0 + DynamicLibrary + + + Windows10 + False + Desktop + + WindowsApplicationForDrivers10.0 + DynamicLibrary + + + Windows10 + True + Desktop + + WindowsApplicationForDrivers10.0 + DynamicLibrary + + + + $(IntDir) + + + + + + + + + + + + + + + + xdscale + + + xdscale + + + xdscale + + + xdscale + + + + _DllMainCRTStartup@12 + _DllMainCRTStartup + + + + + _DllMainCRTStartup@12 + _DllMainCRTStartup + + + + + _DllMainCRTStartup@12 + _DllMainCRTStartup + + + + + _DllMainCRTStartup@12 + _DllMainCRTStartup + + + + + %(AdditionalIncludeDirectories);..\xdcont + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + %(AdditionalIncludeDirectories);..\xdcont + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + MultiThreaded + MultiThreadedDebug + true + Level4 + Sync + + + %(AdditionalIncludeDirectories);..\xdcont + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + %(AdditionalDependencies);.\..\xdcont\$(IntDir)\xdcont.lib + %(AdditionalDependencies);uuid.lib;WIAGUID.lib;msxml6.lib;Kernel32.lib;ole32.lib;oleaut32.lib;prntvpt.lib;winspool.lib;gdi32.lib;gdiplus.lib;shlwapi.lib;Advapi32.lib;user32.lib;.\..\..\debug\$(IntDir)\xdsdbg.lib;.\..\..\common\$(IntDir)\xdsmplcmn.lib;.\..\..\filters\common\$(IntDir)\xdfltcmn.lib + + + + + %(AdditionalIncludeDirectories);..\xdcont + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + %(AdditionalIncludeDirectories);..\xdcont + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + MultiThreaded + MultiThreadedDebug + true + Level4 + Sync + + + %(AdditionalIncludeDirectories);..\xdcont + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + %(AdditionalDependencies);.\..\xdcont\$(IntDir)\xdcont.lib + %(AdditionalDependencies);uuid.lib;WIAGUID.lib;msxml6.lib;Kernel32.lib;ole32.lib;oleaut32.lib;prntvpt.lib;winspool.lib;gdi32.lib;gdiplus.lib;shlwapi.lib;Advapi32.lib;user32.lib;.\..\..\debug\$(IntDir)\xdsdbg.lib;.\..\..\common\$(IntDir)\xdsmplcmn.lib;.\..\..\filters\common\$(IntDir)\xdfltcmn.lib + + + + + %(AdditionalIncludeDirectories);..\xdcont + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + %(AdditionalIncludeDirectories);..\xdcont + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + MultiThreaded + MultiThreadedDebug + true + Level4 + Sync + + + %(AdditionalIncludeDirectories);..\xdcont + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + %(AdditionalDependencies);.\..\xdcont\$(IntDir)\xdcont.lib + %(AdditionalDependencies);uuid.lib;WIAGUID.lib;msxml6.lib;Kernel32.lib;ole32.lib;oleaut32.lib;prntvpt.lib;winspool.lib;gdi32.lib;gdiplus.lib;shlwapi.lib;Advapi32.lib;user32.lib;.\..\..\debug\$(IntDir)\xdsdbg.lib;.\..\..\common\$(IntDir)\xdsmplcmn.lib;.\..\..\filters\common\$(IntDir)\xdfltcmn.lib + + + + + %(AdditionalIncludeDirectories);..\xdcont + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + %(AdditionalIncludeDirectories);..\xdcont + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + MultiThreaded + MultiThreadedDebug + true + Level4 + Sync + + + %(AdditionalIncludeDirectories);..\xdcont + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + %(AdditionalDependencies);.\..\xdcont\$(IntDir)\xdcont.lib + %(AdditionalDependencies);uuid.lib;WIAGUID.lib;msxml6.lib;Kernel32.lib;ole32.lib;oleaut32.lib;prntvpt.lib;winspool.lib;gdi32.lib;gdiplus.lib;shlwapi.lib;Advapi32.lib;user32.lib;.\..\..\debug\$(IntDir)\xdsdbg.lib;.\..\..\common\$(IntDir)\xdsmplcmn.lib;.\..\..\filters\common\$(IntDir)\xdfltcmn.lib + + + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + + + ..;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ..;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ..;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ..;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ..;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + + + + xdscale.def + + + + + xdscale.def + + + + + xdscale.def + + + + + xdscale.def + + + + + ..;%(AdditionalIncludeDirectories) + precomp.h + Create + $(IntDir)\precomp.h.pch + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/print/XPSDrvSmpl/src/filters/scaling/xdscale.vcxproj.Filters b/print/XPSDrvSmpl/src/filters/scaling/xdscale.vcxproj.Filters new file mode 100644 index 00000000..0bdfddca --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/scaling/xdscale.vcxproj.Filters @@ -0,0 +1,45 @@ + + + + + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* + {7FC932B7-0F2E-4826-B0FC-52E916DD3022} + + + h;hpp;hxx;hm;inl;inc;xsd + {7E202E93-C032-4246-8F2C-C782F069F11A} + + + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml + {0443A342-9E26-4F36-891C-FFEB01C44016} + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Resource Files + + + \ No newline at end of file diff --git a/print/XPSDrvSmpl/src/filters/watermark/Raster1.png b/print/XPSDrvSmpl/src/filters/watermark/Raster1.png new file mode 100644 index 00000000..4c11e3c0 Binary files /dev/null and b/print/XPSDrvSmpl/src/filters/watermark/Raster1.png differ diff --git a/print/XPSDrvSmpl/src/filters/watermark/Vector1.xps b/print/XPSDrvSmpl/src/filters/watermark/Vector1.xps new file mode 100644 index 00000000..8227a215 Binary files /dev/null and b/print/XPSDrvSmpl/src/filters/watermark/Vector1.xps differ diff --git a/print/XPSDrvSmpl/src/filters/watermark/dllentry.cpp b/print/XPSDrvSmpl/src/filters/watermark/dllentry.cpp new file mode 100644 index 00000000..dc4f7974 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/watermark/dllentry.cpp @@ -0,0 +1,143 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + dllentry.cpp + +Abstract: + + Implementation of the watermark filter dllentry points. Dllmain only + stores the instance handle. DllGetClassObject calls on to a generic + get class factory template function. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "clasfact.h" +#include "wmflt.h" +#include "xdexcept.h" + +/*++ + +Routine Name: + + DllMain + +Routine Description: + + Entry point to the watermark filter which is called when a new process is started + +Arguments: + + hInst - Handle to the DLL + wReason - Specifies a flag indicating why the DLL entry-point function is being called + +Return Value: + + TRUE + +--*/ +BOOL WINAPI +DllMain( + _In_ HINSTANCE hInst, + _In_ WORD wReason, + _In_opt_ LPVOID + ) +{ + switch (wReason) + { + case DLL_PROCESS_ATTACH: + { + g_hInstance = hInst; + } + break; + } + + return TRUE; +} + +/*++ + +Routine Name: + + DllCanUnloadNow + +Routine Description: + + Method which reports whether the DLL is in use to allow the caller to unload + the DLL safely + +Arguments: + + None + +Return Value: + + HRESULT + S_OK - Dll can unload + S_FALSE - Dll can't unload + +--*/ +STDAPI +DllCanUnloadNow() +{ + if (g_cServerLocks == 0) + { + return S_OK ; + } + else + { + return S_FALSE; + } +} + +/*++ + +Routine Name: + + DllGetClassObject + +Routine Description: + + Method to return the current class object + +Arguments: + + rclsid - CLSID that will associate the correct data and code + riid - Reference to the identifier of the interface that the caller is to use to communicate with the class object + ppv - Address of pointer variable that receives the interface pointer requested in riid + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + CLASS_E_CLASSNOTAVAILABLE - On unsupported class + +--*/ +STDAPI +DllGetClassObject( + _In_ REFCLSID rclsid, + _In_ REFIID riid, + _Outptr_ LPVOID FAR* ppv + ) +{ + // + // B8B525BF-F147-460a-B2D5-9DFB1F30D0FD + // + CLSID watermarkCLSID = {0xB8B525BF, 0xF147, 0x460a, {0xB2, 0xD5, 0x9D, 0xFB, 0x1F, 0x30, 0xD0, 0xFD}}; + + return GetFilterClassFactory(rclsid, riid, watermarkCLSID, ppv); +} + diff --git a/print/XPSDrvSmpl/src/filters/watermark/precompsrc.cpp b/print/XPSDrvSmpl/src/filters/watermark/precompsrc.cpp new file mode 100644 index 00000000..5944cf51 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/watermark/precompsrc.cpp @@ -0,0 +1 @@ +#include "precomp.h" \ No newline at end of file diff --git a/print/XPSDrvSmpl/src/filters/watermark/wmbase.cpp b/print/XPSDrvSmpl/src/filters/watermark/wmbase.cpp new file mode 100644 index 00000000..97d15b3e --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/watermark/wmbase.cpp @@ -0,0 +1,416 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + wmbase.cpp + +Abstract: + + Base watermark class implementation. The base watermark class provides + common functionality required between different watermarks (Text, RasterGraphic + and VectorGraphic. This includes methods for converting a GDI matrix object + into the appropriate XPS matrix mark-up and intialising the matrix according to + the watermark options. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdstring.h" +#include "wmbase.h" + +using XDPrintSchema::PageWatermark::Layering::ELayeringOption; +using XDPrintSchema::PageWatermark::Layering::Overlay; +using XDPrintSchema::PageWatermark::Layering::Underlay; + +/*++ + +Routine Name: + + CWatermark::CWatermark + +Routine Description: + + Constructor for the base watermark class + +Arguments: + + wmProps - Watermark PrintTicket properties class + +Return Value: + + None + Throws CXDException(HRESULT) on an error + +--*/ +CWatermark::CWatermark( + _In_ CONST CWMPTProperties& wmProps + ) : + m_pDOMDoc(NULL), + m_WMProps(wmProps) +{ + // + // Create the DOM document so that sub-classes have access ASAP + // + HRESULT hr = m_pDOMDoc.CoCreateInstance(CLSID_DOMDocument60); + + if (FAILED(hr)) + { + ERR("Failed to create watermark DOM document.\n"); + throw CXDException(hr); + } +} + +/*++ + +Routine Name: + + CWatermark::~CWatermark + +Routine Description: + + Default destructor for the watermarks base class + +Arguments: + + None + +Return Value: + + None + +--*/ +CWatermark::~CWatermark() +{ +} + +/*++ + +Routine Name: + + CWatermark::MatrixToXML + +Routine Description: + + Method to create XML markup representing the + supplied transformation matrix + +Arguments: + + pMatrix - Pointer to the transformation matrix to convert to XML + pbstrMatrixXForm - Pointer to the string which will containg the matrix markup + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CWatermark::MatrixToXML( + _In_ CONST Matrix* pMatrix, + _Outptr_ BSTR* pbstrMatrixXForm + ) +{ + // + // Construct the matric mark-up from a GDI+ matrix + // + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pbstrMatrixXForm, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pMatrix, E_POINTER))) + { + REAL matElems[6]; + if (Ok == pMatrix->GetElements(matElems)) + { + try + { + CStringXDW cstrMatrix; + cstrMatrix.Format(L"%.2f,%.2f,%.2f,%.2f,%.2f,%.2f", + matElems[0], + matElems[1], + matElems[2], + matElems[3], + matElems[4], + matElems[5]); + + *pbstrMatrixXForm = cstrMatrix.AllocSysString(); + } + catch (CXDException& e) + { + hr = e; + } + } + else + { + *pbstrMatrixXForm = NULL; + hr = E_FAIL; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CWatermark::GetXML + +Routine Description: + + Method to get the XML containing the watermark text + +Arguments: + + pbstrXML - Pointer to the string to hold the watermark XML text + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CWatermark::GetXML( + _Outptr_ BSTR* pbstrXML + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pbstrXML, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(m_pWMElem, E_PENDING))) + { + hr = m_pWMElem->get_xml(pbstrXML); + + if (SUCCEEDED(hr)) + { + _Analysis_assume_nullterminated_(*pbstrXML); + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CWatermark::CreateWMTransform + +Routine Description: + + Method to create a transformation matrix which will scale, translate and rotate + the watermark to correctly fit onto the page. This overload perform scaling to fit + the watermark content to the requested bounds and is used when creating the bitmap + or vector watermark. + +Arguments: + + wmBounds - Rectangular area to contain the watermark + pbstrMatrixXForm - Pointer to the string to contain the watermark transformation matrix + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CWatermark::CreateWMTransform( + _In_ RectF wmBounds, + _Outptr_ BSTR* pbstrMatrixXForm + ) +{ + ASSERTMSG(wmBounds.Width > 0, "Zero width watermark found whilst creating transform\n"); + ASSERTMSG(wmBounds.Height > 0, "Zero height watermark found whilst creating transform\n"); + + HRESULT hr = S_OK; + + if (wmBounds.Width <= 0 || wmBounds.Height <= 0) + { + hr = E_INVALIDARG; + } + + if (SUCCEEDED(hr) && + SUCCEEDED(hr = CHECK_POINTER(pbstrMatrixXForm, E_POINTER))) + { + *pbstrMatrixXForm = NULL; + + RectF targetBounds; + REAL angle = 0; + + if (SUCCEEDED(hr = m_WMProps.GetBounds(&targetBounds)) && + SUCCEEDED(hr = m_WMProps.GetAngle(&angle))) + { + ASSERTMSG(targetBounds.Width > 0, "Zero width target found whilst creating transform\n"); + ASSERTMSG(targetBounds.Height > 0, "Zero height target found whilst creating transform\n"); + + // + // Start with the identity matrix + // + Matrix xForm; + + // + // Offset to the target bounds + // + PointF offset(targetBounds.X - wmBounds.X, targetBounds.Y - wmBounds.Y); + + // + // Apply the transforms to the matrix + // + xForm.Scale(targetBounds.Width/wmBounds.Width, targetBounds.Height/wmBounds.Height, MatrixOrderAppend); + xForm.Rotate(angle, MatrixOrderAppend); + xForm.Translate(offset.X, offset.Y, MatrixOrderAppend); + + // + // Retrieve the matrix string + // + hr = MatrixToXML(&xForm, pbstrMatrixXForm); + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CWatermark::CreateWMTransform + +Routine Description: + + Method to create a transformation matrix which will translate and rotate. This overload + does not perform any scaling to fit the watermark content and is used when creating the + text watermark. + +Arguments: + + wmOrigin - Point defining the watermark origin + pbstrMatrixXForm - Pointer to the string to contain the watermark transformation matrix + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CWatermark::CreateWMTransform( + _In_ PointF wmOrigin, + _Outptr_ BSTR* pbstrMatrixXForm + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pbstrMatrixXForm, E_POINTER))) + { + *pbstrMatrixXForm = NULL; + REAL angle = 0; + + if (SUCCEEDED(hr = m_WMProps.GetAngle(&angle))) + { + // + // Start with the identity matrix + // + Matrix xForm; + + // + // Apply the transforms to the matrix + // + xForm.Rotate(angle, MatrixOrderAppend); + xForm.Translate(wmOrigin.X, wmOrigin.Y, MatrixOrderAppend); + + // + // Retrieve the matrix string + // + hr = MatrixToXML(&xForm, pbstrMatrixXForm); + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CWatermark::InsertStart + +Routine Description: + + Method to check whether the watermark should be inserted at the start of the + page to create an underlay effect + +Arguments: + + None + +Return Value: + + BOOL + TRUE - The watermark mark-up needs to be inserted at the start of the fixed page + FALSE - The watermark mark-up needs to be inserted at the end of the fixed page + +--*/ +BOOL +CWatermark::InsertStart( + VOID + ) +{ + ELayeringOption wmLayering = Overlay; + + m_WMProps.GetLayering(&wmLayering); + + return wmLayering == Underlay; +} + +/*++ + +Routine Name: + + CWatermark::InsertEnd + +Routine Description: + + Method to check whether the watermark should be inserted at the + end of the page to create an overlay effect + +Arguments: + + None + +Return Value: + + BOOL + TRUE - The watermark mark-up needs to be inserted at the end of the fixed page + FALSE - The watermark mark-up needs to be inserted at the start of the fixed page + +--*/ +BOOL +CWatermark::InsertEnd( + VOID + ) +{ + return !InsertStart(); +} + diff --git a/print/XPSDrvSmpl/src/filters/watermark/wmbase.h b/print/XPSDrvSmpl/src/filters/watermark/wmbase.h new file mode 100644 index 00000000..9638425e --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/watermark/wmbase.h @@ -0,0 +1,95 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + wmbase.h + +Abstract: + + Base watermark class implementation. The base watermark class provides + common functionality required between different watermarks (Text, RasterGraphic + and VectorGraphic. This includes methods for converting a GDI matrix object + into the appropriate XPS matrix mark-up and intialising the matrix according to + the watermark options. + +--*/ + +#pragma once + +#include "rescache.h" +#include "wmptprop.h" + +class CWatermark +{ +public: + CWatermark( + _In_ CONST CWMPTProperties& wmProps + ); + + virtual ~CWatermark(); + + virtual HRESULT + CreateXMLElement( + VOID + ) = 0; + + virtual HRESULT + AddParts( + _In_ IXpsDocumentConsumer* pXpsConsumer, + _In_ IFixedPage* pFixedPage, + _In_ CFileResourceCache* pResCache + + ) = 0; + + virtual HRESULT + GetXML( + _Outptr_ BSTR* pbstrXML + ); + + virtual BOOL + InsertStart( + VOID + ); + + virtual BOOL + InsertEnd( + VOID + ); + +protected: + HRESULT + CreateWMTransform( + _In_ RectF wmBounds, + _Outptr_ BSTR* pbstrMatrixXForm + ); + + HRESULT + CreateWMTransform( + _In_ PointF wmOrigin, + _Outptr_ BSTR* pbstrMatrixXForm + ); + +private: + HRESULT + MatrixToXML( + _In_ CONST Matrix* pMatrix, + _Outptr_ BSTR* pbstrMatrixXForm + ); + +protected: + CComPtr m_pDOMDoc; + + CComPtr m_pWMElem; + + CWMPTProperties m_WMProps; +}; + diff --git a/print/XPSDrvSmpl/src/filters/watermark/wmflt.cpp b/print/XPSDrvSmpl/src/filters/watermark/wmflt.cpp new file mode 100644 index 00000000..13e171d4 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/watermark/wmflt.cpp @@ -0,0 +1,340 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + wmflt.cpp + +Abstract: + + Watermark filter implementation. This class derives from the Xps filter + class and implements the necessary part handlers to support Watermark + printing. The Watermark filter is responsible for adding resources to + the XPS document and putting the appropriate mark-up onto pages with a + watermark. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdstring.h" +#include "xdexcept.h" +#include "wmflt.h" +#include "wmtext.h" +#include "wmrast.h" +#include "wmvect.h" +#include "wmsax.h" +#include "wmpthndlr.h" +#include "wmres.h" + +using XDPrintSchema::PageWatermark::WatermarkData; +using XDPrintSchema::PageWatermark::EWatermarkOption; +using XDPrintSchema::PageWatermark::TextWatermark; +using XDPrintSchema::PageWatermark::BitmapWatermark; +using XDPrintSchema::PageWatermark::VectorWatermark; + +/*++ + +Routine Name: + + CWatermarkFilter::CWatermarkFilter + +Routine Description: + + Default constructor for the watermark filter which ensures GDI plus is correctly running + +Arguments: + + None + +Return Value: + + None + +--*/ +CWatermarkFilter::CWatermarkFilter() +{ + ASSERTMSG(m_gdiPlus.GetGDIPlusStartStatus() == Ok, "GDI plus is not correctly initialized.\n"); +} + +/*++ + +Routine Name: + + CWatermarkFilter::~CWatermarkFilter + +Routine Description: + + Default destructor for the watermark filter + +Arguments: + + None + +Return Value: + + None + +--*/ +CWatermarkFilter::~CWatermarkFilter() +{ +} + +/*++ + +Routine Name: + + CWatermarkFilter::ProcessPart + +Routine Description: + + Method for processing each fixed page part in a container + +Arguments: + + pFP - Pointer to the fixed page to process + +Return Value: + + HRESULT + S_OK - On success + S_FALSE - When not enabled in the PT + E_* - On error + +--*/ +HRESULT +CWatermarkFilter::ProcessPart( + _Inout_ IFixedPage* pFP + ) +{ + VERBOSE("Processing Fixed Page part with watermark handler\n"); + + HRESULT hr = S_OK; + CWatermark* pWatermark = NULL; + + if (SUCCEEDED(hr = CHECK_POINTER(pFP, E_POINTER))) + { + // + // Retrieve the watermark settings from the PrintTicket + // + IXMLDOMDocument2* pPT = NULL; + if (SUCCEEDED(hr = m_ptManager.SetTicket(pFP)) && + SUCCEEDED(hr = m_ptManager.GetTicket(kPTPageScope, &pPT)) && + SUCCEEDED(hr = GetWatermark(pPT, &pWatermark)) && + SUCCEEDED(hr = CHECK_POINTER(pWatermark, E_FAIL))) + { + // + // Add the resource part + // + if (SUCCEEDED(hr = pWatermark->AddParts(m_pXDWriter, pFP, &m_resCache))) + { + // + // Retrieve the writer from the fixed page + // + CComPtr pWriter(NULL); + + if (SUCCEEDED(hr = pFP->GetWriteStream(&pWriter))) + { + // + // Set-up the SAX reader and begin parsing the mark-up + // + CComPtr pSaxRdr(NULL); + CComPtr pReader(NULL); + + try + { + CWMSaxHandler wmSaxHndlr(pWriter, pWatermark); + + if (SUCCEEDED(hr = pSaxRdr.CoCreateInstance(CLSID_SAXXMLReader60)) && + SUCCEEDED(hr = pSaxRdr->putContentHandler(&wmSaxHndlr)) && + SUCCEEDED(hr = pFP->GetStream(&pReader))) + { + CComPtr pReadStreamToSeq(NULL); + + pReadStreamToSeq.Attach(new(std::nothrow) pfp::PrintReadStreamToSeqStream(pReader)); + + if (SUCCEEDED(hr = CHECK_POINTER(pReadStreamToSeq, E_OUTOFMEMORY))) + { + hr = pSaxRdr->parse(CComVariant(static_cast(pReadStreamToSeq))); + } + } + } + catch (CXDException& e) + { + hr = e; + } + + pWriter->Close(); + } + } + else if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) + { + // + // Could not find resource file - fail gracefully so we continue + // to process the document + // + ERR("Specified resource file does not exist\n"); + hr = S_FALSE; + } + else if (hr == HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED)) + { + // + // Insufficient rights to open file - fail gracefully so we continue + // to process the document + // + ERR("Insufficient rights to open resource file\n"); + hr = S_FALSE; + } + else if (hr == HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED)) + { + // + // We do not support this URI as a resource - fail gracefully so we continue + // to process the document + // + ERR("Unsupported URI to resource resource\n"); + hr = S_FALSE; + } + } + else if (hr == E_ELEMENT_NOT_FOUND) + { + // + // No watermark was found in the PrintTicket - do not propogate this error + // + hr = S_FALSE; + } + } + + // + // Clean up the watermark if it was successfully created + // + if (pWatermark != NULL) + { + delete pWatermark; + pWatermark = NULL; + } + + if (SUCCEEDED(hr)) + { + // + // We can send the fixed page + // + hr = m_pXDWriter->SendFixedPage(pFP); + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CWatermarkFilter::GetWatermark + +Routine Description: + + Method for obtaining the watermark PrintTicket preferences + +Arguments: + + pPrintTicket - DOM document containing the PrintTicket + ppWatermark - Pointer to object which will contain the values + read from the PrintTicket + +Return Value: + + HRESULT + S_OK - On success + E_ELEMENT_NOT_FOUND - When feature not present in the PT + E_* - On error + +--*/ +HRESULT +CWatermarkFilter::GetWatermark( + _In_ IXMLDOMDocument2* pPrintTicket, + _Outptr_result_maybenull_ CWatermark** ppWatermark + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(ppWatermark, E_POINTER))) + { + *ppWatermark = NULL; + + try + { + + CWMPTHandler wmPTHandler(pPrintTicket); + WatermarkData wmData; + + if (SUCCEEDED(hr = wmPTHandler.GetData(&wmData))) + { + CWMPTProperties wmProperties(wmData); + + EWatermarkOption wmOption; + + if (SUCCEEDED(hr = wmProperties.GetType(&wmOption))) + { + switch (wmOption) + { + case TextWatermark: + { + *ppWatermark = new(std::nothrow) CTextWatermark(wmProperties); + + if (*ppWatermark == NULL) + { + hr = E_OUTOFMEMORY; + } + } + break; + + case BitmapWatermark: + { + *ppWatermark = new(std::nothrow) CRasterWatermark(wmProperties, IDR_WM_PNG1); + + if (*ppWatermark == NULL) + { + hr = E_OUTOFMEMORY; + } + } + break; + + case VectorWatermark: + { + *ppWatermark = new(std::nothrow) CVectorWatermark(wmProperties, IDR_WM_XPS1); + + if (*ppWatermark == NULL) + { + hr = E_OUTOFMEMORY; + } + } + break; + + default: + { + hr = E_ELEMENT_NOT_FOUND; + } + break; + } + } + } + } + catch (CXDException& e) + { + hr = e; + } + } + + ERR_ON_HR_EXC(hr, E_ELEMENT_NOT_FOUND); + return hr; +} + diff --git a/print/XPSDrvSmpl/src/filters/watermark/wmflt.h b/print/XPSDrvSmpl/src/filters/watermark/wmflt.h new file mode 100644 index 00000000..8fa42ca1 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/watermark/wmflt.h @@ -0,0 +1,54 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + wmflt.h + +Abstract: + + Watermark filter defnition. This class derives from the Xps filter + class and implements the necessary part handlers to support Watermark + printing. The Watermark filter is responsible for adding resources to + the XPS document and putting the appropriate mark-up onto pages with a + watermark + +--*/ + +#pragma once + +#include "xdrchflt.h" +#include "wmbase.h" +#include "gdip.h" + +class CWatermarkFilter : public CXDXpsFilter +{ +public: + CWatermarkFilter(); + + virtual ~CWatermarkFilter(); + +private: + virtual HRESULT + ProcessPart( + _Inout_ IFixedPage* pFP + ); + + HRESULT + GetWatermark( + _In_ IXMLDOMDocument2* pPrintTicket, + _Outptr_result_maybenull_ CWatermark** ppWatermark + ); + +private: + GDIPlus m_gdiPlus; +}; + diff --git a/print/XPSDrvSmpl/src/filters/watermark/wmflt.rc b/print/XPSDrvSmpl/src/filters/watermark/wmflt.rc new file mode 100644 index 00000000..06f5485c --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/watermark/wmflt.rc @@ -0,0 +1,54 @@ +// +// Copyright (c) 2005 Microsoft Corporation +// +// All rights reserved. +// +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +// PARTICULAR PURPOSE. +// +// File Name: +// +// wmflt.rc +// +// Abstract: +// +// Watermark filter resource file. +// +// + +#include +#include + +#include "wmres.h" + +#define VER_FILETYPE VFT_DLL +#define VER_FILESUBTYPE VFT2_UNKNOWN +#define VER_FILEDESCRIPTION_STR "XPSDrv Sample Watermark Filter" +#define VER_INTERNALNAME_STR "PrintFeatureFilters" + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Watermark Resources +// + +IDR_WM_PNG1 RCDATA "Raster1.png" + +IDR_WM_XPS1 RCDATA "Vector1.xps" + +#endif // English (U.S.) resources + +///////////////////////////////////////////////////////////////////////////// + +#include "common.ver" + diff --git a/print/XPSDrvSmpl/src/filters/watermark/wmfont.cpp b/print/XPSDrvSmpl/src/filters/watermark/wmfont.cpp new file mode 100644 index 00000000..5bb49548 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/watermark/wmfont.cpp @@ -0,0 +1,413 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + wmfont.cpp + +Abstract: + + Watermark font implementation. The CWatermarkFont class is responsible + for managing the font resource for a text watermark. This implements + the IResWriter interface so that the font can be added to the resource + cache. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdstring.h" +#include "wmfont.h" + +using XDPrintSchema::PageWatermark::EWatermarkOption; +using XDPrintSchema::PageWatermark::TextWatermark; + +/*++ + +Routine Name: + + CWatermarkFont::CWatermarkFont + +Routine Description: + + Constructor for the CWatermarkFont font management class which + sets the member variables to sensible defaults and ensures the + current watermark which uses this font is a text based watermark + +Arguments: + + wmProps - Object containing the PrintTicket settings + +Return Value: + + None + Throws CXDException(HRESULT) on an error + +--*/ +CWatermarkFont::CWatermarkFont( + _In_ CONST CWMPTProperties& wmProps + ) : + m_hDC(CreateDC(TEXT("DISPLAY"), NULL, NULL, NULL)), + m_WMProps(wmProps), + m_hFont(NULL), + m_hOldFont(NULL), + m_bstrFaceName(L"Arial") +{ + HRESULT hr = S_OK; + + ASSERTMSG(m_hDC != NULL, "NULL DC passed.\n"); + + EWatermarkOption wmType; + + if (SUCCEEDED(hr = m_WMProps.GetType(&wmType))) + { + if (wmType == TextWatermark) + { + hr = SetFont(); + } + else + { + hr = E_INVALIDARG; + } + } + + if (FAILED(hr)) + { + throw CXDException(hr); + } +} + +/*++ + +Routine Name: + + CWatermarkFont::~CWatermarkFont + +Routine Description: + + Default destructor for the font management class + +Arguments: + + None + +Return Value: + + None + +--*/ +CWatermarkFont::~CWatermarkFont() +{ + UnsetFont(); + + if (SUCCEEDED(CHECK_HANDLE(m_hDC, E_PENDING))) + { + DeleteDC(m_hDC); + } +} + +/*++ + +Routine Name: + + CWatermarkFont::WriteData + +Routine Description: + + Method for writing out the font to the container + +Arguments: + + pStream - Pointer to the stream to write the font out to + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CWatermarkFont::WriteData( + _In_ IPartBase* pResource, + _In_ IPrintWriteStream* pStream + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pResource, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pStream, E_POINTER))) + { + // + // Find the size of the font data + // + DWORD cbFontData = GetFontData(m_hDC, 0, 0, 0, 0); + + if (cbFontData != GDI_ERROR) + { + PBYTE pFontData = new(std::nothrow) BYTE[cbFontData]; + + if (SUCCEEDED(hr = CHECK_POINTER(pFontData, E_OUTOFMEMORY))) + { + // + // Retrieve the font data + // + if (GDI_ERROR != GetFontData(m_hDC, + 0, + 0, + reinterpret_cast(pFontData), + cbFontData)) + { + // + // SetFontOptions(Font_Obfusticate) sets the appropriate content type + // The pipeline takes care of XORing the font data with the URI GUID + // + CComQIPtr pFont = pResource; + if (SUCCEEDED(hr = CHECK_POINTER(pFont, E_NOINTERFACE)) && + SUCCEEDED(hr = pFont->SetFontOptions(Font_Obfusticate))) + { + // + // Write font data to stream + // + ULONG cbWritten = 0; + hr = pStream->WriteBytes(reinterpret_cast(pFontData), + cbFontData, + &cbWritten); + + ASSERTMSG(cbFontData == cbWritten, "Failed to write all font data.\n"); + } + } + else + { + hr = GetLastErrorAsHResult(); + } + + delete[] pFontData; + pFontData = NULL; + } + } + else + { + hr = GetLastErrorAsHResult(); + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CWatermarkFont::SetFont + +Routine Description: + + Method to select a font into the device context + +Arguments: + + None + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CWatermarkFont::SetFont( + VOID + ) +{ + ASSERTMSG(m_hFont == NULL, "Non NULL font handle when setting new font. Possible resource leak.\n"); + ASSERTMSG(m_hOldFont == NULL, "Non NULL old font handle when setting new font. Possible resource leak.\n"); + + HRESULT hr = S_OK; + + INT fontSize; + + if (SUCCEEDED(hr = m_WMProps.GetFontSize(&fontSize))) + { + LOGFONTW logfont; + + logfont.lfHeight = -MulDiv(fontSize, GetDeviceCaps(m_hDC, LOGPIXELSY), 72); + logfont.lfWidth = 0; + logfont.lfEscapement = 0; + logfont.lfOrientation = 0; + logfont.lfWeight = FW_NORMAL; + logfont.lfItalic = FALSE; + logfont.lfUnderline = FALSE; + logfont.lfStrikeOut = FALSE; + logfont.lfCharSet = ANSI_CHARSET; + logfont.lfOutPrecision = OUT_TT_ONLY_PRECIS; + logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS; + logfont.lfQuality = CLEARTYPE_QUALITY; + logfont.lfPitchAndFamily = FF_DONTCARE; + + size_t cchSrc = 0; + if (SUCCEEDED(hr = StringCchLength(m_bstrFaceName, LF_FACESIZE, &cchSrc)) && + SUCCEEDED(hr = StringCchCopyN(logfont.lfFaceName, LF_FACESIZE, m_bstrFaceName, cchSrc))) + { + if (m_hFont != NULL) + { + UnsetFont(); + } + + m_hFont = CreateFontIndirect(&logfont); + + if (m_hFont != NULL) + { + m_hOldFont = SelectFont(m_hDC, m_hFont); + } + else + { + hr = GetLastErrorAsHResult(); + } + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CWatermarkFont::UnsetFont + +Routine Description: + + Method de-select a font from the current device context + +Arguments: + + None + +Return Value: + + None + +--*/ +VOID +CWatermarkFont::UnsetFont( + VOID + ) +{ + ASSERTMSG(m_hFont != NULL, "Attempting to deselect invalid font.\n"); + ASSERTMSG(m_hOldFont != NULL, "Attempting to select invalid font.\n"); + + SelectFont(m_hDC, m_hOldFont); + if (m_hFont != NULL) + { + DeleteObject(m_hFont); + m_hFont = NULL; + } +} + +/*++ + +Routine Name: + + CWatermarkFont::GetKeyName + +Routine Description: + + Method to obtain a unique key for the stored font based on the resource name + +Arguments: + + pbstrKeyName - Pointer to the string to contain the generated key name + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CWatermarkFont::GetKeyName( + _Outptr_ BSTR* pbstrKeyName + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pbstrKeyName, E_POINTER))) + { + // + // The name of the resource is a suitable key + // + if (SUCCEEDED(hr = m_bstrFaceName.CopyTo(pbstrKeyName)) && + !*pbstrKeyName) + { + hr = E_OUTOFMEMORY; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CWatermarkFont::GetResURI + +Routine Description: + + Method to obtain the URI to the stored font + +Arguments: + + pbstrResURI - Pointer to the string to contain the font resource URI + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CWatermarkFont::GetResURI( + _Outptr_ BSTR* pbstrResURI + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pbstrResURI, E_POINTER))) + { + *pbstrResURI = NULL; + + try + { + // + // Create an obfuscated font name using our font GUID + // + CStringXDW cstrURI(L"Resources/Fonts/78F47176-ADD7-0E49-AB3A-C59F137240AC.odttf"); + *pbstrResURI = cstrURI.AllocSysString(); + } + catch (CXDException& e) + { + hr = e; + } + } + + ERR_ON_HR(hr); + return hr; +} + diff --git a/print/XPSDrvSmpl/src/filters/watermark/wmfont.h b/print/XPSDrvSmpl/src/filters/watermark/wmfont.h new file mode 100644 index 00000000..a7990011 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/watermark/wmfont.h @@ -0,0 +1,82 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + wmfont.h + +Abstract: + + Watermark font definition. The CWatermarkFont class is responsible + for managing the font resource for a text watermark. This implements + the IResWriter interface so that the font can be added to the resource + cache. + +Known Issues: + + The watermark font does not yet use the Uniscript interface to retrieve glyph + indices. + +--*/ + +#pragma once + +#include "rescache.h" +#include "wmptprop.h" + +class CWatermarkFont : public IResWriter +{ +public: + CWatermarkFont( + _In_ CONST CWMPTProperties& wmProps + ); + + ~CWatermarkFont(); + + HRESULT + WriteData( + _In_ IPartBase* pResource, + _In_ IPrintWriteStream* pStream + ); + + HRESULT + GetKeyName( + _Outptr_ BSTR* pbstrKeyName + ); + + HRESULT + GetResURI( + _Outptr_ BSTR* pbstrResURI + ); + +private: + HRESULT + SetFont( + VOID + ); + + VOID + UnsetFont( + VOID + ); + +private: + HDC m_hDC; + + HFONT m_hFont; + + HFONT m_hOldFont; + + CComBSTR m_bstrFaceName; + + CWMPTProperties m_WMProps; +}; + diff --git a/print/XPSDrvSmpl/src/filters/watermark/wmimg.cpp b/print/XPSDrvSmpl/src/filters/watermark/wmimg.cpp new file mode 100644 index 00000000..38f78f4d --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/watermark/wmimg.cpp @@ -0,0 +1,503 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + wmimg.cpp + +Abstract: + + Watermark image implementation. The CWatermarkImage class is responsible + for managing the image resource for a raster watermark. This implements + the IResWriter interface so that the font can be added to the resource + cache. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdstring.h" +#include "wmimg.h" + +using XDPrintSchema::PageWatermark::EWatermarkOption; +using XDPrintSchema::PageWatermark::BitmapWatermark; + +/*++ + +Routine Name: + + CWatermarkImage::CWatermarkImage + +Routine Description: + + Constructor for the CWatermarkFont bitmap management class which + sets the member variables to sensible defaults and ensures the + current watermark which uses this bitmap is a bitmap based watermark + +Arguments: + + wmProps - Object containing the PrintTicket settings + resourceID - Resource ID for the watermark +Return Value: + + None + Throws CXDException(HRESULT) on an error + +--*/ +CWatermarkImage::CWatermarkImage( + _In_ CONST CWMPTProperties& wmProps, + _In_ CONST INT resourceID + ) : + m_WMProps(wmProps), + m_resourceID(resourceID), + m_pPNGData(NULL), + m_pPNGStream(NULL), + m_hPNGRes(NULL), + m_cbPNGData(0) +{ + HRESULT hr = S_OK; + + EWatermarkOption wmType; + + if (SUCCEEDED(hr = m_WMProps.GetType(&wmType))) + { + if (wmType != BitmapWatermark) + { + hr = E_INVALIDARG; + } + } + + if (FAILED(hr)) + { + throw CXDException(hr); + } +} + +/*++ + +Routine Name: + + CWatermarkImage::~CWatermarkImage + +Routine Description: + + Default destructor for the font management class + +Arguments: + + None + +Return Value: + + None + +--*/ +CWatermarkImage::~CWatermarkImage() +{ + if (m_hPNGRes != NULL) + { + FreeResource(m_hPNGRes); + m_hPNGRes = NULL; + } +} + +/*++ + +Routine Name: + + CWatermarkImage::GetImageDimensions + +Routine Description: + + Method to obtain the width and height for the watermark bitmap + +Arguments: + + pDimensions - Pointer to a structure which will hold the bitmap dimensions + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CWatermarkImage::GetImageDimensions( + _Out_ SizeF* pDimensions + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pDimensions, E_POINTER)) && + SUCCEEDED(hr = CreatePNGStream())) + { + pDimensions->Width = 0; + pDimensions->Height = 0; + + Bitmap image(m_pPNGStream); + Status gdiPStat = image.GetLastStatus(); + + if (gdiPStat == Ok) + { + pDimensions->Width = (REAL)image.GetWidth(); + pDimensions->Height = (REAL)image.GetHeight(); + + REAL horzRes = image.GetHorizontalResolution(); + REAL vertRes = image.GetVerticalResolution(); + + if (horzRes > 0 && + vertRes > 0) + { + pDimensions->Width *= 96.0f / horzRes; + pDimensions->Height *= 96.0f / vertRes; + } + } + else + { + hr = GetGDIStatusErrorAsHResult(gdiPStat); + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CWatermarkImage::WriteData + +Routine Description: + + Method for writing out the bitmap to the container + +Arguments: + + pStream - Pointer to the stream to write the bitmap out to + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CWatermarkImage::WriteData( + _In_ IPartBase* pResource, + _In_ IPrintWriteStream* pStream + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pResource, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pStream, E_POINTER))) + { + if (SUCCEEDED(hr = LoadPNGResource())) + { + ULONG cbWritten = 0; + + hr = pStream->WriteBytes(m_pPNGData, m_cbPNGData, &cbWritten); + + ASSERTMSG(m_cbPNGData == cbWritten, "Failed to write all data.\n"); + + // + // Set the content type of the image part + // + CComQIPtr pImage = pResource; + if (SUCCEEDED(hr) && + SUCCEEDED(hr = CHECK_POINTER(pImage, E_NOINTERFACE))) + { + hr = pImage->SetImageContent(CComBSTR(L"image/png")); + } + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CWatermarkImage::GetKeyName + +Routine Description: + + Method to obtain a unique key for the stored bitmap based on the resource name + +Arguments: + + pbstrKeyName - Pointer to the string to contain the generated key name + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CWatermarkImage::GetKeyName( + _Outptr_ BSTR* pbstrKeyName + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pbstrKeyName, E_POINTER))) + { + try + { + // + // The id of the resource is a suitable key + // + + CStringXDW cstrKeyName; + cstrKeyName.Format(L"%d", m_resourceID); + + *pbstrKeyName = cstrKeyName.AllocSysString(); + } + catch (CXDException& e) + { + hr = e; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CWatermarkImage::GetResURI + +Routine Description: + + Method to obtain the URI to the stored bitmap + +Arguments: + + pbstrResURI - Pointer to the string to contain the bitmap resource URI + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CWatermarkImage::GetResURI( + _Outptr_ BSTR* pbstrResURI + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pbstrResURI, E_POINTER))) + { + *pbstrResURI = NULL; + + try + { + // + // Create a unique name for the watermark bitmap for this print session + // + CStringXDW cstrURI; + cstrURI.Format(L"/WM_%d_%u.png", m_resourceID, GetUniqueNumber()); + + *pbstrResURI = cstrURI.AllocSysString(); + } + catch (CXDException& e) + { + hr = e; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CWatermarkImage::CheckResID + +Routine Description: + + Method to check that the bitmap resource exists + +Arguments: + + None + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CWatermarkImage::CheckResID( + VOID + ) +{ + HRESULT hr = S_OK; + + HRSRC hrSrc = FindResourceEx(g_hInstance, + RT_RCDATA, + MAKEINTRESOURCE(m_resourceID), + MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US)); + + if (hrSrc == NULL) + { + hr = GetLastErrorAsHResult(); + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CWatermarkImage::CreatePNGStream + +Routine Description: + + Method to write out the PNG bitmap to the container + +Arguments: + + None + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CWatermarkImage::CreatePNGStream( + VOID + ) +{ + HRESULT hr = S_OK; + + // + // If a stream hasn't already been created, load the PNG image resource + // and create a new stream + // + if (m_pPNGStream == NULL && + SUCCEEDED(hr = LoadPNGResource()) && + SUCCEEDED(hr = CreateStreamOnHGlobal(NULL, TRUE, &m_pPNGStream))) + { + ULONG cbWritten = 0; + + // + // Write the data to the stream + // + hr = m_pPNGStream->Write(m_pPNGData, m_cbPNGData, &cbWritten); + } + + // + // Make sure the stream is pointing back at the start of the data + // + if (SUCCEEDED(hr)) + { + LARGE_INTEGER cbMoveFromStart = {0}; + + hr = m_pPNGStream->Seek(cbMoveFromStart, STREAM_SEEK_SET, NULL); + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CWatermarkImage::LoadPNGResource + +Routine Description: + + Method to load the PNG bitmap resource + +Arguments: + + None + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CWatermarkImage::LoadPNGResource( + VOID + ) +{ + HRESULT hr = S_OK; + + if (m_pPNGData == NULL) + { + HRSRC hrSrc = FindResourceEx(g_hInstance, + RT_RCDATA, + MAKEINTRESOURCE(m_resourceID), + MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US)); + if (hrSrc != NULL) + { + // + // Load the resource + // + m_hPNGRes = LoadResource(g_hInstance, hrSrc); + + if (m_hPNGRes != NULL) + { + // + // Retrieve the PNG data and the size of the data + // + m_pPNGData = LockResource(m_hPNGRes); + m_cbPNGData = SizeofResource(g_hInstance, hrSrc); + + if (m_pPNGData == NULL || + m_cbPNGData <= 0) + { + hr = E_FAIL; + } + } + else + { + hr = GetLastErrorAsHResult(); + } + } + else + { + hr = GetLastErrorAsHResult(); + } + } + + ERR_ON_HR(hr); + return hr; +} + diff --git a/print/XPSDrvSmpl/src/filters/watermark/wmimg.h b/print/XPSDrvSmpl/src/filters/watermark/wmimg.h new file mode 100644 index 00000000..f7ab0e8c --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/watermark/wmimg.h @@ -0,0 +1,90 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + wmimg.h + +Abstract: + + Watermark image definition. The CWatermarkImage class is responsible + for managing the image resource for a raster watermark. This implements + the IResWriter interface so that the font can be added to the resource + cache. + +--*/ + +#pragma once + +#include "rescache.h" +#include "wmptprop.h" + +class CWatermarkImage : public IResWriter +{ +public: + CWatermarkImage( + _In_ CONST CWMPTProperties& wmProps, + _In_ CONST INT resourceID + ); + + ~CWatermarkImage(); + + HRESULT + GetImageDimensions( + _Out_ SizeF* pDimensions + ); + + HRESULT + WriteData( + _In_ IPartBase* pResource, + _In_ IPrintWriteStream* pStream + ); + + HRESULT + GetKeyName( + _Outptr_ BSTR* pbstrKeyName + ); + + HRESULT + GetResURI( + _Outptr_ BSTR* pbstrResURI + ); + + HRESULT + CheckResID( + VOID + ); + +private: + HRESULT + CreatePNGStream( + VOID + ); + + HRESULT + LoadPNGResource( + VOID + ); + +private: + CWMPTProperties m_WMProps; + + INT m_resourceID; + + CComPtr m_pPNGStream; + + PVOID m_pPNGData; + + DWORD m_cbPNGData; + + HGLOBAL m_hPNGRes; +}; + diff --git a/print/XPSDrvSmpl/src/filters/watermark/wmptprop.cpp b/print/XPSDrvSmpl/src/filters/watermark/wmptprop.cpp new file mode 100644 index 00000000..c8b102a1 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/watermark/wmptprop.cpp @@ -0,0 +1,683 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + wmptprop.cpp + +Abstract: + + Watermark properties class implementation. The Watermark properties class + is responsible for holding and controling Watermark properties. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdstring.h" +#include "wmptprop.h" + +using XDPrintSchema::PageWatermark::WatermarkData; +using XDPrintSchema::PageWatermark::EWatermarkOption; +using XDPrintSchema::PageWatermark::NoWatermark; +using XDPrintSchema::PageWatermark::TextWatermark; +using XDPrintSchema::PageWatermark::BitmapWatermark; +using XDPrintSchema::PageWatermark::VectorWatermark; +using XDPrintSchema::PageWatermark::Layering::ELayeringOption; + +/*++ + +Routine Name: + + CWMPTProperties::CWMPTProperties + +Routine Description: + + Constructor for the CWMPTProperties PrintTicket properties class + +Arguments: + + wmData - Structure containing watermark properties read from the PrintTicket + +Return Value: + + None + +--*/ +CWMPTProperties::CWMPTProperties( + _In_ CONST WatermarkData& wmData + ) : + m_wmData(wmData) +{ +} + +/*++ + +Routine Name: + + CWMPTProperties::~CWMPTProperties + +Routine Description: + + Default destructor for the CWMPTProperties class + +Arguments: + + None + +Return Value: + + None + +--*/ +CWMPTProperties::~CWMPTProperties() +{ +} + +/*++ + +Routine Name: + + CWMPTProperties::GetType + +Routine Description: + + Method to obtain the watermark type to identify as vector, text or bitmap + +Arguments: + + pType - Enumerated type to indicate the watermark type + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CWMPTProperties::GetType( + _Out_ EWatermarkOption* pType + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pType, E_POINTER))) + { + *pType = m_wmData.type; + + // + // If we are a bitmap or vector watermark and the extents are zero, report no watermark + // + if (m_wmData.type == BitmapWatermark || + m_wmData.type == VectorWatermark) + { + if (m_wmData.widthExtent == 0 || + m_wmData.heightExtent == 0) + { + *pType = NoWatermark; + } + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CWMPTProperties::GetLayering + +Routine Description: + + Method to obtain the watermark layering type + +Arguments: + + pLayering - Enumerated type to indicate the watermark layering type + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CWMPTProperties::GetLayering( + _Out_ ELayeringOption* pLayering + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pLayering, E_POINTER))) + { + *pLayering = m_wmData.layering; + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CWMPTProperties::GetBounds + +Routine Description: + + Method to obtain the watermark bounding area + +Arguments: + + pBounds - Variable which is set to the watermark bounding area + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CWMPTProperties::GetBounds( + _Out_ RectF* pBounds + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pBounds, E_POINTER))) + { + // + // Convert from microns to 96ths of an inch + // + pBounds->X = static_cast(m_wmData.widthOrigin)/k96thInchAsMicrons; + pBounds->Y = static_cast(m_wmData.heightOrigin)/k96thInchAsMicrons; + pBounds->Width = static_cast(m_wmData.widthExtent)/k96thInchAsMicrons; + pBounds->Height = static_cast(m_wmData.heightExtent)/k96thInchAsMicrons; + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CWMPTProperties::GetOrigin + +Routine Description: + + Method to obtain the watermark origin + +Arguments: + + pOrigin - Variable which is set to the watermark origin + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CWMPTProperties::GetOrigin( + _Out_ PointF* pOrigin + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pOrigin, E_POINTER))) + { + // + // Convert from microns to 96ths of an inch + // + pOrigin->X = static_cast(m_wmData.widthOrigin)/k96thInchAsMicrons; + pOrigin->Y = static_cast(m_wmData.heightOrigin)/k96thInchAsMicrons; + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CWMPTProperties::GetAngle + +Routine Description: + + Method to obtain the watermark angle + +Arguments: + + pAngle - Variable which is set to the watermark angle + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CWMPTProperties::GetAngle( + _Out_ REAL* pAngle + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pAngle, E_POINTER))) + { + *pAngle = static_cast(m_wmData.angle); + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CWMPTProperties::GetTransparency + +Routine Description: + + Method to obtain the watermark transparency value + +Arguments: + + pTransparency - Variable which is set to the watermark transparency value + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CWMPTProperties::GetTransparency( + _Out_ INT* pTransparency + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pTransparency, E_POINTER))) + { + *pTransparency = m_wmData.transparency; + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CWMPTProperties::GetOpacity + +Routine Description: + + Method to obtain the watermark opacity value + +Arguments: + + pOpacity - Variable which is set to the watermark opacity value + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CWMPTProperties::GetOpacity( + _Out_ REAL* pOpacity + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pOpacity, E_POINTER))) + { + *pOpacity = 1.0f - (m_wmData.transparency / 100.0f); + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CWMPTProperties::GetTransparency + +Routine Description: + + Method to obtain the watermark transparency value as a string + +Arguments: + + pbstrTransparency - String which is set to contain the watermark transparency value + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CWMPTProperties::GetTransparency( + _Outptr_ BSTR* pbstrTransparency + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pbstrTransparency, E_POINTER))) + { + *pbstrTransparency = NULL; + INT transparency = 0; + if (SUCCEEDED(hr = GetTransparency(&transparency))) + { + try + { + CStringXDW szTransparency; + szTransparency.Format(L"%i", transparency); + + *pbstrTransparency = szTransparency.AllocSysString(); + } + catch (CXDException& e) + { + hr = e; + } + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CWMPTProperties::GetOpacity + +Routine Description: + + Method to obtain the watermark opacity value as a string + +Arguments: + + pbstrOpacity - String which is set to contain the watermark opacity value + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CWMPTProperties::GetOpacity( + _Outptr_ BSTR* pbstrOpacity + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pbstrOpacity, E_POINTER))) + { + *pbstrOpacity = NULL; + REAL opacity = 0; + if (SUCCEEDED(hr = GetOpacity(&opacity))) + { + try + { + CStringXDW szOpacity; + szOpacity.Format(L"%.2f", opacity); + + *pbstrOpacity = szOpacity.AllocSysString(); + } + catch (CXDException& e) + { + hr = e; + } + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CWMPTProperties::GetFontColor + +Routine Description: + + Method to obtain the watermark font color as a string + +Arguments: + + pbstrColor - String which is set to contain the watermark font color. Any BSTR + this points to will be freed. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CWMPTProperties::GetFontColor( + _Inout_ _At_(*pbstrColor, _Pre_maybenull_ _Post_valid_) BSTR* pbstrColor + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pbstrColor, E_POINTER))) + { + SysFreeString(*pbstrColor); + *pbstrColor = NULL; + if (m_wmData.type == TextWatermark) + { + if (SUCCEEDED(hr = m_wmData.txtData.bstrFontColor.CopyTo(pbstrColor)) && + !*pbstrColor) + { + hr = E_OUTOFMEMORY; + } + } + else + { + hr = HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CWMPTProperties::GetText + +Routine Description: + + Method to obtain the watermark text as a string + +Arguments: + + pbstrText - String which is set to contain the watermark text + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CWMPTProperties::GetText( + _Inout_ _At_(*pbstrText, _Pre_maybenull_ _Post_valid_) BSTR* pbstrText + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pbstrText, E_POINTER))) + { + SysFreeString(*pbstrText); + *pbstrText = NULL; + if (m_wmData.type == TextWatermark) + { + if (SUCCEEDED(hr = m_wmData.txtData.bstrText.CopyTo(pbstrText)) && + !*pbstrText) + { + hr = E_OUTOFMEMORY; + } + } + else + { + hr = HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CWMPTProperties::GetFontSize + +Routine Description: + + Method to obtain the watermark font size + +Arguments: + + pSize - Variable which is set to contain the watermark font size + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CWMPTProperties::GetFontSize( + _Out_ INT* pSize + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pSize, E_POINTER))) + { + if (m_wmData.type == TextWatermark) + { + *pSize = m_wmData.txtData.fontSize; + } + else + { + hr = HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CWMPTProperties::GetFontEmSize + +Routine Description: + + Method to obtain the watermark font EM size as a string + +Arguments: + + pbstrSize - String which is set to contain the watermark EM font size + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CWMPTProperties::GetFontEmSize( + _Outptr_ BSTR* pbstrSize + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pbstrSize, E_POINTER))) + { + *pbstrSize = NULL; + + if (m_wmData.type != TextWatermark) + { + hr = HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); + } + } + + if (SUCCEEDED(hr)) + { + INT size = 0; + + if (SUCCEEDED(hr = GetFontSize(&size))) + { + // + // Convert from 72nds to 96ths of an inch + // + size = MulDiv(size, 96, 72); + + try + { + CStringXDW szFontSize; + szFontSize.Format(L"%d", size); + + *pbstrSize = szFontSize.AllocSysString(); + } + catch (CXDException& e) + { + hr = e; + } + } + } + + ERR_ON_HR(hr); + return hr; +} + diff --git a/print/XPSDrvSmpl/src/filters/watermark/wmptprop.h b/print/XPSDrvSmpl/src/filters/watermark/wmptprop.h new file mode 100644 index 00000000..eec7fed4 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/watermark/wmptprop.h @@ -0,0 +1,103 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + wmptprop.h + +Abstract: + + Watermark properties class definition. The Watermark properties class + is responsible for holding and controling Watermark properties. + +--*/ + +#pragma once + +#include "wmdata.h" + +class CWMPTProperties +{ +public: + CWMPTProperties( + _In_ CONST XDPrintSchema::PageWatermark::WatermarkData& wmData + ); + + virtual ~CWMPTProperties(); + + HRESULT + GetType( + _Out_ XDPrintSchema::PageWatermark::EWatermarkOption* pType + ); + + HRESULT + GetLayering( + _Out_ XDPrintSchema::PageWatermark::Layering::ELayeringOption* pLayering + ); + + HRESULT + GetBounds( + _Out_ RectF* pBounds + ); + + HRESULT GetOrigin( + _Out_ PointF* pOrigin + ); + + HRESULT + GetAngle( + _Out_ REAL* pAngle + ); + + HRESULT + GetTransparency( + _Out_ INT* pTransparency + ); + + HRESULT + GetOpacity( + _Out_ REAL* pOpacity + ); + + HRESULT + GetTransparency( + _Outptr_ BSTR* pbstrTransparency + ); + + HRESULT + GetOpacity( + _Outptr_ BSTR* pbstrOpacity + ); + + HRESULT + GetFontColor( + _Inout_ _At_(*pbstrColor, _Pre_maybenull_ _Post_valid_) BSTR* pbstrColor + ); + + HRESULT + GetText( + _Inout_ _At_(*pbstrText, _Pre_maybenull_ _Post_valid_) BSTR* pbstrText + ); + + HRESULT + GetFontSize( + _Out_ INT* pSize + ); + + HRESULT + GetFontEmSize( + _Outptr_ BSTR* pbstrSize + ); + +protected: + XDPrintSchema::PageWatermark::WatermarkData m_wmData; +}; + diff --git a/print/XPSDrvSmpl/src/filters/watermark/wmrast.cpp b/print/XPSDrvSmpl/src/filters/watermark/wmrast.cpp new file mode 100644 index 00000000..d83a0783 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/watermark/wmrast.cpp @@ -0,0 +1,271 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + wmrast.cpp + +Abstract: + + RasterGraphic watermark class implamentation. CRasterWatermark is the + raster implementation of the CWatermark class. This implements methods + for creating the page mark-up and adding the watermark resource to the + resource cache. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdstring.h" +#include "wmrast.h" +#include "wmptprop.h" + +using XDPrintSchema::PageWatermark::EWatermarkOption; +using XDPrintSchema::PageWatermark::BitmapWatermark; + +/*++ + +Routine Name: + + CRasterWatermark::CRasterWatermark + +Routine Description: + + Constructor for the raster watermark class + +Arguments: + + wmProps - Watermark PrintTicket properties class + resourceID - Resource ID for the watermark + +Return Value: + + None + Throws CXDException(HRESULT) on an error + +--*/ +CRasterWatermark::CRasterWatermark( + _In_ CONST CWMPTProperties& wmProps, + _In_ CONST INT resourceID + ) : + CWatermark(wmProps), + m_wmBMP(wmProps, resourceID) +{ + HRESULT hr = S_OK; + + EWatermarkOption wmType; + + if (SUCCEEDED(hr = m_WMProps.GetType(&wmType))) + { + if (wmType != BitmapWatermark) + { + hr = E_INVALIDARG; + } + } + + if (FAILED(hr)) + { + throw CXDException(hr); + } +} + +/*++ + +Routine Name: + + CRasterWatermark::~CRasterWatermark + +Routine Description: + + Default destructor for the watermarks base class + +Arguments: + + None + +Return Value: + + None + +--*/ +CRasterWatermark::~CRasterWatermark() +{ +} + +/*++ + +Routine Name: + + CRasterWatermark::CreateXMLElement + +Routine Description: + + Method to create the XML markup which describes the transform and properties used + to present the watermark correctly on the page + +Arguments: + + None + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CRasterWatermark::CreateXMLElement( + VOID + ) +{ + ASSERTMSG(m_pDOMDoc != NULL, "NULL DOM document detected whilst creating text watermark\n"); + ASSERTMSG(m_bstrImageURI.Length() > 0, "Invalid image URI detected whilst creating text watermark\n"); + + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(m_pDOMDoc, E_PENDING))) + { + if (m_bstrImageURI.Length() == 0) + { + hr = E_PENDING; + } + } + + // + // We need to retrieve the bitmap bounds to calculate + // the correct render transform for the watermark + // + SizeF bmpDims; + CComBSTR bstrWMOpacity; + if (SUCCEEDED(hr) && + SUCCEEDED(hr = m_wmBMP.GetImageDimensions(&bmpDims)) && + SUCCEEDED(hr = m_WMProps.GetOpacity(&bstrWMOpacity))) + { + // + // The markup will look like this (square bracketed values "[]" + // describes content): + // + // + // + // + // + // + // + CComPtr pPathFill(NULL); + CComPtr pImageBrush(NULL); + CComPtr pInsertNode(NULL); + + CStringXDW strPathData; + CStringXDW strViewbox; + CStringXDW strViewport; + + CComBSTR bstrMatrixXForm; + + // + // Create the transform and elements and add attributes + // + try + { + strPathData.Format(L"M 0,0 L 0,%.2f %.2f,%.2f %.2f,0 z", bmpDims.Height, bmpDims.Width, bmpDims.Height, bmpDims.Width); + strViewbox.Format(L"0,0,%.2f,%.2f", bmpDims.Width, bmpDims.Height); + strViewport.Format(L"0,0,%.2f,%.2f", bmpDims.Width, bmpDims.Height); + + if (SUCCEEDED(hr = CreateWMTransform(RectF(0, 0, bmpDims.Width, bmpDims.Height), &bstrMatrixXForm)) && + SUCCEEDED(hr = m_pDOMDoc->createElement(CComBSTR(L"Path"), &m_pWMElem)) && + SUCCEEDED(hr = m_pDOMDoc->createElement(CComBSTR(L"Path.Fill"), &pPathFill)) && + SUCCEEDED(hr = m_pDOMDoc->createElement(CComBSTR(L"ImageBrush"), &pImageBrush)) && + SUCCEEDED(hr = m_pWMElem->setAttribute(CComBSTR(L"RenderTransform"), CComVariant(bstrMatrixXForm))) && + SUCCEEDED(hr = m_pWMElem->setAttribute(CComBSTR(L"Data"), CComVariant(strPathData.GetBuffer()))) && + SUCCEEDED(hr = pImageBrush->setAttribute(CComBSTR(L"ImageSource"), CComVariant(m_bstrImageURI))) && + SUCCEEDED(hr = pImageBrush->setAttribute(CComBSTR(L"Opacity"), CComVariant(bstrWMOpacity))) && + SUCCEEDED(hr = pImageBrush->setAttribute(CComBSTR(L"ViewboxUnits"), CComVariant(L"Absolute"))) && + SUCCEEDED(hr = pImageBrush->setAttribute(CComBSTR(L"Viewbox"), CComVariant(strViewbox.GetBuffer()))) && + SUCCEEDED(hr = pImageBrush->setAttribute(CComBSTR(L"ViewportUnits"), CComVariant(L"Absolute"))) && + SUCCEEDED(hr = pImageBrush->setAttribute(CComBSTR(L"Viewport"), CComVariant(strViewport.GetBuffer()))) && + SUCCEEDED(hr = pPathFill->appendChild(pImageBrush, &pInsertNode)) && + SUCCEEDED(hr = m_pWMElem->appendChild(pPathFill, &pInsertNode))) + { + hr = m_pWMElem->appendChild(pPathFill, &pInsertNode); + } + } + catch (CXDException& e) + { + hr = e; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CRasterWatermark::AddParts + +Routine Description: + + Method to add the watermark bitmap resource to the cache + +Arguments: + + pXpsConsumer - Pointer to the writer used when writing the resource back out to the pipeline + pFixedPage - Pointer to the fixed page associated with the bitmap + pResCache - Pointer to a resource cache object which manages the writing of the bitmap + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CRasterWatermark::AddParts( + _In_ IXpsDocumentConsumer* pXpsConsumer, + _In_ IFixedPage* pFixedPage, + _In_ CFileResourceCache* pResCache + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pXpsConsumer, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pFixedPage, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pResCache, E_POINTER))) + { + // + // Write the font resource to the cache + // + m_bstrImageURI.Empty(); + CComBSTR bstrKey; + if (SUCCEEDED(hr = m_wmBMP.CheckResID()) && + SUCCEEDED(hr = pResCache->WriteResource(pXpsConsumer, pFixedPage, &m_wmBMP)) && + SUCCEEDED(hr = m_wmBMP.GetKeyName(&bstrKey))) + { + hr = pResCache->GetURI(bstrKey, &m_bstrImageURI); + } + } + + ERR_ON_HR(hr); + return hr; +} + diff --git a/print/XPSDrvSmpl/src/filters/watermark/wmrast.h b/print/XPSDrvSmpl/src/filters/watermark/wmrast.h new file mode 100644 index 00000000..22e17b85 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/watermark/wmrast.h @@ -0,0 +1,58 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + wmrast.h + +Abstract: + + RasterGraphic watermark class definition. CRasterWatermark is the + raster implementation of the CWatermark class. This implements methods + for creating the page mark-up and adding the watermark resource to the + resource cache. + +--*/ + +#pragma once + +#include "wmbase.h" +#include "wmimg.h" +#include "wmptprop.h" + +class CRasterWatermark : public CWatermark +{ +public: + CRasterWatermark( + _In_ CONST CWMPTProperties& wmProps, + _In_ CONST INT resourceID + ); + + virtual ~CRasterWatermark(); + + virtual HRESULT + CreateXMLElement( + VOID + ); + + virtual HRESULT + AddParts( + _In_ IXpsDocumentConsumer* pXpsConsumer, + _In_ IFixedPage* pFixedPage, + _In_ CFileResourceCache* pResCache + ); + +private: + CComBSTR m_bstrImageURI; + + CWatermarkImage m_wmBMP; +}; + diff --git a/print/XPSDrvSmpl/src/filters/watermark/wmres.h b/print/XPSDrvSmpl/src/filters/watermark/wmres.h new file mode 100644 index 00000000..0df8f4d4 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/watermark/wmres.h @@ -0,0 +1,27 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + wmres.h + +Abstract: + + Warmark specific resource defines. + +--*/ + +#pragma once + +#define IDR_WM_PNG1 101 + +#define IDR_WM_XPS1 201 + diff --git a/print/XPSDrvSmpl/src/filters/watermark/wmsax.cpp b/print/XPSDrvSmpl/src/filters/watermark/wmsax.cpp new file mode 100644 index 00000000..be165d53 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/watermark/wmsax.cpp @@ -0,0 +1,427 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + wmsax.cpp + +Abstract: + + Watermark sax handler implementation. The watermark SAX handler is + responsible for parsing the FixedPage mark-up for the page size and + adding the inserting the watermark mark-up in appropriate place. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdstring.h" +#include "wmsax.h" + +/*++ + +Routine Name: + + CWMSaxHandler::CWMSaxHandler + +Routine Description: + + Contructor for the watermark filters SAX handler. + The constructor registers a writer for streaming out any markup and a watermark + handler object for generating any new watermark markup and handling related resources + +Arguments: + + pWriter - Pointer to a write stream which receives markup + pWatermark - Pointer to a watermark handler object + +Return Value: + + None + Throws CXDException(HRESULT) on an error + +--*/ +CWMSaxHandler::CWMSaxHandler( + _In_ IPrintWriteStream* pWriter, + _In_ CWatermark* pWatermark + ) : + m_pWriter(pWriter), + m_watermark(pWatermark), + m_bOpenTag(FALSE) +{ + ASSERTMSG(m_pWriter != NULL, "NULL writer passed to watermark SAX handler.\n"); + ASSERTMSG(m_watermark != NULL, "NULL watermark passed to watermark SAX handler.\n"); + + HRESULT hr = S_OK; + if (FAILED(hr = CHECK_POINTER(m_pWriter, E_POINTER)) || + FAILED(hr = CHECK_POINTER(m_watermark, E_POINTER))) + { + throw CXDException(hr); + } +} + +/*++ + +Routine Name: + + CWMSaxHandler::~CWMSaxHandler + +Routine Description: + + Default destructor for the watermark filter SAX handler + +Arguments: + + None + +Return Value: + + None + +--*/ +CWMSaxHandler::~CWMSaxHandler() +{ +} + +/*++ + +Routine Name: + + CWMSaxHandler::startElement + +Routine Description: + + SAX handler method which handles each start element for the XML markup + +Arguments: + + pwchQName - Pointer to a string containing the element name + cchQName - Count of the number of characters in the element name + pAttributes - Pointer to the attribute list for the supplied element + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT STDMETHODCALLTYPE +CWMSaxHandler::startElement( + CONST wchar_t*, + INT, + CONST wchar_t*, + INT, + _In_reads_(cchQName) CONST wchar_t* pwchQName, + _In_ INT cchQName, + _In_ ISAXAttributes* pAttributes + ) +{ + HRESULT hr = S_OK; + CStringXDW cstrOut; + + try + { + // + // Check if we need to close an opened tag + // + if (m_bOpenTag) + { + cstrOut.Append(L">"); + } + + // + // Store the opened element name so we can handle nested elements + // + m_bstrOpenElement = CComBSTR(cchQName, pwchQName); + + // + // Write out element + // + cstrOut.Append(L"<"); + cstrOut.Append(m_bstrOpenElement); + } + catch (CXDException& e) + { + hr = e; + } + + // + // We opened a tag + // + m_bOpenTag = TRUE; + + // + // If this is the fixed page we need the width and height retreived + // + BOOL bIsFixedPage = (m_bstrOpenElement == L"FixedPage"); + + // + // Find the number of attributes and enumerate over all of them + // + INT cAttributes = 0; + if (SUCCEEDED(hr) && + SUCCEEDED(hr = pAttributes->getLength(&cAttributes))) + { + for (INT cIndex = 0; cIndex < cAttributes; cIndex++) + { + PCWSTR pszAttUri = NULL; + INT cchAttUri = 0; + PCWSTR pszAttName = NULL; + INT cchAttName = 0; + PCWSTR pszAttQName = NULL; + INT cchAttQName = 0; + PCWSTR pszAttValue = NULL; + INT cchAttValue = 0; + + // + // Get the attribute data ready to write out + // + if (SUCCEEDED(hr = pAttributes->getName(cIndex, + &pszAttUri, + &cchAttUri, + &pszAttName, + &cchAttName, + &pszAttQName, + &cchAttQName))) + { + if (SUCCEEDED(pAttributes->getValue(cIndex, &pszAttValue, &cchAttValue))) + { + try + { + CComBSTR bstrAttName(cchAttQName, pszAttQName); + CComBSTR bstrAttValue(cchAttValue, pszAttValue); + + // + // Delimit attributes with a space + // + cstrOut.Append(L" "); + + // + // Reconstruct the attribute and write back to + // the fixed page + // + cstrOut.Append(bstrAttName); + cstrOut.Append(L"=\""); + + // + // If this is a UnicodeString we may need to escape entities + // + if (bstrAttName == L"UnicodeString") + { + hr = EscapeEntity(&bstrAttValue); + } + + cstrOut.Append(bstrAttValue); + cstrOut.Append(L"\""); + } + catch (CXDException& e) + { + hr = e; + } + } + } + } + } + + // + // We output the mark-up here for underlaid watermarks + // + if (SUCCEEDED(hr) && + bIsFixedPage) + { + // + // If this is the fixed page element make sure we close it in case the + // page has no content. + // + try + { + cstrOut.Append(L">"); + m_bOpenTag = FALSE; + } + catch (CXDException& e) + { + hr = e; + } + + if (SUCCEEDED(hr) && + SUCCEEDED(hr = CHECK_POINTER(m_watermark, E_PENDING))) + { + + // + // Create the watermark markup + // + if (SUCCEEDED(hr) && + SUCCEEDED(hr = m_watermark->CreateXMLElement())) + { + // + // Check if the mark-up needs to inserted at the start of the + // fixed page (underlay) + // + if (m_watermark->InsertStart()) + { + CComBSTR bstrWMText; + if (SUCCEEDED(hr = m_watermark->GetXML(&bstrWMText))) + { + // + // Insert the watermark mark-up + // + cstrOut.Append(bstrWMText); + } + } + } + } + } + + if (SUCCEEDED(hr)) + { + hr = WriteToPrintStream(&cstrOut, m_pWriter); + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CWMSaxHandler::endElement + +Routine Description: + + SAX handler method which handles each end element for the XML markup + +Arguments: + + pwchQName - Pointer to a string containing the element name + cchQName - Count of the number of characters in the element name + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT STDMETHODCALLTYPE +CWMSaxHandler::endElement( + CONST wchar_t*, + INT, + CONST wchar_t*, + INT, + _In_reads_(cchQName) CONST wchar_t* pwchQName, + _In_ INT cchQName + ) +{ + HRESULT hr = S_OK; + CStringXDW cstrClose; + + try + { + CComBSTR bstrElement(cchQName, pwchQName); + + if (bstrElement == L"FixedPage") + { + if (SUCCEEDED(hr = CHECK_POINTER(m_watermark, E_PENDING)) && + m_watermark->InsertEnd()) + { + CComBSTR bstrWMText; + if (SUCCEEDED(hr = m_watermark->GetXML(&bstrWMText))) + { + cstrClose.Append(bstrWMText); + } + } + } + + // + // If this element matches the current open element, use shorthand to close + // the tag + // + if (bstrElement == m_bstrOpenElement && + m_bOpenTag) + { + cstrClose.Append(L"/>"); + } + else + { + // + // Close the element + // + cstrClose.Append(L""); + } + } + catch (CXDException& e) + { + hr = e; + } + + if (SUCCEEDED(hr)) + { + hr = WriteToPrintStream(&cstrClose, m_pWriter); + } + + m_bOpenTag = FALSE; + + ERR_ON_HR(hr); + return hr; +} + + +/*++ + +Routine Name: + + CWMSaxHandler::startDocument + +Routine Description: + + SAX handler method which handles the start document call to ensure + the xml version is correctly set + +Arguments: + + None + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT STDMETHODCALLTYPE +CWMSaxHandler::startDocument( + void + ) +{ + HRESULT hr = S_OK; + + try + { + if (SUCCEEDED(hr = CHECK_POINTER(m_pWriter, E_FAIL))) + { + CStringXDW cstrOut(L""); + hr = WriteToPrintStream(&cstrOut, m_pWriter); + } + } + catch (CXDException& e) + { + hr = e; + } + + ERR_ON_HR(hr); + return hr; +} + diff --git a/print/XPSDrvSmpl/src/filters/watermark/wmsax.h b/print/XPSDrvSmpl/src/filters/watermark/wmsax.h new file mode 100644 index 00000000..cd76ca9e --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/watermark/wmsax.h @@ -0,0 +1,74 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + wmsax.h + +Abstract: + + Watermark sax handler definition. The watermark SAX handler is responsible for + parsing the FixedPage mark-up for the page size and inserting the watermark mark-up + in appropriate place. + +--*/ + +#pragma once + +#include "saxhndlr.h" +#include "wmtext.h" + +class CWMSaxHandler : public CSaxHandler +{ +public: + CWMSaxHandler( + _In_ IPrintWriteStream* pWriter, + _In_ CWatermark* pWatermark + ); + + virtual ~CWMSaxHandler(); + + virtual HRESULT STDMETHODCALLTYPE + startElement( + CONST wchar_t*, + INT, + CONST wchar_t*, + INT, + _In_reads_(cchQName) CONST wchar_t* pwchQName, + _In_ INT cchQName, + _In_ ISAXAttributes* pAttributes + ); + + virtual HRESULT STDMETHODCALLTYPE + endElement( + CONST wchar_t*, + INT, + CONST wchar_t*, + INT, + _In_reads_(cchQName) CONST wchar_t* pwchQName, + _In_ INT cchQName + ); + + HRESULT STDMETHODCALLTYPE + startDocument( + void + ); + +private: + CComPtr m_pWriter; + + CComBSTR m_bstrOpenElement; + + BOOL m_bOpenTag; + + CWatermark* m_watermark; +}; + diff --git a/print/XPSDrvSmpl/src/filters/watermark/wmtext.cpp b/print/XPSDrvSmpl/src/filters/watermark/wmtext.cpp new file mode 100644 index 00000000..a249648d --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/watermark/wmtext.cpp @@ -0,0 +1,250 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + wmtext.cpp + +Abstract: + + Text watermark class implamentation. CTextWatermark is the + text implementation of the CWatermark class. This implements methods + for creating the page mark-up and adding the watermark resource to the + resource cache. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdexcept.h" +#include "wmtext.h" +#include "wmptprop.h" +#include "rescache.h" + +using XDPrintSchema::PageWatermark::EWatermarkOption; +using XDPrintSchema::PageWatermark::TextWatermark; + +/*++ + +Routine Name: + + CTextWatermark::CTextWatermark + +Routine Description: + + Constructor for the text watermark class + +Arguments: + + wmProps - Watermark PrintTicket properties class + +Return Value: + + None + Throws CXDException(HRESULT) on an error + +--*/ +CTextWatermark::CTextWatermark( + _In_ CONST CWMPTProperties& wmProps + ) : + CWatermark(wmProps), + m_wmFont(wmProps) +{ + HRESULT hr = S_OK; + + EWatermarkOption wmType; + + if (SUCCEEDED(hr = m_WMProps.GetType(&wmType))) + { + if (wmType != TextWatermark) + { + hr = E_INVALIDARG; + } + } + + if (FAILED(hr)) + { + throw CXDException(hr); + } +} + +/*++ + +Routine Name: + + CTextWatermark::~CTextWatermark + +Routine Description: + + Default destructor for the watermarks base class + +Arguments: + + None + +Return Value: + + None + +--*/ +CTextWatermark::~CTextWatermark() +{ +} + +/*++ + +Routine Name: + + CTextWatermark::CreateXMLElement + +Routine Description: + + Method to create the XML markup which describes the transform and properties used + to present the watermark correctly on the page + +Arguments: + + None + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CTextWatermark::CreateXMLElement( + VOID + ) +{ + ASSERTMSG(m_pDOMDoc != NULL, "NULL DOM document detected whilst creating text watermark\n"); + ASSERTMSG(m_bstrFontURI.Length() > 0, "Invalid font URI detected whilst creating text watermark\n"); + + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(m_pDOMDoc, E_PENDING))) + { + if (m_bstrFontURI.Length() == 0) + { + hr = E_PENDING; + } + } + + PointF stringOrigin; + + CComBSTR bstrWMText; + CComBSTR bstrWMOpacity; + CComBSTR bstrWMFontSize; + CComBSTR bstrWMFontColor; + + if (SUCCEEDED(hr) && + SUCCEEDED(hr = m_WMProps.GetText(&bstrWMText)) && + SUCCEEDED(hr = m_WMProps.GetFontColor(&bstrWMFontColor)) && + SUCCEEDED(hr = m_WMProps.GetFontEmSize(&bstrWMFontSize)) && + SUCCEEDED(hr = m_WMProps.GetOpacity(&bstrWMOpacity)) && + SUCCEEDED(hr = m_WMProps.GetOrigin(&stringOrigin))) + { + // + // The markup will look like this (square bracketed values "[]" + // describes content): + // + // + // + CComBSTR bstrMatrixXForm; + + CComBSTR bstrFontName(L"/"); + hr = bstrFontName.Append(m_bstrFontURI); + + // + // Create the transform and element and add attributes + // + if (SUCCEEDED(hr) && + SUCCEEDED(hr = CreateWMTransform(stringOrigin, &bstrMatrixXForm)) && + SUCCEEDED(hr = m_pDOMDoc->createElement(CComBSTR(L"Glyphs"), &m_pWMElem)) && + SUCCEEDED(hr = m_pWMElem->setAttribute(CComBSTR(L"Fill"), CComVariant(bstrWMFontColor))) && + SUCCEEDED(hr = m_pWMElem->setAttribute(CComBSTR(L"Opacity"), CComVariant(bstrWMOpacity))) && + SUCCEEDED(hr = m_pWMElem->setAttribute(CComBSTR(L"RenderTransform"), CComVariant(bstrMatrixXForm))) && + SUCCEEDED(hr = m_pWMElem->setAttribute(CComBSTR(L"FontUri"), CComVariant(bstrFontName))) && + SUCCEEDED(hr = m_pWMElem->setAttribute(CComBSTR(L"FontRenderingEmSize"), CComVariant(bstrWMFontSize))) && + SUCCEEDED(hr = m_pWMElem->setAttribute(CComBSTR(L"OriginX"), CComVariant(L"0"))) && + SUCCEEDED(hr = m_pWMElem->setAttribute(CComBSTR(L"OriginY"), CComVariant(L"0")))) + { + hr = m_pWMElem->setAttribute(CComBSTR(L"UnicodeString"), CComVariant(bstrWMText)); + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CTextWatermark::AddParts + +Routine Description: + + Method to add the watermark font resource to the cache + +Arguments: + + pXpsConsumer - Pointer to the writer used when writing the resource back out to the pipeline + pFixedPage - Pointer to the fixed page associated with the font + pResCache - Pointer to a resource cache object which manages the writing of the font + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CTextWatermark::AddParts( + _In_ IXpsDocumentConsumer* pXpsConsumer, + _In_ IFixedPage* pFixedPage, + _In_ CFileResourceCache* pResCache + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pXpsConsumer, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pFixedPage, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pResCache, E_POINTER))) + { + // + // Write the font resource to the cache + // + m_bstrFontURI.Empty(); + CComBSTR bstrKey; + if (SUCCEEDED(hr = pResCache->WriteResource(pXpsConsumer, pFixedPage, &m_wmFont)) && + SUCCEEDED(hr = m_wmFont.GetKeyName(&bstrKey))) + { + hr = pResCache->GetURI(bstrKey, &m_bstrFontURI); + } + } + + ERR_ON_HR(hr); + return hr; +} + diff --git a/print/XPSDrvSmpl/src/filters/watermark/wmtext.h b/print/XPSDrvSmpl/src/filters/watermark/wmtext.h new file mode 100644 index 00000000..ff439fdc --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/watermark/wmtext.h @@ -0,0 +1,57 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + wmtext.h + +Abstract: + + Text watermark class definition. CTextWatermark is the + text implementation of the CWatermark class. This implements methods + for creating the page mark-up and adding the watermark resource to the + resource cache. + +--*/ + +#pragma once + +#include "wmbase.h" +#include "wmfont.h" +#include "rescache.h" + +class CTextWatermark : public CWatermark +{ +public: + CTextWatermark( + _In_ CONST CWMPTProperties& wmProps + ); + + virtual ~CTextWatermark(); + + virtual HRESULT + CreateXMLElement( + VOID + ); + + virtual HRESULT + AddParts( + _In_ IXpsDocumentConsumer* pXpsConsumer, + _In_ IFixedPage* pFixedPage, + _In_ CFileResourceCache* pResCache + ); + +private: + CComBSTR m_bstrFontURI; + + CWatermarkFont m_wmFont; +}; + diff --git a/print/XPSDrvSmpl/src/filters/watermark/wmvect.cpp b/print/XPSDrvSmpl/src/filters/watermark/wmvect.cpp new file mode 100644 index 00000000..578995bf --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/watermark/wmvect.cpp @@ -0,0 +1,278 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + wmvect.cpp + +Abstract: + + VectorGraphic watermark class implamentation. CVectorWatermark is the + vecotr implementation of the CWatermark class. This implements methods + for creating the page mark-up and adding the watermark resource to the + markup. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdstring.h" +#include "wmvect.h" +#include "wmptprop.h" + +using XDPrintSchema::PageWatermark::EWatermarkOption; +using XDPrintSchema::PageWatermark::VectorWatermark; + +/*++ + +Routine Name: + + CVectorWatermark::CVectorWatermark + +Routine Description: + + Constructor for the vector watermark class + +Arguments: + + wmProps - Watermark PrintTicket properties class + resourceID - Resource ID for the watermark + +Return Value: + + None + Throws CXDException(HRESULT) on an error + +--*/ +CVectorWatermark::CVectorWatermark( + _In_ CONST CWMPTProperties& wmProps, + _In_ CONST INT resourceID + ) : + CWatermark(wmProps), + m_wmMarkup(wmProps, resourceID) +{ + HRESULT hr = S_OK; + + EWatermarkOption wmType; + + if (SUCCEEDED(hr = m_WMProps.GetType(&wmType))) + { + if (wmType != VectorWatermark) + { + hr = E_INVALIDARG; + } + } + + if (FAILED(hr)) + { + throw CXDException(hr); + } +} + +/*++ + +Routine Name: + + CVectorWatermark::~CVectorWatermark + +Routine Description: + + Default destructor for the watermarks base class + +Arguments: + + None + +Return Value: + + None + +--*/ +CVectorWatermark::~CVectorWatermark() +{ +} + +/*++ + +Routine Name: + + CVectorWatermark::CreateXMLElement + +Routine Description: + + Method to create the XML markup which describes the transform and properties used + to present the watermark correctly on the page + +Arguments: + + None + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CVectorWatermark::CreateXMLElement( + VOID + ) +{ + ASSERTMSG(m_pDOMDoc != NULL, "NULL DOM document detected whilst creating text watermark\n"); + + HRESULT hr = S_OK; + + // + // We need to retrieve the RAW Markup bounds to calculate + // the correct render transform for the watermark + // + SizeF markupDims; + CComBSTR bstrWMOpacity; + if (SUCCEEDED(hr = CHECK_POINTER(m_pDOMDoc, E_PENDING)) && + SUCCEEDED(hr = m_wmMarkup.GetImageDimensions(&markupDims)) && + SUCCEEDED(hr = m_WMProps.GetOpacity(&bstrWMOpacity))) + { + // + // The markup will look like this (square bracketed values "[]" + // describes content): + // + // + // + CComBSTR bstrMatrixXForm; + + if (SUCCEEDED(hr = CreateWMTransform(RectF(0, 0, markupDims.Width, markupDims.Height), &bstrMatrixXForm))) + { + try + { + CStringXDW strOpenCanvas; + strOpenCanvas.Format(L"", bstrWMOpacity, bstrMatrixXForm); + + IStream* pStream; + CComBSTR bstrContent; + + if (SUCCEEDED(hr = m_wmMarkup.GetStream(&pStream)) && + SUCCEEDED(hr = bstrContent.ReadFromStream(pStream))) + { + m_bstrMarkup.Empty(); + + if (SUCCEEDED(hr = m_bstrMarkup.Append(strOpenCanvas)) && + SUCCEEDED(hr = m_bstrMarkup.Append(bstrContent))) + { + hr = m_bstrMarkup.Append(L"\n"); + } + } + } + catch (CXDException& e) + { + hr = e; + } + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CVectorWatermark::GetXML + +Routine Description: + + Method for copying the XML markup which describes the watermark text + +Arguments: + + pbstrXML - Pointer to the string to contain the XML vector markup. Any BSTR + this points to will be freed. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CVectorWatermark::GetXML( + _Inout_ _At_(*pbstrXML, _Pre_maybenull_ _Post_valid_) BSTR* pbstrXML + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pbstrXML, E_POINTER))) + { + SysFreeString(*pbstrXML); + + if (m_bstrMarkup.Length() > 0) + { + if (SUCCEEDED(hr = m_bstrMarkup.CopyTo(pbstrXML)) && + !*pbstrXML) + { + hr = E_OUTOFMEMORY; + } + } + else + { + hr = E_PENDING; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CVectorWatermark::AddParts + +Routine Description: + + Method to add any required resource to the cache. + This isn't required for vector based watermarks. + +Arguments: + + pXpsConsumer - Pointer to the writer used when writing the resource back out to the pipeline + pFixedPage - Pointer to the fixed page associated with the resource + pResCache - Pointer to a resource cache object which manages the writing of the resource + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CVectorWatermark::AddParts( + _In_ IXpsDocumentConsumer*, + _In_ IFixedPage*, + _In_ CFileResourceCache* + ) +{ + // + // No Implementation required. + // + + return S_OK; +} + diff --git a/print/XPSDrvSmpl/src/filters/watermark/wmvect.h b/print/XPSDrvSmpl/src/filters/watermark/wmvect.h new file mode 100644 index 00000000..54b9e01c --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/watermark/wmvect.h @@ -0,0 +1,62 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + wmvect.h + +Abstract: + + VectorGraphic watermark class definition. CVectorWatermark is the + Vector implementation of the CWatermark class. This implements methods + for creating the page mark-up and adding the watermark resource to fixed page. + +--*/ + +#pragma once + +#include "wmbase.h" +#include "wmxps.h" +#include "wmptprop.h" + +class CVectorWatermark : public CWatermark +{ +public: + CVectorWatermark( + _In_ CONST CWMPTProperties& wmProps, + _In_ CONST INT resourceID + ); + + virtual ~CVectorWatermark(); + + virtual HRESULT + CreateXMLElement( + VOID + ); + + virtual HRESULT + GetXML( + _Inout_ _At_(*pbstrXML, _Pre_maybenull_ _Post_valid_) BSTR* pbstrXML + ); + + virtual HRESULT + AddParts( + _In_ IXpsDocumentConsumer* pXpsConsumer, + _In_ IFixedPage* pFixedPage, + _In_ CFileResourceCache* pResCache + ); + +private: + CWatermarkMarkup m_wmMarkup; + + CComBSTR m_bstrMarkup; +}; + diff --git a/print/XPSDrvSmpl/src/filters/watermark/wmxps.cpp b/print/XPSDrvSmpl/src/filters/watermark/wmxps.cpp new file mode 100644 index 00000000..82d819e8 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/watermark/wmxps.cpp @@ -0,0 +1,291 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + wmxps.cpp + +Abstract: + + Watermark XPS markup class implementation. The CWatermarkMarkup class is responsible + for creating a stream that contains markup loaded from a resource. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdexcept.h" +#include "wmxps.h" + +using XDPrintSchema::PageWatermark::EWatermarkOption; +using XDPrintSchema::PageWatermark::VectorWatermark; + +/*++ + +Routine Name: + + CWatermarkMarkup::CWatermarkMarkup + +Routine Description: + + Constructor for the CWatermarkMarkup vector management class + which sets the member variables to sensible defaults and + ensures the current watermark is a vector based watermark + +Arguments: + + wmProps - Object containing the PrintTicket settings + resourceID - Resource ID for the watermark + +Return Value: + + None + Throws CXDException(HRESULT) on an error + +--*/ +CWatermarkMarkup::CWatermarkMarkup( + _In_ CONST CWMPTProperties& wmProps, + _In_ CONST INT resourceID + ) : + m_WMProps(wmProps), + m_resourceID(resourceID) +{ + HRESULT hr = S_OK; + + EWatermarkOption wmType; + + if (SUCCEEDED(hr = m_WMProps.GetType(&wmType))) + { + if (wmType != VectorWatermark) + { + hr = E_INVALIDARG; + } + } + + if (FAILED(hr)) + { + throw CXDException(hr); + } +} + +/*++ + +Routine Name: + + CWatermarkMarkup::~CWatermarkMarkup + +Routine Description: + + Default destructor for the font management class + +Arguments: + + None + +Return Value: + + None + +--*/ +CWatermarkMarkup::~CWatermarkMarkup() +{ +} + +/*++ + +Routine Name: + + CWatermarkMarkup::GetImageDimensions + +Routine Description: + + Method to obtain the width and height for the watermark vector image + +Arguments: + + pDimensions - Pointer to a structure which will hold the vector image dimensions + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CWatermarkMarkup::GetImageDimensions( + _Out_ SizeF* pDimensions + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pDimensions, E_POINTER))) + { + // + // Currently fixed to A4 dimensions + // + pDimensions->Width = 793.76f; + pDimensions->Height = 1122.56f; + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CWatermarkMarkup::CreateXPSStream + +Routine Description: + + Method for writing out the vector image to the container + +Arguments: + + None + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CWatermarkMarkup::CreateXPSStream( + VOID + ) +{ + HRESULT hr = S_OK; + + if (m_pXPSStream == NULL) + { + HRSRC hrSrc = FindResourceEx(g_hInstance, + RT_RCDATA, + MAKEINTRESOURCE(m_resourceID), + MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US)); + if (hrSrc != NULL) + { + // + // Load the resource + // + HGLOBAL hXPSRes = LoadResource(g_hInstance, hrSrc); + + if (hXPSRes != NULL) + { + if (SUCCEEDED(hr = CreateStreamOnHGlobal(NULL, TRUE, &m_pXPSStream))) + { + // + // Retrieve the XPS data and the size of the data + // + PVOID pXPSData = LockResource(hXPSRes); + DWORD cbXPSData = SizeofResource(g_hInstance, hrSrc); + + if (SUCCEEDED(hr = CHECK_POINTER(pXPSData, E_FAIL)) && + cbXPSData > 0) + { + ULONG cbTotalWritten = 0; + + // + // Write the size of the data to the stream. + // This is required as the stream will be read back using the CComBSTR ReadFromStream() method + // + DWORD cbXPSDataWithTerm = cbXPSData + sizeof(OLECHAR); + + if (SUCCEEDED(hr = m_pXPSStream->Write(&cbXPSDataWithTerm, sizeof(cbXPSDataWithTerm), &cbTotalWritten))) + { + // + // Write the data to the stream + // Note the XPS data content must be in Unicode format to be compatible with + // the CComBSTR ReadFromStream() method. + // + ULONG cbWritten = 0; + + if (SUCCEEDED(hr = m_pXPSStream->Write(pXPSData, cbXPSData, &cbWritten))) + { + cbTotalWritten += cbWritten; + + hr = m_pXPSStream->Write(OLESTR("\0"), sizeof(OLECHAR), &cbWritten); + cbTotalWritten += cbWritten; + } + } + } + } + + FreeResource(hXPSRes); + } + else + { + hr = GetLastErrorAsHResult(); + } + } + else + { + hr = GetLastErrorAsHResult(); + } + } + + // + // Make sure the stream is pointing back at the start of the data + // + if (SUCCEEDED(hr)) + { + LARGE_INTEGER cbMoveFromStart = {0}; + + hr = m_pXPSStream->Seek(cbMoveFromStart, + STREAM_SEEK_SET, + NULL); + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CWatermarkMarkup::GetStream + +Routine Description: + + Method for obtaining a stream to write the vector image out to + +Arguments: + + ppStream - Pointer to a pointer to the stream + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CWatermarkMarkup::GetStream( + _Out_ IStream** ppStream + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(ppStream, E_POINTER)) && + SUCCEEDED(hr = CreateXPSStream())) + { + *ppStream = m_pXPSStream; + } + + ERR_ON_HR(hr); + return hr; +} diff --git a/print/XPSDrvSmpl/src/filters/watermark/wmxps.h b/print/XPSDrvSmpl/src/filters/watermark/wmxps.h new file mode 100644 index 00000000..125edaac --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/watermark/wmxps.h @@ -0,0 +1,60 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + wmxps.h + +Abstract: + + Watermark XPS markup class definition. The CWatermarkMarkup class is responsible + for creating a stream that contains markup loaded from a resource. + +--*/ + +#pragma once + +#include "wmptprop.h" + +class CWatermarkMarkup +{ +public: + CWatermarkMarkup( + _In_ CONST CWMPTProperties& wmProps, + _In_ CONST INT resourceID + ); + + ~CWatermarkMarkup(); + + HRESULT + GetImageDimensions( + _Out_ SizeF* pDimensions + ); + + HRESULT + GetStream( + _Out_ IStream** ppStream + ); + +private: + HRESULT + CreateXPSStream( + VOID + ); + +private: + CWMPTProperties m_WMProps; + + INT m_resourceID; + + CComPtr m_pXPSStream; +}; + diff --git a/print/XPSDrvSmpl/src/filters/watermark/xdwmark.def b/print/XPSDrvSmpl/src/filters/watermark/xdwmark.def new file mode 100644 index 00000000..dee0a0d7 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/watermark/xdwmark.def @@ -0,0 +1,26 @@ +; +; Copyright (c) 2005 Microsoft Corporation +; +; All rights reserved. +; +; THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +; ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +; THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +; PARTICULAR PURPOSE. +; +; File Name: +; +; xdwmark.def +; +; Abstract: +; +; Watermark filter module definition file +; + +LIBRARY XDWMark + +EXPORTS + DllMain + DllCanUnloadNow PRIVATE + DllGetClassObject PRIVATE + diff --git a/print/XPSDrvSmpl/src/filters/watermark/xdwmark.vcxproj b/print/XPSDrvSmpl/src/filters/watermark/xdwmark.vcxproj new file mode 100644 index 00000000..de8aa0e3 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/watermark/xdwmark.vcxproj @@ -0,0 +1,347 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {89DE916B-9E07-4E1F-BFF9-3FC16328B0DD} + $(MSBuildProjectName) + false + true + Debug + Win32 + {FC896AD8-0326-42FA-84FF-74DFFBBB8BCD} + + + + Windows10 + False + Desktop + + WindowsApplicationForDrivers10.0 + DynamicLibrary + + + Windows10 + True + Desktop + + WindowsApplicationForDrivers10.0 + DynamicLibrary + + + Windows10 + False + Desktop + + WindowsApplicationForDrivers10.0 + DynamicLibrary + + + Windows10 + True + Desktop + + WindowsApplicationForDrivers10.0 + DynamicLibrary + + + + $(IntDir) + + + + + + + + + + + + + + + + xdwmark + + + xdwmark + + + xdwmark + + + xdwmark + + + + _DllMainCRTStartup@12 + _DllMainCRTStartup + + + + + _DllMainCRTStartup@12 + _DllMainCRTStartup + + + + + _DllMainCRTStartup@12 + _DllMainCRTStartup + + + + + _DllMainCRTStartup@12 + _DllMainCRTStartup + + + + + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + MultiThreaded + MultiThreadedDebug + true + Level4 + Sync + + + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + %(AdditionalDependencies);uuid.lib;WIAGUID.lib;msxml6.lib;Kernel32.lib;ole32.lib;oleaut32.lib;prntvpt.lib;winspool.lib;gdi32.lib;gdiplus.lib;shlwapi.lib;Advapi32.lib;user32.lib;.\..\..\debug\$(IntDir)\xdsdbg.lib;.\..\..\common\$(IntDir)\xdsmplcmn.lib;.\..\..\filters\common\$(IntDir)\xdfltcmn.lib + + + + + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + MultiThreaded + MultiThreadedDebug + true + Level4 + Sync + + + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + %(AdditionalDependencies);uuid.lib;WIAGUID.lib;msxml6.lib;Kernel32.lib;ole32.lib;oleaut32.lib;prntvpt.lib;winspool.lib;gdi32.lib;gdiplus.lib;shlwapi.lib;Advapi32.lib;user32.lib;.\..\..\debug\$(IntDir)\xdsdbg.lib;.\..\..\common\$(IntDir)\xdsmplcmn.lib;.\..\..\filters\common\$(IntDir)\xdfltcmn.lib + + + + + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + MultiThreaded + MultiThreadedDebug + true + Level4 + Sync + + + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + %(AdditionalDependencies);uuid.lib;WIAGUID.lib;msxml6.lib;Kernel32.lib;ole32.lib;oleaut32.lib;prntvpt.lib;winspool.lib;gdi32.lib;gdiplus.lib;shlwapi.lib;Advapi32.lib;user32.lib;.\..\..\debug\$(IntDir)\xdsdbg.lib;.\..\..\common\$(IntDir)\xdsmplcmn.lib;.\..\..\filters\common\$(IntDir)\xdfltcmn.lib + + + + + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + MultiThreaded + MultiThreadedDebug + true + Level4 + Sync + + + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + %(AdditionalDependencies);uuid.lib;WIAGUID.lib;msxml6.lib;Kernel32.lib;ole32.lib;oleaut32.lib;prntvpt.lib;winspool.lib;gdi32.lib;gdiplus.lib;shlwapi.lib;Advapi32.lib;user32.lib;.\..\..\debug\$(IntDir)\xdsdbg.lib;.\..\..\common\$(IntDir)\xdsmplcmn.lib;.\..\..\filters\common\$(IntDir)\xdfltcmn.lib + + + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + + + ..;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ..;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ..;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ..;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ..;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ..;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ..;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ..;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ..;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ..;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ..;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + + + + xdwmark.def + + + + + xdwmark.def + + + + + xdwmark.def + + + + + xdwmark.def + + + + + ..;%(AdditionalIncludeDirectories) + precomp.h + Create + $(IntDir)\precomp.h.pch + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/print/XPSDrvSmpl/src/filters/watermark/xdwmark.vcxproj.Filters b/print/XPSDrvSmpl/src/filters/watermark/xdwmark.vcxproj.Filters new file mode 100644 index 00000000..4abb1cc8 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/watermark/xdwmark.vcxproj.Filters @@ -0,0 +1,63 @@ + + + + + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* + {0CD3E75F-8D40-4264-B579-7CA300A9F466} + + + h;hpp;hxx;hm;inl;inc;xsd + {E1482037-819F-42C2-8DC7-4E9CE5611C32} + + + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml + {3F288E23-A157-4F1F-9D76-99A7C00BCE32} + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Resource Files + + + \ No newline at end of file diff --git a/print/XPSDrvSmpl/src/filters/xdcont/precompsrc.cpp b/print/XPSDrvSmpl/src/filters/xdcont/precompsrc.cpp new file mode 100644 index 00000000..5944cf51 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/xdcont/precompsrc.cpp @@ -0,0 +1 @@ +#include "precomp.h" \ No newline at end of file diff --git a/print/XPSDrvSmpl/src/filters/xdcont/xdcont.vcxproj b/print/XPSDrvSmpl/src/filters/xdcont/xdcont.vcxproj new file mode 100644 index 00000000..549334d6 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/xdcont/xdcont.vcxproj @@ -0,0 +1,282 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {BCB6A109-EB2A-4D55-908E-22EE132F75AD} + $(MSBuildProjectName) + false + true + Debug + Win32 + {AF55903D-6801-4AD7-AB79-C3BFA6DAA878} + + + + Windows10 + False + Desktop + + WindowsApplicationForDrivers10.0 + StaticLibrary + + + Windows10 + True + Desktop + + WindowsApplicationForDrivers10.0 + StaticLibrary + + + Windows10 + False + Desktop + + WindowsApplicationForDrivers10.0 + StaticLibrary + + + Windows10 + True + Desktop + + WindowsApplicationForDrivers10.0 + StaticLibrary + + + + $(IntDir) + + + + + + + + + + + + + + + + xdcont + + + xdcont + + + xdcont + + + xdcont + + + + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + MultiThreaded + MultiThreadedDebug + true + Level4 + Sync + + + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + %(AdditionalDependencies);uuid.lib;WIAGUID.lib;msxml6.lib;Kernel32.lib;ole32.lib;oleaut32.lib;prntvpt.lib;winspool.lib;gdi32.lib;gdiplus.lib;shlwapi.lib;Advapi32.lib;user32.lib;.\..\..\debug\$(IntDir)\xdsdbg.lib;.\..\..\common\$(IntDir)\xdsmplcmn.lib;.\..\..\filters\common\$(IntDir)\xdfltcmn.lib + + + + + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + MultiThreaded + MultiThreadedDebug + true + Level4 + Sync + + + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + %(AdditionalDependencies);uuid.lib;WIAGUID.lib;msxml6.lib;Kernel32.lib;ole32.lib;oleaut32.lib;prntvpt.lib;winspool.lib;gdi32.lib;gdiplus.lib;shlwapi.lib;Advapi32.lib;user32.lib;.\..\..\debug\$(IntDir)\xdsdbg.lib;.\..\..\common\$(IntDir)\xdsmplcmn.lib;.\..\..\filters\common\$(IntDir)\xdfltcmn.lib + + + + + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + MultiThreaded + MultiThreadedDebug + true + Level4 + Sync + + + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + %(AdditionalDependencies);uuid.lib;WIAGUID.lib;msxml6.lib;Kernel32.lib;ole32.lib;oleaut32.lib;prntvpt.lib;winspool.lib;gdi32.lib;gdiplus.lib;shlwapi.lib;Advapi32.lib;user32.lib;.\..\..\debug\$(IntDir)\xdsdbg.lib;.\..\..\common\$(IntDir)\xdsmplcmn.lib;.\..\..\filters\common\$(IntDir)\xdfltcmn.lib + + + + + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + MultiThreaded + MultiThreadedDebug + true + Level4 + Sync + + + %(AdditionalIncludeDirectories);..\;..\common;..\..\inc;..\..\common;..\..\debug;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + %(AdditionalDependencies);uuid.lib;WIAGUID.lib;msxml6.lib;Kernel32.lib;ole32.lib;oleaut32.lib;prntvpt.lib;winspool.lib;gdi32.lib;gdiplus.lib;shlwapi.lib;Advapi32.lib;user32.lib;.\..\..\debug\$(IntDir)\xdsdbg.lib;.\..\..\common\$(IntDir)\xdsmplcmn.lib;.\..\..\filters\common\$(IntDir)\xdfltcmn.lib + + + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + + + ..;%(AdditionalIncludeDirectories) + precomp.h + Create + $(IntDir)\precomp.h.pch + + + ..;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ..;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ..;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ..;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ..;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ..;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ..;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ..;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/print/XPSDrvSmpl/src/filters/xdcont/xdcont.vcxproj.Filters b/print/XPSDrvSmpl/src/filters/xdcont/xdcont.vcxproj.Filters new file mode 100644 index 00000000..f57f6b02 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/xdcont/xdcont.vcxproj.Filters @@ -0,0 +1,46 @@ + + + + + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* + {1DF780BE-6E8F-4617-AE75-8C606750D00D} + + + h;hpp;hxx;hm;inl;inc;xsd + {F116F7A3-4916-4038-841E-4A11113EDD9E} + + + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml + {12FD05BA-ED9A-4299-BA75-FA51A639EAD8} + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/print/XPSDrvSmpl/src/filters/xdcont/xps.h b/print/XPSDrvSmpl/src/filters/xdcont/xps.h new file mode 100644 index 00000000..0b2ae4b8 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/xdcont/xps.h @@ -0,0 +1,83 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + xps.h + +Abstract: + + Enumerations and definitions used by the stream filter. + +--*/ + +#pragma once + +#include "xdstring.h" +#include "ipkfile.h" + +enum ERelsType +{ + RelsAnnotations = 0, ERelsTypeMin = 0, + RelsDigitalSignatureDefinitions, + RelsDiscardControl, + RelsDocumentStructure, + RelsPrintTicket, + RelsRequiredResource, + RelsRestrictedFont, + RelsStartPart, + RelsStoryFragments, + RelsCoreProperties, + RelsDigitalSignature, + RelsDigitalSignatureCertificate, + RelsDigitalSignatureOrigin, + RelsThumbnail, + RelsUnknown, ERelsTypeMax = RelsUnknown +}; + +typedef std::pair RelsNameType; +typedef std::vector RelsTypeList; +typedef std::map RelsMap; + +enum EContentType +{ + ContentFixedDocumentSequence = 0, EContentTypeMin = 0, + ContentFixedDocument, + ContentFixedPage, + ContentDiscardControl, + ContentDocumentStructure, + ContentFont, + ContentICCProfile, + ContentObfuscatedFont, + ContentPrintTicket, + ContentRemoteResourceDictionary, + ContentStoryFragments, + ContentJPEGImage, + ContentPNGImage, + ContentTIFFImage, + ContentWindowsMediaPhotoImage, + ContentCoreProperties, + ContentDigitalSignatureCertificate, + ContentDigitalSignatureOrigin, + ContentDigitalSignatureXMLSignature, + ContentRelationships, + ContentUnknown, EContentTypeMax = ContentUnknown +}; + +typedef std::map ContentMap; + +typedef std::vector FileList; + +typedef std::map SentList; + +typedef std::pair RecordTracker; +typedef std::vector XPSPartStack; + diff --git a/print/XPSDrvSmpl/src/filters/xdcont/xpsarch.cpp b/print/XPSDrvSmpl/src/filters/xdcont/xpsarch.cpp new file mode 100644 index 00000000..68800b31 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/xdcont/xpsarch.cpp @@ -0,0 +1,639 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + xpsarch.cpp + +Abstract: + + Implementation of the XPS archive class. This class is responsible for providing + an interface to clients that removes the potentially interleaved nature of an + XPS document. This allows clients to manipulate files using the parts full name + instead of having to worry about the semantics of interleaved parts. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdstring.h" +#include "xdexcept.h" +#include "xpsarch.h" + +typedef HRESULT (*GetClassObject)(REFCLSID, REFIID, LPVOID FAR*); + +static PCSTR szPartNameFormatString = "%s/[%i].piece"; +static PCSTR szLastPartNameFormatString = "%s/[%i].last.piece"; + +// +// GUIDs for the archive handler +// +CONST GUID CLSID_PKArchiveHandler = {0x5a0f4115, 0xd4d3, 0x401e, {0x80, 0x71, 0xa4, 0x40, 0xd6, 0xd0, 0x70, 0x92}}; +CONST GUID IID_IPKArchive = {0xbdbbdf56, 0xc742, 0x4efd, {0x80, 0x75, 0xaf, 0x2c, 0x7b, 0x24, 0x7f, 0x38}}; + +/*++ + +Routine Name: + + CXPSArchive::CXPSArchive + +Routine Description: + + CXPSArchive class constructor + +Arguments: + + pReadStream - Pointer to the print read stream + pWriteStream - Pointer to the print write stream + +Return Value: + + None + Throws CXDException(HRESULT) on an error + +--*/ +CXPSArchive::CXPSArchive( + _In_ IPrintReadStream* pReadStream, + _In_ IPrintWriteStream* pWriteStream + ) : + m_pWriteStream(pWriteStream), + m_pPkArchive(NULL), + m_hPkArch(NULL) +{ + HRESULT hr = S_OK; + + // + // Get the current directory to load the pk archive library + // + DWORD cchName = 0; + TCHAR* szFileName = new(std::nothrow) TCHAR[MAX_PATH]; + + if (SUCCEEDED(hr = CHECK_POINTER(szFileName, E_OUTOFMEMORY))) + { + cchName = GetModuleFileName(g_hInstance, szFileName, MAX_PATH); + + if (cchName == 0) + { + hr = GetLastErrorAsHResult(); + } + } + + if (SUCCEEDED(hr) && + cchName > 0) + { + // + // Remove the filespec + // + PathRemoveFileSpec(szFileName); + + try + { + // + // Append the PK archive DLL name + // + CStringXD cstrPath(szFileName); + cstrPath += TEXT("\\pkarch.dll"); + + // + // Try to load the PK archive DLL + // + m_hPkArch = LoadLibrary(cstrPath); + } + catch (CXDException& e) + { + hr = e; + } + } + + if (szFileName != NULL) + { + delete[] szFileName; + szFileName = NULL; + } + + if (SUCCEEDED(hr)) + { + // + // Get DllGetClassObject from the PK archive and instantiate the PK archive handler + // + if (m_hPkArch != NULL) + { + GetClassObject pfnGetClassObject = reinterpret_cast(GetProcAddress(m_hPkArch, "DllGetClassObject")); + + if (SUCCEEDED(hr = CHECK_POINTER(pfnGetClassObject, E_NOINTERFACE)) && + SUCCEEDED(hr = pfnGetClassObject(CLSID_PKArchiveHandler, IID_IPKArchive, reinterpret_cast(&m_pPkArchive)))) + { + hr = CHECK_POINTER(m_pPkArchive, E_NOINTERFACE); + } + } + else + { + hr = E_NOINTERFACE; + } + } + + // + // Initialise the IO streams + // + if (SUCCEEDED(hr) && + SUCCEEDED(hr = CHECK_POINTER(pReadStream, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(m_pWriteStream, E_POINTER)) && + SUCCEEDED(hr = m_pPkArchive->SetReadStream(pReadStream)) && + SUCCEEDED(hr = m_pPkArchive->SetWriteStream(m_pWriteStream))) + { + // + // We can now process the read stream to create the file index + // + hr = m_pPkArchive->ProcessReadStream(); + } + + if (FAILED(hr)) + { + throw CXDException(hr); + } +} + +/*++ + +Routine Name: + + CXPSArchive::~CXPSArchive + +Routine Description: + + CXPSArchive class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CXPSArchive::~CXPSArchive() +{ + if (m_pPkArchive != NULL) + { + m_pPkArchive->Close(); + m_pPkArchive = NULL; + } + + if (m_pWriteStream != NULL) + { + m_pWriteStream->Close(); + } + + if (m_hPkArch != NULL) + { + FreeLibrary(m_hPkArch); + } +} + +/*++ + +Routine Name: + + CXPSArchive::InitialiseFile + +Routine Description: + + This routine intialises the named file ready for processing + or sending on. This entails locating all the PK archive files + that constitute the XPS part. + +Arguments: + + szFileName - The name of the part to intialise + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CXPSArchive::InitialiseFile( + _In_z_ PCSTR szFileName + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(szFileName, E_POINTER))) + { + try + { + CStringXDA cstrFileName(szFileName); + + // + // Open the file handler - if it is still in use this will fail + // + if (SUCCEEDED(hr = m_XpsFile.Open(szFileName))) + { + // + // Find the record or the parts comprising the record + // + hr = AddFile(szFileName); + } + else + { + RIP("File handler has not been closed correctly\n"); + } + } + catch (CXDException& e) + { + hr = e; + } + } + + ERR_ON_HR_EXC(hr, E_ELEMENT_NOT_FOUND); + return hr; +} + +/*++ + +Routine Name: + + CXPSArchive::GetFileStream + +Routine Description: + + This routine retrieves the read stream for an XPS part. + +Arguments: + + szFileName - The name of the XPS part the stream is required for + ppFileStream - Pointer to an ISequentialStream pointer that recieves the stream + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CXPSArchive::GetFileStream( + _In_z_ PCSTR szFileName, + _Outptr_ ISequentialStream** ppFileStream + ) +{ + HRESULT hr = S_OK; + + // + // Initialise the current XPS file + // + if (SUCCEEDED(hr = CHECK_POINTER(ppFileStream, E_POINTER)) && + SUCCEEDED(hr = InitialiseFile(szFileName))) + { + // + // Query the XPS file for the file stream + // + *ppFileStream = NULL; + hr = m_XpsFile.QueryInterface(IID_ISequentialStream, reinterpret_cast(ppFileStream)); + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CXPSArchive::CloseCurrent + +Routine Description: + + This routine closes the currently opened XPS file + +Arguments: + + None + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CXPSArchive::CloseCurrent( + VOID + ) +{ + return m_XpsFile.Close(); +} + +/*++ + +Routine Name: + + CXPSArchive::SendCurrentFile + +Routine Description: + + This routine sends the current initialised file and requests the + PK archive handler compresses it according to the requested method + +Arguments: + + eCompType - The requested compression type + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CXPSArchive::SendCurrentFile( + _In_ ECompressionType eCompType + ) +{ + HRESULT hr = S_OK; + + ULONG cb = 0; + PVOID pv = NULL; + PSTR pName = NULL; + + // + // Get the data buffer and file name + // + if (SUCCEEDED(hr = m_XpsFile.GetBuffer(&pv, &cb)) && + SUCCEEDED(hr = m_XpsFile.GetFileName(&pName))) + { + hr = SendFile(pName, pv, cb, eCompType); + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CXPSArchive::SendCurrentFile + +Routine Description: + + This routine sends the current initialised file by requesting the + PK archive handler send the original constituent PK records + +Arguments: + + None + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CXPSArchive::SendCurrentFile( + VOID + ) +{ + HRESULT hr = S_OK; + + XPSPartStack* pPartStack = NULL; + PSTR pName = NULL; + + if (SUCCEEDED(hr = CHECK_POINTER(m_pPkArchive, E_NOINTERFACE)) && + SUCCEEDED(hr = m_XpsFile.GetFileParts(&pPartStack)) && + SUCCEEDED(hr = m_XpsFile.GetFileName(&pName))) + { + try + { + // + // Send all file parts on to the PK archive + // + if (!m_sentList[pName]) + { + XPSPartStack::const_iterator iterParts = pPartStack->begin(); + + for (; + iterParts != pPartStack->end() && SUCCEEDED(hr); + iterParts++) + { + hr = m_pPkArchive->SendFile(iterParts->first); + } + + if (SUCCEEDED(hr)) + { + m_sentList[pName] = TRUE; + } + } + } + catch (exception& DBG_ONLY(e)) + { + ERR(e.what()); + hr = E_FAIL; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CXPSArchive::SendFile + +Routine Description: + + This routine sends a file defined by it's name and constituent data. The + routine passes the name and buffer to the PK archive handler to compress + and add to the archive. + +Arguments: + + szFileName - The name of the part + pBuffer - The buffer containing the part data + cbBuffer - The size of the data buffer + eCompType - The requested compression type + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CXPSArchive::SendFile( + _In_z_ PCSTR szFileName, + _In_reads_bytes_(cbBuffer) PVOID pBuffer, + _In_ ULONG cbBuffer, + _In_ ECompressionType eCompType + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(m_pPkArchive, E_NOINTERFACE)) && + SUCCEEDED(hr = CHECK_POINTER(szFileName, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pBuffer, E_POINTER))) + { + if (eCompType == CompDeflated || + eCompType == CompNone) + { + try + { + // + // Get the PK archive to compress and send the file on + // + if (!m_sentList[szFileName]) + { + if (SUCCEEDED(hr = m_pPkArchive->SendFile(szFileName, pBuffer, cbBuffer, eCompType))) + { + m_sentList[szFileName] = TRUE; + } + } + } + catch (exception& DBG_ONLY(e)) + { + ERR(e.what()); + hr = E_FAIL; + } + } + else + { + hr = HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CXPSArchive::AddFile + +Routine Description: + + This routine adds the PK file or constiuent PK files to the XPS file + ready for retrieval of the read stream. This hides the XPS piece handling + from the client which just adds the part by it's full un-interleaved name + +Arguments: + + szFileName - The name of the part + +Return Value: + + HRESULT + S_OK - On success + E_ELEMENT_NOT_FOUND - When part not present or badly formed in the container + E_* - On error + +--*/ +HRESULT +CXPSArchive::AddFile( + _In_z_ PCSTR szFileName + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(m_pPkArchive, E_NOINTERFACE)) && + SUCCEEDED(hr = CHECK_POINTER(szFileName, E_POINTER))) + { + // + // Find the part or parts comprising the file + // + NameIndex* pNameIndex = NULL; + + if (SUCCEEDED(hr = m_pPkArchive->GetNameIndex(&pNameIndex))) + { + try + { + NameIndex::const_iterator iterNameIndex = pNameIndex->find(szFileName); + if (iterNameIndex != pNameIndex->end()) + { + // + // There is a single part + // + hr = m_XpsFile.AddFilePart(CStringXDA(szFileName), iterNameIndex->second); + } + else + { + // + // This could be a multipart interleaved file + // + UINT cPart = 0; + do + { + CStringXDA cstrPart; + cstrPart.Format(szPartNameFormatString, szFileName, cPart); + + iterNameIndex = pNameIndex->find(cstrPart); + if (iterNameIndex != pNameIndex->end()) + { + // + // We found the next part + // + hr = m_XpsFile.AddFilePart(CStringXDA(szFileName), iterNameIndex->second); + cPart++; + } + else + { + cstrPart.Format(szLastPartNameFormatString, szFileName, cPart); + iterNameIndex = pNameIndex->find(cstrPart); + + if (iterNameIndex != pNameIndex->end()) + { + // + // We found the last part + // + hr = m_XpsFile.AddFilePart(CStringXDA(szFileName), iterNameIndex->second); + cPart++; + break; + } + else + { + // + // The element is either not well constructed (i.e. missing a piece or the last + // part) or it does not exist + // + hr = E_ELEMENT_NOT_FOUND; + } + } + } + while (SUCCEEDED(hr)); + } + } + catch (CXDException& e) + { + hr = e; + } + catch (exception& DBG_ONLY(e)) + { + ERR(e.what()); + hr = E_FAIL; + } + } + } + + ERR_ON_HR_EXC(hr, E_ELEMENT_NOT_FOUND); + return hr; +} diff --git a/print/XPSDrvSmpl/src/filters/xdcont/xpsarch.h b/print/XPSDrvSmpl/src/filters/xdcont/xpsarch.h new file mode 100644 index 00000000..c891faa2 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/xdcont/xpsarch.h @@ -0,0 +1,91 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + xpsarch.h + +Abstract: + + Definition of the XPS archive class. This class is responsible for providing + an interface to clients that removes the potentially interleaved nature of an + XPS document. This allows clients to manipulate files using the parts full name + instead of having to worry about the semantics of interleaved parts. + +--*/ + +#pragma once + +#include "ipkarch.h" +#include "xpsfiler.h" + +class CXPSArchive +{ +public: + CXPSArchive( + _In_ IPrintReadStream* pReadStream, + _In_ IPrintWriteStream* pWriteStream + ); + + virtual ~CXPSArchive(); + + HRESULT + InitialiseFile( + _In_z_ PCSTR szFileName + ); + + HRESULT + GetFileStream( + _In_z_ PCSTR szFileName, + _Outptr_ ISequentialStream** ppFileStream + ); + + HRESULT + CloseCurrent( + VOID + ); + + HRESULT + SendCurrentFile( + _In_ ECompressionType eCompType + ); + + HRESULT + SendCurrentFile( + VOID + ); + + HRESULT + SendFile( + _In_z_ PCSTR szFileName, + _In_reads_bytes_(cbBuffer) PVOID pBuffer, + _In_ ULONG cbBuffer, + _In_ ECompressionType eCompType + ); + +private: + HRESULT + AddFile( + _In_z_ PCSTR szFileName + ); + +private: + HMODULE m_hPkArch; + + CComPtr m_pPkArchive; + + CXPSReadFile m_XpsFile; + + SentList m_sentList; + + CComPtr m_pWriteStream; +}; + diff --git a/print/XPSDrvSmpl/src/filters/xdcont/xpsfd.cpp b/print/XPSDrvSmpl/src/filters/xdcont/xpsfd.cpp new file mode 100644 index 00000000..ebe78ee5 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/xdcont/xpsfd.cpp @@ -0,0 +1,285 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + xpsfd.cpp + +Abstract: + + Implementation of the XPS Fixed Document (FD) SAX handler. This class is + responsible for retrieving and storing in the correct order the Fixed Pages + that comprise the Fixed Document. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdstring.h" +#include "xdexcept.h" +#include "xpsfd.h" + +static PCSTR szPageContent = "PageContent"; +static PCSTR szSource = "Source"; + +/*++ + +Routine Name: + + CFixedDocument::CFixedDocument + +Routine Description: + + CFixedDocument class constructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CFixedDocument::CFixedDocument() +{ +} + +/*++ + +Routine Name: + + CFixedDocument::~CFixedDocument + +Routine Description: + + CFixedDocument class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CFixedDocument::~CFixedDocument() +{ +} + +/*++ + +Routine Name: + + CFixedDocument::startElement + +Routine Description: + + This routine is the startElement method of the SAX handler. This is used + to parse the fixed document mark-up retrieving and storing the list of + fixed pages in the document + +Arguments: + + pwchNamespaceUri - Unused: Local namespace URI + cchNamespaceUri - Unused: Length of the namespace URI + pwchLocalName - Unused: Local name string + cchLocalName - Unused: Length of the local name string + pwchQName - The qualified name with prefix + cchQName - The length of the qualified name with prefix + pAttributes - Pointer to the ISAXAttributes interface containing attributes attached to the element + + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT STDMETHODCALLTYPE +CFixedDocument::startElement( + CONST wchar_t*, + INT, + CONST wchar_t*, + INT, + _In_reads_(cchQName) CONST wchar_t* pwchQName, + _In_ INT cchQName, + _In_ ISAXAttributes* pAttributes + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pwchQName, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pAttributes, E_POINTER))) + { + if (cchQName <= 0) + { + hr = E_INVALIDARG; + } + } + + try + { + CStringXDA cstrElementName(pwchQName, cchQName); + + if (cstrElementName == szPageContent) + { + INT cAttributes = 0; + + if (SUCCEEDED(hr)) + { + hr = pAttributes->getLength(&cAttributes); + } + + // + // Run over all attributes identifying the document in the sequence + // + for (INT cIndex = 0; cIndex < cAttributes && SUCCEEDED(hr); cIndex++) + { + PCWSTR pszAttUri = NULL; + INT cchAttUri = 0; + PCWSTR pszAttName = NULL; + INT cchAttName = 0; + PCWSTR pszAttQName = NULL; + INT cchAttQName = 0; + PCWSTR pszAttValue = NULL; + INT cchAttValue = 0; + + // + // Get the attribute data ready to write out + // + if (SUCCEEDED(hr = pAttributes->getName(cIndex, &pszAttUri, &cchAttUri, &pszAttName, &cchAttName, &pszAttQName, &cchAttQName)) && + SUCCEEDED(hr = pAttributes->getValue(cIndex, &pszAttValue, &cchAttValue))) + { + CStringXDA cstrAttName(pszAttQName, cchAttQName); + CStringXDA cstrAttValue(pszAttValue, cchAttValue); + + if (cstrAttName == szSource) + { + // + // Strip any leading "/" + // + if (cstrAttValue.GetAt(0) == '/') + { + cstrAttValue.Delete(0); + } + + try + { + // + // Add the fixed page to the list + // + m_FixedPageList.push_back(cstrAttValue); + } + catch (exception& DBG_ONLY(e)) + { + ERR(e.what()); + hr = E_FAIL; + } + } + } + } + } + } + catch (CXDException& e) + { + hr = e; + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CFixedDocument::GetFixedPageList + +Routine Description: + + This routine retrieves the fixed page list constructed as the fixed document + mark-up was parsed + +Arguments: + + pFixedPageList - Pointer to the vector that recieves the fixed page list + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CFixedDocument::GetFixedPageList( + _Out_ FileList* pFixedPageList + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pFixedPageList, E_POINTER))) + { + try + { + pFixedPageList->assign(m_FixedPageList.begin(), m_FixedPageList.end()); + } + catch (CXDException& e) + { + hr = e; + } + catch (exception& DBG_ONLY(e)) + { + ERR(e.what()); + hr = E_FAIL; + } + } + + return hr; +} + +/*++ + +Routine Name: + + CFixedDocument::Clear + +Routine Description: + + This routine clears the fixed page list + +Arguments: + + None + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CFixedDocument::Clear( + VOID + ) +{ + HRESULT hr = S_OK; + + m_FixedPageList.clear(); + + ERR_ON_HR(hr); + return hr; +} diff --git a/print/XPSDrvSmpl/src/filters/xdcont/xpsfd.h b/print/XPSDrvSmpl/src/filters/xdcont/xpsfd.h new file mode 100644 index 00000000..65888511 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/xdcont/xpsfd.h @@ -0,0 +1,60 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + xpsfd.h + +Abstract: + + Definition of the XPS Fixed Document (FD) SAX handler. This class is + responsible for retrieving and storing in the correct order the Fixed Pages + that comprise the Fixed Document. + +--*/ + +#pragma once + +#include "saxhndlr.h" +#include "xps.h" + +class CFixedDocument : public CSaxHandler +{ +public: + CFixedDocument(); + + virtual ~CFixedDocument(); + + virtual HRESULT STDMETHODCALLTYPE + startElement( + CONST wchar_t*, + INT, + CONST wchar_t*, + INT, + _In_reads_(cchQName) CONST wchar_t* pwchQName, + _In_ INT cchQName, + _In_ ISAXAttributes* pAttributes + ); + + HRESULT + GetFixedPageList( + _Out_ FileList* pFixedPageList + ); + + HRESULT + Clear( + VOID + ); + +private: + FileList m_FixedPageList; +}; + diff --git a/print/XPSDrvSmpl/src/filters/xdcont/xpsfds.cpp b/print/XPSDrvSmpl/src/filters/xdcont/xpsfds.cpp new file mode 100644 index 00000000..e4eb8bc8 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/xdcont/xpsfds.cpp @@ -0,0 +1,285 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + xpsfds.cpp + +Abstract: + + Implementation of the XPS Fixed Document Sequence (FDS) SAX handler. + This class is responsible for retrieving and storing in the correct + order the Fixed Documentss that comprise the Fixed Document + Sequence. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdstring.h" +#include "xdexcept.h" +#include "xpsfds.h" + +static PCSTR szDocumentReference = "DocumentReference"; +static PCSTR szSource = "Source"; + +/*++ + +Routine Name: + + CFixedDocumentSequence::CFixedDocumentSequence + +Routine Description: + + CFixedDocumentSequence class constructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CFixedDocumentSequence::CFixedDocumentSequence() +{ +} + +/*++ + +Routine Name: + + CFixedDocumentSequence::~CFixedDocumentSequence + +Routine Description: + + CFixedDocumentSequence class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CFixedDocumentSequence::~CFixedDocumentSequence() +{ +} + +/*++ + +Routine Name: + + CFixedDocumentSequence::startElement + +Routine Description: + + This routine is the startElement method of the SAX handler. This is used + to parse the fixed document sequence mark-up retrieving and storing the list of + fixed documents in the sequence + +Arguments: + + pwchNamespaceUri - Unused: Local namespace URI + cchNamespaceUri - Unused: Length of the namespace URI + pwchLocalName - Unused: Local name string + cchLocalName - Unused: Length of the local name string + pwchQName - The qualified name with prefix + cchQName - The length of the qualified name with prefix + pAttributes - Pointer to the ISAXAttributes interface containing attributes attached to the element + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT STDMETHODCALLTYPE +CFixedDocumentSequence::startElement( + CONST wchar_t*, + INT, + CONST wchar_t*, + INT, + _In_reads_(cchQName) CONST wchar_t* pwchQName, + _In_ INT cchQName, + _In_ ISAXAttributes* pAttributes + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pwchQName, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pAttributes, E_POINTER))) + { + if (cchQName <= 0) + { + hr = E_INVALIDARG; + } + } + + try + { + CStringXDA cstrElementName(pwchQName, cchQName); + + if (cstrElementName == szDocumentReference) + { + INT cAttributes = 0; + + if (SUCCEEDED(hr)) + { + hr = pAttributes->getLength(&cAttributes); + } + + // + // Run over all attributes identifying the document in the sequence + // + for (INT cIndex = 0; cIndex < cAttributes && SUCCEEDED(hr); cIndex++) + { + PCWSTR pszAttUri = NULL; + INT cchAttUri = 0; + PCWSTR pszAttName = NULL; + INT cchAttName = 0; + PCWSTR pszAttQName = NULL; + INT cchAttQName = 0; + PCWSTR pszAttValue = NULL; + INT cchAttValue = 0; + + // + // Get the attribute data ready to write out + // + if (SUCCEEDED(hr = pAttributes->getName(cIndex, &pszAttUri, &cchAttUri, &pszAttName, &cchAttName, &pszAttQName, &cchAttQName)) && + SUCCEEDED(hr = pAttributes->getValue(cIndex, &pszAttValue, &cchAttValue))) + { + CStringXDA cstrAttName(pszAttQName, cchAttQName); + CStringXDA cstrAttValue(pszAttValue, cchAttValue); + + if (cstrAttName == szSource) + { + // + // Strip any leading "/" + // + if (cstrAttValue.GetAt(0) == '/') + { + cstrAttValue.Delete(0); + } + + try + { + // + // Add the fixed document to the list + // + m_FixedDocumentList.push_back(cstrAttValue); + } + catch (exception& DBG_ONLY(e)) + { + ERR(e.what()); + hr = E_FAIL; + } + } + } + } + } + } + catch (CXDException& e) + { + hr = e; + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CFixedDocumentSequence::GetFixedDocumentList + +Routine Description: + + This routine retrieves the fixed document list constructed as the fixed document + sequence mark-up was parsed + +Arguments: + + pFixedDocumentList - Pointer to the vector that recieves the fixed document list + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CFixedDocumentSequence::GetFixedDocumentList( + _Out_ FileList* pFixedDocumentList + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pFixedDocumentList, E_POINTER))) + { + try + { + pFixedDocumentList->assign(m_FixedDocumentList.begin(), m_FixedDocumentList.end()); + } + catch (CXDException& e) + { + hr = e; + } + catch (exception& DBG_ONLY(e)) + { + ERR(e.what()); + hr = E_FAIL; + } + } + + return hr; +} + +/*++ + +Routine Name: + + CFixedDocumentSequence::Clear + +Routine Description: + + This routine clears the fixed page list + +Arguments: + + None + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CFixedDocumentSequence::Clear( + VOID + ) +{ + HRESULT hr = S_OK; + + m_FixedDocumentList.clear(); + + ERR_ON_HR(hr); + return hr; +} diff --git a/print/XPSDrvSmpl/src/filters/xdcont/xpsfds.h b/print/XPSDrvSmpl/src/filters/xdcont/xpsfds.h new file mode 100644 index 00000000..78860b70 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/xdcont/xpsfds.h @@ -0,0 +1,61 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + xpsfds.h + +Abstract: + + Definition of the XPS Fixed Document Sequence (FDS) SAX handler. + This class is responsible for retrieving and storing in the correct + order the Fixed Documentss that comprise the Fixed Document + Sequence. + +--*/ + +#pragma once + +#include "saxhndlr.h" +#include "xps.h" + +class CFixedDocumentSequence : public CSaxHandler +{ +public: + CFixedDocumentSequence(); + + virtual ~CFixedDocumentSequence(); + + virtual HRESULT STDMETHODCALLTYPE + startElement( + CONST wchar_t*, + INT, + CONST wchar_t*, + INT, + _In_reads_(cchQName) CONST wchar_t* pwchQName, + _In_ INT cchQName, + _In_ ISAXAttributes* pAttributes + ); + + HRESULT + GetFixedDocumentList( + _Out_ FileList* pFixedDocumentList + ); + + HRESULT + Clear( + VOID + ); + +private: + FileList m_FixedDocumentList; +}; + diff --git a/print/XPSDrvSmpl/src/filters/xdcont/xpsfiler.cpp b/print/XPSDrvSmpl/src/filters/xdcont/xpsfiler.cpp new file mode 100644 index 00000000..c8ee85cb --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/xdcont/xpsfiler.cpp @@ -0,0 +1,679 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + xpsfiler.cpp + +Abstract: + + Implementation of the XPS file reader class. This class implements + ISequentialStream::Read by using the IPKFile interface to supply the + client with decompressed data as requested. This allows the file to + be passed directly to a SAX or DOM handler for parsing. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdexcept.h" +#include "xpsfiler.h" + +/*++ + +Routine Name: + + CXPSReadFile::CXPSReadFile + +Routine Description: + + CXPSReadFile class constructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CXPSReadFile::CXPSReadFile() : + CUnknown(IID_ISequentialStream), + m_cbSent(0), + m_cbExtracted(0), + m_bExtractedAll(FALSE) +{ +} + +/*++ + +Routine Name: + + CXPSReadFile::~CXPSReadFile + +Routine Description: + + CXPSReadFile class denstructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CXPSReadFile::~CXPSReadFile() +{ + Close(); +} + +/*++ + +Routine Name: + + CXPSReadFile::Read + +Routine Description: + + This routine implements the ISequentialStream read interface allowing + clients to access file data without having to worry about part + interleaving or decompression. + +Arguments: + + pv - Pointer to the buffer to recieve the file data + cb - The size of the data buffer + pcbRead - Pointer to a ULONG that recieves the number of bytes read + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT STDMETHODCALLTYPE +CXPSReadFile::Read( + _Out_writes_bytes_(cb) void* pv, + _In_ ULONG cb, + _Out_ ULONG* pcbRead + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pv, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pcbRead, E_POINTER))) + { + *pcbRead = 0; + + if (cb > 0) + { + // + // Add data to our working buffer till we have enough to copy or + // we ran out of data + // + while (m_cbExtracted - m_cbSent < cb && + !m_bExtractedAll && + SUCCEEDED(hr)) + { + hr = DecompressNextFile(); + } + + // + // Copy the data into the copy buffer + // + if (SUCCEEDED(hr)) + { + hr = CopyBuffer(pv, cb, pcbRead); + } + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CXPSReadFile::Write + +Routine Description: + + This routine is the ISequentialStream write implementation. It is not + implemented + +Arguments: + + Unused + +Return Value: + + HRESULT + E_NOTIMPL - This method is not implemented + +--*/ +HRESULT STDMETHODCALLTYPE +CXPSReadFile::Write( + _In_reads_bytes_(cb) CONST void*, + _In_ ULONG cb, + _Out_opt_ ULONG* + ) +{ + UNREFERENCED_PARAMETER(cb); + return E_NOTIMPL; +} + +/*++ + +Routine Name: + + CXPSReadFile::Open + +Routine Description: + + This routine intialises a file ready to be read + +Arguments: + + szFileName - The name of the part to be intialised + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CXPSReadFile::Open( + _In_ PCSTR szFileName + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(szFileName, E_POINTER))) + { + try + { + if (m_partStack.empty()) + { + m_cstrFileName = szFileName; + } + else + { + RIP("The file must be closed before another is opened\n"); + + hr = E_FAIL; + } + + } + catch (CXDException& e) + { + hr = e; + } + catch (exception& DBG_ONLY(e)) + { + ERR(e.what()); + hr = E_FAIL; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CXPSReadFile::Close + +Routine Description: + + This routine closes the currently open file + +Arguments: + + None + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CXPSReadFile::Close( + VOID + ) +{ + HRESULT hr = S_OK; + + m_partStack.clear(); + m_cstrFileName.Empty(); + m_cbSent = 0; + m_cbExtracted = 0; + m_bExtractedAll = 0; + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CXPSReadFile::GetBuffer + +Routine Description: + + This routine retrieves the current populated buffer and the count + of bytes available + +Arguments: + + ppv - Pointer to a VOID pointer that recieves the buffer + pcb - Pointer to a ULONG that recieves the size of the buffer + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CXPSReadFile::GetBuffer( + _Outptr_result_bytebuffer_(*pcb) PVOID* ppv, + _Out_ ULONG* pcb + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(ppv, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pcb, E_POINTER))) + { + *ppv = NULL; + *pcb = 0; + + if (!m_bExtractedAll) + { + hr = E_PENDING; + } + } + + if (SUCCEEDED(hr) && + SUCCEEDED(hr = m_workFile.GetBuffer(m_cbExtracted, ppv))) + { + *pcb = static_cast(m_cbExtracted); + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CXPSReadFile::GetFileName + +Routine Description: + + This routine retrieves the file name of the currently opened file + +Arguments: + + pszFileName - Pointer to a string that recieves the filename + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CXPSReadFile::GetFileName( + _Outptr_ PSTR* pszFileName + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pszFileName, E_POINTER))) + { + try + { + if (m_cstrFileName.GetLength() > 0) + { + *pszFileName = m_cstrFileName.GetBuffer(); + } + else + { + hr = E_PENDING; + } + } + catch (CXDException& e) + { + hr = e; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CXPSReadFile::AddFilePart + +Routine Description: + + This routine adds a PK file name to the stack of files that + constitute the XPS part + +Arguments: + + szFileName - The file name to add + pPkFile - The PK file to add to the stack + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CXPSReadFile::AddFilePart( + _In_ PCSTR szFileName, + _In_ CONST IPKFile* pPkFile + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(szFileName, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pPkFile, E_POINTER))) + { + try + { + if (m_cstrFileName == szFileName) + { + m_partStack.push_back(RecordTracker(pPkFile, FALSE)); + } + else + { + RIP("Filename differs from currently open file\n"); + + hr = E_FAIL; + } + } + catch (CXDException& e) + { + hr = e; + } + catch (exception& DBG_ONLY(e)) + { + ERR(e.what()); + hr = E_FAIL; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CXPSReadFile::GetFileParts + +Routine Description: + + This routine retrieves the PK files that constitute the XPS part + +Arguments: + + ppPartStack - Pointer to an XPSPartStack pointer that recieves the part stack + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CXPSReadFile::GetFileParts( + _Outptr_ XPSPartStack** ppPartStack + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(ppPartStack, E_POINTER))) + { + *ppPartStack = &m_partStack; + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CXPSReadFile::DecompressNextFile + +Routine Description: + + This routine decompresses the next compressed part in the part stack + +Arguments: + + None + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CXPSReadFile::DecompressNextFile( + VOID + ) +{ + HRESULT hr = S_OK; + + // + // If there are more files to decompress + // + if (!m_bExtractedAll) + { + try + { + // + // Decompress the next unprocessed file into the working buffer + // + XPSPartStack::iterator iterXpsStack = m_partStack.begin(); + + for (;iterXpsStack != m_partStack.end(); iterXpsStack++) + { + if (!iterXpsStack->second) + { + if (SUCCEEDED(hr = Decompress(iterXpsStack->first))) + { + iterXpsStack->second = TRUE; + } + + break; + } + } + + if (iterXpsStack == m_partStack.end()) + { + // + // That was the last record + // + m_bExtractedAll = TRUE; + } + } + catch (exception& DBG_ONLY(e)) + { + ERR(e.what()); + hr = E_FAIL; + } + } + else + { + RIP("File has already been fully extracted\n"); + + hr = E_FAIL; + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CXPSReadFile::Decompress + +Routine Description: + + This routine uses the PK archive handler to decompress the PK file specified + +Arguments: + + pRecord - The PK file to be decompressed + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CXPSReadFile::Decompress( + _In_ CONST IPKFile* pRecord + ) +{ + HRESULT hr = S_OK; + + ECompressionType eCompType; + ULONG cbDecompressed = 0; + + if (SUCCEEDED(hr = CHECK_POINTER(pRecord, E_POINTER)) && + SUCCEEDED(hr = pRecord->GetDecompressedSize(&cbDecompressed)) && + SUCCEEDED(hr = pRecord->GetCompressionMethod(&eCompType))) + { + if (eCompType == CompDeflated || + eCompType == CompNone) + { + PVOID pUnCompressedData = NULL; + + if (SUCCEEDED(hr = m_workFile.GetBuffer(m_cbExtracted + cbDecompressed, &pUnCompressedData))) + { + pUnCompressedData = reinterpret_cast(pUnCompressedData) + m_cbExtracted; + + if (SUCCEEDED(hr = pRecord->DecompressTo(pUnCompressedData, cbDecompressed))) + { + m_cbExtracted += cbDecompressed; + } + } + } + else + { + ERR("Unsupported compression method\n"); + + hr = HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CXPSReadFile::CopyBuffer + +Routine Description: + + This routine copies the decompressed data from the working buffer to + the specified buffer + +Arguments: + + pv - Pointer to the buffer to recieve the file data + cb - The size of the data buffer + pcbRead - Pointer to a ULONG that recieves the number of bytes written to the buffer + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CXPSReadFile::CopyBuffer( + _Out_writes_bytes_(cb) void* pv, + _In_ ULONG cb, + _Out_ ULONG* pcbRead + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pv, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pcbRead, E_POINTER))) + { + *pcbRead = 0; + + if (cb > 0) + { + // + // We return the smaller of the amount requested and the + // amount available + // + *pcbRead = static_cast(min(m_cbExtracted - m_cbSent, cb)); + + PVOID pData = NULL; + + if (SUCCEEDED(hr = m_workFile.GetBufferAt(static_cast(m_cbSent), static_cast(*pcbRead), &pData))) + { + CopyMemory(pv, pData, *pcbRead); + + m_cbSent += *pcbRead; + } + } + } + + ERR_ON_HR(hr); + return hr; +} diff --git a/print/XPSDrvSmpl/src/filters/xdcont/xpsfiler.h b/print/XPSDrvSmpl/src/filters/xdcont/xpsfiler.h new file mode 100644 index 00000000..03603098 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/xdcont/xpsfiler.h @@ -0,0 +1,119 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + xpsfiler.h + +Abstract: + + Definition of the XPS file reader class. This class implements + ISequentialStream::Read by using the IPKFile interface to supply the + client with decompressed data as requested. This allows the file to + be passed directly to a SAX or DOM handler for parsing. + +--*/ + +#pragma once + +#include "xps.h" +#include "ipkarch.h" +#include "workbuff.h" +#include "cunknown.h" + +class CXPSReadFile : public CUnknown +{ +public: + CXPSReadFile(); + + virtual ~CXPSReadFile(); + + // + // ISequentialStream members + // + HRESULT STDMETHODCALLTYPE + Read( + _Out_writes_bytes_(cb) void* pv, + _In_ ULONG cb, + _Out_ ULONG* pcbRead + ); + + HRESULT STDMETHODCALLTYPE + Write( + _In_reads_bytes_(cb) CONST void*, + _In_ ULONG cb, + _Out_opt_ ULONG* + ); + + HRESULT + Open( + _In_ PCSTR szFileName + ); + + HRESULT + Close( + VOID + ); + + HRESULT + AddFilePart( + _In_ PCSTR szFileName, + _In_ CONST IPKFile* pPkFile + ); + + HRESULT + GetFileParts( + _Outptr_ XPSPartStack** ppPartStack + ); + + HRESULT + GetBuffer( + _Outptr_result_bytebuffer_(*pcb) PVOID* ppv, + _Out_ ULONG* pcb + ); + + HRESULT + GetFileName( + _Outptr_ PSTR* pszFileName + ); + +private: + HRESULT + DecompressNextFile( + VOID + ); + + HRESULT + Decompress( + _In_ CONST IPKFile* pRecord + ); + + HRESULT + CopyBuffer( + _Out_writes_bytes_(cb) void* pv, + _In_ ULONG cb, + _Out_ ULONG* pcbRead + ); + +private: + CWorkingBuffer m_workFile; + + CStringXDA m_cstrFileName; + + XPSPartStack m_partStack; + + SIZE_T m_cbSent; + + SIZE_T m_cbExtracted; + + BOOL m_bExtractedAll; +}; + diff --git a/print/XPSDrvSmpl/src/filters/xdcont/xpsfilew.cpp b/print/XPSDrvSmpl/src/filters/xdcont/xpsfilew.cpp new file mode 100644 index 00000000..64decfac --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/xdcont/xpsfilew.cpp @@ -0,0 +1,291 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + xpsfilew.cpp + +Abstract: + + Implementation of an XPS file writer. This implements ISequentialStream::Write + and essentially wraps a buffer that recieves and stores the part information + so that in can be later compressed and written out. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xpsfilew.h" + +/*++ + +Routine Name: + + CXPSWriteFile::CXPSWriteFile + +Routine Description: + + CXPSWriteFile class constructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CXPSWriteFile::CXPSWriteFile() : + CUnknown(IID_ISequentialStream), + m_cbWritten(0) +{ +} + +/*++ + +Routine Name: + + CXPSWriteFile::CXPSWriteFile + +Routine Description: + + CXPSWriteFile class constructor + +Arguments: + + szFileName - The name of the file to write to + +Return Value: + + None + +--*/ +CXPSWriteFile::CXPSWriteFile( + PCSTR szFileName + ) : + CUnknown(IID_ISequentialStream), + m_cbWritten(0), + m_cstrFileName(szFileName) +{ +} + +/*++ + +Routine Name: + + CXPSWriteFile::~CXPSWriteFile + +Routine Description: + + CXPSWriteFile class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CXPSWriteFile::~CXPSWriteFile() +{ +} + +// +// ISequentialStream members +// +/*++ + +Routine Name: + + CXPSWriteFile::Read + +Routine Description: + + This is the ISequentialStream read method - this is not implemented in + the file writter + +Arguments: + + Unused + +Return Value: + + HRESULT + E_NOTIMPL - This method is not implemented + +--*/ +HRESULT STDMETHODCALLTYPE +CXPSWriteFile::Read( + _Out_writes_bytes_to_(cb, *pcbRead) void*, + _In_ ULONG cb, + _Out_opt_ ULONG* pcbRead + ) +{ + UNREFERENCED_PARAMETER(cb); + UNREFERENCED_PARAMETER(pcbRead); + return E_NOTIMPL; +} + +/*++ + +Routine Name: + + CXPSWriteFile::Write + +Routine Description: + + This routine implements the ISequentialStream wrte interface allowing + clients to write file data. + +Arguments: + + pData - Pointer to the source data + cbData - The size of the data buffer + pcbWritten - Pointer to a ULONG that recieves the number of bytes written + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT STDMETHODCALLTYPE +CXPSWriteFile::Write( + _In_reads_bytes_(cbData) CONST void* pData, + _In_ ULONG cbData, + _Out_ ULONG* pcbWritten + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pData, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pcbWritten, E_POINTER))) + { + *pcbWritten = 0; + + PBYTE pDest = NULL; + if (SUCCEEDED(hr = m_workFile.GetBuffer(m_cbWritten + cbData, reinterpret_cast(&pDest)))) + { + pDest += m_cbWritten; + + CopyMemory(pDest, pData, cbData); + + m_cbWritten += cbData; + *pcbWritten = cbData; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CXPSWriteFile::GetBuffer + +Routine Description: + + This routine retrieves the buffer containing the file data written by + a client + +Arguments: + + ppv - Pointer to a VOID pointer that recieves the buffer + pcb - Pointer to a ULONG that recieves the size of the buffer + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CXPSWriteFile::GetBuffer( + _Outptr_result_bytebuffer_(*pcb) PVOID* ppv, + _Out_ ULONG* pcb + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(ppv, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pcb, E_POINTER))) + { + *ppv = NULL; + *pcb = 0; + + if (SUCCEEDED(hr = m_workFile.GetBuffer(m_cbWritten, ppv))) + { + *pcb = static_cast(m_cbWritten); + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CXPSWriteFile::GetFileName + +Routine Description: + + This routine retrieves the file name of the currently opened file + +Arguments: + + pszFileName - Pointer to a string that recieves the filename + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CXPSWriteFile::GetFileName( + _Outptr_ PSTR* pszFileName + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pszFileName, E_POINTER))) + { + try + { + if (m_cstrFileName.GetLength() > 0) + { + *pszFileName = m_cstrFileName.GetBuffer(); + } + else + { + hr = E_PENDING; + } + } + catch (CXDException& e) + { + hr = e; + } + } + + ERR_ON_HR(hr); + return hr; +} diff --git a/print/XPSDrvSmpl/src/filters/xdcont/xpsfilew.h b/print/XPSDrvSmpl/src/filters/xdcont/xpsfilew.h new file mode 100644 index 00000000..652027b1 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/xdcont/xpsfilew.h @@ -0,0 +1,76 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + xpsfilew.h + +Abstract: + + Definition of an XPS file writer. This implements ISequentialStream::Write + and essentially wraps a buffer that recieves and stores the part information + so that in can be later compressed and written out. + +--*/ + +#pragma once + +#include "workbuff.h" +#include "cunknown.h" +#include "xdstring.h" + +class CXPSWriteFile : public CUnknown +{ +public: + CXPSWriteFile(); + + CXPSWriteFile( + PCSTR szFileName + ); + + virtual ~CXPSWriteFile(); + + // + // ISequentialStream members + // + HRESULT STDMETHODCALLTYPE + Read( + _Out_writes_bytes_to_(cb, *pcbRead) void*, + _In_ ULONG cb, + _Out_opt_ ULONG* pcbRead + ); + + HRESULT STDMETHODCALLTYPE + Write( + _In_reads_bytes_(cbData) CONST void* pData, + _In_ ULONG cbData, + _Out_ ULONG* pcbWritten + ); + + HRESULT + GetBuffer( + _Outptr_result_bytebuffer_(*pcb) PVOID* ppv, + _Out_ ULONG* pcb + ); + + HRESULT + GetFileName( + _Outptr_ PSTR* pszFileName + ); + +private: + CWorkingBuffer m_workFile; + + ULONG m_cbWritten; + + CStringXDA m_cstrFileName; +}; + diff --git a/print/XPSDrvSmpl/src/filters/xdcont/xpsproc.cpp b/print/XPSDrvSmpl/src/filters/xdcont/xpsproc.cpp new file mode 100644 index 00000000..14da1437 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/xdcont/xpsproc.cpp @@ -0,0 +1,916 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + xpsproc.cpp + +Abstract: + + Implementation of the XPS processor. This class is responsible for handling + the logical document and page structure of the XPS container. The class starts + with the content types part and .rels part to find the Fixed Document Sequence. + It then parses the FDS to find the Fixed Documents and finally the FDs to find + each Fixed Page. Each fixed page is then reported to a client FixedPageProcessor + to interpret the mark-up and write out modifications as required. The class is + additionally responsible for ensuring all XPS parts and accompanying resources are + sent on to the PK archive handler to be written out. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdstring.h" +#include "xdexcept.h" +#include "xpsproc.h" +#include "xpsfilew.h" + +static PCSTR szContentTypes = "[Content_Types].xml"; +static PCSTR szRelsPre = "_rels/"; +static PCSTR szRelsPost = ".rels"; + +/*++ + +Routine Name: + + CXPSProcessor::CXPSProcessor + +Routine Description: + + CXPSProcessor class constructor + +Arguments: + + pReadStream - Pointer to the print read stream + pWriteStream - Pointer to the print write stream + pPageProcessor - Pointer to the page processor interface + pPropertyBag - Pointer to the filter pipeline property bag + +Return Value: + + None + Throws CXDException(HRESULT) on an error + +--*/ +CXPSProcessor::CXPSProcessor( + _In_ IPrintReadStream* pReadStream, + _In_ IPrintWriteStream* pWriteStream, + _In_ IFixedPageProcessor* pPageProcessor, + _In_ IPrintPipelinePropertyBag* pPropertyBag, + _In_ CPTManager* pPtManager + ) : + m_xpsArchive(pReadStream, pWriteStream), + m_pSaxRdr(NULL), + m_pPageProcessor(pPageProcessor), + m_pPrintPropertyBag(pPropertyBag), + m_pPtManager(pPtManager) +{ + HRESULT hr = S_OK; + + CComPtr pFileReader(NULL); + + // + // Setup the SAX reader and extract the content types + // + if (SUCCEEDED(hr) && + SUCCEEDED(hr = CHECK_POINTER(pReadStream, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pWriteStream, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(m_pPageProcessor, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(m_pPtManager, E_POINTER)) && + SUCCEEDED(hr = m_pSaxRdr.CoCreateInstance(CLSID_SAXXMLReader60)) && + SUCCEEDED(hr = m_xpsArchive.GetFileStream(szContentTypes, &pFileReader)) && + SUCCEEDED(hr = m_pSaxRdr->putContentHandler(&m_contentTypes)) && + SUCCEEDED(hr = m_pSaxRdr->parse(CComVariant(pFileReader)))) + { + // + // We've got all the data we need - send it on + // + hr = m_xpsArchive.SendCurrentFile(); + } + + // + // Close the curent file ready for the next + // + m_xpsArchive.CloseCurrent(); + + if (FAILED(hr)) + { + throw CXDException(hr); + } +} + +/*++ + +Routine Name: + + CXPSProcessor::~CXPSProcessor + +Routine Description: + + CXPSProcessor class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CXPSProcessor::~CXPSProcessor() +{ +} + +/*++ + +Routine Name: + + CXPSProcessor::Start + +Routine Description: + + This routine kicks off the processing of the XPS archive struture. The + routine parses the Fixed Document Sequence mark-up to find the Fixed + Document parts, then parses the Fixed Document mark-up to find the Fixed + Page parts before passing these on to the Fixed Page processor. Additionally + the routine handles indentifying, processing and sending resources and part + relationships. Note: This limits the XPS document processing to only modifying + the fixed page data; the client is not presented the opportunity to modify any + other parts. + +Arguments: + + None + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CXPSProcessor::Start( + VOID + ) +{ + HRESULT hr = S_OK; + + try + { + // + // Get the start part list and iterate over all parts + // + FileList fixedDocumentSequenceParts; + if (SUCCEEDED(hr = GetFixedDocumentSequenceParts(&fixedDocumentSequenceParts))) + { + FileList::const_iterator iterFDS = fixedDocumentSequenceParts.begin(); + + for (; + iterFDS != fixedDocumentSequenceParts.end() && + SUCCEEDED(hr) && + SUCCEEDED(hr = ProcessRelsParts(*iterFDS, ContentFixedDocumentSequence)); + iterFDS++) + { + // + // Parse the start part retrieving the FD list - iterate over all FDs + // + FileList fixedDocumentParts; + if (SUCCEEDED(hr = GetFixedDocumentParts(*iterFDS, &fixedDocumentParts))) + { + FileList::const_iterator iterFD = fixedDocumentParts.begin(); + + for (; + iterFD != fixedDocumentParts.end() && + SUCCEEDED(hr) && + SUCCEEDED(hr = ProcessRelsParts(*iterFD, ContentFixedDocument)); + iterFD++) + { + // + // Parse the FD retrieving the FP list - iterate over all FPs + // + FileList fixedPageParts; + if (SUCCEEDED(hr = GetFixedPageParts(*iterFD, &fixedPageParts))) + { + FileList::const_iterator iterFP = fixedPageParts.begin(); + + for (; + iterFP != fixedPageParts.end() && + SUCCEEDED(hr) && + SUCCEEDED(hr = ProcessRelsParts(*iterFP, ContentFixedPage)); + iterFP++) + { + // + // Process the fixed page - this calls on to the IFixedPageProcessor + // interface for the client to do the work + // + hr = ProcessFixedPage(*iterFP); + } + } + } + } + } + } + } + catch (CXDException& e) + { + hr = e; + } + catch (exception& DBG_ONLY(e)) + { + ERR(e.what()); + hr = E_FAIL; + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CXPSProcessor::GetFixedDocumentSequenceParts + +Routine Description: + + This routine retrieves the Fixed Document Sequence from the root + relationships part. + +Arguments: + + pFixedDocumentSequencePartsList - List of fixed document sequences found to be populated + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CXPSProcessor::GetFixedDocumentSequenceParts( + _Inout_ FileList* pFixedDocumentSequencePartsList + ) +{ + HRESULT hr = S_OK; + + // + // Extract the .rels part to find the start part + // + if (SUCCEEDED(hr = CHECK_POINTER(pFixedDocumentSequencePartsList, E_POINTER)) && + SUCCEEDED(hr = GetRelsForPart(""))) + { + CONST RelsTypeList* pRelsTypeList = NULL; + + hr = m_rels.GetRelsTypeList("", &pRelsTypeList); + + RelsTypeList::const_iterator iterRels = pRelsTypeList->begin(); + + for (;iterRels != pRelsTypeList->end() && SUCCEEDED(hr); iterRels++) + { + if (iterRels->second == RelsStartPart) + { + // + // We have a start part add it to the part list + // + pFixedDocumentSequencePartsList->push_back(iterRels->first); + } + else + { + // + // Send any other part on + // + if (SUCCEEDED(hr = m_xpsArchive.InitialiseFile(iterRels->first)) && + SUCCEEDED(hr = m_xpsArchive.SendCurrentFile())) + { + m_xpsArchive.CloseCurrent(); + } + } + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CXPSProcessor::GetFixedDocumentParts + +Routine Description: + + This routine retrieves the list of fixed documents from the fixed document + sequence + +Arguments: + + szFixedDocSeq - The name of the FDS part to parse + pFixedDocumentParts - Pointer to the document list to be populated + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CXPSProcessor::GetFixedDocumentParts( + _In_ PCSTR szFixedDocSeq, + _Out_ FileList* pFixedDocumentParts + ) +{ + HRESULT hr = S_OK; + CComPtr pFileReader(NULL); + + // + // Set up the fixed document sequence as the current file in the + // XPS archive and parse the file stream using the FDS SAX content + // handler to retrieve all fixed documents in the sequence + // + if (SUCCEEDED(hr = CHECK_POINTER(szFixedDocSeq, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pFixedDocumentParts, E_POINTER)) && + SUCCEEDED(hr = m_contentTypes.ValidateContentType(szFixedDocSeq, ContentFixedDocumentSequence)) && + SUCCEEDED(hr = m_xpsArchive.GetFileStream(szFixedDocSeq, &pFileReader)) && + SUCCEEDED(hr = m_fixedDocSeq.Clear()) && + SUCCEEDED(hr = m_pSaxRdr->putContentHandler(&m_fixedDocSeq)) && + SUCCEEDED(hr = m_pSaxRdr->parse(CComVariant(pFileReader))) && + SUCCEEDED(hr = m_fixedDocSeq.GetFixedDocumentList(pFixedDocumentParts))) + { + // + // We are done with the FDS - send it on + // + hr = m_xpsArchive.SendCurrentFile(); + } + + // + // Close the curent file ready for the next + // + m_xpsArchive.CloseCurrent(); + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CXPSProcessor::GetFixedPageParts + +Routine Description: + + This routine retrieves the list of fixed pages from the Fixed Document + +Arguments: + + szFixedDoc - The name of the FD part to parse + pFixedPageParts - Pointer to the page list to be populated + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CXPSProcessor::GetFixedPageParts( + _In_ PCSTR szFixedDoc, + _Out_ FileList* pFixedPageParts + ) +{ + HRESULT hr = S_OK; + CComPtr pFileReader(NULL); + + // + // Set up the fixed document as the current file in the XPS + // archive and parse the file stream using the FD SAX content + // handler to retrieve all fixed pages in the document + // + if (SUCCEEDED(hr = CHECK_POINTER(szFixedDoc, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pFixedPageParts, E_POINTER)) && + SUCCEEDED(hr = m_contentTypes.ValidateContentType(szFixedDoc, ContentFixedDocument)) && + SUCCEEDED(hr = m_xpsArchive.GetFileStream(szFixedDoc, &pFileReader)) && + SUCCEEDED(hr = m_fixedDoc.Clear()) && + SUCCEEDED(hr = m_pSaxRdr->putContentHandler(&m_fixedDoc)) && + SUCCEEDED(hr = m_pSaxRdr->parse(CComVariant(pFileReader))) && + SUCCEEDED(hr = m_fixedDoc.GetFixedPageList(pFixedPageParts))) + { + // + // We are done with the FD - send it on + // + hr = m_xpsArchive.SendCurrentFile(); + } + + // + // Close the curent file ready for the next + // + m_xpsArchive.CloseCurrent(); + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CXPSProcessor::GetRelsForPart + +Routine Description: + + This routine retrieves and populates the rels object with the relationships + for the specified part + +Arguments: + + szPartName - The name of the part to retrieve the relationships for + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CXPSProcessor::GetRelsForPart( + _In_ PCSTR szPartName + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(szPartName, E_POINTER))) + { + try + { + CStringXDA cstrRelsPartName; + CComPtr pFileReader(NULL); + + // + // Construct the rels part from the parent part name and parse for + // relationships + // + if (SUCCEEDED(hr = MakeRelsPartName(szPartName, &cstrRelsPartName)) && + SUCCEEDED(hr = m_contentTypes.ValidateContentType(cstrRelsPartName, ContentRelationships)) && + SUCCEEDED(hr = m_xpsArchive.GetFileStream(cstrRelsPartName, &pFileReader)) && + SUCCEEDED(hr = m_pSaxRdr->putContentHandler(&m_rels)) && + SUCCEEDED(hr = m_rels.SetCurrentFileName(szPartName)) && + SUCCEEDED(hr = m_pSaxRdr->parse(CComVariant(pFileReader)))) + { + // + // We are done with the .rels part - send it on + // + hr = m_xpsArchive.SendCurrentFile(); + } + + // + // Close the curent file ready for the next + // + m_xpsArchive.CloseCurrent(); + } + catch (CXDException& e) + { + hr = e; + } + } + + ERR_ON_HR_EXC(hr, E_ELEMENT_NOT_FOUND); + return hr; +} + +/*++ + +Routine Name: + + CXPSProcessor::MakeRelsPartName + +Routine Description: + + This routine converts a part name into the appropriate .rels name. + The rules for naming are: + rels parts are stored in a directory named _rels relative to the current part + rels parts always end in .rels + e.g. \Documents\FixedDoc.fdseq has rels part \Documents\_rels\FixedDoc.fdseq.rels + +Arguments: + + szPartName - The name of the part to be converted + pcstrRelsPartName - Pointer to a CStringXDA that recieves the new name + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CXPSProcessor::MakeRelsPartName( + _In_ PCSTR szPartName, + _Out_ CStringXDA* pcstrRelsPartName + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(szPartName, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pcstrRelsPartName, E_POINTER))) + { + try + { + *pcstrRelsPartName = szPartName; + + // + // Find the slash that splits the directory and part name + // + INT cLastSlash = -1; + for (;;) + { + INT cSlash = pcstrRelsPartName->Find("/", cLastSlash + 1); + + if (cSlash != -1) + { + cLastSlash = cSlash; + } + else + { + break; + } + } + cLastSlash++; + + // + // Insert "_rels/" after the slash and append ".rels" + // + pcstrRelsPartName->Insert(cLastSlash, szRelsPre); + pcstrRelsPartName->Append(szRelsPost); + } + catch (CXDException& e) + { + hr = e; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CXPSProcessor::ProcessRelsParts + +Routine Description: + + This routine processes the related parts for a given part + +Arguments: + + szPartName - The name of the part + eContentType - The type of the part to be processed. This must be either an FDS, FD or FP. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CXPSProcessor::ProcessRelsParts( + _In_ PCSTR szPartName, + _In_ CONST EContentType eContentType + ) +{ + HRESULT hr = S_OK; + + BOOL bPrintTicketSent = FALSE; + + if (SUCCEEDED(hr = CHECK_POINTER(szPartName, E_POINTER))) + { + if (eContentType != ContentFixedDocumentSequence && + eContentType != ContentFixedDocument && + eContentType != ContentFixedPage) + { + hr = E_INVALIDARG; + } + } + + if (SUCCEEDED(hr)) + { + try + { + // + // Validate the part content type + // Get the rels and handle any print tickets + // + CONST RelsTypeList* pRelsTypeList; + if (SUCCEEDED(hr = m_contentTypes.ValidateContentType(szPartName, eContentType)) && + SUCCEEDED(hr = GetRelsForPart(szPartName)) && + SUCCEEDED(hr = m_rels.GetRelsTypeList(szPartName, &pRelsTypeList))) + { + + RelsTypeList::const_iterator iterRels = pRelsTypeList->begin(); + + for (;iterRels != pRelsTypeList->end() && SUCCEEDED(hr); iterRels++) + { + // + // Strip any leading "/" + // + CStringXDA cstrName(iterRels->first); + if (cstrName.GetAt(0) == '/') + { + cstrName.Delete(0); + } + + // + // The second of the pair in the RelsTypeList iterator is the rels type + // + switch (iterRels->second) + { + case RelsPrintTicket: + { + hr = AddPrintTicket(cstrName, eContentType); + bPrintTicketSent = TRUE; + } + break; + + case RelsAnnotations: + case RelsDigitalSignatureDefinitions: + case RelsDiscardControl: + case RelsDocumentStructure: + case RelsRequiredResource: + case RelsRestrictedFont: + case RelsStoryFragments: + case RelsCoreProperties: + case RelsDigitalSignature: + case RelsDigitalSignatureCertificate: + case RelsDigitalSignatureOrigin: + case RelsThumbnail: + { + // + // We are not interested in the content so intialise the current + // file in the XPS archive and send it on + // + if (SUCCEEDED(hr = m_xpsArchive.InitialiseFile(cstrName))) + { + hr = m_xpsArchive.SendCurrentFile(); + } + } + break; + + default: + { + ERR("Unrecognised rels part\n"); + + hr = E_FAIL; + } + break; + } + + // + // Close the current file ready for the next + // + m_xpsArchive.CloseCurrent(); + } + } + else if (hr == E_ELEMENT_NOT_FOUND) + { + // + // There is no PrintTicket + // + hr = S_OK; + } + + // + // No print ticket has been sent so just inform the print ticket + // manager that a suitable ticket needs to be set for this level + // + if (bPrintTicketSent == FALSE) + { + switch (eContentType) + { + case ContentFixedPage: + { + hr = m_pPtManager->SetTicket(kPTPageScope, NULL); + } + break; + case ContentFixedDocument: + { + hr = m_pPtManager->SetTicket(kPTDocumentScope, NULL); + } + break; + case ContentFixedDocumentSequence: + { + hr = m_pPtManager->SetTicket(kPTJobScope, NULL); + } + break; + default: + { + hr = ERROR_NOT_SUPPORTED; + } + break; + } + } + } + catch (CXDException& e) + { + hr = e; + } + catch (exception& DBG_ONLY(e)) + { + ERR(e.what()); + hr = E_FAIL; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CXPSProcessor::AddPrintTicket + +Routine Description: + + This routine retrieves the PrintTicket information and updates the PrintTicket + manager at the appropriate scope + +Arguments: + + szPTPartName - The part name for the PrintTicket + eContentType - The type of the containing part. This must be either an FDS, FD or FP. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CXPSProcessor::AddPrintTicket( + _In_ PCSTR szPTPartName, + _In_ CONST EContentType eContentType + ) +{ + HRESULT hr = S_OK; + + // + // Validate the parameters + // + if (SUCCEEDED(hr = CHECK_POINTER(szPTPartName, E_POINTER))) + { + if (eContentType != ContentFixedDocumentSequence && + eContentType != ContentFixedDocument && + eContentType != ContentFixedPage) + { + hr = E_INVALIDARG; + } + } + + // + // Extract the PrintTicket from the current file in the XPS archive + // and pass to the PrinTicket manager at the appropriate scope + // + CComPtr pFileReader(NULL); + CComPtr pPT(NULL); + + VARIANT_BOOL fLoaded = VARIANT_FALSE; + + if (SUCCEEDED(hr) && + SUCCEEDED(hr = m_xpsArchive.GetFileStream(szPTPartName, &pFileReader)) && + SUCCEEDED(hr = pPT.CoCreateInstance(CLSID_DOMDocument60)) && + SUCCEEDED(hr = pPT->load(CComVariant(pFileReader), &fLoaded))) + { + if (fLoaded == VARIANT_TRUE) + { + // + // Determine the scope from the parent parts content type + // + EPrintTicketScope ePTScope = kPTPageScope; + + if (eContentType == ContentFixedDocumentSequence) + { + ePTScope = kPTJobScope; + } + else if (eContentType == ContentFixedDocument) + { + ePTScope = kPTDocumentScope; + } + + if (SUCCEEDED(hr = m_pPtManager->SetTicket(ePTScope, pPT))) + { + // + // Make sure the PrintTicket is passed on + // + hr = m_xpsArchive.SendCurrentFile(); + } + } + else + { + ERR("Failed to load PT\n"); + + hr = E_FAIL; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CXPSProcessor::AddPrintTicket + +Routine Description: + + This routine intialises the appropriate read and write streams for a fixed + page processor and calls the processor to do the work + +Arguments: + + szFPPartName - The name of the FixedPage part + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CXPSProcessor::ProcessFixedPage( + _In_ PCSTR szFPPartName + ) +{ + HRESULT hr = S_OK; + // + // Retrieve the file stream and pass to the page scaling handler + // + CComPtr pFileReader(NULL); + CXPSWriteFile* pXpsWriteFile = new(std::nothrow) CXPSWriteFile(szFPPartName); + + IXMLDOMDocument2* pPT = NULL; + + if (SUCCEEDED(hr = CHECK_POINTER(pXpsWriteFile, E_OUTOFMEMORY)) && + SUCCEEDED(hr = CHECK_POINTER(m_pPageProcessor, E_PENDING)) && + SUCCEEDED(hr = CHECK_POINTER(szFPPartName, E_PENDING)) && + SUCCEEDED(hr = m_xpsArchive.GetFileStream(szFPPartName, &pFileReader)) && + SUCCEEDED(hr = m_pPtManager->GetTicket(kPTPageScope, &pPT)) && + SUCCEEDED(hr = CHECK_POINTER(pPT, E_FAIL)) && + SUCCEEDED(hr = m_pPageProcessor->ProcessFixedPage(pPT, pFileReader, pXpsWriteFile))) + { + // + // Send the new fixed page + // + ULONG cb = 0; + PVOID pv = NULL; + + if (SUCCEEDED(hr = pXpsWriteFile->GetBuffer(&pv, &cb))) + { + hr = m_xpsArchive.SendFile(szFPPartName, pv, cb, CompDeflated); + } + } + else if (hr == HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED)) + { + // + // The page processor does not want to do any work - just send the page + // + hr = m_xpsArchive.SendCurrentFile(); + } + + if (pXpsWriteFile != NULL) + { + delete pXpsWriteFile; + pXpsWriteFile = NULL; + } + + // + // Close the current file ready for the next + // + m_xpsArchive.CloseCurrent(); + + ERR_ON_HR(hr); + return hr; +} diff --git a/print/XPSDrvSmpl/src/filters/xdcont/xpsproc.h b/print/XPSDrvSmpl/src/filters/xdcont/xpsproc.h new file mode 100644 index 00000000..70b08ec6 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/xdcont/xpsproc.h @@ -0,0 +1,137 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + xpsproc.h + +Abstract: + + Definition of the XPS processor. This class is responsible for handling + the logical document and page structure of the XPS container. The class starts + with the content types part and .rels part to find the Fixed Document Sequence. + It then parses the FDS to find the Fixed Documents and finally the FDs to find + each Fixed Page. Each fixed page is then reported to a client FixedPageProcessor + to interpret the mark-up and write out modifications as required. The class is + additionally responsible for ensuring all XPS parts and accompanying resources are + sent on to the PK archive handler to be written out. + +--*/ + +#pragma once + +#include "xps.h" +#include "xpsarch.h" +#include "xpstype.h" +#include "xpsrels.h" +#include "xpsfds.h" +#include "xpsfd.h" +#include "ptmanage.h" + +class IFixedPageProcessor +{ +public: + IFixedPageProcessor(){} + + virtual ~IFixedPageProcessor(){} + + virtual HRESULT + ProcessFixedPage( + _In_ IXMLDOMDocument2* pFPPT, + _In_ ISequentialStream* pPageReadStream, + _Out_ ISequentialStream* pPageWriteStream + ) = 0; +}; + +class CXPSProcessor +{ +public: + CXPSProcessor( + _In_ IPrintReadStream* pReadStream, + _In_ IPrintWriteStream* pWriteStream, + _In_ IFixedPageProcessor* pPageProcessor, + _In_ IPrintPipelinePropertyBag* pPropertyBag, + _In_ CPTManager* pPtManager + ); + + virtual ~CXPSProcessor(); + + HRESULT + Start( + VOID + ); + +private: + HRESULT + GetFixedDocumentSequenceParts( + _Inout_ FileList* pFixedDocumentSequenceParts + ); + + HRESULT + GetFixedDocumentParts( + _In_ PCSTR szFixedDocSeq, + _Out_ FileList* pFixedDocumentParts + ); + + HRESULT + GetFixedPageParts( + _In_ PCSTR szFixedDoc, + _Out_ FileList* pFixedPageParts + ); + + HRESULT + GetRelsForPart( + _In_ PCSTR szPartName + ); + + HRESULT + MakeRelsPartName( + _In_ PCSTR szPartName, + _Out_ CStringXDA* pcstrRelsPartName + ); + + HRESULT + ProcessRelsParts( + _In_ PCSTR szPartName, + _In_ CONST EContentType contentType + ); + + HRESULT + AddPrintTicket( + _In_ PCSTR szPartName, + _In_ CONST EContentType eContentType + ); + + HRESULT + ProcessFixedPage( + _In_ PCSTR szPartName + ); + +private: + CXPSArchive m_xpsArchive; + + CContentTypes m_contentTypes; + + CRels m_rels; + + CFixedDocumentSequence m_fixedDocSeq; + + CFixedDocument m_fixedDoc; + + CComPtr m_pSaxRdr; + + IFixedPageProcessor* m_pPageProcessor; + + CPTManager* m_pPtManager; + + CComPtr m_pPrintPropertyBag; +}; + diff --git a/print/XPSDrvSmpl/src/filters/xdcont/xpsrels.cpp b/print/XPSDrvSmpl/src/filters/xdcont/xpsrels.cpp new file mode 100644 index 00000000..8bb8fed8 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/xdcont/xpsrels.cpp @@ -0,0 +1,419 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + xpsrels.cpp + +Abstract: + + Implementation of the XPS rels part SAX handler. This class is responsible + for retrieving all the rels parts for a particular rels file and storing + them for access by the XPS processor. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdstring.h" +#include "xdexcept.h" +#include "xpsrels.h" + +static PCSTR szRelationship = "Relationship"; +static PCSTR szTarget = "Target"; +static PCSTR szType = "Type"; + +static PCSTR szRels[ERelsTypeMax] = { + "http://schemas.microsoft.com/xps/2005/06/annotations", + "http://schemas.microsoft.com/xps/2005/06/signature-definitions", + "http://schemas.microsoft.com/xps/2005/06/discard-control", + "http://schemas.microsoft.com/xps/2005/06/documentstructure", + "http://schemas.microsoft.com/xps/2005/06/printticket", + "http://schemas.microsoft.com/xps/2005/06/required-resource", + "http://schemas.microsoft.com/xps/2005/06/restricted-font", + "http://schemas.microsoft.com/xps/2005/06/fixedrepresentation", + "http://schemas.microsoft.com/xps/2005/06/storyfragments", + "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties", + "http://schemas.openxmlformats.org/package/2006/relationships/digital-signature/signature", + "http://schemas.openxmlformats.org/package/2006/relationships/digital-signature/certificate", + "http://schemas.openxmlformats.org/package/2006/relationships/digital-signature/origin", + "http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail", +}; + +/*++ + +Routine Name: + + CRels::CRels + +Routine Description: + + CRels class constructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CRels::CRels() +{ +} + +/*++ + +Routine Name: + + CRels::~CRels + +Routine Description: + + CRels class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CRels::~CRels() +{ +} + +/*++ + +Routine Name: + + CRels::startElement + +Routine Description: + + This routine is the startElement method of the SAX handler. This is used + to parse a relationships part mark-up retrieving and storing the list of + relationships + +Arguments: + + pwchNamespaceUri - Unused: Local namespace URI + cchNamespaceUri - Unused: Length of the namespace URI + pwchLocalName - Unused: Local name string + cchLocalName - Unused: Length of the local name string + pwchQName - The qualified name with prefix + cchQName - The length of the qualified name with prefix + pAttributes - Pointer to the ISAXAttributes interface containing attributes attached to the element + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT STDMETHODCALLTYPE +CRels::startElement( + CONST wchar_t*, + INT, + CONST wchar_t*, + INT, + _In_reads_(cchQName) CONST wchar_t* pwchQName, + _In_ INT cchQName, + _In_ ISAXAttributes* pAttributes + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pwchQName, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pAttributes, E_POINTER))) + { + if (cchQName <= 0) + { + hr = E_INVALIDARG; + } + } + + try + { + CStringXDA cstrElementName(pwchQName, cchQName); + + if (SUCCEEDED(hr) && + cstrElementName == szRelationship) + { + CStringXDA cstrTargetName; + CStringXDA cstrRelsType; + + INT cAttributes = 0; + + if (SUCCEEDED(hr)) + { + hr = pAttributes->getLength(&cAttributes); + } + + // + // Run over all attributes identifying part names and part types + // + for (INT cIndex = 0; cIndex < cAttributes && SUCCEEDED(hr); cIndex++) + { + PCWSTR pszAttUri = NULL; + INT cchAttUri = 0; + PCWSTR pszAttName = NULL; + INT cchAttName = 0; + PCWSTR pszAttQName = NULL; + INT cchAttQName = 0; + PCWSTR pszAttValue = NULL; + INT cchAttValue = 0; + + // + // Get the attribute data ready to write out + // + if (SUCCEEDED(hr = pAttributes->getName(cIndex, &pszAttUri, &cchAttUri, &pszAttName, &cchAttName, &pszAttQName, &cchAttQName)) && + SUCCEEDED(hr = pAttributes->getValue(cIndex, &pszAttValue, &cchAttValue))) + { + CStringXDA cstrAttName(pszAttQName, cchAttQName); + CStringXDA cstrAttValue(pszAttValue, cchAttValue); + + if (cstrAttName == szTarget) + { + cstrTargetName = cstrAttValue; + } + else if (cstrAttName == szType) + { + cstrRelsType = cstrAttValue; + } + } + } + + if (cstrTargetName.GetLength() > 0) + { + if (cstrRelsType.GetLength() > 0) + { + ERelsType relsType; + if (SUCCEEDED(hr = GetRelsTypeFromString(cstrRelsType, &relsType))) + { + // + // Strip any leading "/" + // + if (cstrTargetName.GetAt(0) == '/') + { + cstrTargetName.Delete(0); + } + + try + { + m_relsMap[m_cstrCurrentFileName].push_back(RelsNameType(cstrTargetName, relsType)); + } + catch (exception& DBG_ONLY(e)) + { + ERR(e.what()); + hr = E_FAIL; + } + } + } + else + { + RIP("Target name identified with no corresponding type\n"); + + hr = E_FAIL; + } + } + } + } + catch (CXDException& e) + { + hr = e; + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CRels::SetCurrentFileName + +Routine Description: + + This routine sets the filename of the part for which the relationships + are being identified + +Arguments: + + szFileName - The name of the XPS part + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CRels::SetCurrentFileName( + _In_ PCSTR szFileName + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(szFileName, E_POINTER))) + { + try + { + m_cstrCurrentFileName = szFileName; + } + catch (CXDException& e) + { + hr = e; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CRels::GetRelsTypeList + +Routine Description: + + This routine retrieves the list of the relationships for the specified + part name + +Arguments: + + szFileName - The name of the XPS part to retrieve the relationships list for + ppFileList - Pointer to a RelsTypeList pointer that recieves the relationships list + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CRels::GetRelsTypeList( + _In_ PCSTR szFileName, + _Outptr_ CONST RelsTypeList** ppFileList + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(ppFileList, E_POINTER))) + { + try + { + RelsMap::const_iterator iterRels = m_relsMap.find(szFileName); + if (iterRels != m_relsMap.end()) + { + *ppFileList = &(iterRels->second); + } + else + { + hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND); + } + } + catch (CXDException& e) + { + hr = e; + } + catch (exception& DBG_ONLY(e)) + { + ERR(e.what()); + hr = E_FAIL; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CRels::GetRelsTypeFromString + +Routine Description: + + This routine retrieves the relationship enumeration defining the type from the + relationships string defining the type + +Arguments: + + cstrRelsType - The string defining the rels type + pRelsType - Pointer to the rels type that recieves the type + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CRels::GetRelsTypeFromString( + _In_ CONST CStringXDA& cstrRelsType, + _Out_ ERelsType* pRelsType + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pRelsType, E_POINTER))) + { + *pRelsType = RelsUnknown; + + try + { + if (cstrRelsType.GetLength() > 0) + { + for (ERelsType relsType = ERelsTypeMin; + relsType < ERelsTypeMax; + relsType = static_cast(relsType + 1)) + { + if (cstrRelsType.CompareNoCase(szRels[relsType]) == 0) + { + *pRelsType = relsType; + break; + } + } + + if (*pRelsType == RelsUnknown) + { + ERR("Unrecognized relationships type string.\n"); + + hr = E_FAIL; + } + } + else + { + hr = E_INVALIDARG; + } + } + catch (CXDException& e) + { + hr = e; + } + } + + ERR_ON_HR(hr); + return hr; +} diff --git a/print/XPSDrvSmpl/src/filters/xdcont/xpsrels.h b/print/XPSDrvSmpl/src/filters/xdcont/xpsrels.h new file mode 100644 index 00000000..29ee4a9c --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/xdcont/xpsrels.h @@ -0,0 +1,70 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + xpsrels.h + +Abstract: + + Definition of the XPS rels part SAX handler. This class is responsible + for retrieving all the rels parts for a particular rels file and storing + them for access by the XPS processor. + +--*/ + +#pragma once + +#include "saxhndlr.h" +#include "xps.h" + +class CRels : public CSaxHandler +{ +public: + CRels(); + + virtual ~CRels(); + + virtual HRESULT STDMETHODCALLTYPE + startElement( + CONST wchar_t*, + INT, + CONST wchar_t*, + INT, + _In_reads_(cchQName) CONST wchar_t* pwchQName, + _In_ INT cchQName, + _In_ ISAXAttributes* pAttributes + ); + + HRESULT + GetRelsTypeList( + _In_ PCSTR szFileName, + _Outptr_ CONST RelsTypeList** ppFileList + ); + + HRESULT + SetCurrentFileName( + _In_ PCSTR szFileName + ); + +private: + HRESULT + GetRelsTypeFromString( + _In_ CONST CStringXDA& cstrRelsType, + _Out_ ERelsType* pRelsType + ); + +private: + RelsMap m_relsMap; + + CStringXDA m_cstrCurrentFileName; +}; + diff --git a/print/XPSDrvSmpl/src/filters/xdcont/xpstype.cpp b/print/XPSDrvSmpl/src/filters/xdcont/xpstype.cpp new file mode 100644 index 00000000..35dca7cf --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/xdcont/xpstype.cpp @@ -0,0 +1,417 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + xpstype.cpp + +Abstract: + + Implementation of the XPS content type part SAX handler. This class is responsible + for retrieving all the content types information and storing them for access by the + XPS processor. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdstring.h" +#include "xdexcept.h" +#include "xpstype.h" + +static PCSTR szCTOverride = "Override"; +static PCSTR szCTPartName = "PartName"; +static PCSTR szCTContentType = "ContentType"; +static PCSTR szCTDefault = "Default"; +static PCSTR szCTExtension = "Extension"; + +static PCSTR szContentType[EContentTypeMax] = { + "application/vnd.ms-package.xps-fixeddocumentsequence+xml", + "application/vnd.ms-package.xps-fixeddocument+xml", + "application/vnd.ms-package.xps-fixedpage+xml", + "application/vnd.ms-package.xps-discard-control+xml", + "application/vnd.ms-package.xps-documentstructure+xml", + "application/vnd.ms-opentype", + "application/vnd.ms-color.iccprofile", + "application/vnd.ms-package.obfuscated-opentype", + "application/vnd.ms-printing.printticket+xml", + "application/vnd.ms-package.xps-resourcedictionary+xml", + "application/vnd.ms-package.xps-storyfragments+xml", + "image/jpeg", + "image/png", + "image/tiff", + "image/vnd.ms-photo", + "application/vnd.openxmlformats-package.core-properties+xml", + "application/vnd.openxmlformats-package.digital-signature-certificate", + "application/vnd.openxmlformats-package.digital-signature-origin", + "application/vnd.openxmlformats-package.digital-signature-xmlsignature+xml", + "application/vnd.openxmlformats-package.relationships+xml", +}; + +/*++ + +Routine Name: + + CContentTypes::CContentTypes + +Routine Description: + + CContentTypes class constructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CContentTypes::CContentTypes() +{ +} + +/*++ + +Routine Name: + + CContentTypes::~CContentTypes + +Routine Description: + + CContentTypes class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CContentTypes::~CContentTypes() +{ +} + +/*++ + +Routine Name: + + CContentTypes::startElement + +Routine Description: + + This routine is the startElement method of the SAX handler. This is used + to parse the content types part mark-up retrieving and storing the list of + content types + +Arguments: + + pwchNamespaceUri - Unused: Local namespace URI + cchNamespaceUri - Unused: Length of the namespace URI + pwchLocalName - Unused: Local name string + cchLocalName - Unused: Length of the local name string + pwchQName - The qualified name with prefix + cchQName - The length of the qualified name with prefix + pAttributes - Pointer to the ISAXAttributes interface containing attributes attached to the element + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT STDMETHODCALLTYPE +CContentTypes::startElement( + CONST wchar_t*, + INT, + CONST wchar_t*, + INT, + _In_reads_(cchQName) CONST wchar_t* pwchQName, + _In_ INT cchQName, + _In_ ISAXAttributes* pAttributes + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pwchQName, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pAttributes, E_POINTER))) + { + if (cchQName <= 0) + { + hr = E_INVALIDARG; + } + } + + try + { + CStringXDA cstrElementName(pwchQName, cchQName); + + if (cstrElementName == szCTOverride || + cstrElementName == szCTDefault) + { + CStringXDA cstrPartName; + CStringXDA cstrPartType; + + INT cAttributes = 0; + + if (SUCCEEDED(hr)) + { + hr = pAttributes->getLength(&cAttributes); + } + + // + // Run over all attributes identifying part names and part types + // + for (INT cIndex = 0; cIndex < cAttributes && SUCCEEDED(hr); cIndex++) + { + PCWSTR pszAttUri = NULL; + INT cchAttUri = 0; + PCWSTR pszAttName = NULL; + INT cchAttName = 0; + PCWSTR pszAttQName = NULL; + INT cchAttQName = 0; + PCWSTR pszAttValue = NULL; + INT cchAttValue = 0; + + // + // Get the attribute data ready to write out + // + if (SUCCEEDED(hr = pAttributes->getName(cIndex, &pszAttUri, &cchAttUri, &pszAttName, &cchAttName, &pszAttQName, &cchAttQName)) && + SUCCEEDED(hr = pAttributes->getValue(cIndex, &pszAttValue, &cchAttValue))) + { + CStringXDA cstrAttName(pszAttQName, cchAttQName); + CStringXDA cstrAttValue(pszAttValue, cchAttValue); + + if (cstrAttName == szCTPartName || + cstrAttName == szCTExtension) + { + cstrPartName = cstrAttValue; + } + else if (cstrAttName == szCTContentType) + { + cstrPartType = cstrAttValue; + } + } + } + + if (cstrPartName.GetLength() > 0) + { + if (cstrPartType.GetLength() > 0) + { + EContentType contentType; + if (SUCCEEDED(hr = GetContentTypeFromString(cstrPartType, &contentType))) + { + // + // Strip any leading "/" + // + if (cstrPartName.GetAt(0) == '/') + { + cstrPartName.Delete(0); + } + + try + { + m_contentMap[cstrPartName] = contentType; + } + catch (exception& DBG_ONLY(e)) + { + ERR(e.what()); + hr = E_FAIL; + } + } + } + else + { + RIP("Part name identified with no corresponding type\n"); + + hr = E_FAIL; + } + } + } + } + catch (CXDException& e) + { + hr = e; + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CContentTypes::ValidateContentType + +Routine Description: + + This routine validates a part against a content type + +Arguments: + + szPartName - The name of the XPS part + contentType - The content type to validate against + +Return Value: + + HRESULT + S_OK - On success + E_ELEMENT_NOT_FOUND - When the part is not present + E_* - On error + +--*/ +HRESULT +CContentTypes::ValidateContentType( + _In_ PCSTR szPartName, + _In_ CONST EContentType contentType + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(szPartName, E_POINTER))) + { + try + { + CStringXDA cstrPartName(szPartName); + + if (cstrPartName.GetLength() > 0) + { + // + // Check if the content type is defined for the full part name + // + ContentMap::const_iterator iterContents = m_contentMap.find(cstrPartName); + if (iterContents == m_contentMap.end()) + { + // + // Check if the type is defined by the extension + // + CStringXDA partExt(PathFindExtensionA(cstrPartName)); + + // + // Strip any leading "/" + // + if (partExt.GetAt(0) == '/') + { + partExt.Delete(0); + } + + iterContents = m_contentMap.find(partExt); + } + + if (iterContents != m_contentMap.end()) + { + if (contentType != iterContents->second) + { + hr = E_FAIL; + } + } + else + { + hr = E_ELEMENT_NOT_FOUND; + } + } + else + { + hr = E_INVALIDARG; + } + } + catch (CXDException& e) + { + hr = e; + } + catch (exception& DBG_ONLY(e)) + { + ERR(e.what()); + hr = E_FAIL; + } + } + + ERR_ON_HR_EXC(hr, E_ELEMENT_NOT_FOUND); + return hr; +} + +/*++ + +Routine Name: + + CContentTypes::GetContentTypeFromString + +Routine Description: + + This routine retrieves the content type enumeration defining the type from the + content type string defining the type + +Arguments: + + cstrPartType - The string defining the content type + pContentType - Pointer to the content type that recieves the type + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CContentTypes::GetContentTypeFromString( + _In_ CONST CStringXDA& cstrPartType, + _Out_ EContentType* pContentType + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pContentType, E_POINTER))) + { + *pContentType = ContentUnknown; + + try + { + if (cstrPartType.GetLength() > 0) + { + for (EContentType contentType = EContentTypeMin; + contentType < EContentTypeMax; + contentType = static_cast(contentType + 1)) + { + if (cstrPartType.CompareNoCase(szContentType[contentType]) == 0) + { + *pContentType = contentType; + break; + } + } + + if (*pContentType == ContentUnknown) + { + ERR("Unrecognized content type string.\n"); + + hr = E_FAIL; + } + } + else + { + hr = E_INVALIDARG; + } + } + catch (CXDException& e) + { + hr = e; + } + } + + ERR_ON_HR(hr); + return hr; +} + diff --git a/print/XPSDrvSmpl/src/filters/xdcont/xpstype.h b/print/XPSDrvSmpl/src/filters/xdcont/xpstype.h new file mode 100644 index 00000000..0a5b5b06 --- /dev/null +++ b/print/XPSDrvSmpl/src/filters/xdcont/xpstype.h @@ -0,0 +1,63 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + xpstype.h + +Abstract: + + Definition of the XPS content type part SAX handler. This class is responsible + for retrieving all the content types information and storing them for access by the + XPS processor. + +--*/ + +#pragma once + +#include "saxhndlr.h" +#include "xps.h" + +class CContentTypes : public CSaxHandler +{ +public: + CContentTypes(); + + virtual ~CContentTypes(); + + virtual HRESULT STDMETHODCALLTYPE + startElement( + CONST wchar_t*, + INT, + CONST wchar_t*, + INT, + _In_reads_(cchQName) CONST wchar_t* pwchQName, + _In_ INT cchQName, + _In_ ISAXAttributes* pAttributes + ); + + HRESULT + ValidateContentType( + _In_ PCSTR szPartName, + _In_ CONST EContentType contentType + ); + +private: + HRESULT + GetContentTypeFromString( + _In_ CONST CStringXDA& cstrPartType, + _Out_ EContentType* pContentType + ); + +private: + ContentMap m_contentMap; +}; + diff --git a/print/XPSDrvSmpl/src/inc/cunknown.h b/print/XPSDrvSmpl/src/inc/cunknown.h new file mode 100644 index 00000000..c7cceff0 --- /dev/null +++ b/print/XPSDrvSmpl/src/inc/cunknown.h @@ -0,0 +1,212 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + cunknown.h + +Abstract: + + Provides a simple template implementation for classes that need to + implement IUnknown. + +--*/ + +#pragma once + +template +class CUnknown : public _T +{ +public: + /*++ + + Routine Name: + + CUnknown + + Routine Description: + + CUnknown class constructor + + Arguments: + + IIDTarget - The target interface guid + + Return Value: + + None + + --*/ + CUnknown( + REFIID IIDTarget + ) : + m_IIDTarget(IIDTarget), + m_cRef(1) + { + } + + /*++ + + Routine Name: + + ~CUnknown + + Routine Description: + + CUnknown class destructor + + Arguments: + + None + + Return Value: + + None + + --*/ + virtual ~CUnknown() + { + } + + // + // IUnknown methods + // + /*++ + + Routine Name: + + QueryInterface + + Routine Description: + + This routine implements the IUnknown::QueryInterface method. Returns the raw interface + pointer for the requested IID if it matches the target IID + + Arguments: + + riid - The IID of the requested interface + ppv - The raw interface pointer + + Return Value: + + HRESULT + S_OK - On success + E_* - On error + + --*/ + virtual HRESULT STDMETHODCALLTYPE + QueryInterface( + REFIID riid, + _Out_ PVOID* ppv + ) + { + HRESULT hr = S_OK; + + if (ppv != NULL) + { + if (riid == IID_IUnknown || + riid == m_IIDTarget) + { + *ppv = static_cast<_T*>(this); + } + else + { + *ppv = NULL; + + hr = E_NOINTERFACE; + } + } + else + { + hr = E_POINTER; + } + + if (SUCCEEDED(hr)) + { + AddRef(); + } + + return hr; + } + + /*++ + + Routine Name: + + AddRef + + Routine Description: + + This routine increments the reference count on the current interface + + Arguments: + + None + + Return Value: + + HRESULT + S_OK - On success + E_* - On error + + --*/ + virtual ULONG STDMETHODCALLTYPE + AddRef() + { + return InterlockedIncrement(&m_cRef); + } + + /*++ + + Routine Name: + + Release + + Routine Description: + + This routine decrements the reference count on the current interface + + Arguments: + + None + + Return Value: + + HRESULT + S_OK - On success + E_* - On error + + Notes: + + The drv_at annotation tells Prefast to consider this object's memory + freed after Release has been called. + + --*/ + virtual + ULONG STDMETHODCALLTYPE + Release() + { + ULONG cRef = InterlockedDecrement(&m_cRef); + + if (0 == cRef) + { + delete this; + } + + return cRef; + } + +private: + LONG m_cRef; + + IID m_IIDTarget; +}; + diff --git a/print/XPSDrvSmpl/src/inc/gdip.h b/print/XPSDrvSmpl/src/inc/gdip.h new file mode 100644 index 00000000..923c3430 --- /dev/null +++ b/print/XPSDrvSmpl/src/inc/gdip.h @@ -0,0 +1,121 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + gdip.h + +Abstract: + + Provides a wrapper class around GDIPlus that takes care of intialisation + and shutdown. A class only need define this as a member variable to use + GDIPlus - intialisation and shutdown are handled during construction and + destruction. + +Known issues: + + The class does not yet implement debug event handling. + +--*/ + +#pragma once + +class GDIPlus +{ +public: + /*++ + + Routine Name: + + GDIPlus + + Routine Description: + + GDIPlus class constructor + + Arguments: + + None + + Return Value: + + None + + --*/ + GDIPlus() : + m_pGDIPlusToken(NULL), + m_GDIPlusStartStatus(GdiplusNotInitialized) + { + GdiplusStartupInput gdiPlusStartInput; + + m_GDIPlusStartStatus = GdiplusStartup(&m_pGDIPlusToken, &gdiPlusStartInput, NULL); + } + + /*++ + + Routine Name: + + ~GDIPlus + + Routine Description: + + GDIPlus class destructor + + Arguments: + + None + + Return Value: + + None + + --*/ + virtual ~GDIPlus() + { + GdiplusShutdown(m_pGDIPlusToken); + m_pGDIPlusToken = NULL; + m_GDIPlusStartStatus = GdiplusNotInitialized; + } + + /*++ + + Routine Name: + + GetGDIPlusStartStatus + + Routine Description: + + This routine returns the start status of GDI Plus + + Arguments: + + None + + Return Value: + + Gdiplus::Status + Ok - On success + Gdiplus error - On Error + + --*/ + Status GetGDIPlusStartStatus( + VOID + ) + { + return m_GDIPlusStartStatus; + } + +private: + ULONG_PTR m_pGDIPlusToken; + + Status m_GDIPlusStartStatus; +}; + diff --git a/print/XPSDrvSmpl/src/inc/ipkarch.h b/print/XPSDrvSmpl/src/inc/ipkarch.h new file mode 100644 index 00000000..7721a2db --- /dev/null +++ b/print/XPSDrvSmpl/src/inc/ipkarch.h @@ -0,0 +1,230 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + ipkarch.h + +Abstract: + + Definition of the interface supported by the PK archive handling module. + +--*/ + +#pragma once + +#include "ipkfile.h" + +// +// {5A0F4115-D4D3-401e-8071-A440D6D07092} +// +DEFINE_GUID(CLSID_PKArchiveHandler, 0x5a0f4115, 0xd4d3, 0x401e, 0x80, 0x71, 0xa4, 0x40, 0xd6, 0xd0, 0x70, 0x92); + +// +// {BDBBDF56-C742-4efd-8075-AF2C7B247F38} +// +DEFINE_GUID(IID_IPKArchive, 0xbdbbdf56, 0xc742, 0x4efd, 0x80, 0x75, 0xaf, 0x2c, 0x7b, 0x24, 0x7f, 0x38); + + +typedef map NameIndex; + +class IPKArchive : public IUnknown +{ +public: + /*++ + + Routine Name: + + SetReadStream + + Routine Description: + + This routine sets the read stream for the PK archive handler + + Arguments: + + pReadStream - Pointer to the print read stream interface + + Return Value: + + HRESULT + S_OK - On success + E_* - On error + + --*/ + HRESULT + virtual SetReadStream( + _In_ IPrintReadStream* pReadStream + ) = 0; + + /*++ + + Routine Name: + + SetWriteStream + + Routine Description: + + This routine sets the write stream for the PK archive handler + + Arguments: + + pWriteStream - Pointer to the print write stream interface + + Return Value: + + HRESULT + S_OK - On success + E_* - On error + + --*/ + HRESULT + virtual SetWriteStream( + _In_ IPrintWriteStream* pWriteStream + ) = 0; + + /*++ + + Routine Name: + + ProcessReadStream + + Routine Description: + + This method instructs the PK archive handler to process the PK archive for all records + + Arguments: + + None + + Return Value: + + HRESULT + S_OK - On success + E_* - On error + + --*/ + HRESULT + virtual ProcessReadStream( + VOID + ) = 0; + + /*++ + + Routine Name: + + GetNameIndex + + Routine Description: + + This routine retrieves the archives indexed by name + + Arguments: + + ppNameIdx - Pointer to a NameIndex pointer that recieves the archive index + + Return Value: + + HRESULT + S_OK - On success + E_* - On error + + --*/ + HRESULT + virtual GetNameIndex( + _Outptr_ NameIndex** ppNameIdx + ) = 0; + + /*++ + + Routine Name: + + SendFile + + Routine Description: + + This routine sends the PK file to the write stream + + Arguments: + + pFile - Pointer to the IPKFile to be sent to the write stream + + Return Value: + + HRESULT + S_OK - On success + E_* - On error + + --*/ + HRESULT + virtual SendFile( + _In_ CONST IPKFile* pFile + ) = 0; + + /*++ + + Routine Name: + + SendFile + + Routine Description: + + This routine compresses and sends a buffer as a PK archive to the write stream + + Arguments: + + szFileName - The name of the archive to be created + pBuffer - The buffer containing the uncompressed archive data + cbBuffer - The size of the uncompressed archive data + compressionType - The type of compression to be used (only CompNone and CompDeflated are supported) + + Return Value: + + HRESULT + S_OK - On success + E_* - On error + + --*/ + HRESULT + virtual SendFile( + _In_z_ PCSTR szFileName, + _In_reads_bytes_(cbBuffer) PVOID pBuffer, + ULONG cbBuffer, + ECompressionType eCompType + ) = 0; + + /*++ + + Routine Name: + + Close + + Routine Description: + + This routine closes and finalises the PK archive + + Arguments: + + None + + Return Value: + + HRESULT + S_OK - On success + E_* - On error + + --*/ + HRESULT + virtual Close( + VOID + ) = 0; +}; + diff --git a/print/XPSDrvSmpl/src/inc/ipkfile.h b/print/XPSDrvSmpl/src/inc/ipkfile.h new file mode 100644 index 00000000..184b194c --- /dev/null +++ b/print/XPSDrvSmpl/src/inc/ipkfile.h @@ -0,0 +1,128 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + ipkfile.h + +Abstract: + + Definition of the PK file interface supported by the PK archive handling module. + +--*/ + +#pragma once + +// +// All compression types added for completeness. Only CompNone and +// CompDeflated are correctly supported. +// +enum ECompressionType +{ + CompNone = 0, + CompShrunk, + CompFactor1, + CompFactor2, + CompFactor3, + CompFactor4, + CompImploded, + CompTokenized, + CompDeflated, + CompDefalted64, + CompPKImploded, + CompPKReserved, + CompBZIP2 +}; + +class IPKFile +{ +public: + /*++ + + Routine Name: + + GetCompressionMethod + + Routine Description: + + This method returns the current compression methof for the archive file + + Arguments: + + pCompType - Pointer to the ECompressionType enumeration that recieves the compression type + + Return Value: + + HRESULT + S_OK - On success + E_* - On error + + --*/ + virtual HRESULT + GetCompressionMethod( + _Out_ ECompressionType* peCompType + ) CONST = 0; + + /*++ + + Routine Name: + + GetDecompressedSize + + Routine Description: + + This routine retrieves the size of the uncompressed archive file + + Arguments: + + pcbUnCompressed - Pointer to a ULONG that recieves the decompressed data size + + Return Value: + + HRESULT + S_OK - On success + E_* - On error + + --*/ + virtual HRESULT + GetDecompressedSize( + _Out_ ULONG* pcbUnCompressed + ) CONST = 0; + + /*++ + + Routine Name: + + DecompressTo + + Routine Description: + + This routine decompresses the archive file data to the buffer passed + + Arguments: + + pDecompBuffer - Pointer to the buffer to be filled with decompressed data + cbDecompBuffer - Size of the decompresssion buffer passed + + Return Value: + + HRESULT + S_OK - On success + E_* - On error + + --*/ + virtual HRESULT + DecompressTo( + _Out_writes_bytes_(cbDecompBuffer) PVOID pDecompBuffer, + ULONG cbDecompBuffer + ) CONST = 0; +}; + diff --git a/print/XPSDrvSmpl/src/inc/streamcnv.h b/print/XPSDrvSmpl/src/inc/streamcnv.h new file mode 100644 index 00000000..2877073f --- /dev/null +++ b/print/XPSDrvSmpl/src/inc/streamcnv.h @@ -0,0 +1,593 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + streamcnv.h + +Abstract: + + This wrapper class presents an IStream interface to an IPrintReadStream object. + This is useful for where an IStream interface is required for an API but is not + available without creating a seperate buffer and copying data in, e.g. decoding + bitmap data in WIC. This is not appropriate for use with interfaces that write + back into the stream. + +--*/ + +#pragma once + +#include "cunknown.h" + +class CPrintReadStreamToIStream : public CUnknown +{ +public: + /*++ + + Routine Name: + + CPrintReadStreamToIStream + + Routine Description: + + CPrintReadStreamToIStream constructor + + Arguments: + + pReadStream - the print read stream to wrap with an IStream interface + + Return Value: + + None + + --*/ + CPrintReadStreamToIStream( + _In_ IPrintReadStream* pReadStream + ) : + CUnknown(IID_IStream), + m_pReadStream(pReadStream) + { + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CoFileTimeNow(&m_mTime)) && + SUCCEEDED(hr = CoFileTimeNow(&m_cTime)) && + SUCCEEDED(hr = CoFileTimeNow(&m_aTime))) + { + m_cbStream.QuadPart = 0; + if (m_pReadStream == NULL) + { + hr = E_POINTER; + } + } + + if (FAILED(hr)) + { + throw CXDException(hr); + } + } + + /*++ + + Routine Name: + + ~CPrintReadStreamToIStream + + Routine Description: + + CPrintReadStreamToIStream destructor + + Arguments: + + None + + Return Value: + + None + + --*/ + virtual ~CPrintReadStreamToIStream() + { + } + + // + // ISequentialStream methods + // + /*++ + + Routine Name: + + Read + + Routine Description: + + Implements IStream::Read by calling on to IPrintReadStream::ReadBytes + + Arguments: + + pv - Pointer to the buffer to read into + cb - Count of bytes avaiable in the buffer pointed to by pv + pcbRead - pointer to a ULONG that recieves the count of bytes actually read + + Return Value: + + HRESULT + S_OK - On success and *pcbRead == cb + S_FALSE - On success and *pcbRead < cb + E_* - On error + + --*/ + HRESULT STDMETHODCALLTYPE + Read( + _Out_writes_bytes_to_(cb, *pcbRead) PVOID pv, + _In_ ULONG cb, + _Out_opt_ PULONG pcbRead + ) + { + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pv, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pcbRead, E_POINTER)) && + SUCCEEDED(hr = CoFileTimeNow(&m_aTime))) + { + BOOL bEOF = FALSE; + + *pcbRead = 0; + + while (SUCCEEDED(hr) && + !bEOF && + *pcbRead < cb) + { + DWORD cbRead = 0; + + hr = m_pReadStream->ReadBytes(reinterpret_cast(reinterpret_cast(pv) + *pcbRead), cb - *pcbRead, &cbRead, &bEOF); + + if (SUCCEEDED(hr)) + { + *pcbRead += cbRead; + } + } + } + + if (SUCCEEDED(hr) && + *pcbRead < cb) + { + hr = S_FALSE; + } + + ERR_ON_HR(hr); + return hr; + } + + /*++ + + Routine Name: + + Write + + Routine Description: + + Not implemented + + Arguments: + + None + + Return Value: + + E_NOTIMPL + + --*/ + HRESULT STDMETHODCALLTYPE + Write( + _In_reads_bytes_(cb) CONST VOID*, + _In_ ULONG cb, + _Out_opt_ PULONG + ) + { + UNREFERENCED_PARAMETER(cb); + ERR("Unsupported method called.\n"); + return E_NOTIMPL; + } + + // + // IStream methods + // + /*++ + + Routine Name: + + Seek + + Routine Description: + + Implements IStream::Seek by calling on to IPrintReadStream::Seek + + Arguments: + + dlibMove - Count of bytes to displace the current position relative to the dwOrigin parameter + dwOrigin - The origin to apply the displacement from + plibNewPosition - Pointer to a variable to recieve the new position of the seek pointer + + Return Value: + + HRESULT + S_OK - On success + E_* - On error + + --*/ + HRESULT STDMETHODCALLTYPE + Seek( + LARGE_INTEGER dlibMove, + DWORD dwOrigin, + _Out_opt_ ULARGE_INTEGER* plibNewPosition + ) + { + HRESULT hr = S_OK; + + ULONGLONG libNewPos = 0; + if (SUCCEEDED(hr = m_pReadStream->Seek(dlibMove.QuadPart, dwOrigin, &libNewPos)) && + plibNewPosition != NULL) + { + plibNewPosition->QuadPart = libNewPos; + } + + ERR_ON_HR(hr); + return hr; + } + + /*++ + + Routine Name: + + SetSize + + Routine Description: + + Not implemented + + Arguments: + + None + + Return Value: + + E_NOTIMPL + + --*/ + HRESULT STDMETHODCALLTYPE + SetSize( + ULARGE_INTEGER + ) + { + ERR("Unsupported method called.\n"); + return E_NOTIMPL; + } + + /*++ + + Routine Name: + + CopyTo + + Routine Description: + + Not implemented + + Arguments: + + None + + Return Value: + + E_NOTIMPL + + --*/ + HRESULT STDMETHODCALLTYPE + CopyTo( + _In_ IStream*, + ULARGE_INTEGER, + _Out_opt_ ULARGE_INTEGER*, + _Out_opt_ ULARGE_INTEGER* + ) + { + ERR("Unsupported method called.\n"); + return E_NOTIMPL; + } + + /*++ + + Routine Name: + + Commit + + Routine Description: + + Not implemented + + Arguments: + + None + + Return Value: + + E_NOTIMPL + + --*/ + HRESULT STDMETHODCALLTYPE + Commit( + DWORD + ) + { + ERR("Unsupported method called.\n"); + return E_NOTIMPL; + } + + /*++ + + Routine Name: + + Revert + + Routine Description: + + Not implemented + + Arguments: + + None + + Return Value: + + E_NOTIMPL + + --*/ + HRESULT STDMETHODCALLTYPE + Revert( + VOID + ) + { + ERR("Unsupported method called.\n"); + return E_NOTIMPL; + } + + /*++ + + Routine Name: + + LockRegion + + Routine Description: + + Not implemented + + Arguments: + + None + + Return Value: + + E_NOTIMPL + + --*/ + HRESULT STDMETHODCALLTYPE + LockRegion( + ULARGE_INTEGER, + ULARGE_INTEGER, + DWORD + ) + { + ERR("Unsupported method called.\n"); + return E_NOTIMPL; + } + + /*++ + + Routine Name: + + UnlockRegion + + Routine Description: + + Not implemented + + Arguments: + + None + + Return Value: + + E_NOTIMPL + + --*/ + HRESULT STDMETHODCALLTYPE + UnlockRegion( + ULARGE_INTEGER, + ULARGE_INTEGER, + DWORD + ) + { + ERR("Unsupported method called.\n"); + return E_NOTIMPL; + } + + /*++ + + Routine Name: + + Stat + + Routine Description: + + Retrieves the STATSG structure for this stream + + Arguments: + + pstatstg - Pointer to the STATSG structure to be completed + grfStatFlag - Flag determining what should be completed + + Return Value: + + HRESULT + S_OK - On success + E_* - On error + + --*/ + HRESULT STDMETHODCALLTYPE Stat( + STATSTG* pstatstg, + DWORD grfStatFlag + ) + { + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pstatstg, E_POINTER)) && + SUCCEEDED(hr = GetStreamSize(&pstatstg->cbSize))) + { + if (grfStatFlag == STATFLAG_DEFAULT) + { + CComBSTR bstrStoreName(L"PrintReadStream"); + UINT cchStoreName = bstrStoreName.Length(); + + pstatstg->pwcsName = reinterpret_cast(CoTaskMemAlloc((cchStoreName + 1) * sizeof(BSTR))); + + if (pstatstg->pwcsName != NULL) + { + CopyMemory(pstatstg->pwcsName, bstrStoreName.m_str, cchStoreName * sizeof(BSTR)); + pstatstg->pwcsName[cchStoreName] = 0; + } + else + { + hr = E_OUTOFMEMORY; + } + } + else + { + pstatstg->pwcsName = NULL; + } + + pstatstg->type = STGTY_STREAM; + pstatstg->mtime = m_mTime; + pstatstg->ctime = m_cTime; + pstatstg->atime = m_aTime; + pstatstg->grfMode = STGM_READ | STGM_SHARE_DENY_WRITE; + pstatstg->grfLocksSupported = LOCK_WRITE; + pstatstg->clsid = CLSID_NULL; + pstatstg->grfStateBits = 0; + } + + ERR_ON_HR(hr); + return hr; + } + + /*++ + + Routine Name: + + Clone + + Routine Description: + + Not implemented + + Arguments: + + None + + Return Value: + + E_NOTIMPL + + --*/ + HRESULT STDMETHODCALLTYPE + Clone( + IStream** + ) + { + ERR("Unsupported method called.\n"); + return E_NOTIMPL; + } + +private: + /*++ + + Routine Name: + + GetStreamSize + + Routine Description: + + Retrieves the stream size. If this is the first time the stream size is accessed + the method retrieves teh size by seeking to the end of the stream and reporting + the offset from the start. This value is then stored and used in subsequent + calls to this method + + Arguments: + + pcbSize - Pointer to the size to be filled out + + Return Value: + + HRESULT + S_OK - On success + E_* - On error + + --*/ + HRESULT + GetStreamSize( + ULARGE_INTEGER* pcbSize + ) + { + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pcbSize, E_POINTER))) + { + // + // This stream implementation can never shrink, so if the size is greater + // than 0 we do not need to re-acquire. + // + if (m_cbStream.QuadPart > 0) + { + *pcbSize = m_cbStream; + } + else + { + // + // Seek to the end of the stream to find the size then reset to the current position + // + ULONGLONG libOldPosition = 0; + if (SUCCEEDED(hr = m_pReadStream->Seek(0, STREAM_SEEK_CUR, &libOldPosition)) && + SUCCEEDED(hr = m_pReadStream->Seek(0, STREAM_SEEK_END, &pcbSize->QuadPart)) && + SUCCEEDED(hr = m_pReadStream->Seek(libOldPosition, STREAM_SEEK_SET, NULL))) + { + // + // Store the result + // + m_cbStream.QuadPart = pcbSize->QuadPart; + } + } + } + + ERR_ON_HR(hr); + return hr; + } + + +private: + CComPtr m_pReadStream; + + ULARGE_INTEGER m_cbStream; + + FILETIME m_mTime; + + FILETIME m_cTime; + + FILETIME m_aTime; +}; + diff --git a/print/XPSDrvSmpl/src/inc/xdexcept.h b/print/XPSDrvSmpl/src/inc/xdexcept.h new file mode 100644 index 00000000..6dfc653f --- /dev/null +++ b/print/XPSDrvSmpl/src/inc/xdexcept.h @@ -0,0 +1,104 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + xdexcept.h + +Abstract: + + XPSDrv sample driver exception class + +--*/ + +#pragma once + +class CXDException +{ +public: + /*++ + + Routine Name: + + CXDException + + Routine Description: + + Class constructor + + Arguments: + + None + + Return Value: + + None + + --*/ + CXDException() throw() : + m_hr(E_FAIL) + { + } + + /*++ + + Routine Name: + + CXDException + + Routine Description: + + Class constructor + + Arguments: + + hr - HRESULT value for the error for which the exception is thrown + + Return Value: + + None + + --*/ + CXDException( + HRESULT hr + ) throw() : + m_hr(hr) + { + } + + /*++ + + Routine Name: + + operator HRESULT() + + Routine Description: + + HRESULT cast operator + + Arguments: + + None + + Return Value: + + The HRESULT value associated with the exception + + --*/ + operator HRESULT() CONST throw() + { + return m_hr; + } + +public: + HRESULT m_hr; +}; + diff --git a/print/XPSDrvSmpl/src/inc/xdstring.h b/print/XPSDrvSmpl/src/inc/xdstring.h new file mode 100644 index 00000000..0a1f7177 --- /dev/null +++ b/print/XPSDrvSmpl/src/inc/xdstring.h @@ -0,0 +1,2889 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + xdstring.h + +Abstract: + + A string class that emulates the CStringT class interface. The class uses an + internal string of default length 128 characters. The string size is doubled + on each resize. + +--*/ + +#pragma once + +#include +#include "xdexcept.h" + +#define CCH_INITIAL_BUFFER 128 + +template< typename _T = CHAR > +class ChTraitsBaseXD +{ +public: + typedef CHAR XCHARXD; + typedef WCHAR YCHARXD; +}; + +template<> +class ChTraitsBaseXD< WCHAR > +{ +public: + typedef WCHAR XCHARXD; + typedef CHAR YCHARXD; +}; + +template +class CStringXDT +{ +public: + typedef typename ChTraitsBaseXD<_T>::XCHARXD XCHARXD; + typedef typename ChTraitsBaseXD<_T>::YCHARXD YCHARXD; + +public: + /*++ + + Routine Name: + + CStringXDT + + Routine Description: + + Class constructor + + Arguments: + + None + + Return Value: + + None + + --*/ + CStringXDT() : + m_pszData(NULL) + { + } + + /*++ + + Routine Name: + + CStringXDT + + Routine Description: + + Class constructor + + Arguments: + + cstrSrc - source CStringXDT class to construct from + + Return Value: + + None + + --*/ + CStringXDT( + _In_ CONST CStringXDT<_T>& cstrSrc + ) : + m_pszData(NULL) + { + CreateString(cstrSrc.GetString()); + } + + /*++ + + Routine Name: + + CStringXDT + + Routine Description: + + Class constructor + + Arguments: + + pszSrc - source string that matches the template argument to construct from + + Return Value: + + None + + --*/ + CStringXDT( + _In_z_ CONST XCHARXD* pszSrc + ) : + m_pszData(NULL) + { + CreateString(pszSrc); + } + + + /*++ + + Routine Name: + + CStringXDT + + Routine Description: + + Class constructor + + Arguments: + + pszSrc - source string to construct from. This is the "cross" + string, i.e. CHAR for WCHAR template and vice versa + + Return Value: + + None + + --*/ + CStringXDT( + _In_z_ CONST YCHARXD* pszSrc + ) : + m_pszData(NULL) + { + CreateStringFromY(pszSrc); + } + + /*++ + + Routine Name: + + CStringXDT + + Routine Description: + + Class constructor + + Arguments: + + pszSrc - source string that matches the template argument to construct from + cchSrc - the length of the source string to construct from + + Return Value: + + None + + --*/ + CStringXDT( + _In_reads_(cchSrc) CONST XCHARXD* pszSrc, + _In_ INT cchSrc + ) : + m_pszData(NULL) + { + if (cchSrc < 0) + { + RIP("Negative string size requested.\n"); + throw CXDException(E_INVALIDARG); + } + + CreateString(pszSrc, static_cast(cchSrc)); + } + + /*++ + + Routine Name: + + CStringXDT + + Routine Description: + + Class constructor + + Arguments: + + pszSrc - source string to construct from. This is the "cross" + string, i.e. CHAR for WCHAR template and vice versa + cchSrc - the length of the source string to construct from + + Return Value: + + None + + --*/ + CStringXDT( + _In_reads_(cchSrc) CONST YCHARXD* pszSrc, + _In_ INT cchSrc + ) : + m_pszData(NULL) + { + if (cchSrc < 0) + { + RIP("Negative string size requested.\n"); + throw CXDException(E_INVALIDARG); + } + + CreateStringFromY(pszSrc, static_cast(cchSrc)); + } + + /*++ + + Routine Name: + + ~CStringXDT + + Routine Description: + + Class destructor + + Arguments: + + None + + Return Value: + + None + + --*/ + ~CStringXDT() + { + if (m_pszData != NULL) + { + HeapFree(GetProcessHeap(), 0, GetDataBuffer()); + m_pszData = NULL; + } + } + + // + // Operators + // + /*++ + + Routine Name: + + operator= + + Routine Description: + + Assignment operator + + Arguments: + + cstrSrc - const reference to the source CStringXDT + + Return Value: + + Reference to the newly assigned CStringXDT instance + + --*/ + CStringXDT<_T>& + operator=( + _In_ CONST CStringXDT<_T>& cstrSrc + ) + { + *this = cstrSrc.m_pszData; + + return *this; + } + + /*++ + + Routine Name: + + operator= + + Routine Description: + + Assignment operator + + Arguments: + + pszSrc - const pointer to the source string of the same type as the template + + Return Value: + + Reference to the newly assigned CStringXDT instance + + --*/ + CStringXDT<_T>& + operator=( + _In_z_ CONST XCHARXD* pszSrc + ) + { + if (this->operator!=(pszSrc)) + { + Empty(); + CreateString(pszSrc); + } + + return *this; + } + + /*++ + + Routine Name: + + operator= + + Routine Description: + + Assignment operator + + Arguments: + + pszSrc - const pointer to the source string of the opposite type to the template + + Return Value: + + Reference to the newly assigned CStringXDT instance + + --*/ + CStringXDT<_T>& + operator=( + _In_z_ CONST YCHARXD* pszSrc + ) + { + if (this->operator!=(pszSrc)) + { + Empty(); + CreateStringFromY(pszSrc); + } + + return *this; + } + + /*++ + + Routine Name: + + operator+= + + Routine Description: + + Addition assignment operator - appends a source string to the current underlying string + + Arguments: + + pszSrc - pointer to the native string to append + + Return Value: + + Reference to this instance + + --*/ + CStringXDT<_T>& + operator+=( + _In_z_ CONST XCHARXD* pszSrc + ) + { + size_t cchSrc = StringLength(pszSrc); + size_t cchCur = StringLength(GetString()); + + SetBufferSize(cchSrc + cchCur); + CopyString(GetString() + cchCur, GetBufferCharCount() - cchCur, pszSrc, cchSrc); + + return *this; + } + + /*++ + + Routine Name: + + operator+= + + Routine Description: + + Addition assignment operator - appends a source string to the current underlying string + + Arguments: + + pszSrc - pointer to the opposite string type to append + + Return Value: + + Reference to this instance + + --*/ + CStringXDT<_T>& + operator+=( + _In_z_ CONST YCHARXD* pszSrc + ) + { + size_t cchSrc = StringLength(pszSrc); + size_t cchCur = StringLength(GetString()); + + SetBufferSize(cchSrc + cchCur); + CopyYString(GetString() + cchCur, GetBufferCharCount() - cchCur, pszSrc, cchSrc); + + return *this; + } + + /*++ + + Routine Name: + + operator CONST _T*() + + Routine Description: + + const cast operator + + Arguments: + + None + + Return Value: + + Pointer to the underlying string + + --*/ + operator CONST _T*() CONST throw() + { + return GetString(); + } + + /*++ + + Routine Name: + + operator!= + + Routine Description: + + Inequality operator - compares against the native string type + + Arguments: + + pszCompare - the string to compare to + + Return Value: + + true - the strings do not match + false - the strings match + + --*/ + bool + operator!=( + _In_z_ CONST XCHARXD* pszCompare + ) CONST + { + return !operator==(pszCompare); + } + + /*++ + + Routine Name: + + operator== + + Routine Description: + + Equality operator - compares against the native string type + + Arguments: + + pszCompare - the string to compare to + + Return Value: + + true - the strings match + false - the strings do not match + + --*/ + bool + operator==( + _In_z_ CONST XCHARXD* pszCompare + ) CONST + { + return CompareXDString(GetString(), pszCompare) == 0; + } + + /*++ + + Routine Name: + + operator!= + + Routine Description: + + Inequality operator - compares against the oposite string type + + Arguments: + + pszCompare - the string to compare to + + Return Value: + + true - the strings do not match + false - the strings match + + --*/ + bool + operator!=( + _In_z_ CONST YCHARXD* pszCompare + ) CONST + { + return !operator==(pszCompare); + } + + /*++ + + Routine Name: + + operator== + + Routine Description: + + Equality operator - compares against the opposite string type + + Arguments: + + pszCompare - the string to compare to + + Return Value: + + true - the strings match + false - the strings do not match + + --*/ + bool + operator==( + _In_z_ CONST YCHARXD* pszCompare + ) CONST + { + CStringXDT cstrCompare(pszCompare); + return CompareXDString(GetString(), cstrCompare) == 0; + } + + /*++ + + Routine Name: + + operator< + + Routine Description: + + Less than operator + + Arguments: + + cstrCompare - The CStringXDT instance to compare to + + Return Value: + + true - this string instance is less than the compare string + false - this string instance is not less than the compare string + + --*/ + bool + operator<( + _In_ CONST CStringXDT<_T>& cstrCompare + ) CONST + { + return CompareXDString(GetString(), cstrCompare.GetString()) < 0; + } + + /*++ + + Routine Name: + + operator< + + Routine Description: + + Less than operator + + Arguments: + + cstrCompare - pointer to a native string to compate with + + Return Value: + + true - this string instance is less than the compare string + false - this string instance is not less than the compare string + + --*/ + bool + operator<( + _In_z_ CONST XCHARXD* pszCompare + ) CONST + { + return CompareXDString(GetString(), pszCompare) < 0; + } + + /*++ + + Routine Name: + + operator< + + Routine Description: + + Less than operator + + Arguments: + + cstrCompare - pointer to a opposite string type to compate with + + Return Value: + + true - this string instance is less than the compare string + false - this string instance is not less than the compare string + + --*/ + bool + operator<( + _In_z_ CONST YCHARXD* pszCompare + ) CONST + { + CStringXDT cstrCompare(pszCompare); + return CompareXDString(GetString(), cstrCompare) < 0; + } + + /*++ + + Routine Name: + + operator[] + + Routine Description: + + Array index operator + + Arguments: + + cchIndex - the character index into the string + + Return Value: + + The value of the character at the specified index + + --*/ + _T operator[]( + _In_ INT cchIndex + ) CONST + { + if (cchIndex < 0 || + cchIndex > GetLength()) + { + throw CXDException(E_INVALIDARG); + } + + return GetString()[cchIndex]; + } + + // + // Methods + // + /*++ + + Routine Name: + + AllocSysString + + Routine Description: + + Allocates a BSTR from the underlying string + + Arguments: + + None + + Return Value: + + The newly allocated BSTR + + --*/ + BSTR + AllocSysString() + { + return AllocSysString(GetString()); + } + + /*++ + + Routine Name: + + Find + + Routine Description: + + Finds the location of a sub string in the underlying string + + Arguments: + + pszSub - the sub string to search for + cchStart - the point to start searching the underlying string from + + Return Value: + + -1 if the sub string is not found + the index of the sub-string in the underlying strings + + --*/ + INT + Find( + _In_z_ CONST _T* pszSub, + _In_ INT cchStart = 0 + ) CONST throw() + { + return Find(GetString(), pszSub, cchStart); + } + + /*++ + + Routine Name: + + Delete + + Routine Description: + + Deletes one or more characters from a given offset + + Arguments: + + cchStart - the starting character to delete from + cchDelete - the number of characters to delete + + Return Value: + + The length of the remaining string + + --*/ + INT + Delete( + INT cchStart, + INT cchDelete = 1 + ) + { + if (cchStart < 0) + { + cchStart = 0; + } + + if (cchDelete < 0) + { + cchDelete = 0; + } + + size_t cchStr = StringLength(GetString()); + if (cchStr < static_cast(cchStart + cchDelete)) + { + throw CXDException(E_INVALIDARG); + } + + size_t cchToMove = cchStr + 1 - static_cast(cchDelete + cchStart); + MoveMemory(GetString() + cchStart, m_pszData + cchStart + cchDelete, cchToMove * sizeof(_T)); + + return GetLength(); + } + + /*++ + + Routine Name: + + GetLength + + Routine Description: + + Retrieves the length of the string + + Arguments: + + None + + Return Value: + + The count of characters in the string + + --*/ + INT + GetLength() CONST throw() + { + INT cch = 0; + + try + { + cch = static_cast(StringLength(GetString())); + } + catch (CXDException&) + { + } + + return cch; + } + + /*++ + + Routine Name: + + Format + + Routine Description: + + Writes formatted data to the string. + + Arguments: + + pszFormat - the format string + ... - Variable argument list + + Return Value: + + None + + --*/ + VOID + Format( + _In_z_ CONST _T* pszFormat, + ... + ) + { + if (pszFormat == NULL) + { + throw CXDException(E_INVALIDARG); + } + + va_list argList; + va_start(argList, pszFormat); + Format(pszFormat, argList); + va_end(argList); + } + + /*++ + + Routine Name: + + Empty + + Routine Description: + + Sets the string to zero length + + Arguments: + + None + + Return Value: + + None + + --*/ + VOID + Empty() + { + try + { + *GetString() = 0; + } + catch (CXDException&) + { + } + } + + /*++ + + Routine Name: + + Compare + + Routine Description: + + Compares the string data with a compare string passed in - case sensitive. + This is the same functionality as strcmp. + + Arguments: + + pszCompare - the string to compare against + + Return Value: + + < 0 if the string data is less than the compare string + 0 if the strings are identical + > 0 if the string data is more than the compare string + + --*/ + INT + Compare( + _In_z_ CONST _T* pszCompare + ) CONST + { + return CompareXDString(GetString(), pszCompare); + } + + /*++ + + Routine Name: + + CompareNoCase + + Routine Description: + + Compares the string data with a compare string passed in - case insensitive. + This is the same functionality as stricmp. + + Arguments: + + pszCompare - the string to compare against + + Return Value: + + < 0 if the string data is less than the compare string + 0 if the strings are identical + > 0 if the string data is more than the compare string + + --*/ + INT + CompareNoCase( + _In_z_ CONST _T* pszCompare + ) CONST throw() + { + return CompareXDStringNoCase(GetString(), pszCompare); + } + + /*++ + + Routine Name: + + Replace + + Routine Description: + + Replaces all instances of a target string with a new string + + Arguments: + + pszOld - the string to replace + pszNew - the replacement string + + Return Value: + + The number of replaced instances + + --*/ + INT + Replace( + _In_z_ CONST _T* pszOld, + _In_z_ CONST _T* pszNew + ) + { + // + // Find the length of the old and new strings + // + size_t cchOld = StringLength(pszOld); + size_t cchNew = StringLength(pszNew); + + // + // Count the instances of the string to replace + // + _T* pszCurr = GetString(); + INT cReplace = 0; + INT cchStart = Find(pszCurr, pszOld, 0); + while (cchStart >= 0) + { + cReplace++; + pszCurr += cchStart + cchOld; + cchStart = Find(pszCurr, pszOld, 0); + } + + if (cReplace > 0) + { + // + // Resize the buffer to accomodate the replacements + // + INT cchDelta = static_cast(cchNew - cchOld); + INT cchDeltaBuffer = cReplace * cchDelta; + SetBufferSize(StringLength(GetString()) + cchDeltaBuffer); + + // + // Replace all instances of the old string and replace with + // the new string + // + pszCurr = GetString(); + cchStart = Find(pszCurr, pszOld, 0); + while (cchStart >= 0) + { + // + // Move the remainder of the string up by the length of the replacement + // this makes room to insert the replacement string + // + pszCurr += cchStart; + _T* pszOldEnd = pszCurr + cchOld; + size_t cchToMove = StringLength(pszOldEnd) + 1; + MoveMemory(pszCurr + cchNew, pszOldEnd, cchToMove * sizeof(_T)); + + // + // Fill the "gap" with the new string + // + CopyMemory(pszCurr, pszNew, cchNew * sizeof(_T)); + + // + // Look for the next string from the end of the current instance + // + pszCurr += cchNew; + cchStart = Find(pszCurr, pszOld, 0); + } + } + + return cReplace; + } + + /*++ + + Routine Name: + + Append + + Routine Description: + + Appends a string to the current string data + + Arguments: + + pszSrc - the string to append + + Return Value: + + None + + --*/ + VOID + Append( + _In_z_ CONST _T* pszSrc + ) + { + *this += pszSrc; + } + + /*++ + + Routine Name: + + Insert + + Routine Description: + + Inserts a string to the current string data + + Arguments: + + cch - the index at which to insert the string + pszSrc - the string to insert + + Return Value: + + None + + --*/ + INT + Insert( + _In_ CONST INT& cch, + _In_z_ CONST _T* pszSrc + ) + { + if (cch >= 0 && + pszSrc != NULL) + { + _T* pszCurr = GetString(); + size_t cchCurr = StringLength(pszCurr); + + if (cchCurr >= static_cast(cch)) + { + size_t cchSrc = StringLength(pszSrc); + SetBufferSize(cchCurr + cchSrc); + + // + // Move the remainder of the string up by the length of the replacement + // this makes room to insert the replacement string + // + pszCurr += cch; + size_t cchToMove = StringLength(pszCurr) + 1; + MoveMemory(pszCurr + cchSrc, pszCurr, cchToMove * sizeof(_T)); + + // + // Fill the "gap" with the new string + // + CopyMemory(pszCurr, pszSrc, cchSrc * sizeof(_T)); + } + } + else + { + throw CXDException(E_INVALIDARG); + } + + return static_cast(StringLength(GetString())); + } + + /*++ + + Routine Name: + + IsEmpty + + Routine Description: + + Indicates whether the string is zero length + + Arguments: + + None + + Return Value: + + true - the string is empty + false - otherwise + + --*/ + bool + IsEmpty() CONST throw() + { + return GetLength() == 0; + } + + /*++ + + Routine Name: + + GetBuffer + + Routine Description: + + Returns the underlying string buffer + + Arguments: + + None + + Return Value: + + The underlying string buffer + + --*/ + _T* + GetBuffer() + { + return GetString(); + } + + /*++ + + Routine Name: + + Tokenize + + Routine Description: + + Retrieves the position of the next token in a string + + Arguments: + + pszTokens - string defining the token + cchStart - the point at which the token search should start. This value is updated + by the call to the posiion following the end character of the token. + + Return Value: + + Returns a CStringXDT object containing the token value. + + --*/ + CStringXDT<_T> + Tokenize( + _In_z_ CONST _T* pszTokens, + _Inout_ INT& cchStart + ) CONST + { + CStringXDT<_T> cstrResult; + + if (cchStart < 0) + { + throw CXDException(E_INVALIDARG); + } + + INT cchTokens = static_cast(StringLength(pszTokens)); + if (cchTokens == 0) + { + if (cchStart < GetLength()) + { + cstrResult = GetString() + cchStart; + } + else + { + // + // There are no tokens or data + // + cchStart = -1; + } + } + else + { + // + // Skip leading tokens + // + while (Find(pszTokens, cchStart) == cchStart) + { + cchStart += cchTokens; + } + + INT cchFirstToken = Find(pszTokens, cchStart); + + if (cchFirstToken > 0) + { + // + // The result string runs from the start to the first token + // + cstrResult = Mid(cchStart, cchFirstToken - cchStart); + cchStart = cchFirstToken + cchTokens; + } + else + { + if (cchStart < GetLength()) + { + // + // There are no more tokens but there is data left + // + cstrResult = GetString() + cchStart; + cchStart = GetLength() + cchTokens; + } + else + { + // + // There are no more tokens or data + // + cchStart = -1; + } + } + } + + return cstrResult; + } + + /*++ + + Routine Name: + + GetAt + + Routine Description: + + Retrieves character at the given index + + Arguments: + + cchAt - character count index of the character to return + + Return Value: + + The character value at the specified index + + --*/ + _T GetAt( + _In_ INT cchAt + ) CONST + { + if (cchAt < 0 || + cchAt > GetLength()) + { + throw CXDException(E_INVALIDARG); + } + + return GetString()[cchAt]; + } + + /*++ + + Routine Name: + + Trim + + Routine Description: + + Trims the string of leading and trailing white space + + Arguments: + + None + + Return Value: + + Reference to the trimmed CStringXDT object + + --*/ + CStringXDT<_T>& + Trim() + { + return TrimRight().TrimLeft(); + } + + /*++ + + Routine Name: + + TrimRight + + Routine Description: + + Trims the string of trailing white space + + Arguments: + + None + + Return Value: + + Reference to the trimmed CStringXDT object + + --*/ + CStringXDT<_T>& + TrimRight() + { + _T* pszFirstTrailing = NULL; + _T* pszData = GetString(); + while (*pszData != 0) + { + if (IsSpace(*pszData)) + { + if (pszFirstTrailing == NULL) + { + pszFirstTrailing = pszData; + } + } + else + { + pszFirstTrailing = NULL; + } + pszData++; + } + + if (pszFirstTrailing != NULL) + { + Truncate(static_cast(pszFirstTrailing - GetString())); + } + + return *this; + } + + /*++ + + Routine Name: + + Trim + + Routine Description: + + Trims the string of leading white space + + Arguments: + + None + + Return Value: + + Reference to the trimmed CStringXDT object + + --*/ + CStringXDT<_T>& + TrimLeft() + { + _T* pszData = GetString(); + + while (IsSpace(*pszData)) + { + pszData++; + } + + INT cchWhite = static_cast(pszData - GetString()); + if (cchWhite > 0) + { + Delete(0, cchWhite); + } + + return *this; + } + + /*++ + + Routine Name: + + Left + + Routine Description: + + Returns a CStringXDT object containing the string of the specified length + from the left of the string data + + Arguments: + + cchLeft - count of characters to return from the string data + + Return Value: + + The CStringXDT object containing the requested string + + --*/ + CStringXDT<_T> + Left( + _In_ INT cchLeft + ) CONST + { + if (cchLeft < 0) + { + cchLeft = 0; + } + + if (cchLeft > GetLength()) + { + return *this; + } + + return CStringXDT<_T>(GetString(), cchLeft); + } + + /*++ + + Routine Name: + + Mid + + Routine Description: + + Returns a CStringXDT object containing the string from the specified offset + to the end of the string data + + Arguments: + + cchFirst - the index of the character to start the string + + Return Value: + + The CStringXDT object containing the requested string + + --*/ + CStringXDT<_T> + Mid( + _In_ INT cchFirst + ) CONST + { + return Mid(cchFirst, GetLength() - cchFirst); + } + + /*++ + + Routine Name: + + Mid + + Routine Description: + + Returns a CStringXDT object containing the string from the specified offset + of the requested length + + Arguments: + + cchFirst - the index of the character to start the string + cchSize - the count of characters to compose the return string from + + Return Value: + + The CStringXDT object containing the requested string + + --*/ + CStringXDT<_T> + Mid( + _In_ INT cchFirst, + _In_ INT cchSize + ) CONST + { + INT cchCurr = GetLength(); + + if (cchFirst < 0 || + cchSize < 0 || + cchSize + cchFirst > cchCurr || + cchFirst > cchCurr) + { + throw CXDException(E_INVALIDARG); + } + + if (cchFirst == 0 && + cchSize == cchCurr) + { + return *this; + } + + return CStringXDT<_T>(GetString() + cchFirst, cchSize); + } + + /*++ + + Routine Name: + + MakeLower + + Routine Description: + + Makes all characters in the string lower case + + Arguments: + + None + + Return Value: + + Reference to the modified string object + + --*/ + CStringXDT<_T>& + MakeLower() + { + MakeLower(GetString(), GetBufferCharCount()); + return *this; + } + + /*++ + + Routine Name: + + Truncate + + Routine Description: + + Truncates the string data to the specified size + + Arguments: + + cchNew - the length to which the string data is to be truncated + + Return Value: + + None + + --*/ + VOID + Truncate( + INT cchNew + ) + { + if (cchNew < 0) + { + cchNew = 0; + } + + if (cchNew < GetLength()) + { + GetString()[cchNew] = 0; + } + } + + /*++ + + Routine Name: + + Preallocate + + Routine Description: + + Preallocate the string buffer to accomodate a string of length cChars + Note: this function adds one for the NULL terminator + + Arguments: + + cChars - the count of chars to allocate for + + Return Value: + + None + + --*/ + VOID + Preallocate( + INT cChars + ) + { + if (cChars < 0) + { + cChars = 0; + } + + SetBufferSize(static_cast(cChars) + 1); + } + + +private: + /*++ + + Routine Name: + + CreateString + + Routine Description: + + Creates a native string specifically from a WCHAR source string + + Arguments: + + pszSrc - the WCHAR source string + + Return Value: + + None + + --*/ + VOID + CreateString( + _In_z_ CONST WCHAR* pszSrc + ) + { + if (pszSrc != NULL) + { + CreateString(pszSrc, StringLength(pszSrc)); + } + } + + /*++ + + Routine Name: + + CreateString + + Routine Description: + + Creates a native string specifically from a CHAR source string + + Arguments: + + pszSrc - the CHAR source string + + Return Value: + + None + + --*/ + VOID + CreateString( + _In_z_ CONST CHAR* pszSrc + ) + { + if (pszSrc != NULL) + { + CreateString(pszSrc, StringLength(pszSrc)); + } + } + + /*++ + + Routine Name: + + CreateString + + Routine Description: + + Creates a snative tring from a native source string and character count + + Arguments: + + pszSrc - the source string + cchSrc - count of characters to copy from the source string + + Return Value: + + None + + --*/ + VOID + CreateString( + _In_reads_(cchSrc) CONST _T* pszSrc, + _In_ size_t cchSrc + ) + { + if (pszSrc != NULL) + { + SetBufferSize(cchSrc); + CopyString(GetString(), GetBufferCharCount(), pszSrc, cchSrc); + } + } + + /*++ + + Routine Name: + + CreateStringFromY + + Routine Description: + + Creates a string from a source string of the opposite type. + WCHAR specific implementation. + + Arguments: + + pszSrc - the source string + cchSrc - count of characters to copy from the source string + + Return Value: + + None + + --*/ + VOID + CreateStringFromY( + _In_z_ CONST WCHAR* pszSrc + ) + { + if (pszSrc != NULL) + { + CreateStringFromY(pszSrc, StringLength(pszSrc)); + } + } + + /*++ + + Routine Name: + + CreateStringFromY + + Routine Description: + + Creates a string from a source string of the opposite type and character count. + WCHAR specific implementation. + + Arguments: + + pszSrc - the source string + cchSrc - count of characters to copy from the source string + + Return Value: + + None + + --*/ + VOID + CreateStringFromY( + _In_reads_(cchSrc) CONST WCHAR* pszSrc, + _In_ size_t cchSrc + ) + { + if (pszSrc != NULL && + cchSrc > 0) + { + SetBufferSize(cchSrc); + CopyYString(GetString(), GetBufferCharCount(), pszSrc, cchSrc); + } + } + + /*++ + + Routine Name: + + CreateStringFromY + + Routine Description: + + Creates a string from a source string of the opposite type and a chacter count. + CHAR specific implementation. + + Arguments: + + pszSrc - the source string + + Return Value: + + None + + --*/ + VOID + CreateStringFromY( + _In_z_ CONST CHAR* pszSrc + ) + { + if (pszSrc != NULL) + { + CreateStringFromY(pszSrc, StringLength(pszSrc)); + } + } + + /*++ + + Routine Name: + + CreateStringFromY + + Routine Description: + + Creates a string from a source string of the opposite type. + CHAR specific implementation. + + Arguments: + + pszSrc - the source string + cchSrc - count of characters to copy from the source string + + Return Value: + + None + + --*/ + VOID + CreateStringFromY( + _In_reads_(cchSrc) CONST CHAR* pszSrc, + _In_ size_t cchSrc + ) + { + if (pszSrc != NULL && + cchSrc > 0) + { + SetBufferSize(cchSrc); + CopyYString(GetString(), GetBufferCharCount(), pszSrc, cchSrc); + } + } + + /*++ + + Routine Name: + + StringLength + + Routine Description: + + Returns the character count of the string. WCHAR specific. + + Arguments: + + pszSrc - source to string to retrieve the length of + + Return Value: + + The count of characters in the string + + --*/ + static size_t + StringLength( + _In_opt_z_ CONST WCHAR* pszSrc + ) + { + size_t cch = 0; + if( pszSrc != NULL ) + { + while( *pszSrc != 0 ) + { + cch++; + pszSrc++; + } + } + + return cch; + } + + /*++ + + Routine Name: + + StringLength + + Routine Description: + + Returns the character count of the string. CHAR specific. + + Arguments: + + pszSrc - source to string to retrieve the length of + + Return Value: + + The count of characters in the string + + --*/ + static size_t + StringLength( + _In_opt_z_ CONST CHAR* pszSrc + ) + { + size_t cch = 0; + + if( pszSrc != NULL ) + { + while( *pszSrc != 0 ) + { + cch++; + pszSrc++; + } + } + + return cch; + } + + /*++ + + Routine Name: + + GetBufferCharCount + + Routine Description: + + Gets the total count of available characters in the buffer. This is the length + of the buffer as opposed to the count of characters in the string (the buffer) + can be larger. + + Arguments: + + None + + Return Value: + + The count of available characters in the data buffer + + --*/ + size_t + GetBufferCharCount( + VOID + ) CONST + { + size_t cch = 0; + + if (m_pszData != NULL) + { + cch = *reinterpret_cast(reinterpret_cast(m_pszData) - sizeof(size_t)); + } + else + { + throw CXDException(E_PENDING); + } + + return cch; + } + + /*++ + + Routine Name: + + GetDataBuffer + + Routine Description: + + Retrieves the pointer to the start of the data buffer. The size of the + buffer is stored before the actual string data. + + Arguments: + + None + + Return Value: + + Pointer to the start of the data buffer + + --*/ + PVOID + GetDataBuffer( + VOID + ) CONST + { + PVOID pData = NULL; + + if (m_pszData != NULL) + { + pData = reinterpret_cast(reinterpret_cast(m_pszData) - sizeof(size_t)); + } + else + { + throw CXDException(E_PENDING); + } + + return pData; + } + + /*++ + + Routine Name: + + SetBufferSize + + Routine Description: + + Sets the size of the buffer according to the character count passed in. If + the character count is less than that available no action is required. If it + is larger the data buffer is doubled in size till it is sufficient. + + Arguments: + + cch - count of characters the buffer must accomodate + + Return Value: + + None + + --*/ + VOID + SetBufferSize( + size_t cch + ) CONST + { + if (m_pszData == NULL) + { + // + // Allocate a new buffer + // + size_t cchAllocate = CCH_INITIAL_BUFFER; + + // + // Double the buffer size till we have enough room + // + while (cch >= cchAllocate) + { + cchAllocate *= 2; + } + + LPVOID pData = HeapAlloc(GetProcessHeap(), 0, cchAllocate * sizeof(_T) + sizeof(size_t)); + + if (pData != NULL) + { + *static_cast(pData) = cchAllocate; + m_pszData = reinterpret_cast<_T*>(reinterpret_cast(pData) + sizeof(size_t)); + *m_pszData = 0; + } + else + { + throw CXDException(E_OUTOFMEMORY); + } + } + else + { + size_t cchAllocated = GetBufferCharCount(); + + if (cch >= cchAllocated) + { + // + // Double the buffer size till we have enough room + // + while (cch >= cchAllocated) + { + cchAllocated *= 2; + } + + // + // Re-allocate the existing buffer + // + LPVOID pData = HeapReAlloc(GetProcessHeap(), 0, GetDataBuffer(), cchAllocated * sizeof(_T) + sizeof(size_t)); + + if (pData != NULL) + { + *static_cast(pData) = cchAllocated; + m_pszData = reinterpret_cast<_T*>(reinterpret_cast(pData) + sizeof(size_t)); + } + else + { + throw CXDException(E_OUTOFMEMORY); + } + } + } + } + + /*++ + + Routine Name: + + CopyString + + Routine Description: + + Copys a native string from one buffer to another. WCHAR specific implementation. + + Arguments: + + pszDst - pointer to the destination buffer to copy to + cchDst - count of characters available in the destination buffer + pszSrc - pointer to the source buffer + cchSrc - count of characters to copy + + Return Value: + + None + + --*/ + static VOID + CopyString( + _Inout_updates_(cchDst) WCHAR* pszDst, + _In_ size_t cchDst, + _In_reads_(cchSrc) CONST WCHAR* pszSrc, + _In_ size_t cchSrc + ) + { + HRESULT hr = S_OK; + + if (cchDst < cchSrc) + { + hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); + } + else if (pszDst == NULL) + { + hr = E_INVALIDARG; + } + + if (SUCCEEDED(hr) && + pszSrc != NULL && + cchSrc > 0) + { + hr = StringCchCopyNW(pszDst, cchDst, pszSrc, cchSrc); + } + + if (FAILED(hr)) + { + throw CXDException(hr); + } + } + + /*++ + + Routine Name: + + CopyString + + Routine Description: + + Copys a native string from one buffer to another. CHAR specific implementation. + + Arguments: + + pszDst - pointer to the destination buffer to copy to + cchDst - count of characters available in the destination buffer + pszSrc - pointer to the source buffer + cchSrc - count of characters to copy + + Return Value: + + None + + --*/ + static VOID + CopyString( + _Inout_updates_(cchDst) CHAR* pszDst, + _In_ size_t cchDst, + _In_reads_(cchSrc) CONST CHAR* pszSrc, + _In_ size_t cchSrc + ) + { + HRESULT hr = S_OK; + + if (cchDst < cchSrc) + { + hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); + } + else if (pszDst == NULL) + { + hr = E_INVALIDARG; + } + + if (SUCCEEDED(hr) && + pszSrc != NULL && + cchSrc > 0) + { + hr = StringCchCopyNA(pszDst, cchDst, pszSrc, cchSrc); + } + + if (FAILED(hr)) + { + throw CXDException(hr); + } + } + + /*++ + + Routine Name: + + CopyYString + + Routine Description: + + Copys a string of the opposite type from one buffer to another. CHAR specific implementation. + + Arguments: + + pszDst - pointer to the destination buffer to copy to + cchDst - count of characters available in the destination buffer + pszSrc - pointer to the source buffer + cchSrc - count of characters to copy + + Return Value: + + None + + --*/ + static VOID + CopyYString( + _Inout_updates_(cchDst) CHAR* pszDst, + _In_ size_t cchDst, + _In_reads_(cchSrc) CONST WCHAR* pszSrc, + _In_ size_t cchSrc + ) + { + HRESULT hr = S_OK; + + if (cchDst < cchSrc) + { + hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); + } + else if (pszDst == NULL) + { + hr = E_INVALIDARG; + } + + if (SUCCEEDED(hr) && + pszSrc != NULL && + cchSrc > 0) + { + size_t cbWritten = WideCharToMultiByte(CP_ACP, + 0, + pszSrc, + static_cast(cchSrc), + pszDst, + static_cast(cchDst * sizeof(_T)), + NULL, + NULL); + + if (cbWritten == cchSrc && + cchSrc < cchDst) + { + pszDst[cchSrc] = 0; + } + else + { + ERR("Failed to convert wide char to multibyte string\n"); + throw CXDException(E_FAIL); + } + } + + if (FAILED(hr)) + { + throw CXDException(hr); + } + } + + /*++ + + Routine Name: + + CopyYString + + Routine Description: + + Copys a string of the opposite type from one buffer to another. WCHAR specific implementation. + + Arguments: + + pszDst - pointer to the destination buffer to copy to + cchDst - count of characters available in the destination buffer + pszSrc - pointer to the source buffer + cchSrc - count of characters to copy + + Return Value: + + None + + --*/ + static VOID + CopyYString( + _Inout_updates_(cchDst) WCHAR* pszDst, + _In_ size_t cchDst, + _In_reads_(cchSrc) CONST CHAR* pszSrc, + _In_ size_t cchSrc + ) + { + HRESULT hr = S_OK; + + if (cchDst < cchSrc) + { + hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); + } + else if (pszDst == NULL) + { + hr = E_INVALIDARG; + } + + if (SUCCEEDED(hr) && + pszSrc != NULL && + cchSrc > 0) + { + size_t cchWritten = MultiByteToWideChar(CP_ACP, + 0, + pszSrc, + static_cast(cchSrc), + pszDst, + static_cast(cchDst)); + + if (cchWritten == cchSrc && + cchSrc < cchDst) + { + pszDst[cchSrc] = 0; + } + else + { + ERR("Failed to convert multibyte to wide char string\n"); + throw CXDException(E_FAIL); + } + } + + if (FAILED(hr)) + { + throw CXDException(hr); + } + } + + /*++ + + Routine Name: + + CompareXDString + + Routine Description: + + Case sensitive comparison of a native string with another - WCHAR specific implementation. + + Arguments: + + psz - first string in comparison + pszCmp - second string in comparison + + Return Value: + + < 0 if the string data is less than the compare string + 0 if the strings are identical + > 0 if the string data is more than the compare string + + --*/ + static INT + CompareXDString( + _In_z_ CONST WCHAR* psz, + _In_z_ CONST WCHAR* pszCmp + ) + { + if (pszCmp == NULL) + { + throw CXDException(E_FAIL); + } + + return wcscmp(psz, pszCmp); + } + + /*++ + + Routine Name: + + CompareXDString + + Routine Description: + + Case sensitive comparison of a native string with another - CHAR specific implementation. + + Arguments: + + psz - first string in comparison + pszCmp - second string in comparison + + Return Value: + + < 0 if the string data is less than the compare string + 0 if the strings are identical + > 0 if the string data is more than the compare string + + --*/ + static INT + CompareXDString( + _In_z_ CONST CHAR* psz, + _In_z_ CONST CHAR* pszCmp + ) + { + if (pszCmp == NULL) + { + throw CXDException(E_FAIL); + } + + return strcmp(psz, pszCmp); + } + + /*++ + + Routine Name: + + CompareXDString + + Routine Description: + + Case insensitive comparison of a native string with another - WCHAR specific implementation. + + Arguments: + + psz - first string in comparison + pszCmp - second string in comparison + + Return Value: + + < 0 if the string data is less than the compare string + 0 if the strings are identical + > 0 if the string data is more than the compare string + + --*/ + static INT + CompareXDStringNoCase( + _In_z_ CONST WCHAR* psz, + _In_z_ CONST WCHAR* pszCmp + ) + { + if (pszCmp == NULL) + { + throw CXDException(E_FAIL); + } + + return _wcsicmp(psz, pszCmp); + } + + /*++ + + Routine Name: + + CompareXDString + + Routine Description: + + Case insensitive comparison of a native string with another - CHAR specific implementation. + + Arguments: + + psz - first string in comparison + pszCmp - second string in comparison + + Return Value: + + < 0 if the string data is less than the compare string + 0 if the strings are identical + > 0 if the string data is more than the compare string + + --*/ + static INT + CompareXDStringNoCase( + _In_z_ CONST CHAR* psz, + _In_z_ CONST CHAR* pszCmp + ) + { + if (pszCmp == NULL) + { + throw CXDException(E_FAIL); + } + + return _stricmp(psz, pszCmp); + } + + /*++ + + Routine Name: + + AllocSysString + + Routine Description: + + Allocates a system string from the string data. WCHAR specific implementation. + + Arguments: + + psz - The string to allocate from + + Return Value: + + The newly allocated BSTR + + --*/ + static BSTR + AllocSysString( + _In_z_ CONST WCHAR* psz + ) + { + BSTR bstr = ::SysAllocString(psz); + + if (bstr == NULL) + { + throw CXDException(E_OUTOFMEMORY); + } + + return bstr; + } + + /*++ + + Routine Name: + + AllocSysString + + Routine Description: + + Allocates a system string from the string data. CHAR specific implementation. + + Arguments: + + psz - The string to allocate from + + Return Value: + + The newly allocated BSTR + + --*/ + static BSTR + AllocSysString( + _In_z_ CONST CHAR* psz + ) + { + CStringXDW cstrWide(psz); + BSTR bstr = ::SysAllocString(cstrWide); + + if (bstr == NULL) + { + throw CXDException(E_OUTOFMEMORY); + } + + return bstr; + } + + /*++ + + Routine Name: + + Find + + Routine Description: + + Retrieves the location of a sub string in another string. This is the + CHAR spzecific implementation for native string type + + Arguments: + + pszSrc - string to search in + pszSub - sub string to search for + cchStart - starting point for the search + + Return Value: + + < 0 if the substring was not found + Otherwise, the location of the substring + + --*/ + static INT + Find( + _In_z_ CONST CHAR* pszSrc, + _In_z_ CONST CHAR* pszSub, + _In_ INT cchStart = 0 + ) throw() + { + INT cchIndex = -1; + size_t cchLen = StringLength(pszSrc); + + if (pszSrc != NULL && + pszSub != NULL && + cchStart >= 0 && + cchStart <= static_cast(cchLen)) + { + CHAR* psz = strstr(const_cast(pszSrc + cchStart), pszSub); + + if (psz != NULL) + { + cchIndex = static_cast(psz - pszSrc); + } + } + + return cchIndex; + } + + /*++ + + Routine Name: + + Find + + Routine Description: + + Retrieves the location of a sub string in another string. This is the + WCHAR spzecific implementation for native string type + + Arguments: + + pszSrc - string to search in + pszSub - sub string to search for + cchStart - starting point for the search + + Return Value: + + < 0 if the substring was not found + Otherwise, the location of the substring + + --*/ + static INT + Find( + _In_z_ CONST WCHAR* pszSrc, + _In_z_ CONST WCHAR* pszSub, + _In_ INT cchStart = 0 + ) throw() + { + INT cchIndex = -1; + size_t cchLen = StringLength(pszSrc); + + if (pszSrc != NULL && + pszSub != NULL && + cchStart >= 0 && + cchStart <= static_cast(cchLen)) + { + WCHAR* psz = wcsstr(const_cast(pszSrc + cchStart), pszSub); + + if (psz != NULL) + { + cchIndex = static_cast(psz - pszSrc); + } + } + + return cchIndex; + } + + /*++ + + Routine Name: + + Format + + Routine Description: + + Writes formatted data to the string. WCHAR specific implementation. + + Arguments: + + pszFormat - the format string + argList - Variable argument list + + Return Value: + + None + + --*/ + VOID + Format( + _In_z_ CONST WCHAR* pszFormat, + va_list argList + ) + { + INT cchFormatedLen = _vscwprintf(pszFormat, argList); + + if (cchFormatedLen >= 0) + { + SetBufferSize(cchFormatedLen); + vswprintf_s(GetString(), GetBufferCharCount(), pszFormat, argList); + } + else + { + throw CXDException(E_INVALIDARG); + } + } + + /*++ + + Routine Name: + + Format + + Routine Description: + + Writes formatted data to the string. CHAR specific implementation. + + Arguments: + + pszFormat - the format string + argList - Variable argument list + + Return Value: + + None + + --*/ + VOID + Format( + _In_z_ CONST CHAR* pszFormat, + va_list argList + ) + { + INT cchFormatedLen = _vscprintf(pszFormat, argList); + + if (cchFormatedLen >= 0) + { + SetBufferSize(cchFormatedLen); + vsprintf_s(GetString(), GetBufferCharCount(), pszFormat, argList); + } + else + { + throw CXDException(E_INVALIDARG); + } + } + + /*++ + + Routine Name: + + IsSpace + + Routine Description: + + Determinese if a character is white space character. WCHAR specific implementation. + + Arguments: + + szCandidate - candidate character value + + Return Value: + + true - if the character is a white space character + false - otherwise + + --*/ + static bool + IsSpace( + _In_ CONST WCHAR& szCandidate + ) + { + return iswspace(szCandidate) != 0; + } + + /*++ + + Routine Name: + + IsSpace + + Routine Description: + + Determinese if a character is white space character. CHAR specific implementation. + + Arguments: + + szCandidate - candidate character value + + Return Value: + + true - if the character is a white space character + false - otherwise + + --*/ + static bool + IsSpace( + _In_z_ CONST CHAR& szCandidate + ) + { + return isspace(szCandidate) != 0; + } + + /*++ + + Routine Name: + + MakeLower + + Routine Description: + + Converts all characters in the source string to lower case characters. + WCHAR specific implementation. + + Arguments: + + pszSrc - string to be converted + cchSrc - character count of the string + + Return Value: + + NULL if the conversion fails + Pointer to the converted string on success + + --*/ + static PWSTR + MakeLower( + PWSTR pszSrc, + size_t cchSrc + ) + { + PWSTR pszRet = NULL; + if (_wcslwr_s(pszSrc, cchSrc) == 0) + { + pszRet = pszSrc; + } + + return pszRet; + } + + /*++ + + Routine Name: + + MakeLower + + Routine Description: + + Converts all characters in the source string to lower case characters. + CHAR specific implementation. + + Arguments: + + pszSrc - string to be converted + cchSrc - character count of the string + + Return Value: + + NULL if the conversion fails + Pointer to the converted string on success + + --*/ + static PSTR + MakeLower( + PSTR pszSrc, + size_t cchSrc + ) + { + PSTR pszRet = NULL; + if (_strlwr_s(pszSrc, cchSrc) == 0) + { + pszRet = pszSrc; + } + + return pszRet; + } + + /*++ + + Routine Name: + + GetString + + Routine Description: + + Retrieves the underlying string. + + Arguments: + + None + + Return Value: + + The underlying string + + --*/ + _T*& + GetString( + VOID + ) CONST + { + if (m_pszData == NULL) + { + SetBufferSize(1); + } + + return m_pszData; + } + +private: + mutable _T* m_pszData; +}; + +typedef CStringXDT CStringXD; +typedef CStringXDT CStringXDW; +typedef CStringXDT CStringXDA; + diff --git a/print/XPSDrvSmpl/src/ui/bkdmptcnv.cpp b/print/XPSDrvSmpl/src/ui/bkdmptcnv.cpp new file mode 100644 index 00000000..00c4e905 --- /dev/null +++ b/print/XPSDrvSmpl/src/ui/bkdmptcnv.cpp @@ -0,0 +1,433 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + bkdmptcnv.cpp + +Abstract: + + Booklet/Binding devmode <-> PrintTicket conversion class implementation. The class + defines a common data representation between the DevMode (GPD) and PrintTicket + representations and implements the conversion and validation methods required + by CFeatureDMPTConvert. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdexcept.h" +#include "xdstring.h" +#include "bkdmptcnv.h" +#include "bkpchndlr.h" + +using XDPrintSchema::Binding::BindingData; +using XDPrintSchema::Binding::EBinding; +using XDPrintSchema::Binding::EBindingMin; +using XDPrintSchema::Binding::JobBindAllDocuments; +using XDPrintSchema::Binding::DocumentBinding; +using XDPrintSchema::Binding::EBindingMax; + +using XDPrintSchema::Binding::EBindingOption; +using XDPrintSchema::Binding::None; +using XDPrintSchema::Binding::BindLeft; +using XDPrintSchema::Binding::BindRight; +using XDPrintSchema::Binding::BindTop; +using XDPrintSchema::Binding::BindBottom; + +PCSTR g_pszBindFeature[EBindingMax] = { + "JobBindAllDocuments", + "DocumentBinding", +}; +static GPDStringToOption g_bindingTypeOption[] = { + {"None", None}, + {"BindLeft", BindLeft}, + {"BindRight", BindRight}, + {"BindTop", BindTop}, + {"BindBottom", BindBottom}, +}; +UINT g_cBindOption = sizeof(g_bindingTypeOption)/sizeof(GPDStringToOption); + +/*++ + +Routine Name: + + CBookletDMPTConv::CBookletDMPTConv + +Routine Description: + + CBookletDMPTConv class constructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CBookletDMPTConv::CBookletDMPTConv() +{ +} + +/*++ + +Routine Name: + + CBookletDMPTConv::~CBookletDMPTConv + +Routine Description: + + CBookletDMPTConv class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CBookletDMPTConv::~CBookletDMPTConv() +{ +} + +/*++ + +Routine Name: + + CBookletDMPTConv::GetPTDataSettingsFromDM + +Routine Description: + + Populates the booklet data structure from the Devmode passed in. + +Arguments: + + pDevmode - pointer to input devmode buffer. + cbDevmode - size in bytes of full input devmode. + pPrivateDevmode - pointer to input private devmode buffer. + cbDrvPrivateSize - size in bytes of private devmode. + pDataSettings - Pointer to booklet data structure to be updated. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CBookletDMPTConv::GetPTDataSettingsFromDM( + _In_ PDEVMODE pDevmode, + _In_ ULONG cbDevmode, + _In_ PVOID pPrivateDevmode, + _In_ ULONG cbDrvPrivateSize, + _Out_ BookletSettings* pDataSettings + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pDevmode, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pPrivateDevmode, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pDataSettings, E_POINTER))) + { + if (cbDevmode < sizeof(DEVMODE) || + cbDrvPrivateSize == 0) + { + hr = E_INVALIDARG; + } + } + + // + // Retrieve the GPD and devmode controlled settings for both Job and Document binding + // + for (EBinding bindFeature = EBindingMin; + bindFeature < EBindingMax && SUCCEEDED(hr); + bindFeature = static_cast(bindFeature + 1)) + { + pDataSettings->settings[bindFeature].bindFeature = bindFeature; + hr = GetOptionFromGPDString(pDevmode, + cbDevmode, + g_pszBindFeature[bindFeature], + g_bindingTypeOption, + g_cBindOption, + pDataSettings->settings[bindFeature].bindOption); + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CBookletDMPTConv::MergePTDataSettingsWithPT + +Routine Description: + + This method updates the booklet data structure from a PrintTicket description. + +Arguments: + + pPrintTicket - Pointer to the input PrintTicket. + pDataSettings - Pointer to the booklet data structure + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CBookletDMPTConv::MergePTDataSettingsWithPT( + _In_ IXMLDOMDocument2* pPrintTicket, + _Inout_ BookletSettings* pDataSettings + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pPrintTicket, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pDataSettings, E_POINTER))) + { + try + { + // + // Get the binding settings from the PrintTicket and set the options in + // the appropriate Job or Document equivalent in the BookletSettings structure + // + BindingData bindData; + CBookPTHandler bkPTHndlr(pPrintTicket); + + if (SUCCEEDED(hr = bkPTHndlr.GetData(&bindData))) + { + // + // Only update settings relevant to the feature + // + if (bindData.bindFeature < EBindingMax && + bindData.bindFeature >= EBindingMin) + { + pDataSettings->settings[bindData.bindFeature] = bindData; + } + } + else if (hr == E_ELEMENT_NOT_FOUND) + { + // + // Binding setting not in the PT - make sure neither Job or + // Document binding are set in the outgoing data structure + // + pDataSettings->settings[JobBindAllDocuments].bindOption = None; + pDataSettings->settings[DocumentBinding].bindOption = None; + + hr = S_OK; + } + } + catch (CXDException& e) + { + hr = e; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CBookletDMPTConv::SetPTDataInDM + +Routine Description: + + This method updates the booklet options in the devmode from the UI Settings. + +Arguments: + + dataSettings - Reference to booklet data settings to be updated. + pDevmode - pointer to devmode to be updated. + cbDevmode - size in bytes of full devmode. + pPrivateDevmode - pointer to input private devmode buffer. + cbDrvPrivateSize - size in bytes of private devmode. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CBookletDMPTConv::SetPTDataInDM( + _In_ CONST BookletSettings& dataSettings, + _Inout_ PDEVMODE pDevmode, + _In_ ULONG cbDevmode, + _Inout_ PVOID pPrivateDevmode, + _In_ ULONG cbDrvPrivateSize + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pDevmode, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pPrivateDevmode, E_POINTER))) + { + if (cbDevmode < sizeof(DEVMODE) || + cbDrvPrivateSize == 0) + { + hr = E_INVALIDARG; + } + } + + for (EBinding bindFeature = EBindingMin; + bindFeature < EBindingMax && SUCCEEDED(hr); + bindFeature = static_cast(bindFeature + 1)) + { + hr = SetGPDStringFromOption(pDevmode, + cbDevmode, + g_pszBindFeature[bindFeature], + g_bindingTypeOption, + g_cBindOption, + dataSettings.settings[bindFeature].bindOption); + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CBookletDMPTConv::SetPTDataInPT + +Routine Description: + + This method updates the watemark PrintTicket description from booklet data structure. + +Arguments: + + dataSettings - Reference to booklet data structure to update from. + pPrintTicket - Pointer to the PrintTicket to be updated. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CBookletDMPTConv::SetPTDataInPT( + _In_ CONST BookletSettings& dataSettings, + _Inout_ IXMLDOMDocument2* pPrintTicket + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pPrintTicket, E_POINTER))) + { + try + { + CBookPTHandler bkPTHndlr(pPrintTicket); + BindingData bkData; + + // + // Preferentially set Job over Document + // + if (dataSettings.settings[JobBindAllDocuments].bindOption != None) + { + bkData.bindFeature = JobBindAllDocuments; + bkData.bindOption = dataSettings.settings[JobBindAllDocuments].bindOption; + } + else + { + bkData.bindFeature = DocumentBinding; + bkData.bindOption = dataSettings.settings[DocumentBinding].bindOption; + } + + // + // If the option is enabled set, otherwise delete it from the PT + // + if (bkData.bindOption != None) + { + hr = bkPTHndlr.SetData(&bkData); + } + else + { + hr = bkPTHndlr.Delete(); + } + } + catch (CXDException& e) + { + hr = e; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CBookletDMPTConv::CompletePrintCapabilities + +Routine Description: + + Unidrv calls this routine with an input Device Capabilities Document + that is partially populated with Device capabilities information + filled in by Unidrv for features that it understands. The plug-in + needs to read any private features in the input PrintTicket, delete + them and add them back under Printschema namespace so that higher + level applications can understand them and make use of them. + +Arguments: + + pPrintTicket - pointer to input PrintTicket + pCapabilities - pointer to Device Capabilities Document. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT STDMETHODCALLTYPE +CBookletDMPTConv::CompletePrintCapabilities( + _In_opt_ IXMLDOMDocument2*, + _Inout_ IXMLDOMDocument2* pPrintCapabilities + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pPrintCapabilities, E_POINTER))) + { + try + { + CBookPCHandler bookpcHandler(pPrintCapabilities); + bookpcHandler.SetCapabilities(); + } + catch(CXDException& e) + { + hr = e; + } + } + + ERR_ON_HR(hr); + return hr; +} diff --git a/print/XPSDrvSmpl/src/ui/bkdmptcnv.h b/print/XPSDrvSmpl/src/ui/bkdmptcnv.h new file mode 100644 index 00000000..bd6640c9 --- /dev/null +++ b/print/XPSDrvSmpl/src/ui/bkdmptcnv.h @@ -0,0 +1,84 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + bkdmptcnv.h + +Abstract: + + Booklet/Binding devmode <-> PrintTicket conversion class definition. The class + defines a common data representation between the DevMode (GPD) and PrintTicket + representations and implements the conversion and validation methods required + by CFeatureDMPTConvert. + +--*/ + +#pragma once + +#include "ftrdmptcnv.h" +#include "bkpthndlr.h" + +// +// The PT handling code defines a single BindingData structure that covers both +// JobBindAllDocuments and DocumentBinding to avoid conflicts. The GPD however +// controls both so we re-use the BindingData structure to handle both in +// the DevMode +// +struct BookletSettings +{ + XDPrintSchema::Binding::BindingData settings[XDPrintSchema::Binding::EBindingMax]; +}; + +class CBookletDMPTConv : public CFeatureDMPTConvert +{ +public: + CBookletDMPTConv(); + + ~CBookletDMPTConv(); + +private: + HRESULT + GetPTDataSettingsFromDM( + _In_ PDEVMODE pDevmode, + _In_ ULONG cbDevmode, + _In_ PVOID pPrivateDevmode, + _In_ ULONG cbDrvPrivateSize, + _Out_ BookletSettings* pDataSettings + ); + + HRESULT + MergePTDataSettingsWithPT( + _In_ IXMLDOMDocument2* pPrintTicket, + _Inout_ BookletSettings* pDrvSettings + ); + + HRESULT + SetPTDataInDM( + _In_ CONST BookletSettings& drvSettings, + _Inout_ PDEVMODE pDevmode, + _In_ ULONG cbDevmode, + _Inout_ PVOID pPrivateDevmode, + _In_ ULONG cbDrvPrivateSize + ); + + HRESULT + SetPTDataInPT( + _In_ CONST BookletSettings& drvSettings, + _Inout_ IXMLDOMDocument2* pPrintTicket + ); + + HRESULT STDMETHODCALLTYPE + CompletePrintCapabilities( + _In_opt_ IXMLDOMDocument2* pPrintTicket, + _Inout_ IXMLDOMDocument2* pPrintCapabilities + ); +}; diff --git a/print/XPSDrvSmpl/src/ui/colctrls.cpp b/print/XPSDrvSmpl/src/ui/colctrls.cpp new file mode 100644 index 00000000..acffdada --- /dev/null +++ b/print/XPSDrvSmpl/src/ui/colctrls.cpp @@ -0,0 +1,371 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + colctrls.cpp + +Abstract: + + Implementation of the color management specific UI controls. These are the + combo box used to select the PageColorManagement option, a list box + for selecting the PageSourceColorProfile option and a combo box for + selecting the PageSourceColorProfile option. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdstring.h" +#include "resource.h" +#include "colctrls.h" + +PCSTR CUICtrlPageColManCombo::m_pszPageColManName = "PageColorManagement"; +PCSTR CUICtrlColProfList::m_pszDestColProf = "PageSourceColorProfile"; +PCSTR CUICtrlPageColIntentCombo::m_pszPageIntentName = "PageICMRenderingIntent"; + +#define DRIVER_COL_MAN_SEL 2 + +/*++ + +Routine Name: + + CUICtrlPageColManCombo::CUICtrlPageColManCombo + +Routine Description: + + CUICtrlPageColManCombo class constructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlPageColManCombo::CUICtrlPageColManCombo() : + CUICtrlDefaultCombo(m_pszPageColManName, IDC_COMBO_COL_MANAGE) +{ +} + +/*++ + +Routine Name: + + CUICtrlPageColManCombo::~CUICtrlPageColManCombo + +Routine Description: + + CUICtrlPageColManCombo class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlPageColManCombo::~CUICtrlPageColManCombo() +{ +} + +/*++ + +Routine Name: + + CUICtrlPageColManCombo::OnInit + +Routine Description: + + This is responsible for initialising the control and is called when + the WM_INITDIALOG message is recieved. This method populates the combo + box with the appropriate option strings. + +Arguments: + + hDlg - handle to the parent window + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CUICtrlPageColManCombo::OnInit( + _In_ CONST HWND hDlg + ) +{ + HRESULT hr = S_OK; + // + // Populate the combo box + // + if (SUCCEEDED(hr = AddString(hDlg, g_hInstance, IDS_GPD_NONE)) && + SUCCEEDED(hr = AddString(hDlg, g_hInstance, IDS_GPD_DEVICE)) && + SUCCEEDED(hr = AddString(hDlg, g_hInstance, IDS_GPD_DRIVER))) + { + hr = AddString(hDlg, g_hInstance, IDS_GPD_SYSTEM); + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CUICtrlPageColManCombo::EnableDependentCtrls + +Routine Description: + + This method is used to enable or disable other controls in the UI based on the + current combo box selection. + +Arguments: + + hDlg - handle to the parent window + lSel - current combo box selection + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CUICtrlPageColManCombo::EnableDependentCtrls( + _In_ CONST HWND hDlg, + _In_ CONST LONG lSel + ) +{ + HRESULT hr = S_OK; + HWND hWnd = NULL; + + if (SUCCEEDED(hr = CHECK_HANDLE(hWnd = GetDlgItem(hDlg, IDC_TEXT_COLPROF), E_HANDLE))) + { + EnableWindow(hWnd, lSel == DRIVER_COL_MAN_SEL); + } + + if (SUCCEEDED(hr) && + (SUCCEEDED(hr = CHECK_HANDLE(hWnd = GetDlgItem(hDlg, IDC_LIST_COLPROF), E_HANDLE)))) + { + EnableWindow(hWnd, lSel == DRIVER_COL_MAN_SEL); + } + + if (SUCCEEDED(hr) && + (SUCCEEDED(hr = CHECK_HANDLE(hWnd = GetDlgItem(hDlg, IDC_TXT_COL_INTENT), E_HANDLE)))) + { + EnableWindow(hWnd, lSel == DRIVER_COL_MAN_SEL); + } + + if (SUCCEEDED(hr) && + (SUCCEEDED(hr = CHECK_HANDLE(hWnd = GetDlgItem(hDlg, IDC_COMBO_COL_INTENT), E_HANDLE)))) + { + EnableWindow(hWnd, lSel == DRIVER_COL_MAN_SEL); + } + + if (FAILED(hr)) + { + hr = HRESULT_FROM_WIN32(GetLastError()); + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CUICtrlColProfList::CUICtrlColProfList + +Routine Description: + + CUICtrlColProfList class constructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlColProfList::CUICtrlColProfList() : + CUICtrlDefaultList(m_pszDestColProf, IDC_LIST_COLPROF) +{ +} + +/*++ + +Routine Name: + + CUICtrlColProfList::~CUICtrlColProfList + +Routine Description: + + CUICtrlColProfList class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlColProfList::~CUICtrlColProfList() +{ +} + +/*++ + +Routine Name: + + CUICtrlColProfList::OnInit + +Routine Description: + + This is responsible for initialising the control and is called when + the WM_INITDIALOG message is recieved. This method populates the list + box with the appropriate option strings. + +Arguments: + + hDlg - handle to the parent window + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CUICtrlColProfList::OnInit( + _In_ CONST HWND hDlg + ) +{ + HRESULT hr = S_OK; + // + // Populate the combo box + // + if (SUCCEEDED(hr = AddString(hDlg, g_hInstance, IDS_GPD_CMYK))) + { + hr = AddString(hDlg, g_hInstance, IDS_GPD_SCRGB); + } + + ERR_ON_HR(hr); + return hr; +} + + +/*++ + +Routine Name: + + CUICtrlPageColIntentCombo::CUICtrlPageColIntentCombo + +Routine Description: + + CUICtrlPageColIntentCombo class constructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlPageColIntentCombo::CUICtrlPageColIntentCombo() : + CUICtrlDefaultCombo(m_pszPageIntentName, IDC_COMBO_COL_INTENT) +{ +} + +/*++ + +Routine Name: + + CUICtrlPageColIntentCombo::~CUICtrlPageColIntentCombo + +Routine Description: + + CUICtrlPageColIntentCombo class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlPageColIntentCombo::~CUICtrlPageColIntentCombo() +{ +} + +/*++ + +Routine Name: + + CUICtrlPageColIntentCombo::OnInit + +Routine Description: + + This is responsible for initialising the control and is called when + the WM_INITDIALOG message is recieved. This method populates the combo + box with the appropriate option strings. + +Arguments: + + hDlg - handle to the parent window + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CUICtrlPageColIntentCombo::OnInit( + _In_ CONST HWND hDlg + ) +{ + HRESULT hr = S_OK; + + // + // Populate the combo box + // + if (SUCCEEDED(hr = AddString(hDlg, g_hInstance, IDS_GPD_ABSCOLINTENT)) && + SUCCEEDED(hr = AddString(hDlg, g_hInstance, IDS_GPD_RELCOLINTENT)) && + SUCCEEDED(hr = AddString(hDlg, g_hInstance, IDS_GPD_PHOTOINTENT))) + { + hr = AddString(hDlg, g_hInstance, IDS_GPD_BIZINTENT); + } + + ERR_ON_HR(hr); + return hr; +} + diff --git a/print/XPSDrvSmpl/src/ui/colctrls.h b/print/XPSDrvSmpl/src/ui/colctrls.h new file mode 100644 index 00000000..90ebd21c --- /dev/null +++ b/print/XPSDrvSmpl/src/ui/colctrls.h @@ -0,0 +1,83 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + colctrls.h + +Abstract: + + Definition of the color management specific UI controls. These are the + combo box used to select the PageColorManagement option, a list box + for selecting the PageSourceColorProfile option and a combo box for + selecting the PageSourceColorProfile option. + +--*/ + +#pragma once + +#include "uictrl.h" + +class CUICtrlPageColManCombo : public CUICtrlDefaultCombo +{ +public: + CUICtrlPageColManCombo(); + + virtual ~CUICtrlPageColManCombo(); + + HRESULT + OnInit( + _In_ CONST HWND hDlg + ); + +private: + HRESULT + EnableDependentCtrls( + _In_ CONST HWND hDlg, + _In_ CONST LONG lSel + ); + +private: + static PCSTR m_pszPageColManName; +}; + +class CUICtrlColProfList : public CUICtrlDefaultList +{ +public: + CUICtrlColProfList(); + + virtual ~CUICtrlColProfList(); + + HRESULT + OnInit( + _In_ CONST HWND hDlg + ); + +private: + static PCSTR m_pszDestColProf; +}; + +class CUICtrlPageColIntentCombo : public CUICtrlDefaultCombo +{ +public: + CUICtrlPageColIntentCombo(); + + virtual ~CUICtrlPageColIntentCombo(); + + HRESULT + OnInit( + _In_ CONST HWND hDlg + ); + +private: + static PCSTR m_pszPageIntentName; +}; + diff --git a/print/XPSDrvSmpl/src/ui/coldmptcnv.cpp b/print/XPSDrvSmpl/src/ui/coldmptcnv.cpp new file mode 100644 index 00000000..3d20af57 --- /dev/null +++ b/print/XPSDrvSmpl/src/ui/coldmptcnv.cpp @@ -0,0 +1,395 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + coldmptcnv.cpp + +Abstract: + + PageSourceColorProfile devmode <-> PrintTicket conversion class implementation. + The class defines a common data representation between the DevMode (GPD) and PrintTicket + representations and implements the conversion and validation methods required + by CFeatureDMPTConvert. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdexcept.h" +#include "xdstring.h" +#include "cmprofpchndlr.h" +#include "coldmptcnv.h" + +using XDPrintSchema::PageSourceColorProfile::PageSourceColorProfileData; +using XDPrintSchema::PageSourceColorProfile::EProfileOption; +using XDPrintSchema::PageSourceColorProfile::RGB; +using XDPrintSchema::PageSourceColorProfile::CMYK; + +PCWSTR g_pszCMYKProfileName = L"xdCMYKPrinter.icc"; +PCWSTR g_pszRGBProfileName = L"xdwscRGB.icc"; +PCSTR g_pszColProfFeature = "PageSourceColorProfile"; +static GPDStringToOption g_colProfTypeOption[] = { + {"CMYK", CMYK}, + {"scRGB", RGB}, +}; +UINT g_cColProfOption = sizeof(g_colProfTypeOption)/sizeof(GPDStringToOption); + +/*++ + +Routine Name: + + CColorProfileDMPTConv::CColorProfileDMPTConv + +Routine Description: + + CColorProfileDMPTConv class constructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CColorProfileDMPTConv::CColorProfileDMPTConv() +{ +} + +/*++ + +Routine Name: + + CColorProfileDMPTConv::~CColorProfileDMPTConv + +Routine Description: + + CColorProfileDMPTConv class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CColorProfileDMPTConv::~CColorProfileDMPTConv() +{ +} + +/*++ + +Routine Name: + + CColorProfileDMPTConv::GetPTDataSettingsFromDM + +Routine Description: + + Populates the color profile data structure from the Devmode passed in. + +Arguments: + + pDevmode - pointer to input devmode buffer. + cbDevmode - size in bytes of full input devmode. + pPrivateDevmode - pointer to input private devmode buffer. + cbDrvPrivateSize - size in bytes of private devmode. + pDataSettings - Pointer to color profile data structure to be updated. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CColorProfileDMPTConv::GetPTDataSettingsFromDM( + _In_ PDEVMODE pDevmode, + _In_ ULONG cbDevmode, + _In_ PVOID pPrivateDevmode, + _In_ ULONG cbDrvPrivateSize, + _Out_ PageSourceColorProfileData* pDataSettings + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pDevmode, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pPrivateDevmode, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pDataSettings, E_POINTER))) + { + if (cbDevmode < sizeof(DEVMODE) || + cbDrvPrivateSize == 0) + { + hr = E_INVALIDARG; + } + } + + // + // Defer setting up the profile file names until we write to the PT + // as they only have meaning at that point + // + if (SUCCEEDED(hr)) + { + GetOptionFromGPDString(pDevmode, + cbDevmode, + g_pszColProfFeature, + g_colProfTypeOption, + g_cColProfOption, + pDataSettings->cmProfile); + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CColorProfileDMPTConv::MergePTDataSettingsWithPT + +Routine Description: + + This method updates the color profile data structure from a PrintTicket description. + +Arguments: + + pPrintTicket - Pointer to the input PrintTicket. + pDataSettings - Pointer to the color profile data structure + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CColorProfileDMPTConv::MergePTDataSettingsWithPT( + _In_ IXMLDOMDocument2* pPrintTicket, + _Inout_ PageSourceColorProfileData* pDataSettings + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr) && + SUCCEEDED(hr = CHECK_POINTER(pPrintTicket, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pDataSettings, E_POINTER))) + { + try + { + PageSourceColorProfileData profData; + CColorManageProfilePTHandler profPTHndlr(pPrintTicket); + + if (SUCCEEDED(hr = profPTHndlr.GetData(&profData))) + { + pDataSettings->cmProfile = profData.cmProfile; + } + else if (hr == E_ELEMENT_NOT_FOUND) + { + // + // The property is not in the PT. This is not an error - reset hresult + // and continue + // + hr = S_OK; + } + } + catch (CXDException& e) + { + hr = e; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CColorProfileDMPTConv::SetPTDataInDM + +Routine Description: + + This method updates the color profile options in the devmode from the UI Settings. + +Arguments: + + dataSettings - Reference to color profile data settings to be updated. + pDevmode - pointer to devmode to be updated. + cbDevmode - size in bytes of full devmode. + pPrivateDevmode - pointer to input private devmode buffer. + cbDrvPrivateSize - size in bytes of private devmode. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CColorProfileDMPTConv::SetPTDataInDM( + _In_ CONST PageSourceColorProfileData& dataSettings, + _Inout_ PDEVMODE pDevmode, + _In_ ULONG cbDevmode, + _Inout_ PVOID pPrivateDevmode, + _In_ ULONG cbDrvPrivateSize + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pDevmode, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pPrivateDevmode, E_POINTER))) + { + if (cbDevmode < sizeof(DEVMODE) || + cbDrvPrivateSize == 0) + { + hr = E_INVALIDARG; + } + } + + if (SUCCEEDED(hr)) + { + hr = SetGPDStringFromOption(pDevmode, + cbDevmode, + g_pszColProfFeature, + g_colProfTypeOption, + g_cColProfOption, + dataSettings.cmProfile); + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CColorProfileDMPTConv::SetPTDataInPT + +Routine Description: + + This method updates the watemark PrintTicket description from color profile data structure. + +Arguments: + + dataSettings - Reference to color profile data structure to update from. + pPrintTicket - Pointer to the PrintTicket to be updated. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CColorProfileDMPTConv::SetPTDataInPT( + _In_ CONST PageSourceColorProfileData& dataSettings, + _Inout_ IXMLDOMDocument2* pPrintTicket + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pPrintTicket, E_POINTER))) + { + try + { + CColorManageProfilePTHandler cmProfPTHndlr(pPrintTicket); + PageSourceColorProfileData profData; + profData.cmProfile = dataSettings.cmProfile; + + // + // Ensure profile file names are set from the enumerated type + // + if (profData.cmProfile == CMYK) + { + profData.cmProfileName = g_pszCMYKProfileName; + } + else + { + profData.cmProfileName = g_pszRGBProfileName; + } + + hr = cmProfPTHndlr.SetData(&profData); + } + catch (CXDException& e) + { + hr = e; + } + } + else + { + hr = E_POINTER; + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CColorProfileDMPTConv::CompletePrintCapabilities + +Routine Description: + + Unidrv calls this routine with an input Device Capabilities Document + that is partially populated with Device capabilities information + filled in by Unidrv for features that it understands. The plug-in + needs to read any private features in the input PrintTicket, delete + them and add them back under Printschema namespace so that higher + level applications can understand them and make use of them. + +Arguments: + + pPrintTicket - pointer to input PrintTicket + pCapabilities - pointer to Device Capabilities Document. + +Return Value: + + HRESULT + S_OK - Always + +--*/ +HRESULT STDMETHODCALLTYPE +CColorProfileDMPTConv::CompletePrintCapabilities( + _In_opt_ IXMLDOMDocument2*, + _Inout_ IXMLDOMDocument2* pPrintCapabilities + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pPrintCapabilities, E_POINTER))) + { + try + { + CColorManageProfilePCHandler cmProfPCHandler(pPrintCapabilities); + cmProfPCHandler.SetCapabilities(); + } + catch(CXDException& e) + { + hr = e; + } + } + + ERR_ON_HR(hr); + return hr; +} diff --git a/print/XPSDrvSmpl/src/ui/coldmptcnv.h b/print/XPSDrvSmpl/src/ui/coldmptcnv.h new file mode 100644 index 00000000..0c890758 --- /dev/null +++ b/print/XPSDrvSmpl/src/ui/coldmptcnv.h @@ -0,0 +1,76 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + coldmptcnv.h + +Abstract: + + PageSourceColorProfile devmode <-> PrintTicket conversion class definition. + The class defines a common data representation between the DevMode (GPD) and PrintTicket + representations and implements the conversion and validation methods required + by CFeatureDMPTConvert. + +--*/ + +#pragma once + +#include "ftrdmptcnv.h" +#include "cmprofpthndlr.h" +#include "cmprofiledata.h" + +class CColorProfileDMPTConv : + public CFeatureDMPTConvert +{ +public: + CColorProfileDMPTConv(); + + virtual ~CColorProfileDMPTConv(); + +private: + HRESULT + GetPTDataSettingsFromDM( + _In_ PDEVMODE pDevmode, + _In_ ULONG cbDevmode, + _In_ PVOID pPrivateDevmode, + _In_ ULONG cbDrvPrivateSize, + _Out_ XDPrintSchema::PageSourceColorProfile::PageSourceColorProfileData* pDataSettings + ); + + HRESULT + MergePTDataSettingsWithPT( + _In_ IXMLDOMDocument2* pPrintTicket, + _Inout_ XDPrintSchema::PageSourceColorProfile::PageSourceColorProfileData* pDrvSettings + ); + + HRESULT + SetPTDataInDM( + _In_ CONST XDPrintSchema::PageSourceColorProfile::PageSourceColorProfileData& drvSettings, + _Inout_ PDEVMODE pDevmode, + _In_ ULONG cbDevmode, + _Inout_ PVOID pPrivateDevmode, + _In_ ULONG cbDrvPrivateSize + ); + + HRESULT + SetPTDataInPT( + _In_ CONST XDPrintSchema::PageSourceColorProfile::PageSourceColorProfileData& drvSettings, + _Inout_ IXMLDOMDocument2* pPrintTicket + ); + + HRESULT STDMETHODCALLTYPE + CompletePrintCapabilities( + _In_opt_ IXMLDOMDocument2*, + _Inout_ IXMLDOMDocument2* pPrintCapabilities + ); +}; + diff --git a/print/XPSDrvSmpl/src/ui/colppg.cpp b/print/XPSDrvSmpl/src/ui/colppg.cpp new file mode 100644 index 00000000..24e9eb35 --- /dev/null +++ b/print/XPSDrvSmpl/src/ui/colppg.cpp @@ -0,0 +1,160 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + colppg.cpp + +Abstract: + + Implementation of the color management property page. This class is + responsible for initialising and registering the color management + property page and its controls. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdexcept.h" +#include "xdstring.h" +#include "resource.h" +#include "colppg.h" +#include "colctrls.h" + +/*++ + +Routine Name: + + CColorPropPage::CColorPropPage + +Routine Description: + + CColorPropPage class constructor. + Creates a handler class object for every control on the color profile property page. + Each of these handlers is stored in a collection. + +Arguments: + + None + +Return Value: + + None + Throws CXDException(HRESULT) on an error + +--*/ +CColorPropPage::CColorPropPage() +{ + HRESULT hr = S_OK; + + try + { + CUIControl* pControl = new(std::nothrow) CUICtrlPageColManCombo(); + if (SUCCEEDED(hr = CHECK_POINTER(pControl, E_OUTOFMEMORY))) + { + hr = AddUIControl(IDC_COMBO_COL_MANAGE, pControl); + } + + if (SUCCEEDED(hr)) + { + pControl = new(std::nothrow) CUICtrlColProfList(); + if (SUCCEEDED(hr = CHECK_POINTER(pControl, E_OUTOFMEMORY))) + { + hr = AddUIControl(IDC_LIST_COLPROF, pControl); + } + } + + if (SUCCEEDED(hr)) + { + pControl = new(std::nothrow) CUICtrlPageColIntentCombo(); + if (SUCCEEDED(hr = CHECK_POINTER(pControl, E_OUTOFMEMORY))) + { + hr = AddUIControl(IDC_COMBO_COL_INTENT, pControl); + } + } + } + catch (CXDException& e) + { + hr = e; + } + + if (FAILED(hr)) + { + DestroyUIComponents(); + throw CXDException(hr); + } +} + +/*++ + +Routine Name: + + CColorPropPage::~CColorPropPage + +Routine Description: + + CColorPropPage class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CColorPropPage::~CColorPropPage() +{ +} + +/*++ + +Routine Name: + + CColorPropPage::InitDlgBox + +Routine Description: + + Provides the base class with the data required to intialise the dialog box. + +Arguments: + + ppszTemplate - Pointer to dialog box template to be intialised. + ppszTitle - Pointer to dialog box title to be intialised. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CColorPropPage::InitDlgBox( + _Out_ LPCTSTR* ppszTemplate, + _Out_ LPCTSTR* ppszTitle + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(ppszTemplate, E_POINTER)) || + SUCCEEDED(hr = CHECK_POINTER(ppszTitle, E_POINTER))) + { + *ppszTemplate = MAKEINTRESOURCE(IDD_COL_MANAGE); + *ppszTitle = MAKEINTRESOURCE(IDS_COLMAN); + } + + ERR_ON_HR(hr); + return hr; +} + diff --git a/print/XPSDrvSmpl/src/ui/colppg.h b/print/XPSDrvSmpl/src/ui/colppg.h new file mode 100644 index 00000000..76fff12d --- /dev/null +++ b/print/XPSDrvSmpl/src/ui/colppg.h @@ -0,0 +1,42 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + colppg.h + +Abstract: + + Definition of the color management property page. This class is + responsible for initialising and registering the color management + property page and its controls. + +--*/ + +#pragma once + +#include "precomp.h" +#include "docppg.h" + +class CColorPropPage : public CDocPropPage +{ +public: + CColorPropPage(); + + virtual ~CColorPropPage(); + + HRESULT + InitDlgBox( + _Out_ LPCTSTR* ppszTemplate, + _Out_ LPCTSTR* ppszTitle + ); +}; + diff --git a/print/XPSDrvSmpl/src/ui/devmode.h b/print/XPSDrvSmpl/src/ui/devmode.h new file mode 100644 index 00000000..c5e74fbc --- /dev/null +++ b/print/XPSDrvSmpl/src/ui/devmode.h @@ -0,0 +1,82 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + devmode.h + +Abstract: + + Definition of the OEM devmode structure. + +--*/ + +#pragma once + + +//////////////////////////////////////////////////////// +// OEM Devmode Defines +//////////////////////////////////////////////////////// + +#define MAX_WATERMARK_TEXT 24 + +//////////////////////////////////////////////////////// +// OEM Devmode Type Definitions +//////////////////////////////////////////////////////// + +// +//Can add info to the private devmode bellow here. +//Note : +// This structure must be prefixed by OEM_DMEXTRAHEADER +// Your plug-in must implement the IPrintOemUI::DevMode method +// +typedef struct tagOEMDEV +{ + OEM_DMEXTRAHEADER dmOEMExtra; + + // + //Private DevMode Members + // + + // + // Page Scaling Members + // + + DWORD dwPgScaleX; + DWORD dwPgScaleY; + INT iPgOffsetX; + INT iPgOffsetY; + + // + // Watermark Members + // + INT iWMTransparency; + INT iWMAngle; + INT iWMOffsetX; + INT iWMOffsetY; + + // + // Text Watermark Members + // + INT iWMFontSize; + DWORD dwColText; + TCHAR strWMText[MAX_WATERMARK_TEXT]; + + // + // Bitmap / Vector Members + // + INT iWMWidth; + INT iWMHeight; + +} OEMDEV, *POEMDEV; + +typedef CONST OEMDEV *PCOEMDEV; + diff --git a/print/XPSDrvSmpl/src/ui/dllentry.cpp b/print/XPSDrvSmpl/src/ui/dllentry.cpp new file mode 100644 index 00000000..47c8a728 --- /dev/null +++ b/print/XPSDrvSmpl/src/ui/dllentry.cpp @@ -0,0 +1,175 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + dllentry.cpp + +Abstract: + + Implementation of the UI plugin dllentry points. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdexcept.h" +#include "xdsmplcf.h" + +/*++ + +Routine Name: + + DllMain + +Routine Description: + + Entry point into the dynamic-link library (DLL). + Called by the system when processes and threads are initialized and terminated, + or upon calls to the LoadLibrary and FreeLibrary functions. + +Arguments: + + hInst - Handle to the DLL module. + wReason - Indicates why the DLL entry-point function is being called. + +Return Value: + + TRUE + +--*/ +BOOL WINAPI +DllMain( + _In_ HINSTANCE hInst, + _In_ WORD wReason, + _In_opt_ LPVOID + ) +{ + switch (wReason) + { + case DLL_PROCESS_ATTACH: + { + g_hInstance = hInst; + } + break; + } + + return TRUE; +} + +/*++ + +Routine Name: + + DllCanUnloadNow + +Routine Description: + + Determines whether the DLL is in use. + If not, the caller can unload the DLL from memory. + +Arguments: + + None + +Return Value: + + HRESULT + S_OK - Dll can unload + S_FALSE - Dll can't unload + +--*/ +STDAPI +DllCanUnloadNow() +{ + if (g_cServerLocks == 0) + { + return S_OK ; + } + else + { + return S_FALSE; + } +} + +/*++ + +Routine Name: + + DllGetClassObject + +Routine Description: + + Retrieves the class objects for the DLL. + Supported class ids are CLSID_OEMUI and CLSID_OEMPTPROVIDER. + Called from within the CoGetClassObject function. + +Arguments: + + rclsid - CLSID that will associate the correct data and code. + riid - Reference to the identifier of the interface that the caller is to use to communicate with the class object. + ppv - Address of pointer variable that receives the interface pointer requested in riid. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + CLASS_E_CLASSNOTAVAILABLE - On unsupported class + +--*/ +STDAPI +DllGetClassObject( + _In_ REFCLSID rclsid, + _In_ REFIID riid, + _Outptr_ LPVOID FAR* ppv + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(ppv, E_POINTER))) + { + *ppv = NULL; + + // + // Make sure the appropriate CLSID is being requested + // + if (rclsid == CLSID_OEMUI || + rclsid == CLSID_OEMPTPROVIDER) + { + CXDSmplUICF* pXDSmplUICF = new(std::nothrow) CXDSmplUICF(); + hr = CHECK_POINTER(pXDSmplUICF, E_OUTOFMEMORY); + + if (SUCCEEDED(hr)) + { + // + // Get the requested interface. + // + hr = pXDSmplUICF->QueryInterface(riid, ppv); + + // + // Release the IUnknown pointer. + // (If QueryInterface failed, component will delete itself.) + // + pXDSmplUICF->Release(); + } + } + else + { + hr = CLASS_E_CLASSNOTAVAILABLE; + } + } + + ERR_ON_HR(hr); + return hr; +} + diff --git a/print/XPSDrvSmpl/src/ui/docppg.cpp b/print/XPSDrvSmpl/src/ui/docppg.cpp new file mode 100644 index 00000000..c297741a --- /dev/null +++ b/print/XPSDrvSmpl/src/ui/docppg.cpp @@ -0,0 +1,1314 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + docppg.cpp + +Abstract: + + Implementation of the document property page class. This is an abstract + class that provides common functionality for all property pages including + accessors and the dialog proc. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdexcept.h" +#include "xdstring.h" +#include "docppg.h" + +/*++ + +Routine Name: + + CDocPropPage::CDocPropPage + +Routine Description: + + CDocPropPage class constructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CDocPropPage::CDocPropPage() : + m_hPage(NULL), + m_hComPropSheet(NULL), + m_pOemCUIPParam(NULL), + m_pfnComPropSheet(NULL), + m_pDriverUIHelp(NULL), + m_pUIProperties(NULL) +{ +} + +/*++ + +Routine Name: + + CDocPropPage::~CDocPropPage + +Routine Description: + + CDocPropPage class destructor. + +Arguments: + + None + +Return Value: + + None + +--*/ +CDocPropPage::~CDocPropPage() +{ + HRESULT hr = S_OK; + hr = DestroyUIComponents(); + + ASSERTMSG(SUCCEEDED(hr), "Error Deleting Property Pages/n"); +} + +/*++ + +Routine Name: + + CDocPropPage::PropPageInit + +Routine Description: + + Adds an additional Feature property page to the existing Unidrv supplied property pages. + Called from the Unidrv UI Plug-in entry point for DocumentPropertySheets(), + on the PROPSHEETUI_REASON_INIT message. + + This base class implementation provides common property page intialisation functionality for + all property pages. Derived property page classes are required to provide the dialog box template + and the dialog box title. + +Arguments: + + pPSUIInfo - Pointer to a PPROPSHEETUI_INFO structure. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CDocPropPage::PropPageInit( + _In_ CONST PPROPSHEETUI_INFO pPSUIInfo + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pPSUIInfo, E_POINTER))) + { + // + // Only proceed if we have effectively published the helper interfaces to the UI + // control objects. + // + // We also need to retrieve the dialog template resource and dialog title from the + // derived property page class. + // + PROPSHEETPAGE page = {0}; + if (SUCCEEDED(hr = PublishHelpToControls()) && + SUCCEEDED(hr = InitDlgBox(&page.pszTemplate, &page.pszTitle))) + { + page.dwSize = sizeof(PROPSHEETPAGE); + page.dwFlags = PSP_DEFAULT | PSP_USETITLE; + page.hInstance = g_hInstance; + + page.pfnDlgProc = CDocPropPage::DlgProc; + page.lParam = reinterpret_cast(this); + + pPSUIInfo->Result = pPSUIInfo->pfnComPropSheet(pPSUIInfo->hComPropSheet, + CPSFUNC_ADD_PROPSHEETPAGE, + reinterpret_cast(&page), + 0); + + if (SUCCEEDED(hr = SetComPropSheetFunc(pPSUIInfo->pfnComPropSheet)) && + SUCCEEDED(hr = SetPageHandle(reinterpret_cast(pPSUIInfo->Result)))) + { + hr = SetComPropSheetHandle(pPSUIInfo->hComPropSheet); + } + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CDocPropPage::StoreThis + +Routine Description: + + Stores a pointer to this instance of the CDocPropPage class + that will be associated with the windows handle provided. + +Arguments: + + hDlg - Handle of the property page window associated with this class. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CDocPropPage::StoreThis( + _In_ CONST HWND hDlg + ) +{ + HRESULT hr = S_OK; + + if (!SetProp(hDlg, MAKEINTATOM(ID_XDSMPL_DLG_ATOM), reinterpret_cast(this))) + { + hr = E_FAIL; + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CDocPropPage::RetrieveThis + +Routine Description: + + Obtains the instance of the CDocPropPage class that is associated with a windows handle. + +Arguments: + + hDlg - Handle of the property page Window associated with this class. + pDocPropPage - Address of a pointer to be filled out with the instance of this class. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ + +HRESULT +CDocPropPage::RetrieveThis( + _In_ CONST HWND hDlg, + _Outptr_ CDocPropPage** pDocPropPage + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_HANDLE(hDlg, E_HANDLE)) && + SUCCEEDED(hr = CHECK_POINTER(pDocPropPage, E_POINTER))) + { + *pDocPropPage = reinterpret_cast(GetProp(hDlg, MAKEINTATOM(ID_XDSMPL_DLG_ATOM))); + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CDocPropPage::RemoveThis + +Routine Description: + + Removes the class pointer from the associated windows handle. + +Arguments: + + hDlg - Handle of the property page Window associated with this class. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CDocPropPage::RemoveThis( + _In_ CONST HWND hDlg + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_HANDLE(hDlg, E_HANDLE))) + { + RemoveProp(hDlg, MAKEINTATOM(ID_XDSMPL_DLG_ATOM)); + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CDocPropPage::SetComPropSheetFunc + +Routine Description: + + Store the pointer to the PFNCOMPROPSHEET function. + +Arguments: + + pfnComPropSheet - pointer to the PFNCOMPROPSHEET function. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CDocPropPage::SetComPropSheetFunc( + _In_ CONST PFNCOMPROPSHEET pfnComPropSheet + ) +{ + HRESULT hr = S_OK; + + ASSERTMSG(pfnComPropSheet != NULL, "NULL pointer to common propert sheet functions.\n"); + + if (SUCCEEDED(hr = CHECK_POINTER(pfnComPropSheet, E_POINTER))) + { + m_pfnComPropSheet = pfnComPropSheet; + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CDocPropPage::SetPageHandle + +Routine Description: + + Store the handle of a property page window. + +Arguments: + + hPage - Handle of a property page window. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CDocPropPage::SetPageHandle( + _In_ CONST HANDLE hPage + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_HANDLE(hPage, E_HANDLE))) + { + m_hPage = hPage; + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CDocPropPage::SetComPropSheetHandle + +Routine Description: + + Store the handle of the Common Property Sheet window. + +Arguments: + + hComPropSheet - Handle of the common property sheet window. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CDocPropPage::SetComPropSheetHandle( + _In_ CONST HANDLE hComPropSheet + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_HANDLE(hComPropSheet, E_HANDLE))) + { + m_hComPropSheet = hComPropSheet; + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CDocPropPage::GetComPropSheetFunc + +Routine Description: + + Retrieve the pointer of the PFNCOMPROPSHEET function. + +Arguments: + + ppfnComPropSheet - Address of a pointer that will be filled out with the PFNCOMPROPSHEET function. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CDocPropPage::GetComPropSheetFunc( + _Outptr_ PFNCOMPROPSHEET* ppfnComPropSheet + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(ppfnComPropSheet, E_POINTER))) + { + *ppfnComPropSheet = m_pfnComPropSheet; + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CDocPropPage::GetPageHandle + +Routine Description: + + Retrieves the property page handle. + +Arguments: + + None + +Return Value: + + Handle to the property page + +--*/ +HANDLE +CDocPropPage::GetPageHandle( + VOID + ) +{ + return m_hPage; +} + +/*++ + +Routine Name: + + CDocPropPage::GetComPropSheetHandle + +Routine Description: + + Retrieves the common property sheet handle + +Arguments: + + None + +Return Value: + + Handle to the common property sheet + +--*/ +HANDLE +CDocPropPage::GetComPropSheetHandle( + VOID + ) +{ + return m_hComPropSheet; +} + +/*++ + +Routine Name: + + CDocPropPage::DestroyUIComponents + +Routine Description: + + Destroy all control handler classes that have been added into the collection. + +Arguments: + + None + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CDocPropPage::DestroyUIComponents( + VOID + ) +{ + HRESULT hr = S_OK; + + try + { + UIControlMap::iterator iterUIComponents = m_UIControls.begin(); + + while (iterUIComponents != m_UIControls.end()) + { + if (iterUIComponents->second != NULL) + { + delete iterUIComponents->second; + iterUIComponents->second = NULL; + } + iterUIComponents++; + } + } + catch (exception& DBG_ONLY(e)) + { + ERR(e.what()); + hr = E_FAIL; + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CDocPropPage::AddUIControl + +Routine Description: + + Adds a control handler class into the collection. + +Arguments: + + iCtrlID - Resource Identifier of control. + pUIControl - Pointer to a control handler class. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CDocPropPage::AddUIControl( + _In_ CONST INT iCtrlID, + _In_ CUIControl* pUIControl + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pUIControl, E_POINTER))) + { + try + { + m_UIControls[iCtrlID] = pUIControl; + } + catch (exception& DBG_ONLY(e)) + { + ERR(e.what()); + hr = E_FAIL; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CDocPropPage::GetUIComponents + +Routine Description: + + Obtains the collection of control handlers. + +Arguments: + + ppUIComponents - Address of the pointer that will be filled out with the contain handler collection. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CDocPropPage::GetUIComponents( + _Outptr_ UIControlMap** ppUIComponents + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(ppUIComponents, E_POINTER))) + { + *ppUIComponents = &m_UIControls; + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CDocPropPage::SetOemCUIPParam + +Routine Description: + + Store the pointer to the POEMCUIPPARAM function. + +Arguments: + + pOemCUIPParam - pointer to the POEMCUIPPARAM function. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CDocPropPage::SetOemCUIPParam( + _In_ CONST POEMCUIPPARAM pOemCUIPParam + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pOemCUIPParam, E_POINTER))) + { + m_pOemCUIPParam = pOemCUIPParam; + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CDocPropPage::SetUIProperties + +Routine Description: + + Store the pointer to an CUIProperties interface. + +Arguments: + + pUIProperties - pointer to an CUIProperties interface. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CDocPropPage::SetUIProperties( + _In_ CUIProperties* pUIProperties + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pUIProperties, E_POINTER))) + { + m_pUIProperties = pUIProperties; + } + + ERR_ON_HR(hr); + return hr; +} + + +/*++ + +Routine Name: + + CDocPropPage::GetOemCUIPParam + +Routine Description: + + Retrieve the pointer to the OEMCUIPPARAM function. + +Arguments: + + ppOemCUIPParam - Address of a pointer that will be filled out with the POEMCUIPPARAM function. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CDocPropPage::GetOemCUIPParam( + _Outptr_ POEMCUIPPARAM* ppOemCUIPParam + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(ppOemCUIPParam, E_POINTER))) + { + *ppOemCUIPParam = m_pOemCUIPParam; + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CDocPropPage::SetPrintOemDriverUI + +Routine Description: + + Store a pointer to the IPrintOemDriverUI interface. + +Arguments: + + pOEMDriverUI - pointer to the IPrintOemDriverUI interface. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CDocPropPage::SetPrintOemDriverUI( + _In_ CONST IPrintOemDriverUI* pOEMDriverUI + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pOEMDriverUI, E_POINTER))) + { + m_pDriverUIHelp = const_cast(pOEMDriverUI); + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CDocPropPage::PublishHelpToControls + +Routine Description: + + Propagate any useful interfaces used in this class down to the collection of control handlers. + This allows access to these helper interfaces in the control handlers classes. + +Arguments: + + None + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CDocPropPage::PublishHelpToControls( + VOID + ) +{ + ASSERTMSG(m_pDriverUIHelp != NULL, "NULL pointer to driver UI help interface.\n"); + ASSERTMSG(m_pOemCUIPParam != NULL, "NULL pointer to OEMCUIPPARAM structure.\n"); + ASSERTMSG(m_pUIProperties != NULL, "NULL pointer to CUIProperties.\n"); + + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(m_pDriverUIHelp, E_PENDING)) && + SUCCEEDED(hr = CHECK_POINTER(m_pOemCUIPParam, E_PENDING)) && + SUCCEEDED(hr = CHECK_POINTER(m_pUIProperties, E_PENDING))) + { + try + { + // + // Iterate over all controls and report the helper interfaces + // + if (!m_UIControls.empty()) + { + UIControlMap::iterator iterUIComponents = m_UIControls.begin(); + + while (iterUIComponents != m_UIControls.end()) + { + CUIControl* pControl = iterUIComponents->second; + + if (SUCCEEDED(hr = CHECK_POINTER(pControl, E_POINTER)) && + SUCCEEDED(hr = pControl->SetPrintOemDriverUI(m_pDriverUIHelp)) && + SUCCEEDED(hr = pControl->SetUIProperties(m_pUIProperties)) && + SUCCEEDED(hr = pControl->SetOemCUIPParam(m_pOemCUIPParam))) + { + iterUIComponents++; + } + } + + } + } + catch (exception& DBG_ONLY(e)) + { + ERR(e.what()); + hr = E_FAIL; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CDocPropPage::SendCommand + +Routine Description: + + Call the OnCommand() method in the relevant control handler in the collection. + +Arguments: + + hDlg - Handle of property page. + wParam - Windows WPARAM value passed with the windows message WM_COMMAND. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CDocPropPage::SendCommand( + _In_ CONST HWND hDlg, + _In_ CONST WPARAM wParam + ) +{ + // + // Use the wParam as the index into the control map and + // inform the control that generated the command + // + HRESULT hr = S_OK; + + UIControlMap* pComponents = NULL; + + if (SUCCEEDED(hr = GetUIComponents(&pComponents)) && + SUCCEEDED(hr = CHECK_POINTER(pComponents, E_POINTER))) + { + try + { + CUIControl* pControl = (*pComponents)[LOWORD(wParam)]; + if (SUCCEEDED(hr = CHECK_POINTER(pControl, E_POINTER))) + { + hr = pControl->OnCommand(hDlg, HIWORD(wParam)); + } + } + catch (exception& DBG_ONLY(e)) + { + ERR(e.what()); + hr = E_FAIL; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CDocPropPage::SendNotify + +Routine Description: + + Call the OnNotify() method in the relevant control handler in the collection. + +Arguments: + + hDlg - Handle of property page. + pNMhdr - Windows Notify structure that was passed with the windows message WM_NOTIFY. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CDocPropPage::SendNotify( + _In_ CONST HWND hDlg, + _In_ CONST NMHDR* pNMhdr + ) +{ + // + // Use the wParam as the index into the control map and + // inform the control of an activation + // + HRESULT hr = S_OK; + + UIControlMap* pComponents = NULL; + + if (SUCCEEDED(hr = GetUIComponents(&pComponents)) && + SUCCEEDED(hr = CHECK_POINTER(pComponents, E_POINTER))) + { + try + { + CUIControl* pControl = (*pComponents)[pNMhdr->idFrom]; + if (SUCCEEDED(hr = CHECK_POINTER(pControl, E_POINTER))) + { + hr = pControl->OnNotify(hDlg, pNMhdr); + } + } + catch (exception& DBG_ONLY(e)) + { + ERR(e.what()); + hr = E_FAIL; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CDocPropPage::SendSetActive + +Routine Description: + + Call the OnActivate() method in all control handlers in the collection. + +Arguments: + + hDlg - Handle of property page. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CDocPropPage::SendSetActive( + _In_ CONST HWND hDlg + ) +{ + // + // Use the wParam as the index into the control map and + // inform the control of an activation + // + HRESULT hr = S_OK; + + UIControlMap* pComponents = NULL; + + if (SUCCEEDED(hr = GetUIComponents(&pComponents)) && + SUCCEEDED(hr = CHECK_POINTER(pComponents, E_POINTER))) + { + try + { + UIControlMap::iterator iterUIComponents = pComponents->begin(); + + while (iterUIComponents != pComponents->end()) + { + CUIControl* pControl = iterUIComponents->second; + if (SUCCEEDED(hr = CHECK_POINTER(pControl, E_POINTER))) + { + if (FAILED(hr = pControl->OnActivate(hDlg))) + { + break; + } + } + + iterUIComponents++; + } + } + catch (exception& DBG_ONLY(e)) + { + ERR(e.what()); + hr = E_FAIL; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CDocPropPage::SendInit + +Routine Description: + + Call the OnInit() method in all control handlers in the collection. + +Arguments: + + hDlg - Handle of property page. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CDocPropPage::SendInit( + _In_ CONST HWND hDlg + ) +{ + // + // Use the wParam as the index into the control map and + // inform the control of an activation + // + HRESULT hr = S_OK; + + UIControlMap* pComponents = NULL; + + if (SUCCEEDED(hr = GetUIComponents(&pComponents)) && + SUCCEEDED(hr = CHECK_POINTER(pComponents, E_POINTER))) + { + try + { + UIControlMap::iterator iterUIComponents = pComponents->begin(); + + while (iterUIComponents != pComponents->end()) + { + CUIControl* pControl = iterUIComponents->second; + if (SUCCEEDED(hr = CHECK_POINTER(pControl, E_POINTER))) + { + if (FAILED(hr = pControl->OnInit(hDlg))) + { + break; + } + } + + iterUIComponents++; + } + } + catch (exception& DBG_ONLY(e)) + { + ERR(e.what()); + hr = E_FAIL; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CDocPropPage::DlgProc + +Routine Description: + + Dialog proccedure for the property page. + This handles all windows messages that are sent to the property page. + +Arguments: + + hDlg - Handle of the property page. + uiMessage - Specifies the message. + wParam - Specifies additional message-specific information. + lParam - Specifies additional message-specific information. + +Return Value: + + The return value is the result of the message processing and depends on the message sent. + +--*/ +INT_PTR CALLBACK +CDocPropPage::DlgProc( + _In_ CONST HWND hDlg, + _In_ CONST UINT uiMessage, + _In_ CONST WPARAM wParam, + _In_ CONST LPARAM lParam + ) +{ + HRESULT hr = S_OK; + BOOL retVal = FALSE; + + switch (uiMessage) + { + case WM_INITDIALOG: + { + // + // Store the class instance + // + PROPSHEETPAGE* pPage = reinterpret_cast(lParam); + + if (SUCCEEDED(hr = CHECK_POINTER(pPage, E_POINTER))) + { + if (pPage->lParam != NULL) + { + CDocPropPage* thisInst = reinterpret_cast(pPage->lParam); + + if (SUCCEEDED(hr = CHECK_POINTER(thisInst, E_FAIL))) + { + if (SUCCEEDED(hr = thisInst->StoreThis(hDlg))) + { + hr = thisInst->SendInit(hDlg); + } + } + } + else + { + hr = E_FAIL; + } + } + + // + // Set the keyboard focus to the control specified by wParam + // + retVal = TRUE; + } + break; + + case WM_COMMAND: + { + switch (HIWORD(wParam)) + { + case EN_CHANGE: + case BN_CLICKED: + case CBN_SELCHANGE: + // case LBN_SELCHANGE: CBN_SELCHANGE=LBN_SELCHANGE + { + CDocPropPage* thisInst; + + if (SUCCEEDED(hr = RetrieveThis(hDlg, &thisInst))) + { + if (SUCCEEDED(hr = CHECK_POINTER(thisInst, E_FAIL))) + { + hr = thisInst->SendCommand(hDlg, wParam); + } + } + + // + // Set to FALSE to indiate that the message has been handled. + // + retVal = FALSE; + } + break; + + default: + { + // + // Unhandled command so return TRUE + // + retVal = TRUE; + } + break; + } + } + break; + + case WM_NOTIFY: + { + NMHDR* pHdr = reinterpret_cast(lParam); + if (SUCCEEDED(hr = CHECK_POINTER(pHdr, E_POINTER))) + { + switch (pHdr->code) + { + case PSN_SETACTIVE: + { + CDocPropPage* thisInst; + + if (SUCCEEDED(hr = RetrieveThis(hDlg, &thisInst)) && + SUCCEEDED(hr = CHECK_POINTER(thisInst, E_FAIL))) + { + hr = thisInst->SendSetActive(hDlg); + } + + // + // Return FALSE to accept the page activation + // + retVal = FALSE; + } + break; + + case PSN_KILLACTIVE: + { + // + // Return FALSE to allow the page to lose activation + // + retVal = FALSE; + } + break; + + case PSN_APPLY: + { + PFNCOMPROPSHEET pfnComPropSheet = NULL; + + CDocPropPage* thisInst; + + if (SUCCEEDED(hr = RetrieveThis(hDlg, &thisInst)) && + SUCCEEDED(hr = CHECK_POINTER(thisInst, E_FAIL)) && + SUCCEEDED(hr = thisInst->GetComPropSheetFunc(&pfnComPropSheet)) && + SUCCEEDED(hr = CHECK_POINTER(pfnComPropSheet, E_FAIL))) + { + // + // Ensure that the last error is in a known state. + // + SetLastError(0); + + // + // We do not need to validate any settings so set PSNRET_NOERROR + // + if (SetWindowLongPtr(hDlg, DWLP_MSGRESULT, PSNRET_NOERROR) == 0) + { + // + // A return value of 0 does not necessarily indicate a failure. + // + hr = HRESULT_FROM_WIN32(GetLastError()); + } + + if (SUCCEEDED(hr)) + { + // + // We have applied the change... + // + PropSheet_UnChanged(GetParent(hDlg), hDlg); + + // + // Inform the propsheet + // + pfnComPropSheet(thisInst->GetComPropSheetHandle(), + CPSFUNC_SET_RESULT, + reinterpret_cast(thisInst->GetPageHandle()), + (LPARAM)CPSUI_OK); + } + } + + retVal = TRUE; + } + break; + + case UDN_DELTAPOS: + { + CDocPropPage* thisInst; + + if (SUCCEEDED(hr = RetrieveThis(hDlg, &thisInst)) && + SUCCEEDED(hr = CHECK_POINTER(thisInst, E_FAIL))) + { + hr = thisInst->SendNotify(hDlg, pHdr); + } + + // + // Set return to FALSE to allow the control value + // + retVal = FALSE; + } + break; + } + } + } + break; + + case WM_NCDESTROY: + { + CDocPropPage* thisInst; + + if (SUCCEEDED(hr = CDocPropPage::RetrieveThis(hDlg, &thisInst)) && + SUCCEEDED(hr = CHECK_POINTER(thisInst, E_FAIL))) + { + hr = thisInst->RemoveThis(hDlg); + } + + // + // Set return to FALSE to indicate that the message was processed + // + retVal = FALSE; + } + break; + } + + ERR_ON_HR(hr); + return retVal; +} + diff --git a/print/XPSDrvSmpl/src/ui/docppg.h b/print/XPSDrvSmpl/src/ui/docppg.h new file mode 100644 index 00000000..1a6d1dc5 --- /dev/null +++ b/print/XPSDrvSmpl/src/ui/docppg.h @@ -0,0 +1,186 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + docppg.h + +Abstract: + + Definition of the document property page class. This is an abstract + class that provides common functionality for all property pages including + accessors and the dialog proc. + +--*/ + +#pragma once + +#include "uictrl.h" + +#define ID_XDSMPL_DLG_ATOM 1000 + +typedef std::map UIControlMap; + +class CDocPropPage +{ +public: + CDocPropPage(); + + virtual ~CDocPropPage(); + + virtual HRESULT + InitDlgBox( + _Out_ LPCTSTR* ppszTemplate, + _Out_ LPCTSTR* ppszTitle + ) = 0; + + // + // Implementation + // + virtual HRESULT + PropPageInit( + _In_ CONST PPROPSHEETUI_INFO pPSUIInfo + ); + + virtual HRESULT + SetPrintOemDriverUI( + _In_ CONST IPrintOemDriverUI* pOEMDriverUI + ); + + virtual HRESULT + SetOemCUIPParam( + _In_ CONST POEMCUIPPARAM pOemCUIParam + ); + + virtual HRESULT + SetUIProperties( + _In_ CUIProperties* pUIProperties + ); + + static INT_PTR CALLBACK + DlgProc( + _In_ HWND hDlg, + _In_ UINT uiMessage, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +protected: + HRESULT + StoreThis( + _In_ CONST HWND hDlg + ); + + static HRESULT + RetrieveThis( + _In_ CONST HWND hDlg, + _Outptr_ CDocPropPage** pDocPropPage + ); + + HRESULT + RemoveThis( + _In_ CONST HWND hDlg + ); + + HRESULT + SetComPropSheetFunc( + _In_ CONST PFNCOMPROPSHEET pfnComPropSheet + ); + + HRESULT + SetPageHandle( + _In_ CONST HANDLE hPage + ); + + HRESULT + SetComPropSheetHandle( + _In_ CONST HANDLE hComPropSheet + ); + + HRESULT + GetComPropSheetFunc( + _Outptr_ PFNCOMPROPSHEET* ppfnComPropSheet + ); + + HANDLE + GetPageHandle( + VOID + ); + + HANDLE + GetComPropSheetHandle( + VOID + ); + + HRESULT + AddUIControl( + _In_ CONST INT iCtrlID, + _In_ CUIControl* pUIControl + ); + + HRESULT + GetUIComponents( + _Outptr_ UIControlMap** ppUIComponents + ); + + HRESULT + GetOemCUIPParam( + _Outptr_ POEMCUIPPARAM* ppOemCUIPParam + ); + + HRESULT + PublishHelpToControls( + VOID + ); + + HRESULT + SendCommand( + _In_ CONST HWND hDlg, + _In_ CONST WPARAM wParam + ); + + HRESULT + SendSetActive( + _In_ CONST HWND hDlg + ); + + HRESULT + SendInit( + _In_ CONST HWND hDlg + ); + + HRESULT + SendNotify( + _In_ CONST HWND hDlg, + _In_ CONST NMHDR* pNMhdr + ); + + HRESULT + DestroyUIComponents( + VOID + ); + +private: + UIControlMap m_UIControls; + + CComPtr m_pDriverUIHelp; + + HANDLE m_hPage; + + HANDLE m_hComPropSheet; + + PFNCOMPROPSHEET m_pfnComPropSheet; + + POEMCUIPPARAM m_pOemCUIPParam; + + CUIProperties* m_pUIProperties; +}; + diff --git a/print/XPSDrvSmpl/src/ui/ftrctrls.cpp b/print/XPSDrvSmpl/src/ui/ftrctrls.cpp new file mode 100644 index 00000000..94923e9a --- /dev/null +++ b/print/XPSDrvSmpl/src/ui/ftrctrls.cpp @@ -0,0 +1,1667 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + ftrctrls.cpp + +Abstract: + + Implementation of the features property page UI controls. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdstring.h" +#include "resource.h" +#include "ftrctrls.h" +#include "privatedefs.h" + +PCSTR CUICtrlFeatPgScaleCombo::m_pszFeatPgScale = "PageScaling"; + +PCSTR CUICtrlFeatScaleOffsetCombo::m_pszFeatScaleOffset = "ScaleOffsetAlignment"; + +PCSTR CUICtrlFeatPgScaleXEdit::m_pszFeatPgScaleX = "PageScalingScaleWidth"; +PCSTR CUICtrlFeatPgScaleXSpin::m_pszFeatPgScaleX = "PageScalingScaleWidth"; +PCSTR CUICtrlFeatPgScaleYEdit::m_pszFeatPgScaleY = "PageScalingScaleHeight"; +PCSTR CUICtrlFeatPgScaleYSpin::m_pszFeatPgScaleY = "PageScalingScaleHeight"; +PCSTR CUICtrlFeatPgOffsetXEdit::m_pszFeatPgOffsetX = "PageScalingOffsetWidth"; +PCSTR CUICtrlFeatPgOffsetXSpin::m_pszFeatPgOffsetX = "PageScalingOffsetWidth"; +PCSTR CUICtrlFeatPgOffsetYEdit::m_pszFeatPgOffsetY = "PageScalingOffsetHeight"; +PCSTR CUICtrlFeatPgOffsetYSpin::m_pszFeatPgOffsetY = "PageScalingOffsetHeight"; + +PCSTR CUICtrlFeatNUpCombo::m_pszFeatNUp = "DocumentNUp"; +PCSTR CUICtrlFeatNUpOrderCombo::m_pszFeatNUpOrder = "DocumentNUpPresentationOrder"; + +PCSTR CUICtrlFeatDocDuplexCombo::m_pszFeatDocDuplex = "DocumentDuplex"; +PCSTR CUICtrlFeatPhotIntCombo::m_pszFeatPhotInt = "PagePhotoPrintingIntent"; +PCSTR CUICtrlFeatBordersCheck::m_pszFeatBorders = "PageBorderless"; + +PCSTR CUICtrlFeatJobBindCombo::m_pszFeatJobBind = "JobBindAllDocuments"; +PCSTR CUICtrlFeatDocBindCombo::m_pszFeatDocBind = "DocumentBinding"; + +#define PGSCALE_NONE_SEL 0 +#define PGSCALE_CUSTOM_SEL 1 +#define PGSCALE_CUSTSQUARE_SEL 2 +#define PGSCALE_FITBLEED_SEL 3 +#define PGSCALE_FITCONTENT_SEL 4 +#define PGSCALE_FITPAGE_SEL 5 +#define PGSCALE_SCALEPAGETOPAGE_SEL 6 + +#define JOBBIND_NONE_SEL 0 + +// +// Page scale selection combo box control +// +/*++ + +Routine Name: + + CUICtrlFeatPgScaleCombo::CUICtrlFeatPgScaleCombo + +Routine Description: + + CUICtrlFeatPgScaleCombo class constructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlFeatPgScaleCombo::CUICtrlFeatPgScaleCombo() : + CUICtrlDefaultCombo(m_pszFeatPgScale, IDC_COMBO_PGSCALE) +{ +} + +/*++ + +Routine Name: + + CUICtrlFeatPgScaleCombo::~CUICtrlFeatPgScaleCombo + +Routine Description: + + CUICtrlFeatPgScaleCombo class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlFeatPgScaleCombo::~CUICtrlFeatPgScaleCombo() +{ +} + +/*++ + +Routine Name: + + CUICtrlFeatPgScaleCombo::OnInit + +Routine Description: + + This is responsible for initialising the control and is called when + the WM_INITDIALOG message is recieved. This method populates the combo + box with the appropriate option strings. + +Arguments: + + hDlg - handle to the parent window + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CUICtrlFeatPgScaleCombo::OnInit( + _In_ CONST HWND hDlg + ) +{ + HRESULT hr = S_OK; + + // + // Populate the combo box + // + if (SUCCEEDED(hr = AddString(hDlg, g_hInstance, IDS_GPD_NONE)) && + SUCCEEDED(hr = AddString(hDlg, g_hInstance, IDS_GPD_CUSTOM)) && + SUCCEEDED(hr = AddString(hDlg, g_hInstance, IDS_GPD_CUSTSQUARE)) && + SUCCEEDED(hr = AddString(hDlg, g_hInstance, IDS_GPD_FITBLEED)) && + SUCCEEDED(hr = AddString(hDlg, g_hInstance, IDS_GPD_FITCONTENT)) && + SUCCEEDED(hr = AddString(hDlg, g_hInstance, IDS_GPD_FITPAGE))) + { + hr = AddString(hDlg, g_hInstance, IDS_GPD_SCALEPAGETOPAGE); + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CUICtrlFeatPgScaleCombo::EnableDependentCtrls + +Routine Description: + + This method is used to enable or disable other controls in the UI based on the + current combo box selection. + +Arguments: + + hDlg - handle to the parent window + lSel - current combo box selection + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CUICtrlFeatPgScaleCombo::EnableDependentCtrls( + _In_ CONST HWND hDlg, + _In_ CONST LONG lSel + ) +{ + HRESULT hr = S_OK; + HWND hWnd = NULL; + + BOOL bNone = (lSel == PGSCALE_NONE_SEL); + BOOL bCustom = (lSel == PGSCALE_CUSTOM_SEL); + BOOL bCustomSquare = (lSel == PGSCALE_CUSTSQUARE_SEL); + BOOL bFit = !(bCustom | bCustomSquare) && !bNone; + + // + // Here we are enabling/disabling and showing/hiding the page scale controls + // based on the currently selected options. + // + // If custom scaling is selected we need to enable and show the X/Y offset and X/Y + // scaling controls and hide the "fit to" options. If we custom square scaling is + // selected we show the same controls as custom scaling but disable the Y scaling + // control so the user can only apply the scale in one dimension. + // + // If one of the "fit to" options (FitApplicationBleedSizeToPageImageableSize etc.) + // is selected we disable and hide the custom controls (X/Y offset and scale) and enable + // the offset alignment option control. + // + if (SUCCEEDED(hr = CHECK_HANDLE(hWnd = GetDlgItem(hDlg, IDC_EDIT_PGSCALEX), E_HANDLE))) + { + EnableWindow(hWnd, bCustom | bCustomSquare); + ShowWindow(hWnd, (bCustom | bCustomSquare | bNone) ? SW_SHOW : SW_HIDE); + } + + if (SUCCEEDED(hr) && + SUCCEEDED(hr = CHECK_HANDLE(hWnd = GetDlgItem(hDlg, IDC_SPIN_PGSCALEX), E_HANDLE))) + { + EnableWindow(hWnd, bCustom | bCustomSquare); + ShowWindow(hWnd, (bCustom | bCustomSquare | bNone) ? SW_SHOW : SW_HIDE); + } + + if (SUCCEEDED(hr) && + SUCCEEDED(hr = CHECK_HANDLE(hWnd = GetDlgItem(hDlg, IDC_TXT_PGSCALEX), E_HANDLE))) + { + EnableWindow(hWnd, bCustom | bCustomSquare); + ShowWindow(hWnd, (bCustom | bCustomSquare | bNone) ? SW_SHOW : SW_HIDE); + } + + if (SUCCEEDED(hr) && + SUCCEEDED(hr = CHECK_HANDLE(hWnd = GetDlgItem(hDlg, IDC_EDIT_PGSCALEY), E_HANDLE))) + { + EnableWindow(hWnd, bCustom); + ShowWindow(hWnd, (bCustom | bCustomSquare | bNone) ? SW_SHOW : SW_HIDE); + } + + if (SUCCEEDED(hr) && + SUCCEEDED(hr = CHECK_HANDLE(hWnd = GetDlgItem(hDlg, IDC_SPIN_PGSCALEY), E_HANDLE))) + { + EnableWindow(hWnd, bCustom); + ShowWindow(hWnd, (bCustom | bCustomSquare | bNone) ? SW_SHOW : SW_HIDE); + } + + if (SUCCEEDED(hr) && + SUCCEEDED(hr = CHECK_HANDLE(hWnd = GetDlgItem(hDlg, IDC_TXT_PGSCALEY), E_HANDLE))) + { + EnableWindow(hWnd, bCustom); + ShowWindow(hWnd, (bCustom | bCustomSquare | bNone) ? SW_SHOW : SW_HIDE); + } + + if (SUCCEEDED(hr) && + SUCCEEDED(hr = CHECK_HANDLE(hWnd = GetDlgItem(hDlg, IDC_EDIT_PGOFFX), E_HANDLE))) + { + EnableWindow(hWnd, bCustom | bCustomSquare); + ShowWindow(hWnd, (bCustom | bCustomSquare | bNone) ? SW_SHOW : SW_HIDE); + } + + if (SUCCEEDED(hr) && + SUCCEEDED(hr = CHECK_HANDLE(hWnd = GetDlgItem(hDlg, IDC_SPIN_PGOFFX), E_HANDLE))) + { + EnableWindow(hWnd, bCustom | bCustomSquare); + ShowWindow(hWnd, (bCustom | bCustomSquare | bNone) ? SW_SHOW : SW_HIDE); + } + + if (SUCCEEDED(hr) && + SUCCEEDED(hr = CHECK_HANDLE(hWnd = GetDlgItem(hDlg, IDC_TXT_PGOFFX), E_HANDLE))) + { + EnableWindow(hWnd, bCustom | bCustomSquare); + ShowWindow(hWnd, (bCustom | bCustomSquare | bNone) ? SW_SHOW : SW_HIDE); + } + + if (SUCCEEDED(hr) && + SUCCEEDED(hr = CHECK_HANDLE(hWnd = GetDlgItem(hDlg, IDC_EDIT_PGOFFY), E_HANDLE))) + { + EnableWindow(hWnd, bCustom | bCustomSquare); + ShowWindow(hWnd, (bCustom | bCustomSquare | bNone) ? SW_SHOW : SW_HIDE); + } + + if (SUCCEEDED(hr) && + SUCCEEDED(hr = CHECK_HANDLE(hWnd = GetDlgItem(hDlg, IDC_SPIN_PGOFFY), E_HANDLE))) + { + EnableWindow(hWnd, bCustom | bCustomSquare); + ShowWindow(hWnd, (bCustom | bCustomSquare | bNone) ? SW_SHOW : SW_HIDE); + } + + if (SUCCEEDED(hr) && + SUCCEEDED(hr = CHECK_HANDLE(hWnd = GetDlgItem(hDlg, IDC_TXT_PGOFFY), E_HANDLE))) + { + EnableWindow(hWnd, bCustom | bCustomSquare); + ShowWindow(hWnd, (bCustom | bCustomSquare | bNone) ? SW_SHOW : SW_HIDE); + } + + if (SUCCEEDED(hr) && + SUCCEEDED(hr = CHECK_HANDLE(hWnd = GetDlgItem(hDlg, IDC_COMBO_SCALEOFF), E_HANDLE))) + { + EnableWindow(hWnd, bFit); + ShowWindow(hWnd, bFit ? SW_SHOW : SW_HIDE); + } + + if (SUCCEEDED(hr) && + SUCCEEDED(hr = CHECK_HANDLE(hWnd = GetDlgItem(hDlg, IDC_TXT_SCALEOFF), E_HANDLE))) + { + EnableWindow(hWnd, bFit); + ShowWindow(hWnd, bFit ? SW_SHOW : SW_HIDE); + } + + if (FAILED(hr)) + { + hr = HRESULT_FROM_WIN32(GetLastError()); + } + + ERR_ON_HR(hr); + return hr; +} + +// +// Page scale selection combo box control +// +/*++ + +Routine Name: + + CUICtrlFeatScaleOffsetCombo::CUICtrlFeatScaleOffsetCombo + +Routine Description: + + CUICtrlFeatScaleOffsetCombo class constructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlFeatScaleOffsetCombo::CUICtrlFeatScaleOffsetCombo() : + CUICtrlDefaultCombo(m_pszFeatScaleOffset, IDC_COMBO_SCALEOFF) +{ +} + +/*++ + +Routine Name: + + CUICtrlFeatScaleOffsetCombo::~CUICtrlFeatScaleOffsetCombo + +Routine Description: + + CUICtrlFeatScaleOffsetCombo class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlFeatScaleOffsetCombo::~CUICtrlFeatScaleOffsetCombo() +{ +} + +/*++ + +Routine Name: + + CUICtrlFeatScaleOffsetCombo::OnInit + +Routine Description: + + This is responsible for initialising the control and is called when + the WM_INITDIALOG message is recieved. This method populates the combo + box with the appropriate option strings. + +Arguments: + + hDlg - handle to the parent window + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CUICtrlFeatScaleOffsetCombo::OnInit( + _In_ CONST HWND hDlg + ) +{ + HRESULT hr = S_OK; + + // + // Populate the combo box + // + if (SUCCEEDED(hr = AddString(hDlg, g_hInstance, IDS_GPD_SCALE_ALIGN_BC)) && + SUCCEEDED(hr = AddString(hDlg, g_hInstance, IDS_GPD_SCALE_ALIGN_BL)) && + SUCCEEDED(hr = AddString(hDlg, g_hInstance, IDS_GPD_SCALE_ALIGN_BR)) && + SUCCEEDED(hr = AddString(hDlg, g_hInstance, IDS_GPD_SCALE_ALIGN_CC)) && + SUCCEEDED(hr = AddString(hDlg, g_hInstance, IDS_GPD_SCALE_ALIGN_LC)) && + SUCCEEDED(hr = AddString(hDlg, g_hInstance, IDS_GPD_SCALE_ALIGN_CR)) && + SUCCEEDED(hr = AddString(hDlg, g_hInstance, IDS_GPD_SCALE_ALIGN_CT)) && + SUCCEEDED(hr = AddString(hDlg, g_hInstance, IDS_GPD_SCALE_ALIGN_TL))) + { + hr = AddString(hDlg, g_hInstance, IDS_GPD_SCALE_ALIGN_TR); + } + + ERR_ON_HR(hr); + return hr; +} + +#define NUP_1PPS_SEL 0 + +// +// NUp page per sheet combo box control +// +/*++ + +Routine Name: + + CUICtrlFeatNUpCombo::CUICtrlFeatNUpCombo + +Routine Description: + + CUICtrlFeatNUpCombo class constructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlFeatNUpCombo::CUICtrlFeatNUpCombo() : + CUICtrlDefaultCombo(m_pszFeatNUp, IDC_COMBO_NUP) +{ +} + +/*++ + +Routine Name: + + CUICtrlFeatNUpCombo::~CUICtrlFeatNUpCombo + +Routine Description: + + CUICtrlFeatNUpCombo class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlFeatNUpCombo::~CUICtrlFeatNUpCombo() +{ +} + +/*++ + +Routine Name: + + CUICtrlFeatNUpCombo::OnInit + +Routine Description: + + This is responsible for initialising the control and is called when + the WM_INITDIALOG message is recieved. This method populates the combo + box with the appropriate option strings. + +Arguments: + + hDlg - handle to the parent window + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CUICtrlFeatNUpCombo::OnInit( + _In_ CONST HWND hDlg + ) +{ + HRESULT hr = S_OK; + + // + // Populate the combo box + // + if (SUCCEEDED(hr = AddString(hDlg, g_hInstance, IDS_GPD_1PPS)) && + SUCCEEDED(hr = AddString(hDlg, g_hInstance, IDS_GPD_2PPS)) && + SUCCEEDED(hr = AddString(hDlg, g_hInstance, IDS_GPD_4PPS)) && + SUCCEEDED(hr = AddString(hDlg, g_hInstance, IDS_GPD_6PPS)) && + SUCCEEDED(hr = AddString(hDlg, g_hInstance, IDS_GPD_8PPS)) && + SUCCEEDED(hr = AddString(hDlg, g_hInstance, IDS_GPD_9PPS))) + { + hr = AddString(hDlg, g_hInstance, IDS_GPD_16PPS); + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CUICtrlFeatNUpCombo::EnableDependentCtrls + +Routine Description: + + This method is used to enable or disable other controls in the UI based on the + current combo box selection. + +Arguments: + + hDlg - handle to the parent window + lSel - current combo box selection + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CUICtrlFeatNUpCombo::EnableDependentCtrls( + _In_ CONST HWND hDlg, + _In_ CONST LONG lSel + ) +{ + HRESULT hr = S_OK; + HWND hWnd = NULL; + + // + // Here we are enabling/disabling the NUp and Binding controls depending on the current + // NUp selection. + // + // When NUp is more than 1 page per sheet we enable the NUp order controls and disable + // binding option controls. + // + if (SUCCEEDED(hr = CHECK_HANDLE(hWnd = GetDlgItem(hDlg, IDC_COMBO_NUP_ORDER), E_HANDLE))) + { + EnableWindow(hWnd, lSel > NUP_1PPS_SEL); + } + + if (SUCCEEDED(hr) && + SUCCEEDED(hr = CHECK_HANDLE(hWnd = GetDlgItem(hDlg, IDC_TXT_NUP_ORDER), E_HANDLE))) + { + EnableWindow(hWnd, lSel > NUP_1PPS_SEL); + } + + if (SUCCEEDED(hr) && + SUCCEEDED(hr = CHECK_HANDLE(hWnd = GetDlgItem(hDlg, IDC_COMBO_JOBBIND), E_HANDLE))) + { + EnableWindow(hWnd, lSel == NUP_1PPS_SEL); + } + + if (SUCCEEDED(hr) && + SUCCEEDED(hr = CHECK_HANDLE(hWnd = GetDlgItem(hDlg, IDC_TXT_JOBBIND), E_HANDLE))) + { + EnableWindow(hWnd, lSel == NUP_1PPS_SEL); + } + + if (SUCCEEDED(hr) && + SUCCEEDED(hr = CHECK_HANDLE(hWnd = GetDlgItem(hDlg, IDC_COMBO_DOCBIND), E_HANDLE))) + { + EnableWindow(hWnd, lSel == NUP_1PPS_SEL); + } + + if (SUCCEEDED(hr) && + SUCCEEDED(hr = CHECK_HANDLE(hWnd = GetDlgItem(hDlg, IDC_TXT_DOCBIND), E_HANDLE))) + { + EnableWindow(hWnd, lSel == NUP_1PPS_SEL); + } + + if (FAILED(hr)) + { + hr = HRESULT_FROM_WIN32(GetLastError()); + } + + ERR_ON_HR(hr); + return hr; +} + +// +// NUp presentation order combo box control +// +/*++ + +Routine Name: + + CUICtrlFeatNUpOrderCombo::CUICtrlFeatNUpOrderCombo + +Routine Description: + + CUICtrlFeatNUpOrderCombo class constructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlFeatNUpOrderCombo::CUICtrlFeatNUpOrderCombo() : + CUICtrlDefaultCombo(m_pszFeatNUpOrder, IDC_COMBO_NUP_ORDER) +{ +} + +/*++ + +Routine Name: + + CUICtrlFeatNUpOrderCombo::~CUICtrlFeatNUpOrderCombo + +Routine Description: + + CUICtrlFeatNUpOrderCombo class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlFeatNUpOrderCombo::~CUICtrlFeatNUpOrderCombo() +{ +} + +/*++ + +Routine Name: + + CUICtrlFeatNUpOrderCombo::OnInit + +Routine Description: + + This is responsible for initialising the control and is called when + the WM_INITDIALOG message is recieved. This method populates the combo + box with the appropriate option strings. + +Arguments: + + hDlg - handle to the parent window + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CUICtrlFeatNUpOrderCombo::OnInit( + _In_ CONST HWND hDlg + ) +{ + HRESULT hr = S_OK; + + // + // Populate the combo box + // + if (SUCCEEDED(hr = AddString(hDlg, g_hInstance, IDS_GPD_LTORTTOB)) && + SUCCEEDED(hr = AddString(hDlg, g_hInstance, IDS_GPD_TTOBLTOR)) && + SUCCEEDED(hr = AddString(hDlg, g_hInstance, IDS_GPD_RTOLTTOB)) && + SUCCEEDED(hr = AddString(hDlg, g_hInstance, IDS_GPD_TTOBRTOL)) && + SUCCEEDED(hr = AddString(hDlg, g_hInstance, IDS_GPD_LTORBTOT)) && + SUCCEEDED(hr = AddString(hDlg, g_hInstance, IDS_GPD_BTOTLTOR)) && + SUCCEEDED(hr = AddString(hDlg, g_hInstance, IDS_GPD_RTOLBTOT))) + { + hr = AddString(hDlg, g_hInstance, IDS_GPD_BTOTRTOL); + } + + ERR_ON_HR(hr); + return hr; +} + +// +// Binding combo box control +// +/*++ + +Routine Name: + + CUICtrlFeatJobBindCombo::CUICtrlFeatJobBindCombo + +Routine Description: + + CUICtrlFeatJobBindCombo class constructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlFeatJobBindCombo::CUICtrlFeatJobBindCombo() : + CUICtrlDefaultCombo(m_pszFeatJobBind, IDC_COMBO_JOBBIND) +{ +} + +/*++ + +Routine Name: + + CUICtrlFeatJobBindCombo::~CUICtrlFeatJobBindCombo + +Routine Description: + + CUICtrlFeatJobBindCombo class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlFeatJobBindCombo::~CUICtrlFeatJobBindCombo() +{ +} + +/*++ + +Routine Name: + + CUICtrlFeatJobBindCombo::OnInit + +Routine Description: + + This is responsible for initialising the control and is called when + the WM_INITDIALOG message is recieved. This method populates the combo + box with the appropriate option strings. + +Arguments: + + hDlg - handle to the parent window + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CUICtrlFeatJobBindCombo::OnInit( + _In_ CONST HWND hDlg + ) +{ + HRESULT hr = S_OK; + // + // Populate the combo box + // + if (SUCCEEDED(hr = AddString(hDlg, g_hInstance, IDS_GPD_NONE)) && + SUCCEEDED(hr = AddString(hDlg, g_hInstance, IDS_GPD_LTOR)) && + SUCCEEDED(hr = AddString(hDlg, g_hInstance, IDS_GPD_RTOL)) && + SUCCEEDED(hr = AddString(hDlg, g_hInstance, IDS_GPD_TTOB))) + { + hr = AddString(hDlg, g_hInstance, IDS_GPD_BTOT); + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CUICtrlFeatJobBindCombo::EnableDependentCtrls + +Routine Description: + + This method is used to enable or disable other controls in the UI based on the + current combo box selection. + +Arguments: + + hDlg - handle to the parent window + lSel - current combo box selection + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CUICtrlFeatJobBindCombo::EnableDependentCtrls( + _In_ CONST HWND hDlg, + _In_ CONST LONG lSel + ) +{ + HRESULT hr = S_OK; + HWND hWnd = NULL; + + // + // Here we are enabling/disabling binding and NUp controls based off the current + // binding option. + // + // If JobBindAllDocuments option is selected we disable DocumentBinding and NUp controls. + // + if (SUCCEEDED(hr = CHECK_HANDLE(hWnd = GetDlgItem(hDlg, IDC_COMBO_DOCBIND), E_HANDLE))) + { + EnableWindow(hWnd, (lSel == JOBBIND_NONE_SEL)); + } + + if (SUCCEEDED(hr) && + (SUCCEEDED(hr = CHECK_HANDLE(hWnd = GetDlgItem(hDlg, IDC_TXT_DOCBIND), E_HANDLE)))) + { + EnableWindow(hWnd, (lSel == JOBBIND_NONE_SEL)); + } + + if (SUCCEEDED(hr = CHECK_HANDLE(hWnd = GetDlgItem(hDlg, IDC_COMBO_NUP), E_HANDLE))) + { + EnableWindow(hWnd, (lSel == JOBBIND_NONE_SEL)); + } + + if (SUCCEEDED(hr) && + (SUCCEEDED(hr = CHECK_HANDLE(hWnd = GetDlgItem(hDlg, IDC_TXT_NUP), E_HANDLE)))) + { + EnableWindow(hWnd, (lSel == JOBBIND_NONE_SEL)); + } + + if (SUCCEEDED(hr = CHECK_HANDLE(hWnd = GetDlgItem(hDlg, IDC_TXT_NUP_ORDER), E_HANDLE))) + { + EnableWindow(hWnd, (lSel == JOBBIND_NONE_SEL)); + } + + if (SUCCEEDED(hr) && + (SUCCEEDED(hr = CHECK_HANDLE(hWnd = GetDlgItem(hDlg, IDC_COMBO_NUP_ORDER), E_HANDLE)))) + { + EnableWindow(hWnd, (lSel == JOBBIND_NONE_SEL)); + } + + if (FAILED(hr)) + { + hr = HRESULT_FROM_WIN32(GetLastError()); + } + + ERR_ON_HR(hr); + return hr; +} + +// +// Binding Direction combo box control +// +/*++ + +Routine Name: + + CUICtrlFeatDocBindCombo::CUICtrlFeatDocBindCombo + +Routine Description: + + CUICtrlFeatDocBindCombo class constructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlFeatDocBindCombo::CUICtrlFeatDocBindCombo() : + CUICtrlDefaultCombo(m_pszFeatDocBind, IDC_COMBO_DOCBIND) +{ +} + +/*++ + +Routine Name: + + CUICtrlFeatDocBindCombo::~CUICtrlFeatDocBindCombo + +Routine Description: + + CUICtrlFeatDocBindCombo class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlFeatDocBindCombo::~CUICtrlFeatDocBindCombo() +{ +} + +/*++ + +Routine Name: + + CUICtrlFeatDocBindCombo::OnInit + +Routine Description: + + This is responsible for initialising the control and is called when + the WM_INITDIALOG message is recieved. This method populates the combo + box with the appropriate option strings. + +Arguments: + + hDlg - handle to the parent window + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CUICtrlFeatDocBindCombo::OnInit( + _In_ CONST HWND hDlg + ) +{ + HRESULT hr = S_OK; + // + // Populate the combo box + // + if (SUCCEEDED(hr = AddString(hDlg, g_hInstance, IDS_GPD_NONE)) && + SUCCEEDED(hr = AddString(hDlg, g_hInstance, IDS_GPD_LTOR)) && + SUCCEEDED(hr = AddString(hDlg, g_hInstance, IDS_GPD_RTOL)) && + SUCCEEDED(hr = AddString(hDlg, g_hInstance, IDS_GPD_TTOB))) + { + hr = AddString(hDlg, g_hInstance, IDS_GPD_BTOT); + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CUICtrlFeatDocBindCombo::EnableDependentCtrls + +Routine Description: + + This method is used to enable or disable other controls in the UI based on the + current combo box selection. + +Arguments: + + hDlg - handle to the parent window + lSel - current combo box selection + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CUICtrlFeatDocBindCombo::EnableDependentCtrls( + _In_ CONST HWND hDlg, + _In_ CONST LONG lSel + ) +{ + HRESULT hr = S_OK; + HWND hWnd = NULL; + + // + // Here we are enabling/disabling binding and NUp controls based off the current + // DocumentBinding option. + // + // If DocumentBinding option is selected we disable JobBindAllDocuments and NUp controls. + // + if (SUCCEEDED(hr = CHECK_HANDLE(hWnd = GetDlgItem(hDlg, IDC_COMBO_NUP), E_HANDLE))) + { + EnableWindow(hWnd, (lSel == JOBBIND_NONE_SEL)); + } + + if (SUCCEEDED(hr) && + (SUCCEEDED(hr = CHECK_HANDLE(hWnd = GetDlgItem(hDlg, IDC_TXT_NUP), E_HANDLE)))) + { + EnableWindow(hWnd, (lSel == JOBBIND_NONE_SEL)); + } + + if (SUCCEEDED(hr = CHECK_HANDLE(hWnd = GetDlgItem(hDlg, IDC_TXT_NUP_ORDER), E_HANDLE))) + { + EnableWindow(hWnd, (lSel == JOBBIND_NONE_SEL)); + } + + if (SUCCEEDED(hr) && + (SUCCEEDED(hr = CHECK_HANDLE(hWnd = GetDlgItem(hDlg, IDC_COMBO_NUP_ORDER), E_HANDLE)))) + { + EnableWindow(hWnd, (lSel == JOBBIND_NONE_SEL)); + } + + if (FAILED(hr)) + { + hr = HRESULT_FROM_WIN32(GetLastError()); + } + + ERR_ON_HR(hr); + return hr; +} + +// +// Document photo printing intent combo box control +// +/*++ + +Routine Name: + + CUICtrlFeatPhotIntCombo::CUICtrlFeatPhotIntCombo + +Routine Description: + + CUICtrlFeatPhotIntCombo class constructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlFeatPhotIntCombo::CUICtrlFeatPhotIntCombo() : + CUICtrlDefaultCombo(m_pszFeatPhotInt, IDC_COMBO_PHOTO_INTENT) +{ +} + +/*++ + +Routine Name: + + CUICtrlFeatPhotIntCombo::~CUICtrlFeatPhotIntCombo + +Routine Description: + + CUICtrlFeatPhotIntCombo class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlFeatPhotIntCombo::~CUICtrlFeatPhotIntCombo() +{ +} + +/*++ + +Routine Name: + + CUICtrlFeatPhotIntCombo::OnInit + +Routine Description: + + This is responsible for initialising the control and is called when + the WM_INITDIALOG message is recieved. This method populates the combo + box with the appropriate option strings. + +Arguments: + + hDlg - handle to the parent window + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CUICtrlFeatPhotIntCombo::OnInit( + _In_ CONST HWND hDlg + ) +{ + HRESULT hr = S_OK; + + // + // Populate the combo box + // + if (SUCCEEDED(hr = AddString(hDlg, g_hInstance, IDS_GPD_NONE)) && + SUCCEEDED(hr = AddString(hDlg, g_hInstance, IDS_GPD_BEST)) && + SUCCEEDED(hr = AddString(hDlg, g_hInstance, IDS_GPD_DRAFT))) + { + hr = AddString(hDlg, g_hInstance, IDS_GPD_STANDARD); + } + + ERR_ON_HR(hr); + return hr; +} + +// +// Document duplex combo box control +// +/*++ + +Routine Name: + + CUICtrlFeatDocDuplexCombo::CUICtrlFeatDocDuplexCombo + +Routine Description: + + CUICtrlFeatDocDuplexCombo class constructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlFeatDocDuplexCombo::CUICtrlFeatDocDuplexCombo() : + CUICtrlDefaultCombo(m_pszFeatDocDuplex, IDC_COMBO_DOCDUPLEX) +{ +} + +/*++ + +Routine Name: + + CUICtrlFeatDocDuplexCombo::~CUICtrlFeatDocDuplexCombo + +Routine Description: + + CUICtrlFeatDocDuplexCombo class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlFeatDocDuplexCombo::~CUICtrlFeatDocDuplexCombo() +{ +} + +/*++ + +Routine Name: + + CUICtrlFeatDocDuplexCombo::OnInit + +Routine Description: + + This is responsible for initialising the control and is called when + the WM_INITDIALOG message is recieved. This method populates the combo + box with the appropriate option strings. + +Arguments: + + hDlg - handle to the parent window + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CUICtrlFeatDocDuplexCombo::OnInit( + _In_ CONST HWND hDlg + ) +{ + HRESULT hr = S_OK; + // + // Populate the combo box + // + if (SUCCEEDED(hr = AddString(hDlg, g_hInstance, IDS_GPD_NONE))&& + SUCCEEDED(hr = AddString(hDlg, g_hInstance, IDS_GPD_HORIZONTAL))) + { + hr = AddString(hDlg, g_hInstance, IDS_GPD_VERTICAL); + } + + ERR_ON_HR(hr); + return hr; +} + +// +// Document duplex combo box control +// +/*++ + +Routine Name: + + CUICtrlFeatPgScaleXEdit::CUICtrlFeatPgScaleXEdit + +Routine Description: + + CUICtrlFeatPgScaleXEdit class constructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlFeatPgScaleXEdit::CUICtrlFeatPgScaleXEdit() : + CUICtrlDefaultEditNum(m_pszFeatPgScaleX, + IDC_EDIT_PGSCALEX, + pgscParamDefIntegers[ePageScalingScaleWidth].min_length, + pgscParamDefIntegers[ePageScalingScaleWidth].max_length, + IDC_SPIN_PGSCALEX) +{ +} + +/*++ + +Routine Name: + + CUICtrlFeatPgScaleXEdit::~CUICtrlFeatPgScaleXEdit + +Routine Description: + + CUICtrlFeatPgScaleXEdit class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlFeatPgScaleXEdit::~CUICtrlFeatPgScaleXEdit() +{ +} + +/*++ + +Routine Name: + + CUICtrlFeatPgScaleXSpin::CUICtrlFeatPgScaleXSpin + +Routine Description: + + CUICtrlFeatPgScaleXSpin class constructor + +Arguments: + + pEdit - Pointer to the edit num buddy control + +Return Value: + + None + +--*/ +CUICtrlFeatPgScaleXSpin::CUICtrlFeatPgScaleXSpin( + _In_ CUICtrlDefaultEditNum* pEdit + ) : + CUICtrlDefaultSpin(pEdit) +{ +} + +/*++ + +Routine Name: + + CUICtrlFeatPgScaleXSpin::~CUICtrlFeatPgScaleXSpin + +Routine Description: + + CUICtrlFeatPgScaleXSpin class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlFeatPgScaleXSpin::~CUICtrlFeatPgScaleXSpin() +{ +} + +/*++ + +Routine Name: + + CUICtrlFeatPgScaleYEdit::CUICtrlFeatPgScaleYEdit + +Routine Description: + + CUICtrlFeatPgScaleYEdit class constructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlFeatPgScaleYEdit::CUICtrlFeatPgScaleYEdit() : + CUICtrlDefaultEditNum(m_pszFeatPgScaleY, + IDC_EDIT_PGSCALEY, + pgscParamDefIntegers[ePageScalingScaleHeight].min_length, + pgscParamDefIntegers[ePageScalingScaleHeight].max_length, + IDC_SPIN_PGSCALEY) +{ +} + +/*++ + +Routine Name: + + CUICtrlFeatPgScaleYEdit::~CUICtrlFeatPgScaleYEdit + +Routine Description: + + CUICtrlFeatPgScaleYEdit class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlFeatPgScaleYEdit::~CUICtrlFeatPgScaleYEdit() +{ +} + +/*++ + +Routine Name: + + CUICtrlFeatPgScaleYSpin::CUICtrlFeatPgScaleYSpin + +Routine Description: + + CUICtrlFeatPgScaleYSpin class constructor + +Arguments: + + pEdit - Pointer to the edit num buddy control + +Return Value: + + None + +--*/ +CUICtrlFeatPgScaleYSpin::CUICtrlFeatPgScaleYSpin( + _In_ CUICtrlDefaultEditNum* pEdit + ) : + CUICtrlDefaultSpin(pEdit) +{ +} + +/*++ + +Routine Name: + + CUICtrlFeatPgScaleYSpin::~CUICtrlFeatPgScaleYSpin + +Routine Description: + + CUICtrlFeatPgScaleYSpin class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlFeatPgScaleYSpin::~CUICtrlFeatPgScaleYSpin() +{ +} + +/*++ + +Routine Name: + + CUICtrlFeatPgOffsetXEdit::CUICtrlFeatPgOffsetXEdit + +Routine Description: + + CUICtrlFeatPgOffsetXEdit class constructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlFeatPgOffsetXEdit::CUICtrlFeatPgOffsetXEdit() : + CUICtrlDefaultEditNum(m_pszFeatPgOffsetX, + IDC_EDIT_PGOFFX, + MICRON_TO_HUNDREDTH_OFINCH(pgscParamDefIntegers[ePageScalingOffsetWidth].min_length), + MICRON_TO_HUNDREDTH_OFINCH(pgscParamDefIntegers[ePageScalingOffsetWidth].max_length), + IDC_SPIN_PGOFFX) +{ +} + +/*++ + +Routine Name: + + CUICtrlFeatPgOffsetXEdit::~CUICtrlFeatPgOffsetXEdit + +Routine Description: + + CUICtrlFeatPgOffsetXEdit class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlFeatPgOffsetXEdit::~CUICtrlFeatPgOffsetXEdit() +{ +} + +/*++ + +Routine Name: + + CUICtrlFeatPgOffsetXSpin::CUICtrlFeatPgOffsetXSpin + +Routine Description: + + CUICtrlFeatPgOffsetXSpin class constructor + +Arguments: + + pEdit - Pointer to the edit num buddy control + +Return Value: + + None + +--*/ +CUICtrlFeatPgOffsetXSpin::CUICtrlFeatPgOffsetXSpin( + _In_ CUICtrlDefaultEditNum* pEdit + ) : + CUICtrlDefaultSpin(pEdit) +{ +} + +/*++ + +Routine Name: + + CUICtrlFeatPgOffsetXSpin::~CUICtrlFeatPgOffsetXSpin + +Routine Description: + + CUICtrlFeatPgOffsetXSpin class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlFeatPgOffsetXSpin::~CUICtrlFeatPgOffsetXSpin() +{ +} + +/*++ + +Routine Name: + + CUICtrlFeatPgOffsetYEdit::CUICtrlFeatPgOffsetYEdit + +Routine Description: + + CUICtrlFeatPgOffsetYEdit class constructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlFeatPgOffsetYEdit::CUICtrlFeatPgOffsetYEdit() : + CUICtrlDefaultEditNum(m_pszFeatPgOffsetY, + IDC_EDIT_PGOFFY, + MICRON_TO_HUNDREDTH_OFINCH(pgscParamDefIntegers[ePageScalingOffsetHeight].min_length), + MICRON_TO_HUNDREDTH_OFINCH(pgscParamDefIntegers[ePageScalingOffsetHeight].max_length), + IDC_SPIN_PGOFFY) +{ +} + +/*++ + +Routine Name: + + CUICtrlFeatPgOffsetYEdit::~CUICtrlFeatPgOffsetYEdit + +Routine Description: + + CUICtrlFeatPgOffsetYEdit class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlFeatPgOffsetYEdit::~CUICtrlFeatPgOffsetYEdit() +{ +} + +/*++ + +Routine Name: + + CUICtrlFeatPgOffsetYSpin::CUICtrlFeatPgOffsetYSpin + +Routine Description: + + CUICtrlFeatPgOffsetYSpin class constructor + +Arguments: + + pEdit - Pointer to the edit num buddy control + +Return Value: + + None + +--*/ +CUICtrlFeatPgOffsetYSpin::CUICtrlFeatPgOffsetYSpin( + _In_ CUICtrlDefaultEditNum* pEdit + ) : + CUICtrlDefaultSpin(pEdit) +{ +} + +/*++ + +Routine Name: + + CUICtrlFeatPgOffsetYSpin::~CUICtrlFeatPgOffsetYSpin + +Routine Description: + + CUICtrlFeatPgOffsetYSpin class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlFeatPgOffsetYSpin::~CUICtrlFeatPgOffsetYSpin() +{ +} + +/*++ + +Routine Name: + + CUICtrlFeatBordersCheck::CUICtrlFeatBordersCheck + +Routine Description: + + CUICtrlFeatBordersCheck class constructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlFeatBordersCheck::CUICtrlFeatBordersCheck() : + CUICtrlDefaultCheck(m_pszFeatBorders, IDC_CHECK_BORDERLESS) +{ +} + +/*++ + +Routine Name: + + CUICtrlFeatBordersCheck::~CUICtrlFeatBordersCheck + +Routine Description: + + CUICtrlFeatBordersCheck class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlFeatBordersCheck::~CUICtrlFeatBordersCheck() +{ +} + diff --git a/print/XPSDrvSmpl/src/ui/ftrctrls.h b/print/XPSDrvSmpl/src/ui/ftrctrls.h new file mode 100644 index 00000000..6351bb49 --- /dev/null +++ b/print/XPSDrvSmpl/src/ui/ftrctrls.h @@ -0,0 +1,288 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + ftrctrls.h + +Abstract: + + Definition of the features property page UI controls. + +--*/ + +#pragma once + +#include "uictrl.h" + +class CUICtrlFeatPgScaleCombo : public CUICtrlDefaultCombo +{ +public: + CUICtrlFeatPgScaleCombo(); + + virtual ~CUICtrlFeatPgScaleCombo(); + + HRESULT + OnInit( + _In_ CONST HWND hDlg + ); + +private: + HRESULT + EnableDependentCtrls( + _In_ CONST HWND hDlg, + _In_ CONST LONG lSel + ); + +private: + static PCSTR m_pszFeatPgScale; +}; + +class CUICtrlFeatScaleOffsetCombo : public CUICtrlDefaultCombo +{ +public: + CUICtrlFeatScaleOffsetCombo(); + + virtual ~CUICtrlFeatScaleOffsetCombo(); + + HRESULT + OnInit( + _In_ CONST HWND hDlg + ); + +private: + static PCSTR m_pszFeatScaleOffset; +}; + +class CUICtrlFeatPgScaleXEdit : public CUICtrlDefaultEditNum +{ +public: + CUICtrlFeatPgScaleXEdit(); + + virtual ~CUICtrlFeatPgScaleXEdit(); + +private: + static PCSTR m_pszFeatPgScaleX; +}; + +class CUICtrlFeatPgScaleXSpin : public CUICtrlDefaultSpin +{ +public: + CUICtrlFeatPgScaleXSpin( + _In_ CUICtrlDefaultEditNum* pEdit + ); + + virtual ~CUICtrlFeatPgScaleXSpin(); + +private: + static PCSTR m_pszFeatPgScaleX; +}; + +class CUICtrlFeatPgOffsetXEdit : public CUICtrlDefaultEditNum +{ +public: + CUICtrlFeatPgOffsetXEdit(); + + virtual ~CUICtrlFeatPgOffsetXEdit(); + +private: + static PCSTR m_pszFeatPgOffsetX; +}; + +class CUICtrlFeatPgOffsetXSpin : public CUICtrlDefaultSpin +{ +public: + CUICtrlFeatPgOffsetXSpin( + _In_ CUICtrlDefaultEditNum* pEdit + ); + + virtual ~CUICtrlFeatPgOffsetXSpin(); + +private: + static PCSTR m_pszFeatPgOffsetX; +}; + +class CUICtrlFeatPgScaleYEdit : public CUICtrlDefaultEditNum +{ +public: + CUICtrlFeatPgScaleYEdit(); + + virtual ~CUICtrlFeatPgScaleYEdit(); + +private: + static PCSTR m_pszFeatPgScaleY; +}; + +class CUICtrlFeatPgScaleYSpin : public CUICtrlDefaultSpin +{ +public: + CUICtrlFeatPgScaleYSpin( + _In_ CUICtrlDefaultEditNum* pEdit + ); + + virtual ~CUICtrlFeatPgScaleYSpin(); + +private: + static PCSTR m_pszFeatPgScaleY; +}; + +class CUICtrlFeatPgOffsetYEdit : public CUICtrlDefaultEditNum +{ +public: + CUICtrlFeatPgOffsetYEdit(); + + virtual ~CUICtrlFeatPgOffsetYEdit(); + +private: + static PCSTR m_pszFeatPgOffsetY; +}; + +class CUICtrlFeatPgOffsetYSpin : public CUICtrlDefaultSpin +{ +public: + CUICtrlFeatPgOffsetYSpin( + _In_ CUICtrlDefaultEditNum* pEdit + ); + + virtual ~CUICtrlFeatPgOffsetYSpin(); + +private: + static PCSTR m_pszFeatPgOffsetY; +}; + +class CUICtrlFeatNUpCombo : public CUICtrlDefaultCombo +{ +public: + CUICtrlFeatNUpCombo(); + + virtual ~CUICtrlFeatNUpCombo(); + + HRESULT + OnInit( + _In_ CONST HWND hDlg + ); + +private: + HRESULT + EnableDependentCtrls( + _In_ CONST HWND hDlg, + _In_ CONST LONG lSel + ); + +private: + static PCSTR m_pszFeatNUp; +}; + +class CUICtrlFeatNUpOrderCombo : public CUICtrlDefaultCombo +{ +public: + CUICtrlFeatNUpOrderCombo(); + + virtual ~CUICtrlFeatNUpOrderCombo(); + + HRESULT + OnInit( + _In_ CONST HWND hDlg + ); + +private: + static PCSTR m_pszFeatNUpOrder; +}; + +class CUICtrlFeatJobBindCombo : public CUICtrlDefaultCombo +{ +public: + CUICtrlFeatJobBindCombo(); + + virtual ~CUICtrlFeatJobBindCombo(); + + HRESULT + OnInit( + _In_ CONST HWND hDlg + ); + +private: + HRESULT + EnableDependentCtrls( + _In_ CONST HWND hDlg, + _In_ CONST LONG lSel + ); + +private: + static PCSTR m_pszFeatJobBind; +}; + +class CUICtrlFeatDocBindCombo : public CUICtrlDefaultCombo +{ +public: + CUICtrlFeatDocBindCombo(); + + virtual ~CUICtrlFeatDocBindCombo(); + + HRESULT + OnInit( + _In_ CONST HWND hDlg + ); + +private: + HRESULT + EnableDependentCtrls( + _In_ CONST HWND hDlg, + _In_ CONST LONG lSel + ); + +private: + static PCSTR m_pszFeatDocBind; +}; + +class CUICtrlFeatPhotIntCombo : public CUICtrlDefaultCombo +{ +public: + CUICtrlFeatPhotIntCombo(); + + virtual ~CUICtrlFeatPhotIntCombo(); + + HRESULT + OnInit( + _In_ CONST HWND hDlg + ); + +private: + static PCSTR m_pszFeatPhotInt; +}; + +class CUICtrlFeatDocDuplexCombo : public CUICtrlDefaultCombo +{ +public: + CUICtrlFeatDocDuplexCombo(); + + virtual ~CUICtrlFeatDocDuplexCombo(); + + HRESULT + OnInit( + _In_ CONST HWND hDlg + ); + +private: + static PCSTR m_pszFeatDocDuplex; +}; + +class CUICtrlFeatBordersCheck : public CUICtrlDefaultCheck +{ +public: + CUICtrlFeatBordersCheck(); + + virtual ~CUICtrlFeatBordersCheck(); + +private: + static PCSTR m_pszFeatBorders; +}; + diff --git a/print/XPSDrvSmpl/src/ui/ftrdmptcnv.h b/print/XPSDrvSmpl/src/ui/ftrdmptcnv.h new file mode 100644 index 00000000..4ae471ea --- /dev/null +++ b/print/XPSDrvSmpl/src/ui/ftrdmptcnv.h @@ -0,0 +1,631 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + ftrdmptcnv.h + +Abstract: + + Defines the interface for a DevMode <-> PrintTicket feature conversion class + and an abstract class that handles the print core helper interface pointer. + +--*/ + +#pragma once + +template +struct GPDStringToOption +{ + PCSTR pszOption; + _T option; +}; + +class IFeatureDMPTConvert +{ +public: + IFeatureDMPTConvert(){} + + virtual ~IFeatureDMPTConvert(){} + + virtual HRESULT STDMETHODCALLTYPE + ConvertPrintTicketToDevMode( + _In_ IXMLDOMDocument2* pPrintTicket, + _In_ ULONG cbDevmode, + _Inout_ PDEVMODE pDevmode, + _In_ ULONG cbDrvPrivateSize, + _In_ PVOID pPrivateDevmode + ) = 0; + + virtual HRESULT STDMETHODCALLTYPE + ConvertDevModeToPrintTicket( + _In_ ULONG cbDevmode, + _In_ PDEVMODE pDevmode, + _In_ ULONG cbDrvPrivateSize, + _In_ PVOID pPrivateDevmode, + _Inout_ IXMLDOMDocument2* pPrintTicket + ) = 0; + + virtual HRESULT STDMETHODCALLTYPE + CompletePrintCapabilities( + _In_opt_ IXMLDOMDocument2* pPrintTicket, + _Inout_ IXMLDOMDocument2* pPrintCapabilities + ) = 0; + + virtual HRESULT STDMETHODCALLTYPE + PublishPrintTicketHelperInterface( + _In_ IPrintCoreHelperUni* pHelper + ) = 0; + + + virtual HRESULT STDMETHODCALLTYPE + ValidatePrintTicket( + _Inout_ IXMLDOMDocument2* pPrintTicket + ) = 0; +}; + +template +class CFeatureDMPTConvert : public IFeatureDMPTConvert +{ +public: + CFeatureDMPTConvert(){} + + virtual ~CFeatureDMPTConvert(){} + + /*++ + + Routine Name: + + ConvertPrintTicketToDevMode + + Routine Description: + + + The plug-in is passed an input Print Ticket that is fully populated, + and a devmode. This method controls the calls to update the DevMode + to reflect the settings defined in the PrintTicket. + + The template this class is instantiated using defines the data + type passed between routines. Derived classes define this data + and then act on it as appropriate to the feature. + + Arguments: + + pPrintTicket - pointer to input Print Ticket + cbDevmode - size in bytes of input full devmode + pDevmode - pointer to input full devmode buffer + cbDrvPrivateSize - buffer size in bytes of plug-in private devmode + pPrivateDevmode - pointer to plug-in private devmode buffer + + Return Value: + + HRESULT + S_OK - On success + E_* - On error + + --*/ + HRESULT STDMETHODCALLTYPE + ConvertPrintTicketToDevMode( + _In_ IXMLDOMDocument2* pPrintTicket, + _In_ ULONG cbDevmode, + _Inout_ PDEVMODE pDevmode, + _In_ ULONG cbDrvPrivateSize, + _In_ PVOID pPrivateDevmode + ) + { + HRESULT hr = S_OK; + + // + // Validate parameters + // + if (SUCCEEDED(hr = CHECK_POINTER(pDevmode, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pPrivateDevmode, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pPrintTicket, E_POINTER))) + { + if (cbDevmode < sizeof(DEVMODE) || + cbDrvPrivateSize == 0) + { + hr = E_INVALIDARG; + } + } + + if (SUCCEEDED(hr)) + { + // + // Initialise the GPD settings from the devmode and merge with + // the PrintTicket settings + // + _T ptData; + + if (SUCCEEDED(hr = GetPTDataSettingsFromDM(pDevmode, cbDevmode, pPrivateDevmode, cbDrvPrivateSize, &ptData)) && + SUCCEEDED(hr = MergePTDataSettingsWithPT(pPrintTicket, &ptData))) + { + // + // Set the combined options in the devmode + // + hr = SetPTDataInDM(ptData, pDevmode, cbDevmode, pPrivateDevmode, cbDrvPrivateSize); + } + } + + ERR_ON_HR(hr); + return hr; + } + + /*++ + + Routine Name: + + ConvertDevModeToPrintTicket + + Routine Description: + + Unidrv will call the routine with an Input PrintTicket that is + populated with public and Unidrv private features. This method + controls the calls to update the PrintTicket to reflect the + settings defined in the devmode. + + The template this class is instantiated using defines the data + type passed between routines. Derived classes define this data + and then act on it as appropriate to the feature. + + Arguments: + + cbDevmode - size in bytes of input full devmode + pDevmode - pointer to input full devmode buffer + cbDrvPrivateSize - buffer size in bytes of plug-in private devmode + pPrivateDevmode - pointer to plug-in private devmode buffer + pPrintTicket - pointer to input Print Ticket + + + Return Value: + + HRESULT + S_OK - On success + E_* - On error + + --*/ + HRESULT STDMETHODCALLTYPE + ConvertDevModeToPrintTicket( + _In_ ULONG cbDevmode, + _In_ PDEVMODE pDevmode, + _In_ ULONG cbDrvPrivateSize, + _In_ PVOID pPrivateDevmode, + _Inout_ IXMLDOMDocument2* pPrintTicket + ) + { + HRESULT hr = S_OK; + + // + // Validate parameters + // + if (SUCCEEDED(hr = CHECK_POINTER(pDevmode, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pPrivateDevmode, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pPrintTicket, E_POINTER))) + { + if (cbDevmode < sizeof(DEVMODE) || + cbDrvPrivateSize == 0) + { + hr = E_INVALIDARG; + } + } + + if (SUCCEEDED(hr)) + { + // + // Initialise the GPD settings from the devmode + // + _T ptData; + + if (SUCCEEDED(hr = GetPTDataSettingsFromDM(pDevmode, cbDevmode, pPrivateDevmode, cbDrvPrivateSize, &ptData))) + { + // + // Set the options in the PrintTicket + // + hr = SetPTDataInPT(ptData, pPrintTicket); + } + } + + ERR_ON_HR(hr); + return hr; + } + + /*++ + + Routine Name: + + PublishPrintTicketHelperInterface + + Routine Description: + + This routine is stores the print core helper interface for use by + derived feature specific DM<->PT conversion classes. + + Arguments: + + pHelper - Pointer to core helper interface + + Return Value: + + HRESULT + S_OK - On success + E_* - On error + + --*/ + HRESULT STDMETHODCALLTYPE + PublishPrintTicketHelperInterface( + _In_ IPrintCoreHelperUni* pHelper + ) + { + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pHelper, E_POINTER)) && + m_pCoreHelper == NULL) + { + m_pCoreHelper = pHelper; + } + + ERR_ON_HR(hr); + return hr; + } + + /*++ + + Routine Name: + + ValidatePrintTicket + + Routine Description: + + Default validate implementation - just returns S_NO_CONFLICT. If the + derived feature specific class needs to validate the PrintTicket it + should provide its own implementation and handle the PrintTicket + appropriately. + + Arguments: + + pPrintTicket - Pointer to input Print Ticket. + + Return Value: + + HRESULT + S_NO_CONFLICT - On success + E_* - On error + + --*/ + virtual HRESULT STDMETHODCALLTYPE + ValidatePrintTicket( + _Inout_ IXMLDOMDocument2* pPrintTicket + ) + { + HRESULT hr = S_NO_CONFLICT; + + if (SUCCEEDED(hr = CHECK_POINTER(pPrintTicket, E_POINTER))) + { + hr = S_NO_CONFLICT; + } + + ERR_ON_HR(hr); + return hr; + } + +protected: + /*++ + + Routine Name: + + GetPTDataSettingsFromDM + + Routine Description: + + This pure virtual function ensures the concrete feature converter class + implements a means of retrieving the data type defined by that class from + the DevMode. + + Arguments: + + pDevmode - pointer to input devmode buffer. + cbDevmode - size in bytes of full input devmode. + pPrivateDevmode - pointer to input private devmode buffer. + cbDrvPrivateSize - size in bytes of private devmode. + pDataSettings - Pointer to data structure defined by a template argument to be updated. + + Return Value: + + HRESULT + S_OK - On success + E_* - On error + + --*/ + virtual HRESULT + GetPTDataSettingsFromDM( + _In_ PDEVMODE pDevmode, + _In_ ULONG cbDevmode, + _In_ PVOID pPrivateDevmode, + _In_ ULONG cbDrvPrivateSize, + _Out_ _T* pDataSettings + ) = 0; + + /*++ + + Routine Name: + + MergePTDataSettingsWithPT + + Routine Description: + + This pure virtual function ensures the concrete feature converter class + implements a means of merging the data type defined by that class from + the PrintTicket settings. + + Arguments: + + pPrintTicket - Pointer to the PrintTicket to merge the data structure with. + pDataSettings - Pointer to data structure defined by a template argument to be updated. + + Return Value: + + HRESULT + S_OK - On success + E_* - On error + + --*/ + virtual HRESULT + MergePTDataSettingsWithPT( + _In_ IXMLDOMDocument2* pPrintTicket, + _Inout_ _T* pDrvSettings + ) = 0; + + /*++ + + Routine Name: + + SetPTDataInDM + + Routine Description: + + This pure virtual function ensures the concrete feature converter class + implements a means of setting the data type defined by that class in the + DevMode. + + Arguments: + + dataSettings - const reference to the data structure defined by a template argument to be update from. + pDevmode - pointer to input devmode buffer. + cbDevmode - size in bytes of full input devmode. + pPrivateDevmode - pointer to input private devmode buffer. + cbDrvPrivateSize - size in bytes of private devmode. + + Return Value: + + HRESULT + S_OK - On success + E_* - On error + + --*/ + virtual HRESULT + SetPTDataInDM( + _In_ CONST _T& dataSettings, + _Inout_ PDEVMODE pDevmode, + _In_ ULONG cbDevmode, + _Inout_ PVOID pPrivateDevmode, + _In_ ULONG cbDrvPrivateSize + ) = 0; + + /*++ + + Routine Name: + + SetPTDataInPT + + Routine Description: + + This pure virtual function ensures the concrete feature converter class + implements a means of setting the data type defined by that class in the + PrintTicket. + + Arguments: + + dataSettings - const reference to the data structure defined by a template argument to be update from. + pPrintTicket - Pointer to the PrintTicket to update the data structure with. + + Return Value: + + HRESULT + S_OK - On success + E_* - On error + + --*/ + virtual HRESULT + SetPTDataInPT( + _In_ CONST _T& dataSettings, + _Inout_ IXMLDOMDocument2* pPrintTicket + ) = 0; + + /*++ + + Routine Name: + + GetOptionFromGPDString + + Routine Description: + + This template function takes as a template parameter the type of the + data to be retrieved from the DevMode. A table is passed through that + provides the look-up between the GPD string and the data type to be + returned. The routine then iterates through the options for the feature + specified matching against look-up and returning the corresponding value. + + Arguments: + + pDevmode - pointer to input DevMode. + cbDevmode - count of bytes in the input devmode. + pszFeature - string defining the feature name to match against. + pOptTable - pointer to the look-up table matching the GPD option strings to the option value. + cOptEntries - the number of entries in the look-up table + result - reference to the result value to be updated (type defined by the template argument) + + + Return Value: + + HRESULT + S_OK - On success + E_* - On error + + --*/ + template + HRESULT + GetOptionFromGPDString( + _In_ PDEVMODE pDevmode, + _In_ ULONG cbDevmode, + _In_z_ PCSTR pszFeature, + _In_ CONST GPDStringToOption<_U>* pOptTable, + _In_ CONST UINT cOptEntries, + _Out_ _U& result + ) + { + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pDevmode, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pszFeature, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pOptTable, E_POINTER))) + { + if (cbDevmode < sizeof(DEVMODE)) + { + hr = E_INVALIDARG; + } + } + + if (SUCCEEDED(hr)) + { + BOOL bFound = FALSE; + + if (cOptEntries > 0) + { + PCSTR pszOption = NULL; + + if (SUCCEEDED(hr = m_pCoreHelper->GetOption(pDevmode, cbDevmode, pszFeature, &pszOption))) + { + CStringXDA cstrOption(pszOption); + for (UINT index = 0; index < cOptEntries && !bFound; index++) + { + if (cstrOption == pOptTable->pszOption) + { + result = pOptTable->option; + bFound = TRUE; + } + else + { + pOptTable++; + } + } + } + } + + if (!bFound) + { + hr = E_ELEMENT_NOT_FOUND; + } + } + + ERR_ON_HR(hr); + return hr; + } + + /*++ + + Routine Name: + + SetGPDStringFromOption + + Routine Description: + + This template function takes as a template parameter the type of the + data to be set in the DevMode. A table is passed through that provides + the look-up between the GPD string and the data type to be set. The routine + then iterates through the options for the feature specified matching against + the look-up and setting the corresponding value in the DevMode. + + Arguments: + + pDevmode - pointer to input DevMode. + cbDevmode - count of bytes in the input devmode. + pszFeature - string defining the feature name to match against. + pOptTable - pointer to the look-up table matching the GPD option strings to the option value. + cOptEntries - the number of entries in the look-up table + result - const reference to the result value to update from (type defined by the template argument) + + Return Value: + + HRESULT + S_OK - On success + E_* - On error + + --*/ + template + HRESULT + SetGPDStringFromOption( + _Inout_ PDEVMODE pDevmode, + _In_ ULONG cbDevmode, + _In_z_ PCSTR pszFeature, + _In_ CONST GPDStringToOption<_U>* pOptTable, + _In_ CONST UINT cOptEntries, + _In_ CONST _U& option + ) + { + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pDevmode, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pszFeature, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pOptTable, E_POINTER))) + { + if (cbDevmode < sizeof(DEVMODE)) + { + hr = E_INVALIDARG; + } + } + + if (SUCCEEDED(hr)) + { + if (cOptEntries > 0) + { + for (UINT index = 0; index < cOptEntries; index++) + { + if (option == pOptTable->option) + { + PRINT_FEATURE_OPTION featureOption[1] = { + pszFeature, + pOptTable->pszOption + }; + + DWORD dwResult = 0; + DWORD cPairsWritten = 0; + + hr = m_pCoreHelper->SetOptions(pDevmode, cbDevmode, TRUE, featureOption, 1, &cPairsWritten, &dwResult); + + break; + } + else + { + pOptTable++; + } + } + } + } + + ERR_ON_HR(hr); + return hr; + } + + +protected: + CComPtr m_pCoreHelper; +}; + diff --git a/print/XPSDrvSmpl/src/ui/ftrppg.cpp b/print/XPSDrvSmpl/src/ui/ftrppg.cpp new file mode 100644 index 00000000..5cb4ea8f --- /dev/null +++ b/print/XPSDrvSmpl/src/ui/ftrppg.cpp @@ -0,0 +1,270 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + ftrppg.cpp + +Abstract: + + Implementation of the feature property page. This class is + responsible for initialising and registering the features + property page and its controls. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdexcept.h" +#include "xdstring.h" +#include "resource.h" +#include "ftrppg.h" +#include "ftrctrls.h" + +/*++ + +Routine Name: + + CFeaturePropPage::CFeaturePropPage + +Routine Description: + + CFeaturePropPage class constructor. + Creates a handler class object for every control on the feature property page. + Each of these handlers is stored in a collection. + +Arguments: + + None + +Return Value: + + None + Throws CXDException(HRESULT) on an error + +--*/ +CFeaturePropPage::CFeaturePropPage() +{ + HRESULT hr = S_OK; + + try + { + CUIControl* pControl = new(std::nothrow) CUICtrlFeatPgScaleCombo(); + if (SUCCEEDED(hr = CHECK_POINTER(pControl, E_OUTOFMEMORY))) + { + hr = AddUIControl(IDC_COMBO_PGSCALE, pControl); + } + + if (SUCCEEDED(hr)) + { + pControl = new(std::nothrow) CUICtrlFeatScaleOffsetCombo(); + if (SUCCEEDED(hr = CHECK_POINTER(pControl, E_OUTOFMEMORY))) + { + hr = AddUIControl(IDC_COMBO_SCALEOFF, pControl); + } + } + + if (SUCCEEDED(hr)) + { + pControl = new(std::nothrow) CUICtrlFeatPgScaleXEdit(); + if (SUCCEEDED(hr = CHECK_POINTER(pControl, E_OUTOFMEMORY)) && + SUCCEEDED(hr = AddUIControl(IDC_EDIT_PGSCALEX, pControl))) + { + pControl = new(std::nothrow) CUICtrlFeatPgScaleXSpin(reinterpret_cast(pControl)); + if (SUCCEEDED(hr = CHECK_POINTER(pControl, E_OUTOFMEMORY))) + { + hr = AddUIControl(IDC_SPIN_PGSCALEX, pControl); + } + } + } + + if (SUCCEEDED(hr)) + { + pControl = new(std::nothrow) CUICtrlFeatPgOffsetXEdit(); + if (SUCCEEDED(hr = CHECK_POINTER(pControl, E_OUTOFMEMORY)) && + SUCCEEDED(hr = AddUIControl(IDC_EDIT_PGOFFX, pControl))) + { + pControl = new(std::nothrow) CUICtrlFeatPgOffsetXSpin(reinterpret_cast(pControl)); + if (SUCCEEDED(hr = CHECK_POINTER(pControl, E_OUTOFMEMORY))) + { + hr = AddUIControl(IDC_SPIN_PGOFFX, pControl); + } + } + } + + if (SUCCEEDED(hr)) + { + pControl = new(std::nothrow) CUICtrlFeatPgScaleYEdit(); + if (SUCCEEDED(hr = CHECK_POINTER(pControl, E_OUTOFMEMORY)) && + SUCCEEDED(hr = AddUIControl(IDC_EDIT_PGSCALEY, pControl))) + { + pControl = new(std::nothrow) CUICtrlFeatPgScaleYSpin(reinterpret_cast(pControl)); + if (SUCCEEDED(hr = CHECK_POINTER(pControl, E_OUTOFMEMORY))) + { + hr = AddUIControl(IDC_SPIN_PGSCALEY, pControl); + } + } + } + + if (SUCCEEDED(hr)) + { + pControl = new(std::nothrow) CUICtrlFeatPgOffsetYEdit(); + if (SUCCEEDED(hr = CHECK_POINTER(pControl, E_OUTOFMEMORY)) && + SUCCEEDED(hr = AddUIControl(IDC_EDIT_PGOFFY, pControl))) + { + pControl = new(std::nothrow) CUICtrlFeatPgOffsetYSpin(reinterpret_cast(pControl)); + if (SUCCEEDED(hr = CHECK_POINTER(pControl, E_OUTOFMEMORY))) + { + hr = AddUIControl(IDC_SPIN_PGOFFY, pControl); + } + } + } + + if (SUCCEEDED(hr)) + { + pControl = new(std::nothrow) CUICtrlFeatNUpCombo(); + if (SUCCEEDED(hr = CHECK_POINTER(pControl, E_OUTOFMEMORY))) + { + hr = AddUIControl(IDC_COMBO_NUP, pControl); + } + } + + if (SUCCEEDED(hr)) + { + pControl = new(std::nothrow) CUICtrlFeatNUpOrderCombo(); + if (SUCCEEDED(hr = CHECK_POINTER(pControl, E_OUTOFMEMORY))) + { + hr = AddUIControl(IDC_COMBO_NUP_ORDER, pControl); + } + } + + if (SUCCEEDED(hr)) + { + pControl = new(std::nothrow) CUICtrlFeatPhotIntCombo(); + if (SUCCEEDED(hr = CHECK_POINTER(pControl, E_OUTOFMEMORY))) + { + hr = AddUIControl(IDC_COMBO_PHOTO_INTENT, pControl); + } + } + + if (SUCCEEDED(hr)) + { + pControl = new(std::nothrow) CUICtrlFeatDocDuplexCombo(); + if (SUCCEEDED(hr = CHECK_POINTER(pControl, E_OUTOFMEMORY))) + { + hr = AddUIControl(IDC_COMBO_DOCDUPLEX, pControl); + } + } + + if (SUCCEEDED(hr)) + { + pControl = new(std::nothrow) CUICtrlFeatBordersCheck(); + if (SUCCEEDED(hr = CHECK_POINTER(pControl, E_OUTOFMEMORY))) + { + hr = AddUIControl(IDC_CHECK_BORDERLESS, pControl); + } + } + + if (SUCCEEDED(hr)) + { + pControl = new(std::nothrow) CUICtrlFeatJobBindCombo(); + if (SUCCEEDED(hr = CHECK_POINTER(pControl, E_OUTOFMEMORY))) + { + hr = AddUIControl(IDC_COMBO_JOBBIND, pControl); + } + } + + if (SUCCEEDED(hr)) + { + pControl = new(std::nothrow) CUICtrlFeatDocBindCombo(); + if (SUCCEEDED(hr = CHECK_POINTER(pControl, E_OUTOFMEMORY))) + { + hr = AddUIControl(IDC_COMBO_DOCBIND, pControl); + } + } + } + catch (CXDException& e) + { + hr = e; + } + + if (FAILED(hr)) + { + DestroyUIComponents(); + throw CXDException(hr); + } +} + +/*++ + +Routine Name: + + CFeaturePropPage::~CFeaturePropPage + +Routine Description: + + CFeaturePropPage class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CFeaturePropPage::~CFeaturePropPage() +{ +} + +/*++ + +Routine Name: + + CFeaturePropPage::InitDlgBox + +Routine Description: + + Provides the base class with the data required to intialise the dialog box. + +Arguments: + + ppszTemplate - Pointer to dialog box template to be intialised. + ppszTitle - Pointer to dialog box title to be intialised. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CFeaturePropPage::InitDlgBox( + _Out_ LPCTSTR* ppszTemplate, + _Out_ LPCTSTR* ppszTitle + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(ppszTemplate, E_POINTER)) || + SUCCEEDED(hr = CHECK_POINTER(ppszTitle, E_POINTER))) + { + *ppszTemplate = MAKEINTRESOURCE(IDD_FEATURES); + *ppszTitle = MAKEINTRESOURCE(IDS_FEATURE); + } + + ERR_ON_HR(hr); + return hr; +} + diff --git a/print/XPSDrvSmpl/src/ui/ftrppg.h b/print/XPSDrvSmpl/src/ui/ftrppg.h new file mode 100644 index 00000000..73384fa5 --- /dev/null +++ b/print/XPSDrvSmpl/src/ui/ftrppg.h @@ -0,0 +1,42 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + ftrppg.h + +Abstract: + + Definition of the feature property page. This class is + responsible for initialising and registering the features + property page and its controls. + +--*/ + +#pragma once + +#include "precomp.h" +#include "docppg.h" + +class CFeaturePropPage : public CDocPropPage +{ +public: + CFeaturePropPage(); + + virtual ~CFeaturePropPage(); + + HRESULT + InitDlgBox( + _Out_ LPCTSTR* ppszTemplate, + _Out_ LPCTSTR* ppszTitle + ); +}; + diff --git a/print/XPSDrvSmpl/src/ui/nupptcnv.cpp b/print/XPSDrvSmpl/src/ui/nupptcnv.cpp new file mode 100644 index 00000000..017d87ca --- /dev/null +++ b/print/XPSDrvSmpl/src/ui/nupptcnv.cpp @@ -0,0 +1,477 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + nupptcnv.cpp + +Abstract: + + JobNUpAllDocumentsContiguously and DocumentNUp devmode <-> PrintTicket conversion class implementation. + The class defines a common data representation between the DevMode (GPD) and PrintTicket + representations and implements the conversion and validation methods required + by CFeatureDMPTConvert. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdexcept.h" +#include "xdstring.h" +#include "nupptcnv.h" +#include "nupchndlr.h" + +using XDPrintSchema::NUp::NUpData; +using XDPrintSchema::NUp::ENUpFeature; +using XDPrintSchema::NUp::ENUpFeatureMin; +using XDPrintSchema::NUp::JobNUpAllDocumentsContiguously; +using XDPrintSchema::NUp::DocumentNUp; +using XDPrintSchema::NUp::ENUpFeatureMax; + +using XDPrintSchema::NUp::PresentationDirection::ENUpDirectionOption; +using XDPrintSchema::NUp::PresentationDirection::LeftTop; +using XDPrintSchema::NUp::PresentationDirection::LeftBottom; +using XDPrintSchema::NUp::PresentationDirection::RightTop; +using XDPrintSchema::NUp::PresentationDirection::RightBottom; +using XDPrintSchema::NUp::PresentationDirection::BottomRight; +using XDPrintSchema::NUp::PresentationDirection::BottomLeft; +using XDPrintSchema::NUp::PresentationDirection::TopRight; +using XDPrintSchema::NUp::PresentationDirection::TopLeft; + +PCSTR g_pszNUpFeature[ENUpFeatureMax] = { + "JobNUpAllDocumentsContiguously", + "DocumentNUp" +}; +static GPDStringToOption g_pagesPerSheetOption[] = { + {"1", 1}, + {"2", 2}, + {"4", 4}, + {"6", 6}, + {"8", 8}, + {"9", 9}, + {"16", 16}, +}; +UINT g_cPagesPerSheetOption = sizeof(g_pagesPerSheetOption)/sizeof(GPDStringToOption); + +PCSTR g_pszPresDirFeature[ENUpFeatureMax] = { + "JobNUpContiguouslyPresentationOrder", + "DocumentNUpPresentationOrder", +}; +static GPDStringToOption g_presDirTypeOption[] = { + {"RightBottom", RightBottom}, + {"BottomRight", BottomRight}, + {"LeftBottom", LeftBottom}, + {"BottomLeft", BottomLeft}, + {"RightTop", RightTop}, + {"TopRight", TopRight}, + {"LeftTop", LeftTop}, + {"TopLeft", TopLeft}, +}; +UINT g_cPresDirOption = sizeof(g_presDirTypeOption)/sizeof(GPDStringToOption); + + +/*++ + +Routine Name: + + CNUpDMPTConv::CNUpDMPTConv + +Routine Description: + + CNUpDMPTConv class constructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CNUpDMPTConv::CNUpDMPTConv() +{ +} + +/*++ + +Routine Name: + + CNUpDMPTConv::~CNUpDMPTConv + +Routine Description: + + CNUpDMPTConv class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CNUpDMPTConv::~CNUpDMPTConv() +{ +} + +/*++ + +Routine Name: + + CNUpDMPTConv::GetPTDataSettingsFromDM + +Routine Description: + + Populates the NUp data structure from the Devmode passed in. + +Arguments: + + pDevmode - pointer to input devmode buffer. + cbDevmode - size in bytes of full input devmode. + pPrivateDevmode - pointer to input private devmode buffer. + cbDrvPrivateSize - size in bytes of private devmode. + pDataSettings - Pointer to NUp data structure to be updated. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CNUpDMPTConv::GetPTDataSettingsFromDM( + _In_ PDEVMODE pDevmode, + _In_ ULONG cbDevmode, + _In_ PVOID pPrivateDevmode, + _In_ ULONG cbDrvPrivateSize, + _Out_ NUpSettings* pDataSettings + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pDevmode, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pPrivateDevmode, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pDataSettings, E_POINTER))) + { + if (cbDevmode < sizeof(DEVMODE) || + cbDrvPrivateSize == 0) + { + hr = E_INVALIDARG; + } + } + + // + // Retrieve the GPD and devmode controlled settings for both Job and Document NUp + // + for (ENUpFeature nUpFeature = ENUpFeatureMin; + nUpFeature < ENUpFeatureMax && SUCCEEDED(hr); + nUpFeature = static_cast(nUpFeature + 1)) + { + pDataSettings->settings[nUpFeature].nUpFeature = nUpFeature; + if (SUCCEEDED(hr = GetOptionFromGPDString(pDevmode, + cbDevmode, + g_pszNUpFeature[nUpFeature], + g_pagesPerSheetOption, + g_cPagesPerSheetOption, + pDataSettings->settings[nUpFeature].cNUp))) + { + hr = GetOptionFromGPDString(pDevmode, + cbDevmode, + g_pszPresDirFeature[nUpFeature], + g_presDirTypeOption, + g_cPresDirOption, + pDataSettings->settings[nUpFeature].nUpPresentDir); + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CNUpDMPTConv::MergePTDataSettingsWithPT + +Routine Description: + + This method updates the NUp data structure from a PrintTicket description. + +Arguments: + + pPrintTicket - Pointer to the input PrintTicket. + pDataSettings - Pointer to the NUp data structure + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CNUpDMPTConv::MergePTDataSettingsWithPT( + _In_ IXMLDOMDocument2* pPrintTicket, + _Inout_ NUpSettings* pDataSettings + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pPrintTicket, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pDataSettings, E_POINTER))) + { + try + { + // + // Get the NUp settings from the PrintTicket and set the options in + // the appropriate Job or Document equivalent in the NUpSettings structure + // + NUpData nUpData; + CNUpPTHandler nUpPTHndlr(pPrintTicket); + + if (SUCCEEDED(hr = nUpPTHndlr.GetData(&nUpData))) + { + // + // Only update settings relevant to the feature + // + if (nUpData.nUpFeature < ENUpFeatureMax && + nUpData.nUpFeature >= ENUpFeatureMin) + { + pDataSettings->settings[nUpData.nUpFeature] = nUpData; + } + } + else if (hr == E_ELEMENT_NOT_FOUND) + { + // + // NUp setting not in the PT - make sure neither Job or + // Document NUp are set in the outgoing data structure + // + pDataSettings->settings[JobNUpAllDocumentsContiguously].cNUp = 1; + pDataSettings->settings[DocumentNUp].cNUp = 1; + + hr = S_OK; + } + } + catch (CXDException& e) + { + hr = e; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CNUpDMPTConv::SetPTDataInDM + +Routine Description: + + This method updates the NUp options in the devmode from the UI Settings. + +Arguments: + + dataSettings - Reference to NUp data settings to be updated. + pDevmode - pointer to devmode to be updated. + cbDevmode - size in bytes of full devmode. + pPrivateDevmode - pointer to input private devmode buffer. + cbDrvPrivateSize - size in bytes of private devmode. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CNUpDMPTConv::SetPTDataInDM( + _In_ CONST NUpSettings& dataSettings, + _Inout_ PDEVMODE pDevmode, + _In_ ULONG cbDevmode, + _Inout_ PVOID pPrivateDevmode, + _In_ ULONG cbDrvPrivateSize + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pDevmode, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pPrivateDevmode, E_POINTER))) + { + if (cbDevmode < sizeof(DEVMODE) || + cbDrvPrivateSize == 0) + { + hr = E_INVALIDARG; + } + } + + for (ENUpFeature nUpFeature = ENUpFeatureMin; + nUpFeature < ENUpFeatureMax && SUCCEEDED(hr); + nUpFeature = static_cast(nUpFeature + 1)) + { + if (SUCCEEDED(hr = SetGPDStringFromOption(pDevmode, + cbDevmode, + g_pszNUpFeature[nUpFeature], + g_pagesPerSheetOption, + g_cPagesPerSheetOption, + dataSettings.settings[nUpFeature].cNUp))) + { + hr = SetGPDStringFromOption(pDevmode, + cbDevmode, + g_pszPresDirFeature[nUpFeature], + g_presDirTypeOption, + g_cPresDirOption, + dataSettings.settings[nUpFeature].nUpPresentDir); + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CNUpDMPTConv::SetPTDataInPT + +Routine Description: + + This method updates the watemark PrintTicket description from NUp data structure. + +Arguments: + + dataSettings - Reference to NUp data structure to update from. + pPrintTicket - Pointer to the PrintTicket to be updated. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CNUpDMPTConv::SetPTDataInPT( + _In_ CONST NUpSettings& dataSettings, + _Inout_ IXMLDOMDocument2* pPrintTicket + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pPrintTicket, E_POINTER))) + { + try + { + CNUpPTHandler nUpPTHndlr(pPrintTicket); + NUpData nUpData; + + // + // Preferentially set Job over Document + // + if (dataSettings.settings[JobNUpAllDocumentsContiguously].cNUp > 1) + { + nUpData.nUpFeature = JobNUpAllDocumentsContiguously; + nUpData.cNUp = dataSettings.settings[JobNUpAllDocumentsContiguously].cNUp; + nUpData.nUpPresentDir = dataSettings.settings[JobNUpAllDocumentsContiguously].nUpPresentDir; + } + else + { + nUpData.nUpFeature = DocumentNUp; + nUpData.cNUp = dataSettings.settings[DocumentNUp].cNUp; + nUpData.nUpPresentDir = dataSettings.settings[DocumentNUp].nUpPresentDir; + } + + // + // If the option is enabled set, otherwise delete it from the PT + // + if (nUpData.cNUp > 1) + { + hr = nUpPTHndlr.SetData(&nUpData); + } + else + { + hr = nUpPTHndlr.Delete(); + } + } + catch (CXDException& e) + { + hr = e; + } + } + else + { + hr = E_POINTER; + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CNUpDMPTConv::CompletePrintCapabilities + +Routine Description: + + Unidrv calls this routine with an input Device Capabilities Document + that is partially populated with Device capabilities information + filled in by Unidrv for features that it understands. The plug-in + needs to read any private features in the input PrintTicket, delete + them and add them back under Printschema namespace so that higher + level applications can understand them and make use of them. + +Arguments: + + pPrintTicket - pointer to input PrintTicket + pCapabilities - pointer to Device Capabilities Document. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT STDMETHODCALLTYPE +CNUpDMPTConv::CompletePrintCapabilities( + _In_opt_ IXMLDOMDocument2*, + _Inout_ IXMLDOMDocument2* pPrintCapabilities + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pPrintCapabilities, E_POINTER))) + { + try + { + CNUpPCHandler nuppcHandler(pPrintCapabilities); + nuppcHandler.SetCapabilities(); + } + catch(CXDException& e) + { + hr = e; + } + } + + ERR_ON_HR(hr); + return hr; +} diff --git a/print/XPSDrvSmpl/src/ui/nupptcnv.h b/print/XPSDrvSmpl/src/ui/nupptcnv.h new file mode 100644 index 00000000..e77798c8 --- /dev/null +++ b/print/XPSDrvSmpl/src/ui/nupptcnv.h @@ -0,0 +1,86 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + nupptcnv.h + +Abstract: + + JobNUpAllDocumentsContiguously and DocumentNUp devmode <-> PrintTicket conversion class definition. + The class defines a common data representation between the DevMode (GPD) and PrintTicket + representations and implements the conversion and validation methods required + by CFeatureDMPTConvert. + +--*/ + +#pragma once + +#include "ftrdmptcnv.h" +#include "nupthndlr.h" +#include "nupdata.h" + +// +// The PT handling code defines a single NUpData structure that covers +// both JobNUpAllDocumentsContiguously and DocumentNUp to avoid conflicts. The GPD however +// controls both so we re-use the NUpData structure to handle both in +// the DevMode by using a NUpData for each Job and Document feature +// +struct NUpSettings +{ + XDPrintSchema::NUp::NUpData settings[XDPrintSchema::NUp::ENUpFeatureMax]; +}; + +class CNUpDMPTConv : public CFeatureDMPTConvert +{ +public: + CNUpDMPTConv(); + + virtual ~CNUpDMPTConv(); + +private: + HRESULT + GetPTDataSettingsFromDM( + _In_ PDEVMODE pDevmode, + _In_ ULONG cbDevmode, + _In_ PVOID pPrivateDevmode, + _In_ ULONG cbDrvPrivateSize, + _Out_ NUpSettings* pDataSettings + ); + + HRESULT + MergePTDataSettingsWithPT( + _In_ IXMLDOMDocument2* pPrintTicket, + _Inout_ NUpSettings* pDrvSettings + ); + + HRESULT + SetPTDataInDM( + _In_ CONST NUpSettings& drvSettings, + _Inout_ PDEVMODE pDevmode, + _In_ ULONG cbDevmode, + _Inout_ PVOID pPrivateDevmode, + _In_ ULONG cbDrvPrivateSize + ); + + HRESULT + SetPTDataInPT( + _In_ CONST NUpSettings& drvSettings, + _Inout_ IXMLDOMDocument2* pPrintTicket + ); + + HRESULT STDMETHODCALLTYPE + CompletePrintCapabilities( + _In_opt_ IXMLDOMDocument2*, + _Inout_ IXMLDOMDocument2* pPrintCapabilities + ); +}; + diff --git a/print/XPSDrvSmpl/src/ui/pgscdmptcnv.cpp b/print/XPSDrvSmpl/src/ui/pgscdmptcnv.cpp new file mode 100644 index 00000000..73b717d0 --- /dev/null +++ b/print/XPSDrvSmpl/src/ui/pgscdmptcnv.cpp @@ -0,0 +1,468 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + pgscdmptcnv.cpp + +Abstract: + + PageScaling devmode <-> PrintTicket conversion class implementation. + The class defines a common data representation between the DevMode (GPD) and PrintTicket + representations and implements the conversion and validation methods required + by CFeatureDMPTConvert. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdexcept.h" +#include "xdstring.h" +#include "pgscdmptcnv.h" + +using XDPrintSchema::PageScaling::PageScalingData; +using XDPrintSchema::PageScaling::EScaleOption; +using XDPrintSchema::PageScaling::None; +using XDPrintSchema::PageScaling::Custom; +using XDPrintSchema::PageScaling::CustomSquare; +using XDPrintSchema::PageScaling::FitBleedToImageable; +using XDPrintSchema::PageScaling::FitContentToImageable; +using XDPrintSchema::PageScaling::FitMediaToImageable; +using XDPrintSchema::PageScaling::FitMediaToMedia; + +using XDPrintSchema::PageScaling::OffsetAlignment::EScaleOffsetOption; +using XDPrintSchema::PageScaling::OffsetAlignment::BottomCenter; +using XDPrintSchema::PageScaling::OffsetAlignment::BottomLeft; +using XDPrintSchema::PageScaling::OffsetAlignment::BottomRight; +using XDPrintSchema::PageScaling::OffsetAlignment::Center; +using XDPrintSchema::PageScaling::OffsetAlignment::LeftCenter; +using XDPrintSchema::PageScaling::OffsetAlignment::RightCenter; +using XDPrintSchema::PageScaling::OffsetAlignment::TopCenter; +using XDPrintSchema::PageScaling::OffsetAlignment::TopLeft; +using XDPrintSchema::PageScaling::OffsetAlignment::TopRight; + +// +// Lookup table between GPD page scaling option string and schema enumerated type +// +PCSTR g_pszPageScalingTypeFeature = "PageScaling"; +static GPDStringToOption g_pageScalingTypeOption[] = { + {"None", None}, + {"Custom", Custom}, + {"CustomSquare", CustomSquare}, + {"FitApplicationBleedSizeToPageImageableSize", FitBleedToImageable}, + {"FitApplicationContentSizeToPageImageableSize", FitContentToImageable}, + {"FitApplicationMediaSizeToPageImageableSize", FitMediaToImageable}, + {"FitApplicationMediaSizeToPageMediaSize", FitMediaToMedia}, +}; +UINT g_cPageScalingTypeOption = sizeof(g_pageScalingTypeOption)/sizeof(GPDStringToOption); + +// +// Lookup table between GPD scaling offset alignment option string and schema enumerated type +// +PCSTR g_pszScaleOffsetTypeFeature = "ScaleOffsetAlignment"; +static GPDStringToOption g_scaleOffsetTypeOption[] = { + {"BottomCenter", BottomCenter}, + {"BottomLeft", BottomLeft}, + {"BottomRight", BottomRight}, + {"Center", Center}, + {"LeftCenter", LeftCenter}, + {"RightCenter", RightCenter}, + {"TopCenter", TopCenter}, + {"TopLeft", TopLeft}, + {"TopRight", TopRight}, +}; +UINT g_cScaleOffsetTypeOption = sizeof(g_scaleOffsetTypeOption)/sizeof(GPDStringToOption); + + + +/*++ + +Routine Name: + + CPageScalingDMPTConv::CPageScalingDMPTConv + +Routine Description: + + CPageScalingDMPTConv class constructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CPageScalingDMPTConv::CPageScalingDMPTConv() +{ +} + +/*++ + +Routine Name: + + CPageScalingDMPTConv::~CPageScalingDMPTConv + +Routine Description: + + CPageScalingDMPTConv class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CPageScalingDMPTConv::~CPageScalingDMPTConv() +{ +} + +/*++ + +Routine Name: + + CPageScalingDMPTConv::GetPTDataSettingsFromDM + +Routine Description: + + Populates the page scaling data structure from the Devmode passed in. + +Arguments: + + pDevmode - pointer to input devmode buffer. + cbDevmode - size in bytes of full input devmode. + pPrivateDevmode - pointer to input private devmode buffer. + cbDrvPrivateSize - size in bytes of private devmode. + pDataSettings - Pointer to page scaling data structure to be updated. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPageScalingDMPTConv::GetPTDataSettingsFromDM( + _In_ PDEVMODE pDevmode, + _In_ ULONG cbDevmode, + _In_ PVOID pPrivateDevmode, + _In_ ULONG cbDrvPrivateSize, + _Out_ PageScalingData* pDataSettings + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pDevmode, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pPrivateDevmode, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pDataSettings, E_POINTER))) + { + if (cbDevmode < sizeof(DEVMODE) || + cbDrvPrivateSize == 0) + { + hr = E_INVALIDARG; + } + } + + // + // Retrieve the GPD and devmode controlled settings + // + CUIProperties uiProperties(static_cast(pPrivateDevmode)); + if (SUCCEEDED(hr) && + SUCCEEDED(hr = GetOptionFromGPDString(pDevmode, + cbDevmode, + g_pszPageScalingTypeFeature, + g_pageScalingTypeOption, + g_cPageScalingTypeOption, + pDataSettings->pgscOption)) && + SUCCEEDED(hr = GetOptionFromGPDString(pDevmode, + cbDevmode, + g_pszScaleOffsetTypeFeature, + g_scaleOffsetTypeOption, + g_cScaleOffsetTypeOption, + pDataSettings->offsetOption)) && + SUCCEEDED(hr = uiProperties.GetItem(g_pszPSScaleWidth, &pDataSettings->scaleWidth, sizeof(pDataSettings->scaleWidth))) && + SUCCEEDED(hr = uiProperties.GetItem(g_pszPSScaleHeight, &pDataSettings->scaleHeight, sizeof(pDataSettings->scaleHeight))) && + SUCCEEDED(hr = uiProperties.GetItem(g_pszOffsetWidth, &pDataSettings->offWidth, sizeof(pDataSettings->offWidth))) && + SUCCEEDED(hr = uiProperties.GetItem(g_pszOffsetHeight, &pDataSettings->offHeight, sizeof(pDataSettings->offHeight)))) + { + // + // Convert length measurements from 100ths of an inch to microns + // + pDataSettings->scaleWidth = pDataSettings->scaleWidth; + pDataSettings->scaleHeight = pDataSettings->scaleHeight; + pDataSettings->offWidth = HUNDREDTH_OFINCH_TO_MICRON(pDataSettings->offWidth); + pDataSettings->offHeight = HUNDREDTH_OFINCH_TO_MICRON(pDataSettings->offHeight); + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CPageScalingDMPTConv::MergePTDataSettingsWithPT + +Routine Description: + + This method updates the page scaling data structure from a PrintTicket description. + +Arguments: + + pPrintTicket - Pointer to the input PrintTicket. + pDataSettings - Pointer to the page scaling data structure + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPageScalingDMPTConv::MergePTDataSettingsWithPT( + _In_ IXMLDOMDocument2* pPrintTicket, + _Inout_ PageScalingData* pDataSettings + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr) && + SUCCEEDED(hr = CHECK_POINTER(pPrintTicket, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pDataSettings, E_POINTER))) + { + try + { + // + // Get the page scaling settings from the PrintTicket and set the options in + // the input Watermark data structure + // + PageScalingData pgScData; + CPageScalingPTHandler pgScPTHndlr(pPrintTicket); + + if (SUCCEEDED(hr = pgScPTHndlr.GetData(&pgScData))) + { + *pDataSettings = pgScData; + } + else if (hr == E_ELEMENT_NOT_FOUND) + { + // + // PageScaling setting not in the PT - this is not an error. Just + // leave set the type as None and reset the HRESULT to S_OK + // + pDataSettings->pgscOption = None; + hr = S_OK; + } + } + catch (CXDException& e) + { + hr = e; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CPageScalingDMPTConv::SetPTDataInDM + +Routine Description: + + This method updates the page scaling options in the devmode from the UI Settings. + +Arguments: + + dataSettings - Reference to page scaling data settings to be updated. + pDevmode - pointer to devmode to be updated. + cbDevmode - size in bytes of full devmode. + pPrivateDevmode - pointer to input private devmode buffer. + cbDrvPrivateSize - size in bytes of private devmode. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPageScalingDMPTConv::SetPTDataInDM( + _In_ CONST PageScalingData& dataSettings, + _Inout_ PDEVMODE pDevmode, + _In_ ULONG cbDevmode, + _Inout_ PVOID pPrivateDevmode, + _In_ ULONG cbDrvPrivateSize + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pDevmode, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pPrivateDevmode, E_POINTER))) + { + if (cbDevmode < sizeof(DEVMODE) || + cbDrvPrivateSize == 0) + { + hr = E_INVALIDARG; + } + } + + // + // Convert lengths from microns to 100ths of an inch before writing to the DevMode + // + if (SUCCEEDED(hr)) + { + INT scaleWidth = dataSettings.scaleWidth; + INT scaleHeight = dataSettings.scaleHeight; + INT offWidth = MICRON_TO_HUNDREDTH_OFINCH(dataSettings.offWidth); + INT offHeight = MICRON_TO_HUNDREDTH_OFINCH(dataSettings.offHeight); + + // + // Set the GPD and devmode controlled settings + // + CUIProperties uiProperties(static_cast(pPrivateDevmode)); + + if (SUCCEEDED(hr = SetGPDStringFromOption(pDevmode, + cbDevmode, + g_pszPageScalingTypeFeature, + g_pageScalingTypeOption, + g_cPageScalingTypeOption, + dataSettings.pgscOption)) && + SUCCEEDED(hr = SetGPDStringFromOption(pDevmode, + cbDevmode, + g_pszScaleOffsetTypeFeature, + g_scaleOffsetTypeOption, + g_cScaleOffsetTypeOption, + dataSettings.offsetOption)) && + SUCCEEDED(hr = uiProperties.SetItem(g_pszPSScaleWidth, &scaleWidth, sizeof(scaleWidth))) && + SUCCEEDED(hr = uiProperties.SetItem(g_pszPSScaleHeight, &scaleHeight, sizeof(scaleHeight))) && + SUCCEEDED(hr = uiProperties.SetItem(g_pszOffsetWidth, &offWidth, sizeof(offWidth)))) + { + hr = uiProperties.SetItem(g_pszOffsetHeight, &offHeight, sizeof(offHeight)); + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CPageScalingDMPTConv::SetPTDataInPT + +Routine Description: + + This method updates the watemark PrintTicket description from page scaling data structure. + +Arguments: + + drvSettings - Reference to page scaling data structure to update from. + pPrintTicket - Pointer to the PrintTicket to be updated. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CPageScalingDMPTConv::SetPTDataInPT( + _In_ CONST PageScalingData& dataSettings, + _Inout_ IXMLDOMDocument2* pPrintTicket + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pPrintTicket, E_POINTER))) + { + try + { + CPageScalingPTHandler pgScPTHndlr(pPrintTicket); + hr = pgScPTHndlr.SetData(&dataSettings); + } + catch (CXDException& e) + { + hr = e; + } + } + else + { + hr = E_POINTER; + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CPageScalingDMPTConv::CompletePrintCapabilities + +Routine Description: + + Unidrv calls this routine with an input Device Capabilities Document + that is partially populated with Device capabilities information + filled in by Unidrv for features that it understands. The plug-in + needs to read any private features in the input PrintTicket, delete + them and add them back under Printschema namespace so that higher + level applications can understand them and make use of them. + +Arguments: + + pPrintTicket - pointer to input PrintTicket + pCapabilities - pointer to Device Capabilities Document. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT STDMETHODCALLTYPE +CPageScalingDMPTConv::CompletePrintCapabilities( + _In_opt_ IXMLDOMDocument2*, + _Inout_ IXMLDOMDocument2* pPrintCapabilities + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pPrintCapabilities, E_POINTER))) + { + try + { + CPageScalingPCHandler pagescalingpcHandler(pPrintCapabilities); + pagescalingpcHandler.SetCapabilities(); + } + catch(CXDException& e) + { + hr = e; + } + } + + ERR_ON_HR(hr); + return hr; +} diff --git a/print/XPSDrvSmpl/src/ui/pgscdmptcnv.h b/print/XPSDrvSmpl/src/ui/pgscdmptcnv.h new file mode 100644 index 00000000..3f8b188a --- /dev/null +++ b/print/XPSDrvSmpl/src/ui/pgscdmptcnv.h @@ -0,0 +1,76 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + pgscdmptcnv.h + +Abstract: + + PageScaling devmode <-> PrintTicket conversion class definition. + The class defines a common data representation between the DevMode (GPD) and PrintTicket + representations and implements the conversion and validation methods required + by CFeatureDMPTConvert. + +--*/ + +#pragma once + +#include "ftrdmptcnv.h" +#include "pgscpthndlr.h" +#include "pgscpchndlr.h" +#include "uiproperties.h" + +class CPageScalingDMPTConv : public CFeatureDMPTConvert +{ +public: + CPageScalingDMPTConv(); + + ~CPageScalingDMPTConv(); + +private: + HRESULT + GetPTDataSettingsFromDM( + _In_ PDEVMODE pDevmode, + _In_ ULONG cbDevmode, + _In_ PVOID pPrivateDevmode, + _In_ ULONG cbDrvPrivateSize, + _Out_ XDPrintSchema::PageScaling::PageScalingData* pDataSettings + ); + + HRESULT + MergePTDataSettingsWithPT( + _In_ IXMLDOMDocument2* pPrintTicket, + _Inout_ XDPrintSchema::PageScaling::PageScalingData* pDrvSettings + ); + + HRESULT + SetPTDataInDM( + _In_ CONST XDPrintSchema::PageScaling::PageScalingData& drvSettings, + _Inout_ PDEVMODE pDevmode, + _In_ ULONG cbDevmode, + _Inout_ PVOID pPrivateDevmode, + _In_ ULONG cbDrvPrivateSize + ); + + HRESULT + SetPTDataInPT( + _In_ CONST XDPrintSchema::PageScaling::PageScalingData& drvSettings, + _Inout_ IXMLDOMDocument2* pPrintTicket + ); + + HRESULT STDMETHODCALLTYPE + CompletePrintCapabilities( + _In_opt_ IXMLDOMDocument2*, + _Inout_ IXMLDOMDocument2* pPrintCapabilities + ); +}; + diff --git a/print/XPSDrvSmpl/src/ui/precomp.h b/print/XPSDrvSmpl/src/ui/precomp.h new file mode 100644 index 00000000..579abbab --- /dev/null +++ b/print/XPSDrvSmpl/src/ui/precomp.h @@ -0,0 +1,100 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + precomp.h + +Abstract: + + Precompiled header for UI plugin module. + +--*/ + +#pragma once + +// +// Annotate this as a usermode driver for static analysis +// +#include +_Analysis_mode_(_Analysis_code_type_user_driver_) + +// +// Standard Annotation Language include +// +#include + +// +// Prefast warning suppression macros +// +#include + +// +// Windows includes +// +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif // WIN32_LEAN_AND_MEAN +#include +#include +#include +#include + +// +// COM includes +// +#include +#include + +// +// ATL Includes +// +#include + +// +// GDIPlus includes +// +#include + +// +// MSXML includes +// +#include + +// +// Standard library includes +// +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +// +// Commonly used namespaces +// +using namespace std; +using namespace Gdiplus; + +// +// StrSafe.h needs to be included last to disallow bad string functions. +// +#include + +#define E_ELEMENT_NOT_FOUND HRESULT_FROM_WIN32(ERROR_NOT_FOUND) + + diff --git a/print/XPSDrvSmpl/src/ui/precompsrc.cpp b/print/XPSDrvSmpl/src/ui/precompsrc.cpp new file mode 100644 index 00000000..5944cf51 --- /dev/null +++ b/print/XPSDrvSmpl/src/ui/precompsrc.cpp @@ -0,0 +1 @@ +#include "precomp.h" \ No newline at end of file diff --git a/print/XPSDrvSmpl/src/ui/resource.h b/print/XPSDrvSmpl/src/ui/resource.h new file mode 100644 index 00000000..448397a5 --- /dev/null +++ b/print/XPSDrvSmpl/src/ui/resource.h @@ -0,0 +1,232 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + resource.h + +Abstract: + + Resource specific defines. + +--*/ + +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by xdsmpldlg.rc +// +#define IDD_COL_MANAGE 100 +#define IDD_WATERMARK 101 +#define IDD_FEATURES 102 +#define IDS_LAYOUT 126 +#define IDS_PAPQUAL 127 +#define IDS_COLMAN 128 +#define IDS_WMARK 129 +#define IDS_FEATURE 130 +#define IDC_COMBO_COL_MANAGE 1001 +#define IDC_LIST_COLPROF 1002 +#define IDC_TEXT_COLPROF 1003 +#define IDC_COMBO_WMTYPE 1004 +#define IDC_TXT_WMTYPE 1005 +#define IDC_GRP_WM 1006 +#define IDC_COMBO_WMLAYERING 1007 +#define IDC_GRP_COLPROF 1008 +#define IDC_TXT_WMLAYERING 1009 +#define IDC_GRP_PGSCALE 1010 +#define IDC_GRP_DOCNUP 1011 +#define IDC_EDIT_WMTEXT 1012 +#define IDC_TXT_WMTEXT 1013 +#define IDC_COMBO_PGSCALE 1014 +#define IDC_TXT_PGSCALE 1015 +#define IDC_EDIT_PGSCALEX 1018 +#define IDC_EDIT_PGOFFX 1019 +#define IDC_EDIT_PGSCALEY 1022 +#define IDC_GRP_WM_MIMIC 1023 +#define IDC_EDIT_PGOFFY 1024 +#define IDC_SPIN_PGSCALEX 1025 +#define IDC_SPIN_PGOFFX 1026 +#define IDC_SPIN_PGSCALEY 1027 +#define IDC_SPIN_PGOFFY 1028 +#define IDC_COMBO_NUP 1029 +#define IDC_TXT_NUP 1030 +#define IDC_COMBO_NUP_ORDER 1031 +#define IDC_TXT_NUP_ORDER 1032 +#define IDC_COMBO_JOBBIND 1033 +#define IDC_TXT_JOBBIND 1034 +#define IDC_COMBO_DOCBIND 1035 +#define IDC_TXT_DOCBIND 1036 +#define IDC_COMBO_PHOTO_INTENT 1037 +#define IDC_TXT_PHOTO_INTENT 1038 +#define IDC_CHECK_BORDERLESS 1039 +#define IDC_TXT_PGOFFY 1040 +#define IDC_TXT_PGOFFX 1041 +#define IDC_TXT_PGSCALEY 1042 +#define IDC_TXT_PGSCALEX 1043 +#define IDC_CHECK_DEVFONTSUB 1044 +#define IDC_GRP_DOCDUP 1045 +#define IDC_CHECK_DOCDUPLEX 1046 +#define IDC_COMBO_DOCDUPLEX 1047 +#define IDC_TXT_DOCDUPLEX 1048 +#define IDC_TXT_COL_MANAGE 1049 +#define IDC_EDIT_WMTRANSPARENCY 1050 +#define IDC_SPIN_WMTRANSPARENCY 1051 +#define IDC_EDIT_WMANGLE 1052 +#define IDC_SPIN_WMANGLE 1053 +#define IDC_EDIT_WMOFFX 1054 +#define IDC_SPIN_WMOFFX 1055 +#define IDC_EDIT_WMOFFY 1056 +#define IDC_SPIN_WMOFFY 1057 +#define IDC_TXT_WMTRANSPARENCY 1058 +#define IDC_TXT_WMANGLE 1059 +#define IDC_TXT_WMOFFX 1060 +#define IDC_TXT_WMOFFY 1061 +#define IDC_EDIT_WMWIDTH 1062 +#define IDC_SPIN_WMWIDTH 1063 +#define IDC_EDIT_WMHEIGHT 1064 +#define IDC_SPIN_WMHEIGHT 1065 +#define IDC_TXT_WMWIDTH 1066 +#define IDC_TXT_WMHEIGHT 1067 +#define IDC_EDIT_WMSIZE 1068 +#define IDC_SPIN_WMSIZE 1069 +#define IDC_TXT_WMSIZE 1070 +#define IDC_BUTTON_WMCOLOR 1071 +#define IDC_COMBO_COL_INTENT 1073 +#define IDC_TXT_COL_INTENT 1074 +#define IDC_COMBO_SCALEOFF 1075 +#define IDC_TXT_SCALEOFF 1076 + +// +// String resource IDs used in GPD +// +#define IDS_GPD_1PPS 2000 +#define IDS_GPD_2PPS 2001 +#define IDS_GPD_4PPS 2002 +#define IDS_GPD_6PPS 2003 +#define IDS_GPD_8PPS 2004 +#define IDS_GPD_9PPS 2005 +#define IDS_GPD_16PPS 2006 +#define IDS_GPD_RES1200 2007 +#define IDS_GPD_RES600 2008 +#define IDS_GPD_AUTOMATIC 2009 +#define IDS_GPD_BORDERED 2010 +#define IDS_GPD_BORDERLESS 2011 +#define IDS_GPD_BTOT 2012 +#define IDS_GPD_BTOTLTOR 2013 +#define IDS_GPD_BTOTRTOL 2014 +#define IDS_GPD_CMYK 2015 +#define IDS_GPD_COLOR 2016 +#define IDS_GPD_CONFIDENTIAL 2017 +#define IDS_GPD_CUSTSQUARE 2018 +#define IDS_GPD_CUSTOM 2019 +#define IDS_GPD_SRCCOLPROF 2020 +#define IDS_GPD_DEVICE 2021 +#define IDS_GPD_DOCBIND 2022 +#define IDS_GPD_PAGECOLMAN 2023 +#define IDS_GPD_PAGEPHOTINTENT 2024 +#define IDS_GPD_DOCDUPLEX 2025 +#define IDS_GPD_DOCNUP 2026 +#define IDS_GPD_DOCNUPPRESENTORDER 2027 +#define IDS_GPD_DRAFT 2028 +#define IDS_GPD_DRIVER 2029 +#define IDS_GPD_DUPLEX 2030 +#define IDS_GPD_FAX 2031 +#define IDS_GPD_FITBLEED 2032 +#define IDS_GPD_FITCONTENT 2033 +#define IDS_GPD_FITPAGE 2034 +#define IDS_GPD_GLOSSY 2035 +#define IDS_GPD_GRAYSCALE 2036 +#define IDS_GPD_HIGH 2037 +#define IDS_GPD_HORIZONTAL 2038 +#define IDS_GPD_JOBBINDING 2039 +#define IDS_GPD_JOBNUPPRESENTORDER 2040 +#define IDS_GPD_JOBNUP 2041 +#define IDS_GPD_JOBPAGEORDER 2042 +#define IDS_GPD_LANDSCAPE 2043 +#define IDS_GPD_LTOR 2044 +#define IDS_GPD_LTORBTOT 2045 +#define IDS_GPD_LTORTTOB 2046 +#define IDS_GPD_MEDIATYPE 2047 +#define IDS_GPD_MONO 2048 +#define IDS_GPD_NONE 2049 +#define IDS_GPD_NORMAL 2050 +#define IDS_GPD_OFF 2051 +#define IDS_GPD_ON 2052 +#define IDS_GPD_ORIENATION 2053 +#define IDS_GPD_OVERLAYED 2054 +#define IDS_GPD_PAGEBORDER 2055 +#define IDS_GPD_PAGEQUALITY 2056 +#define IDS_GPD_PAGESCALING 2057 +#define IDS_GPD_PAPERSOURCE 2058 +#define IDS_GPD_PHOTOGRAPHIC 2059 +#define IDS_GPD_PORTRAIT 2060 +#define IDS_GPD_RASTERIMAGE 2061 +#define IDS_GPD_RESOLUTION 2062 +#define IDS_GPD_REVERSELANDSCAPE 2063 +#define IDS_GPD_REVERSE 2064 +#define IDS_GPD_RTOL 2065 +#define IDS_GPD_RTOLBTOT 2066 +#define IDS_GPD_RTOLTTOB 2067 +#define IDS_GPD_SCALEPAGETOPAGE 2068 +#define IDS_GPD_SCRGB 2069 +#define IDS_GPD_STANDARD 2070 +#define IDS_GPD_TEXT 2071 +#define IDS_GPD_TTOB 2072 +#define IDS_GPD_TTOBLTOR 2073 +#define IDS_GPD_TTOBRTOL 2074 +#define IDS_GPD_TRANSPARENCY 2075 +#define IDS_GPD_TRANSPARENT 2076 +#define IDS_GPD_UNDERLAYED 2077 +#define IDS_GPD_UPPER 2078 +#define IDS_GPD_VECTORIMAGE 2079 +#define IDS_GPD_VERTICAL 2080 +#define IDS_GPD_WATERMARKLAYERING 2081 +#define IDS_GPD_WATERMARKTEXT 2082 +#define IDS_GPD_WATERMARKTYPE 2083 +#define IDS_GPD_WATERMARKBITMAP 2084 +#define IDS_GPD_WATERMARKGRAPHIC 2087 +#define IDS_GPD_BEST 2090 +#define IDS_GPD_PAGEICMINTENT 2091 +#define IDS_GPD_ABSCOLINTENT 2092 +#define IDS_GPD_RELCOLINTENT 2093 +#define IDS_GPD_PHOTOINTENT 2094 +#define IDS_GPD_BIZINTENT 2095 +#define IDS_GPD_SYSTEM 2096 +#define IDS_GPD_WATERMARKTEXTCOLOR 2097 +#define IDS_GPD_RED 2098 +#define IDS_GPD_GREEN 2099 +#define IDS_GPD_BLUE 2100 +#define IDS_GPD_MAGENTA 2101 +#define IDS_GPD_CYAN 2102 +#define IDS_GPD_YELLOW 2103 +#define IDS_GPD_BLACK 2104 +#define IDS_GPD_SCALE_ALIGN 2105 +#define IDS_GPD_SCALE_ALIGN_BC 2106 +#define IDS_GPD_SCALE_ALIGN_BL 2107 +#define IDS_GPD_SCALE_ALIGN_BR 2108 +#define IDS_GPD_SCALE_ALIGN_CC 2109 +#define IDS_GPD_SCALE_ALIGN_LC 2110 +#define IDS_GPD_SCALE_ALIGN_CR 2111 +#define IDS_GPD_SCALE_ALIGN_CT 2112 +#define IDS_GPD_SCALE_ALIGN_TL 2113 +#define IDS_GPD_SCALE_ALIGN_TR 2114 + +// +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 131 +#define _APS_NEXT_COMMAND_VALUE 32771 +#define _APS_NEXT_CONTROL_VALUE 1077 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif + diff --git a/print/XPSDrvSmpl/src/ui/uictrl.cpp b/print/XPSDrvSmpl/src/ui/uictrl.cpp new file mode 100644 index 00000000..a424a3a4 --- /dev/null +++ b/print/XPSDrvSmpl/src/ui/uictrl.cpp @@ -0,0 +1,2117 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + uictrl.cpp + +Abstract: + + Implementation of the abstract UI control class and the base default + UI controls for check boxe, list, combo, edit and spin controls. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdstring.h" +#include "uictrl.h" + +/*++ + +Routine Name: + + CUIControl::CUIControl + +Routine Description: + + CUIControl class constructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUIControl::CUIControl() : + m_pDriverUIHelp(NULL), + m_pOemCUIPParam(NULL), + m_pUIProperties(NULL) +{ +} + +/*++ + +Routine Name: + + CUIControl::~CUIControl + +Routine Description: + + CUIControl class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUIControl::~CUIControl() +{ +} + +/*++ + +Routine Name: + + CUIControl::SetOemCUIPParam + +Routine Description: + + Store a pointer to a OEMCUIPPARAM structure as a member in the class. + +Arguments: + + pOemCUIPParam - Pointer to a OEMCUIPPARAM structure + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CUIControl::SetOemCUIPParam( + _In_ CONST POEMCUIPPARAM pOemCUIPParam + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pOemCUIPParam, E_POINTER))) + { + m_pOemCUIPParam = pOemCUIPParam; + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CUIControl::SetUIProperties + +Routine Description: + + Store a pointer to an CUIProperties interface as a member in the class. + +Arguments: + + pUIProperties - Pointer to an instance of the CUIProperties interface. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CUIControl::SetUIProperties( + _In_ CUIProperties* pUIProperties + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pUIProperties, E_POINTER))) + { + m_pUIProperties = pUIProperties; + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CUIControl::SetPrintOemDriverUI + +Routine Description: + + Store a pointer to an IPrintOemDriverUI interface as a member in the class. + +Arguments: + + pOEMDriverUI - Pointer to an instance of the IPrintOemDriverUI interface. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CUIControl::SetPrintOemDriverUI( + _In_ CONST IPrintOemDriverUI* pOEMDriverUI + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pOEMDriverUI, E_POINTER))) + { + m_pDriverUIHelp = const_cast(pOEMDriverUI); + } + + ERR_ON_HR(hr); + return hr; +} + +// +// Message handling stubs +// +/*++ + +Routine Name: + + CUIControl::OnInit + +Routine Description: + + This is a default implementation that returns S_OK. + Called from the property page handler on a WM_INITDIALOG message. + +Arguments: + + None referenced. + +Return Value: + + HRESULT + S_OK + +--*/ +HRESULT +CUIControl::OnInit( + _In_ CONST HWND + ) +{ + // + // A sub class is required to implement this method if it requires intialisation. The + // implementation is optional however so we return S_OK by default. + // + return S_OK; +} + +/*++ + +Routine Name: + + CUIControl::OnCommand + +Routine Description: + + This is a place holder method with no implementation. + Called from the property page handler on a WM_COMMAND message. + +Arguments: + + None referenced. + +Return Value: + + HRESULT + E_NOTIMPL - Method not implemented + +--*/ +HRESULT +CUIControl::OnCommand( + _In_ CONST HWND , + _In_ INT + ) +{ + // + // A sub class is required to implement this method if it can recieve command messages. The + // implementation is optional however so we return S_OK by default. + // + return S_OK; +} + +/*++ + +Routine Name: + + CUIControl::OnNotify + +Routine Description: + + This is a place holder method with no implementation. + Called from the property page handler on a WM_NOTIFY message. + +Arguments: + + None referenced. + +Return Value: + + HRESULT + E_NOTIMPL - Method not implemented + +--*/ +HRESULT +CUIControl::OnNotify( + _In_ CONST HWND, + _In_ CONST NMHDR* + ) +{ + // + // A sub class is required to implement this method if it can recieve notify messages. The + // implementation is optional however so we return S_OK by default. + // + return S_OK; +} + +// +// Check box control +// +/*++ + +Routine Name: + + CUICtrlDefaultCheck::CUICtrlDefaultCheck + +Routine Description: + + CUICtrlDefaultCheck class constructor + +Arguments: + + gpdString - Property name of the data associated with this control. + iCheckResID - Resource id for the checkbox control. + +Return Value: + + None + +--*/ +CUICtrlDefaultCheck::CUICtrlDefaultCheck( + _In_ PCSTR gpdString, + _In_ CONST INT iCheckResID + ) : + m_szGPDString(gpdString), + m_iCheckResID(iCheckResID) +{ +} + +/*++ + +Routine Name: + + CUICtrlDefaultCheck::~CUICtrlDefaultCheck + +Routine Description: + + CUICtrlDefaultCheck class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlDefaultCheck::~CUICtrlDefaultCheck() +{ +} + +/*++ + +Routine Name: + + CUICtrlDefaultCheck::OnActivate + +Routine Description: + + Called when the parent property page becomes active. + This method initialises the state of the control to reflect the Unidrv GPD settings. + +Arguments: + + hDlg - handle to the parent window + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CUICtrlDefaultCheck::OnActivate( + _In_ CONST HWND hDlg + ) +{ + HRESULT hr = S_OK; + POPTITEM pOptItem = NULL; + + ASSERTMSG(m_pOemCUIPParam != NULL, "NULL pointer to OEMCUIPPARAM structure.\n"); + ASSERTMSG(m_pUIProperties != NULL, "NULL pointer to UI properties interface.\n"); + + if (SUCCEEDED(hr = CHECK_POINTER(m_pOemCUIPParam, E_PENDING)) && + SUCCEEDED(hr = CHECK_POINTER(m_pUIProperties, E_PENDING)) && + SUCCEEDED(hr = m_pUIProperties->GetOptItem(m_pOemCUIPParam, m_szGPDString, &pOptItem)) && + SUCCEEDED(hr = CHECK_POINTER(pOptItem, E_FAIL))) + { + + // + // Convert from a selection to a checkbox state + // and initialise the controls state. + // + + LONG lSel = pOptItem->Sel; + + UINT uChecked = (lSel == 0) ? BST_UNCHECKED : BST_CHECKED; + + if (CheckDlgButton(hDlg, m_iCheckResID, uChecked) > 0) + { + hr = EnableDependentCtrls(hDlg, lSel); + } + else + { + hr = HRESULT_FROM_WIN32(GetLastError()); + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CUICtrlDefaultCheck::OnCommand + +Routine Description: + + Called from the property page handler when a WM_COMMAND message is recieved. + Filters out any button click (BN_CLICKED) messages intended for this control. + +Arguments: + + hDlg - handle to the parent window + iCommand - specifies the notification code + +Return Value: + + HRESULT + S_OK - On success + E_NOTIMPL - Command not implemented + E_* - On error + +--*/ +HRESULT +CUICtrlDefaultCheck::OnCommand( + _In_ CONST HWND hDlg, + _In_ INT iCommand + ) +{ + HRESULT hr = S_OK; + + switch (iCommand) + { + case BN_CLICKED: + { + hr = OnBnClicked(hDlg); + } + break; + + default: + hr = E_NOTIMPL; + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CUICtrlDefaultCheck::OnBnClicked + +Routine Description: + + This rountine handles the event of a button press. The state of the check box control is read which + can be either checked and unchecked, the result is communicated through the Unidrv helper functions + informing the Unidrv core that a change has occured. + +Arguments: + + hDlg - handle to the parent window + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CUICtrlDefaultCheck::OnBnClicked( + _In_ CONST HWND hDlg + ) +{ + HRESULT hr = S_OK; + + ASSERTMSG(m_pUIProperties != NULL, "NULL pointer to UI properties interface.\n"); + ASSERTMSG(m_pOemCUIPParam != NULL, "NULL pointer to OEMCUIPPARAM structure.\n"); + ASSERTMSG(m_pOemCUIPParam->poemuiobj != NULL, "NULL pointer to OEMCUIPPARAM->poemuiobj structure.\n"); + ASSERTMSG(m_pDriverUIHelp != NULL, "NULL pointer to driver UI help interface.\n"); + + if (SUCCEEDED(hr = CHECK_POINTER(m_pUIProperties, E_PENDING)) && + SUCCEEDED(hr = CHECK_POINTER(m_pOemCUIPParam, E_PENDING)) && + SUCCEEDED(hr = CHECK_POINTER(m_pOemCUIPParam->poemuiobj, E_PENDING)) && + SUCCEEDED(hr = CHECK_POINTER(m_pDriverUIHelp, E_PENDING))) + { + // + // Retrieve the controls current selection + // and convert from checkbox state to a selection + // + UINT uChecked = IsDlgButtonChecked(hDlg, m_iCheckResID); + + LONG lSel = (uChecked == BST_UNCHECKED) ? 0 : 1; + + // + // Check against the optitem + // + POPTITEM pOptItem = NULL; + + if (SUCCEEDED(hr = m_pUIProperties->GetOptItem(m_pOemCUIPParam, m_szGPDString, &pOptItem)) && + SUCCEEDED(hr = CHECK_POINTER(pOptItem, E_FAIL))) + { + if (pOptItem->Sel != lSel) + { + PropSheet_Changed(GetParent(hDlg), hDlg); + + pOptItem->Sel = lSel; + pOptItem->Flags |= OPTIF_CHANGED; + + if (SUCCEEDED(hr = m_pDriverUIHelp->DrvUpdateUISetting(m_pOemCUIPParam->poemuiobj, pOptItem, 0, OEMCUIP_DOCPROP))) + { + hr = EnableDependentCtrls(hDlg, lSel); + } + } + else + { + PropSheet_UnChanged(GetParent(hDlg), hDlg); + } + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CUICtrlDefaultCheck::EnableDependentCtrls + +Routine Description: + + This is a default implementation simply returns S_OK + +Arguments: + + None referenced. + +Return Value: + + HRESULT + S_OK - Success + +--*/ +HRESULT +CUICtrlDefaultCheck::EnableDependentCtrls( + _In_ CONST HWND, + _In_ CONST LONG + ) +{ + return S_OK; +} + + +// +// List box control +// +/*++ + +Routine Name: + + CUICtrlDefaultList::CUICtrlDefaultList + +Routine Description: + + CUICtrlDefaultList class construtor + +Arguments: + + gpdString - Property name of the data associated with this control. + iListResID - Resource id for the List Box control. + +Return Value: + + None + +--*/ +CUICtrlDefaultList::CUICtrlDefaultList( + _In_ PCSTR gpdString, + _In_ CONST INT iListResID + ) : + m_szGPDString(gpdString), + m_iListResID(iListResID) +{ +} + +/*++ + +Routine Name: + + CUICtrlDefaultList::~CUICtrlDefaultList + +Routine Description: + + CUICtrlDefaultList class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlDefaultList::~CUICtrlDefaultList() +{ +} + +/*++ + +Routine Name: + + CUICtrlDefaultList::AddString + +Routine Description: + + Loads a string from the specified resource and adds it to the end of the list box. + +Arguments: + + hDlg - handle to the parent window + hStringResDLL - handle of the resource DLL that contains the string table. + idString - identifer of the string resource to be added + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CUICtrlDefaultList::AddString( + _In_ CONST HWND hDlg, + _In_ CONST HINSTANCE hStringResDLL, + _In_ CONST INT idString + ) +{ + HRESULT hr = S_OK; + + TCHAR szItem[MAX_UISTRING_LEN]; + if (LoadString(hStringResDLL, idString, szItem, countof(szItem)) > 0) + { + LRESULT lResult = SendDlgItemMessage(hDlg, m_iListResID, LB_ADDSTRING, 0, reinterpret_cast(szItem)); + + if (lResult == LB_ERRSPACE || + lResult == LB_ERR) + { + hr = E_FAIL; + } + } + else + { + hr = HRESULT_FROM_WIN32(GetLastError()); + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CUICtrlDefaultList::OnActivate + +Routine Description: + + Called when the parent property page becomes active. + This method initialises the state of the control to reflect the Unidrv GPD settings. + +Arguments: + + hDlg - handle to the parent window + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CUICtrlDefaultList::OnActivate( + _In_ CONST HWND hDlg + ) +{ + HRESULT hr = S_OK; + POPTITEM pOptItem = NULL; + + ASSERTMSG(m_pOemCUIPParam != NULL, "NULL pointer to OEMCUIPPARAM structure.\n"); + ASSERTMSG(m_pUIProperties != NULL, "NULL pointer to UI properties interface.\n"); + + if (SUCCEEDED(hr = CHECK_POINTER(m_pOemCUIPParam, E_PENDING)) && + SUCCEEDED(hr = CHECK_POINTER(m_pUIProperties, E_PENDING)) && + SUCCEEDED(hr = m_pUIProperties->GetOptItem(m_pOemCUIPParam, m_szGPDString, &pOptItem)) && + SUCCEEDED(hr = CHECK_POINTER(pOptItem, E_FAIL))) + { + LONG lSel = pOptItem->Sel; + if (SendDlgItemMessage(hDlg, m_iListResID, LB_SETCURSEL, lSel, 0) != LB_ERR) + { + hr = EnableDependentCtrls(hDlg, lSel); + } + else + { + hr = E_FAIL; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CUICtrlDefaultList::OnCommand + +Routine Description: + + Called from the property page handler when a WM_COMMAND message is recieved. + Filters out any list box selection change (LBN_SELCHANGE) messages intended for this control. + +Arguments: + + hDlg - handle to the parent window + iCommand - specifies the notification code + +Return Value: + + HRESULT + S_OK - On success + E_NOTIMPL - Command not implemented + E_* - On error + +--*/ +HRESULT +CUICtrlDefaultList::OnCommand( + _In_ CONST HWND hDlg, + _In_ INT iCommand + ) +{ + HRESULT hr = S_OK; + + switch (iCommand) + { + case LBN_SELCHANGE: + { + hr = OnSelChange(hDlg); + } + break; + + default: + hr = E_NOTIMPL; + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CUICtrlDefaultList::OnSelChange + +Routine Description: + + This rountine handles the event of a change of selection in the list box. The selection of the + list box control is read and the result is communicated through the Unidrv helper functions + informing the Unidrv core that a change has occured. + +Arguments: + + hDlg - handle to the parent window + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CUICtrlDefaultList::OnSelChange( + _In_ CONST HWND hDlg + ) +{ + HRESULT hr = S_OK; + + ASSERTMSG(m_pUIProperties != NULL, "NULL pointer to UI properties interface.\n"); + ASSERTMSG(m_pOemCUIPParam != NULL, "NULL pointer to OEMCUIPPARAM structure.\n"); + ASSERTMSG(m_pOemCUIPParam->poemuiobj != NULL, "NULL pointer to OEMCUIPPARAM->poemuiobj structure.\n"); + ASSERTMSG(m_pDriverUIHelp != NULL, "NULL pointer to driver UI help interface.\n"); + + + if (SUCCEEDED(hr = CHECK_POINTER(m_pUIProperties, E_PENDING)) && + SUCCEEDED(hr = CHECK_POINTER(m_pOemCUIPParam, E_PENDING)) && + SUCCEEDED(hr = CHECK_POINTER(m_pOemCUIPParam->poemuiobj, E_PENDING)) && + SUCCEEDED(hr = CHECK_POINTER(m_pDriverUIHelp, E_PENDING))) + { + // + // Retrieve the controls current selection + // + LONG lSel = static_cast(SendDlgItemMessage(hDlg, m_iListResID, LB_GETCURSEL, 0, 0)); + + if (lSel != LB_ERR) + { + // + // Check against the optitem + // + POPTITEM pOptItem = NULL; + + if (SUCCEEDED(hr = m_pUIProperties->GetOptItem(m_pOemCUIPParam, m_szGPDString, &pOptItem)) && + SUCCEEDED(hr = CHECK_POINTER(pOptItem, E_FAIL))) + { + if (pOptItem->Sel != lSel) + { + PropSheet_Changed(GetParent(hDlg), hDlg); + + pOptItem->Sel = lSel; + pOptItem->Flags |= OPTIF_CHANGED; + + if (SUCCEEDED(hr = m_pDriverUIHelp->DrvUpdateUISetting(m_pOemCUIPParam->poemuiobj, pOptItem, 0, OEMCUIP_DOCPROP))) + { + hr = EnableDependentCtrls(hDlg, lSel); + } + } + else + { + PropSheet_UnChanged(GetParent(hDlg), hDlg); + } + } + } + else + { + hr = E_FAIL; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CUICtrlDefaultList::EnableDependentCtrls + +Routine Description: + + This is a default implementation that returns S_OK. + Called when a selection is changed in the list box to show/enable any dependent controls. + +Arguments: + + None referenced. + +Return Value: + + HRESULT + S_OK - Success + +--*/ +HRESULT +CUICtrlDefaultList::EnableDependentCtrls( + _In_ CONST HWND, + _In_ CONST LONG + ) +{ + return S_OK; +} + +// +// Combo box control +// +/*++ + +Routine Name: + + CUICtrlDefaultCombo::CUICtrlDefaultCombo + +Routine Description: + + CUICtrlDefaultCombo class constructor. + +Arguments: + + gpdString - Property name of the data associated with this control. + iComboResID - Resource id for the Combo Box control. + +Return Value: + + None + +--*/ +CUICtrlDefaultCombo::CUICtrlDefaultCombo( + _In_ PCSTR gpdString, + _In_ CONST INT iComboResID + ) : + m_szGPDString(gpdString), + m_iComboResID(iComboResID) +{ +} + +/*++ + +Routine Name: + + CUICtrlDefaultCombo::~CUICtrlDefaultCombo + +Routine Description: + + CUICtrlDefaultCombo class destructor. + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlDefaultCombo::~CUICtrlDefaultCombo() +{ +} + +/*++ + +Routine Name: + + CUICtrlDefaultCombo::OnActivate + +Routine Description: + + Called when the parent property page becomes active. + This method initialises the state of the control to reflect the Unidrv GPD settings. + +Arguments: + + hDlg - handle to the parent window + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CUICtrlDefaultCombo::OnActivate( + _In_ CONST HWND hDlg + ) +{ + HRESULT hr = S_OK; + POPTITEM pOptItem = NULL; + + ASSERTMSG(m_pOemCUIPParam != NULL, "NULL pointer to OEMCUIPPARAM structure.\n"); + ASSERTMSG(m_pUIProperties != NULL, "NULL pointer to UI properties interface.\n"); + + if (SUCCEEDED(hr = CHECK_POINTER(m_pOemCUIPParam, E_PENDING)) && + SUCCEEDED(hr = CHECK_POINTER(m_pUIProperties, E_PENDING)) && + SUCCEEDED(hr = m_pUIProperties->GetOptItem(m_pOemCUIPParam, m_szGPDString, &pOptItem)) && + SUCCEEDED(hr = CHECK_POINTER(pOptItem, E_FAIL))) + { + LONG lSel = pOptItem->Sel; + + LRESULT lResult = SendDlgItemMessage(hDlg, m_iComboResID, CB_SETCURSEL, lSel, 0); + + if (lResult != CB_ERR && + lResult != CB_ERRSPACE) + { + hr = EnableDependentCtrls(hDlg, lSel); + } + else + { + hr = E_FAIL; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CUICtrlDefaultCombo::OnCommand + +Routine Description: + + Called from the property page handler when a WM_COMMAND message is recieved. + Filters out any Combo Box selection change (CBN_SELCHANGE) messages intended for this control. + +Arguments: + + hDlg - handle to the parent window + iCommand - specifies the notification code + +Return Value: + + HRESULT + S_OK - On success + E_NOTIMPL - Command not implemented + E_* - On error + +--*/ +HRESULT +CUICtrlDefaultCombo::OnCommand( + _In_ CONST HWND hDlg, + _In_ INT iCommand + ) +{ + HRESULT hr = S_OK; + + switch (iCommand) + { + case CBN_SELCHANGE: + { + hr = OnSelChange(hDlg); + } + break; + + default: + { + hr = E_NOTIMPL; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CUICtrlDefaultCombo::OnSelChange + +Routine Description: + + This rountine handles the event of a change of selection in the combo box. The selection of the + combo box control is read and the result is communicated through the Unidrv helper functions + informing the Unidrv core that a change has occured. + +Arguments: + + hDlg - handle to the parent window + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CUICtrlDefaultCombo::OnSelChange( + _In_ CONST HWND hDlg + ) +{ + HRESULT hr = S_OK; + + ASSERTMSG(m_pUIProperties != NULL, "NULL pointer to UI properties interface.\n"); + ASSERTMSG(m_pOemCUIPParam != NULL, "NULL pointer to OEMCUIPPARAM structure.\n"); + ASSERTMSG(m_pOemCUIPParam->poemuiobj != NULL, "NULL pointer to OEMCUIPPARAM->poemuiobj structure.\n"); + ASSERTMSG(m_pDriverUIHelp != NULL, "NULL pointer to driver UI help interface.\n"); + + if (SUCCEEDED(hr = CHECK_POINTER(m_pUIProperties, E_PENDING)) && + SUCCEEDED(hr = CHECK_POINTER(m_pOemCUIPParam, E_PENDING)) && + SUCCEEDED(hr = CHECK_POINTER(m_pOemCUIPParam->poemuiobj, E_PENDING)) && + SUCCEEDED(hr = CHECK_POINTER(m_pDriverUIHelp, E_PENDING))) + { + // + // Retrieve the controls current selection + // + + LONG lSel = static_cast(SendDlgItemMessage(hDlg, m_iComboResID, CB_GETCURSEL, 0, 0)); + + if (lSel == CB_ERR) + { + hr = E_FAIL; + } + + POPTITEM pOptItem = NULL; + + if (SUCCEEDED(hr) && + SUCCEEDED(hr = m_pUIProperties->GetOptItem(m_pOemCUIPParam, m_szGPDString, &pOptItem)) && + SUCCEEDED(hr = CHECK_POINTER(pOptItem, E_FAIL))) + { + if (pOptItem->Sel != lSel) + { + PropSheet_Changed(GetParent(hDlg), hDlg); + + pOptItem->Sel = lSel; + pOptItem->Flags |= OPTIF_CHANGED; + + if (SUCCEEDED(hr = m_pDriverUIHelp->DrvUpdateUISetting(m_pOemCUIPParam->poemuiobj, pOptItem, 0, OEMCUIP_DOCPROP))) + { + hr = EnableDependentCtrls(hDlg, lSel); + } + } + else + { + PropSheet_UnChanged(GetParent(hDlg), hDlg); + } + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CUICtrlDefaultCombo::EnableDependentCtrls + +Routine Description: + + This is a default implementation that returns S_OK. + Called when a selection is changed in the combo box to show/enable any dependent controls. + +Arguments: + + None referenced + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CUICtrlDefaultCombo::EnableDependentCtrls( + _In_ CONST HWND, + _In_ CONST LONG + ) +{ + return S_OK; +} + +/*++ + +Routine Name: + + CUICtrlDefaultCombo::AddString + +Routine Description: + + Loads a string from the specified resource and adds it to the end of the Combo Box. + +Arguments: + + hDlg - handle to the parent window + hStringResDLL - handle of the resource DLL that contains the string table. + idString - identifer of the string resource to be added + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CUICtrlDefaultCombo::AddString( + _In_ CONST HWND hDlg, + _In_ CONST HINSTANCE hStringResDLL, + _In_ CONST INT idString + ) +{ + HRESULT hr = S_OK; + + TCHAR szItem[MAX_UISTRING_LEN]; + if (LoadString(hStringResDLL, idString, szItem, countof(szItem)) > 0) + { + LRESULT lResult = SendDlgItemMessage(hDlg, m_iComboResID, CB_ADDSTRING, 0, reinterpret_cast(szItem)); + + if (lResult == CB_ERRSPACE || + lResult == CB_ERR) + { + hr = E_FAIL; + } + } + else + { + hr = HRESULT_FROM_WIN32(GetLastError()); + } + + ERR_ON_HR(hr); + return hr; +} + +// +// EditNum control +// +/*++ + +Routine Name: + + CUICtrlDefaultEditNum::CUICtrlDefaultEditNum + +Routine Description: + + CUICtrlDefaultEditNum class constructor + +Arguments: + + gpdString - Property name of the data associated with this control. + iEditResID - Resource id for the Combo Box control. + iPropMin - Minimum integer value that is valid. + iPropMax - Maximum integer value that is valid. + iSpinResID - Resource id for the associated Up/Down spinner control. + +Return Value: + + None + +--*/ +CUICtrlDefaultEditNum::CUICtrlDefaultEditNum( + _In_ PCSTR propString, + _In_ CONST INT iEditResID, + _In_ CONST INT iPropMin, + _In_ CONST INT iPropMax, + _In_ CONST INT iSpinResID + ) : + m_szPropString(propString), + m_iEditResID(iEditResID), + m_iPropMin(iPropMin), + m_iPropMax(iPropMax), + m_iSpinResID(iSpinResID) + +{ +} + +/*++ + +Routine Name: + + CUICtrlDefaultEditNum::~CUICtrlDefaultEditNum + +Routine Description: + + CUICtrlDefaultEditNum class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlDefaultEditNum::~CUICtrlDefaultEditNum() +{ +} + +/*++ + +Routine Name: + + CUICtrlDefaultEditNum::OnActivate + +Routine Description: + + Called when the parent property page becomes active. + This method initialises the state of the control to reflect the OEM private devmode. + +Arguments: + + hDlg - handle to the parent window + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CUICtrlDefaultEditNum::OnActivate( + _In_ CONST HWND hDlg + ) +{ + HRESULT hr = S_OK; + + ASSERTMSG(m_pUIProperties != NULL, "NULL pointer to UI properties interface.\n"); + + if (SUCCEEDED(hr = CHECK_POINTER(m_pUIProperties, E_PENDING))) + { + INT iPos = 0; + TCHAR szItem[MAX_UISTRING_LEN]; + + if (SUCCEEDED(hr = m_pUIProperties->GetItem(m_szPropString, reinterpret_cast(&iPos), sizeof(iPos))) && + SUCCEEDED(hr = StringCchPrintf(szItem, MAX_UISTRING_LEN, TEXT("%d"), iPos))) + { + if (SetDlgItemText(hDlg, m_iEditResID, reinterpret_cast(szItem)) == 0) + { + hr = HRESULT_FROM_WIN32(GetLastError()); + } + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CUICtrlDefaultEditNum::OnCommand + +Routine Description: + + Called from the property page handler when a WM_COMMAND message is recieved. + Filters out any Edit Text change (EN_CHANGE) messages intended for this control. + +Arguments: + + hDlg - handle to the parent window + iCommand - specifies the notification code + +Return Value: + + HRESULT + S_OK - On success + E_NOTIMPL - Command not implemented + E_* - On error + +--*/ +HRESULT +CUICtrlDefaultEditNum::OnCommand( + _In_ CONST HWND hDlg, + _In_ INT iCommand + ) +{ + HRESULT hr = S_OK; + + switch (iCommand) + { + case EN_CHANGE: + { + hr = OnEnChange(hDlg); + } + break; + + default: + hr = E_NOTIMPL; + + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CUICtrlDefaultEditNum::CheckInRange + +Routine Description: + + Ensures that a value is within range of the controls min/max extents. + +Arguments: + + pValue - pointer to the integer value to check. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CUICtrlDefaultEditNum::CheckInRange( + _In_ PINT pValue + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pValue, E_POINTER))) + { + if (*pValue > m_iPropMax) + { + *pValue = m_iPropMax; + } + + if (*pValue < m_iPropMin) + { + *pValue = m_iPropMin; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CUICtrlDefaultEditNum::OnEnChange + +Routine Description: + + This rountine handles the event of a change in the text box. The text in the control is read then + validated and the result is stored in the OEM private devmode. In addition the buddy spinner + control is updated to reflect the change in value. + +Arguments: + + hDlg - handle to the parent window + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CUICtrlDefaultEditNum::OnEnChange( + _In_ CONST HWND hDlg + ) +{ + HRESULT hr = S_OK; + + ASSERTMSG(m_pUIProperties != NULL, "NULL pointer to UI properties interface.\n"); + + BOOL bTranslated; + + INT iPos = static_cast(GetDlgItemInt(hDlg, m_iEditResID, &bTranslated, TRUE)); + + if (bTranslated) + { + INT iOrgPos = 0; + + if (SUCCEEDED(hr = CHECK_POINTER(m_pUIProperties, E_PENDING)) && + SUCCEEDED(hr = m_pUIProperties->GetItem(m_szPropString, reinterpret_cast(&iOrgPos), sizeof(iOrgPos))) && + SUCCEEDED(hr = CheckInRange(&iPos)) && + iOrgPos != iPos) + { + SendDlgItemMessage(hDlg, m_iSpinResID, UDM_SETPOS32, 0, static_cast(iPos)); + + if (SUCCEEDED(hr = m_pUIProperties->SetItem(m_szPropString, reinterpret_cast(&iPos), sizeof(iPos)))) + { + PropSheet_Changed(GetParent(hDlg), hDlg); + } + } + } + else + { + hr = E_FAIL; + } + + ERR_ON_HR(hr); + return hr; +} + +// +// Edit control +// +/*++ + +Routine Name: + + CUICtrlDefaultSpin::CUICtrlDefaultSpin + +Routine Description: + + CUICtrlDefaultSpin class constructor. + + Requires a Text Box buddy control class. + Settings for this Spin control are taken from the buddy class. + +Arguments: + + pEdit - Pointer to the buddy Text Box control. + +Return Value: + + None + +--*/ +CUICtrlDefaultSpin::CUICtrlDefaultSpin( + _In_ CUICtrlDefaultEditNum * pEdit + ): + m_szPropString(0), + m_iSpinResID(0), + m_iPropMin(0), + m_iPropMax(0), + m_iEditResID(0) +{ + if (pEdit !=NULL) + { + m_szPropString = pEdit->m_szPropString; + m_iSpinResID = pEdit->m_iSpinResID; + m_iPropMin = pEdit->m_iPropMin; + m_iPropMax = pEdit->m_iPropMax; + m_iEditResID = pEdit->m_iEditResID; + } +} + +/*++ + +Routine Name: + + CUICtrlDefaultSpin::~CUICtrlDefaultSpin + +Routine Description: + + CUICtrlDefaultSpin class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlDefaultSpin::~CUICtrlDefaultSpin() +{ +} + +/*++ + +Routine Name: + + CUICtrlDefaultSpin::OnActivate + +Routine Description: + + Called when the parent property page becomes active. + This method initialises the state of the control to reflect the OEM private devmode. + +Arguments: + + hDlg - handle to the parent window + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CUICtrlDefaultSpin::OnActivate( + _In_ CONST HWND hDlg + ) +{ + HRESULT hr = S_OK; + INT iPos = 0; + + ASSERTMSG(m_pUIProperties != NULL, "NULL pointer to UI properties interface.\n"); + + if (SUCCEEDED(hr = CHECK_POINTER(m_pUIProperties, E_PENDING)) && + SUCCEEDED(hr = m_pUIProperties->GetItem(m_szPropString, reinterpret_cast(&iPos), sizeof(iPos)))) + { + SendDlgItemMessage(hDlg, m_iSpinResID, UDM_SETRANGE32, m_iPropMin, m_iPropMax); + SendDlgItemMessage(hDlg, m_iSpinResID, UDM_SETPOS32, 0, iPos); + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CUICtrlDefaultSpin::OnNotify + +Routine Description: + + Called from the property page handler when a WM_NOTIFY message is recieved. + Filters out any Up/Down position (UDN_DELTAPOS) messages intended for this control. + +Arguments: + + hDlg - handle to the parent window + pNmhdr - pointer to the notification message + +Return Value: + + HRESULT + S_OK - On success + E_NOTIMPL - Command not implemented + E_* - On error + +--*/ +HRESULT +CUICtrlDefaultSpin::OnNotify( + _In_ CONST HWND hDlg, + _In_ CONST NMHDR* pNmhdr + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pNmhdr, E_POINTER))) + { + switch (pNmhdr->code) + { + case UDN_DELTAPOS: + { + hr = OnDeltaPos(hDlg, reinterpret_cast(pNmhdr)); + } + break; + + default: + hr = E_NOTIMPL; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CUICtrlDefaultSpin::CheckInRange + +Routine Description: + + Ensures that a value is within range of the controls min/max extents. + +Arguments: + + pValue - Pointer to the integer value to check. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CUICtrlDefaultSpin::CheckInRange( + _In_ PINT pValue + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pValue, E_POINTER))) + { + if (*pValue > m_iPropMax) + { + *pValue = m_iPropMax; + } + + if (*pValue < m_iPropMin) + { + *pValue = m_iPropMin; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CUICtrlDefaultSpin::OnDeltaPos + +Routine Description: + + This rountine handles the event of a change in value of the Up/Down control. The new value + of the control is validated and stored in the OEM private devmode. In addition the buddy text + box control is updated to reflect the change. + +Arguments: + + hDlg - handle to the parent window + pNmud - this structure contains information specific to up-down control messages + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CUICtrlDefaultSpin::OnDeltaPos( + _In_ CONST HWND hDlg, + _In_ CONST NMUPDOWN* pNmud + ) +{ + HRESULT hr = S_OK; + INT iOrgPos = 0; + INT iPos = 0; + + ASSERTMSG(m_pUIProperties != NULL, "NULL pointer to UI properties interface.\n"); + + if (SUCCEEDED(hr = CHECK_POINTER(pNmud, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(m_pUIProperties, E_PENDING)) && + SUCCEEDED(hr = m_pUIProperties->GetItem(m_szPropString, reinterpret_cast(&iOrgPos), sizeof(iOrgPos)))) + { + iPos = iOrgPos + pNmud->iDelta; + TCHAR szItem[MAX_UISTRING_LEN]; + + if (SUCCEEDED(hr = CheckInRange(&iPos)) && + iOrgPos != iPos && + SUCCEEDED(hr = StringCchPrintf(szItem, MAX_UISTRING_LEN, TEXT("%d"), iPos))) + { + if (SetDlgItemText(hDlg, m_iEditResID, reinterpret_cast(szItem)) > 0) + { + if (SUCCEEDED(hr = m_pUIProperties->SetItem(m_szPropString, reinterpret_cast(&iPos), sizeof(iPos)))) + { + PropSheet_Changed(GetParent(hDlg), hDlg); + } + } + else + { + hr = HRESULT_FROM_WIN32(GetLastError()); + } + } + } + + ERR_ON_HR(hr); + return hr; +} + +// +// EditText control +// +/*++ + +Routine Name: + + CUICtrlDefaultEditText::CUICtrlDefaultEditText + +Routine Description: + + CUICtrlDefaultEditText class constructor + +Arguments: + + gpdString - Property name of the data associated with this control. + iEditResID - Resource id for the Combo Box control. + cbMaxLength - Maximum number of characters allowed. + +Return Value: + + None + +--*/ +CUICtrlDefaultEditText::CUICtrlDefaultEditText( + _In_ PCSTR propString, + _In_ CONST INT iEditResID, + _In_ CONST INT cbMaxLength + ) : + m_szPropString(propString), + m_iEditResID(iEditResID), + m_cbMaxLength(cbMaxLength) + +{ +} + +/*++ + +Routine Name: + + CUICtrlDefaultEditText::~CUICtrlDefaultEditText + +Routine Description: + + CUICtrlDefaultEditText class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlDefaultEditText::~CUICtrlDefaultEditText() +{ +} + +/*++ + +Routine Name: + + CUICtrlDefaultEditText::OnActivate + +Routine Description: + + Called when the parent property page becomes active. + This method initialises the state of the control to reflect the OEM private devmode. + +Arguments: + + hDlg - handle to the parent window + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CUICtrlDefaultEditText::OnActivate( + _In_ CONST HWND hDlg + ) +{ + HRESULT hr = S_OK; + + ASSERTMSG(m_pUIProperties != NULL, "NULL pointer to UI properties interface.\n"); + + if (SUCCEEDED(hr = CHECK_POINTER(m_pUIProperties, E_PENDING))) + { + SIZE_T cbBuffer = sizeof(TCHAR) * m_cbMaxLength; + LPTSTR lpBuffer = new(std::nothrow) TCHAR[m_cbMaxLength]; + + if (SUCCEEDED(hr = CHECK_POINTER(lpBuffer, E_OUTOFMEMORY))) + { + if (SUCCEEDED(hr = m_pUIProperties->GetItem(m_szPropString, reinterpret_cast(lpBuffer), cbBuffer)) && + SUCCEEDED(hr = CHECK_POINTER(lpBuffer, E_FAIL))) + { + if (SetDlgItemText(hDlg, m_iEditResID, reinterpret_cast(lpBuffer)) == 0) + { + hr = HRESULT_FROM_WIN32(GetLastError()); + } + } + + delete[] lpBuffer; + lpBuffer = NULL; + } + } + + if (SUCCEEDED(hr)) + { + SendDlgItemMessage(hDlg, m_iEditResID, EM_LIMITTEXT, m_cbMaxLength - 1, 0L); + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CUICtrlDefaultEditText::OnCommand + +Routine Description: + + Called from the property page handler when a WM_COMMAND message is recieved. + Filters out any Edit Text change (EN_CHANGE) messages intended for this control. + +Arguments: + + hDlg - handle to the parent window + iCommand - specifies the notification code + +Return Value: + + HRESULT + S_OK - On success + E_NOTIMPL - Command not implemented + E_* - On error + +--*/ +HRESULT +CUICtrlDefaultEditText::OnCommand( + _In_ CONST HWND hDlg, + _In_ INT iCommand + ) +{ + HRESULT hr = S_OK; + + switch (iCommand) + { + case EN_CHANGE: + { + hr = OnEnChange(hDlg); + } + break; + + default: + hr = E_NOTIMPL; + + } + + ERR_ON_HR(hr); + return hr; +} + + +/*++ + +Routine Name: + + CUICtrlDefaultEditNum::OnEnChange + +Routine Description: + + This rountine handles the event of a change in the text box. + The text in the control is read and the result is stored in the OEM private devmode. + +Arguments: + + hDlg - handle to the parent window + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CUICtrlDefaultEditText::OnEnChange( + _In_ CONST HWND hDlg + ) +{ + HRESULT hr = S_OK; + + ASSERTMSG(m_pUIProperties != NULL, "NULL pointer to UI properties interface.\n"); + + SIZE_T cbBuffer = sizeof(TCHAR) * m_cbMaxLength; + LPTSTR lpBuffer = new(std::nothrow) TCHAR[m_cbMaxLength]; + + if (SUCCEEDED(hr = CHECK_POINTER(lpBuffer, E_OUTOFMEMORY))) + { + if (GetDlgItemText(hDlg, m_iEditResID, lpBuffer, m_cbMaxLength) == 0) + { + hr = HRESULT_FROM_WIN32(GetLastError()); + } + else + { + LPTSTR lpOrgBuffer = new(std::nothrow) TCHAR[m_cbMaxLength]; + + if (SUCCEEDED(hr = CHECK_POINTER(lpOrgBuffer, E_OUTOFMEMORY))) + { + if (SUCCEEDED(hr = CHECK_POINTER(m_pUIProperties, E_PENDING)) && + SUCCEEDED(hr = m_pUIProperties->GetItem(m_szPropString, reinterpret_cast(lpOrgBuffer), cbBuffer)) && + SUCCEEDED(hr = CHECK_POINTER(lpOrgBuffer, E_FAIL)) && + wcsncmp(lpBuffer, lpOrgBuffer, m_cbMaxLength) != 0 && + SUCCEEDED(hr = m_pUIProperties->SetItem(m_szPropString, reinterpret_cast(lpBuffer), cbBuffer))) + { + PropSheet_Changed(GetParent(hDlg), hDlg); + } + + delete[] lpOrgBuffer; + lpOrgBuffer = NULL; + } + } + + delete[] lpBuffer; + lpBuffer = NULL; + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CUICtrlDefaultBtn::CUICtrlDefaultBtn + +Routine Description: + + CUICtrlDefaultBtn class constructor. + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlDefaultBtn::CUICtrlDefaultBtn( + _In_ PCSTR propertyString, + _In_ INT iBtnResID + ) : + m_szPropertyString(propertyString), + m_iBtnResID(iBtnResID) +{ +} + +/*++ + +Routine Name: + + CUICtrlDefaultBtn::CUICtrlDefaultBtn + +Routine Description: + + CUICtrlDefaultBtn class constructor. + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlDefaultBtn::~CUICtrlDefaultBtn() +{ +} + +/*++ + +Routine Name: + + CUICtrlDefaultBtn::CUICtrlDefaultBtn + +Routine Description: + + Default button OnActivate handler. + +Arguments: + + None + +Return Value: + + S_OK + +--*/ +HRESULT +CUICtrlDefaultBtn::OnActivate( + _In_ CONST HWND + ) +{ + return S_OK; +} + +/*++ + +Routine Name: + + CUICtrlDefaultBtn::OnCommand + +Routine Description: + + Default button OnCommand handler. + +Arguments: + + hDlg - handle to the parent window + iCommand - specifies the notification code + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CUICtrlDefaultBtn::OnCommand( + _In_ CONST HWND hDlg, + _In_ INT iCommand + ) +{ + HRESULT hr = S_OK; + + switch (iCommand) + { + case BN_CLICKED: + { + hr = OnBnClicked(hDlg); + } + break; + + default: + hr = E_NOTIMPL; + } + + ERR_ON_HR(hr); + return hr; +} + diff --git a/print/XPSDrvSmpl/src/ui/uictrl.h b/print/XPSDrvSmpl/src/ui/uictrl.h new file mode 100644 index 00000000..5292e78b --- /dev/null +++ b/print/XPSDrvSmpl/src/ui/uictrl.h @@ -0,0 +1,405 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + uictrl.h + +Abstract: + + Definition of the UI control interface called by the containing property page, + the abstract UI control class and the base default UI controls for check boxe, + list, combo, edit and spin controls. + +--*/ + +#pragma once + +#include "UIProperties.h" + +class CUIControl +{ +public: + CUIControl(); + + virtual ~CUIControl(); + + virtual HRESULT + SetPrintOemDriverUI( + _In_ CONST IPrintOemDriverUI* pOEMDriverUI + ); + + virtual HRESULT + SetOemCUIPParam( + _In_ CONST POEMCUIPPARAM pOemCUIPParam + ); + + virtual HRESULT + SetUIProperties( + _In_ CUIProperties* pUIProperties + ); + + // + // Message handling stubs + // + virtual HRESULT + OnActivate( + _In_ CONST HWND hDlg + ) = 0; + + virtual HRESULT + OnInit( + _In_ CONST HWND hDlg + ); + + virtual HRESULT + OnCommand( + _In_ CONST HWND hDlg, + _In_ INT iCommand + ); + + virtual HRESULT + OnNotify( + _In_ CONST HWND hDlg, + _In_ CONST NMHDR* pNmhdr + ); + +protected: + CComPtr m_pDriverUIHelp; + + POEMCUIPPARAM m_pOemCUIPParam; + + CUIProperties * m_pUIProperties; +}; + +class CUICtrlDefaultCheck : public CUIControl +{ +public: + CUICtrlDefaultCheck( + _In_ PCSTR gpdString, + _In_ INT iCheckResID + ); + + virtual ~CUICtrlDefaultCheck(); + + HRESULT + OnActivate( + _In_ CONST HWND hDlg + ); + + HRESULT + OnCommand( + _In_ CONST HWND hDlg, + _In_ INT iCommand + ); + +private: + virtual HRESULT + OnBnClicked( + _In_ CONST HWND hDlg + ); + + virtual HRESULT + EnableDependentCtrls( + _In_ CONST HWND hDlg, + _In_ CONST LONG lSel + ); + + CUICtrlDefaultCheck& operator = (CONST CUICtrlDefaultCheck&); + +private: + PCSTR m_szGPDString; + + CONST INT m_iCheckResID; +}; + +class CUICtrlDefaultList : public CUIControl +{ +public: + CUICtrlDefaultList( + _In_ PCSTR gpdString, + _In_ INT iListResID + ); + + virtual ~CUICtrlDefaultList(); + + HRESULT + OnActivate( + _In_ CONST HWND hDlg + ); + + HRESULT + OnCommand( + _In_ CONST HWND hDlg, + _In_ INT iCommand + ); + +protected: + HRESULT + AddString( + _In_ CONST HWND hDlg, + _In_ CONST HINSTANCE hStringResDLL, + _In_ CONST INT idString + ); + +private: + virtual HRESULT + EnableDependentCtrls( + _In_ CONST HWND hDlg, + _In_ CONST LONG lSel + ); + + virtual HRESULT + OnSelChange( + _In_ CONST HWND hDlg + ); + + CUICtrlDefaultList& operator = (CONST CUICtrlDefaultList&); + +private: + PCSTR m_szGPDString; + + CONST INT m_iListResID; +}; + +class CUICtrlDefaultCombo : public CUIControl +{ +public: + CUICtrlDefaultCombo( + _In_ PCSTR gpdString, + _In_ INT iComboResID + ); + + virtual ~CUICtrlDefaultCombo(); + + HRESULT + OnActivate( + _In_ CONST HWND hDlg + ); + + HRESULT + OnCommand( + _In_ CONST HWND hDlg, + _In_ INT iCommand + ); + + virtual HRESULT + OnSelChange( + _In_ CONST HWND hDlg + ); + +protected: + HRESULT + AddString( + _In_ CONST HWND hDlg, + _In_ CONST HINSTANCE hStringResDLL, + _In_ CONST INT idString + ); + +private: + virtual HRESULT + EnableDependentCtrls( + _In_ CONST HWND hDlg, + _In_ CONST LONG lSel + ); + + CUICtrlDefaultCombo& operator = (CONST CUICtrlDefaultCombo&); + +private: + PCSTR m_szGPDString; + + CONST INT m_iComboResID; +}; + +class CUICtrlDefaultSpin; + +class CUICtrlDefaultEditNum : public CUIControl +{ +public: + CUICtrlDefaultEditNum( + _In_ PCSTR propString, + _In_ CONST INT iEditResID, + _In_ CONST INT iPropMin, + _In_ CONST INT iPropMax, + _In_ CONST INT iSpinResID + ); + + virtual ~CUICtrlDefaultEditNum(); + + friend class CUICtrlDefaultSpin; + + HRESULT + virtual OnActivate( + _In_ CONST HWND hDlg + ); + + virtual HRESULT + OnCommand( + _In_ CONST HWND hDlg, + _In_ INT iCommand + ); + +private: + CUICtrlDefaultEditNum() : + m_iEditResID(0), + m_iPropMin(0), + m_iPropMax(0), + m_iSpinResID(0) + {} + + virtual HRESULT + CheckInRange( + _In_ PINT pValue + ); + + virtual HRESULT + OnEnChange( + _In_ CONST HWND hDlg + ); + + CUICtrlDefaultEditNum& operator = (CONST CUICtrlDefaultEditNum&); + + +private: + PCSTR m_szPropString; + + CONST INT m_iPropMin; + + CONST INT m_iPropMax; + + CONST INT m_iEditResID; + + CONST INT m_iSpinResID; +}; + +class CUICtrlDefaultSpin : public CUIControl +{ + +public: + CUICtrlDefaultSpin( + _In_ CUICtrlDefaultEditNum* pEdit + ); + + virtual ~CUICtrlDefaultSpin(); + + virtual HRESULT + OnActivate( + _In_ CONST HWND hDlg + ); + + virtual HRESULT + OnNotify( + _In_ CONST HWND hDlg, + _In_ CONST NMHDR* pNmhdr + ); + + +private: + virtual HRESULT + CheckInRange( + _In_ PINT pValue + ); + + virtual HRESULT + OnDeltaPos( + _In_ CONST HWND hDlg, + _In_ CONST NMUPDOWN* pNmud + ); + + CUICtrlDefaultSpin& operator = (CONST CUICtrlDefaultSpin&); + +private: + PCSTR m_szPropString; + + INT m_iPropMin; + + INT m_iPropMax; + + INT m_iSpinResID; + + INT m_iEditResID; +}; + +class CUICtrlDefaultEditText : public CUIControl +{ +public: + CUICtrlDefaultEditText( + _In_ PCSTR propString, + _In_ CONST INT iEditResID, + _In_ CONST INT cbMaxLength + ); + + virtual ~CUICtrlDefaultEditText(); + + HRESULT + virtual OnActivate( + _In_ CONST HWND hDlg + ); + + virtual HRESULT + OnCommand( + _In_ CONST HWND hDlg, + _In_ INT iCommand + ); + +private: + virtual HRESULT + OnEnChange( + _In_ CONST HWND hDlg + ); + + CUICtrlDefaultEditText& operator = (CONST CUICtrlDefaultEditText&); + + +private: + PCSTR m_szPropString; + + CONST INT m_cbMaxLength; + + CONST INT m_iEditResID; +}; + +class CUICtrlDefaultBtn : public CUIControl +{ +public: + CUICtrlDefaultBtn( + _In_ PCSTR propertyString, + _In_ INT iCheckResID + ); + + virtual ~CUICtrlDefaultBtn(); + + HRESULT + OnActivate( + _In_ CONST HWND hDlg + ); + + HRESULT + OnCommand( + _In_ CONST HWND hDlg, + _In_ INT iCommand + ); + +private: + virtual HRESULT + OnBnClicked( + _In_ CONST HWND hDlg + ) = 0; + + CUICtrlDefaultBtn& operator = (CONST CUICtrlDefaultCheck&); + +protected: + PCSTR m_szPropertyString; + +private: + CONST INT m_iBtnResID; +}; + diff --git a/print/XPSDrvSmpl/src/ui/uiproperties.cpp b/print/XPSDrvSmpl/src/ui/uiproperties.cpp new file mode 100644 index 00000000..c6ceb4e7 --- /dev/null +++ b/print/XPSDrvSmpl/src/ui/uiproperties.cpp @@ -0,0 +1,783 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + uiproperties.cpp + +Abstract: + + This class encapsulates all handling of GPD and OEM private devmode settings + used in the XPSDrv feature sample UI. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdstring.h" +#include "xdexcept.h" +#include "uiproperties.h" +#include "privatedefs.h" + +PCSTR g_pszPSScaleWidth = "PageScalingScaleWidth"; +PCSTR g_pszPSScaleHeight = "PageScalingScaleHeight"; +PCSTR g_pszOffsetWidth = "PageScalingOffsetWidth"; +PCSTR g_pszOffsetHeight = "PageScalingOffsetHeight"; +PCSTR g_pszWMTransparency = "PageWatermarkTransparency"; +PCSTR g_pszWMAngle = "PageWatermarkTextAngle"; +PCSTR g_pszWMOffsetWidth = "PageWatermarkOriginWidth"; +PCSTR g_pszWMOffsetHeight = "PageWatermarkOriginHeight"; +PCSTR g_pszWMSizeWidth = "PageWatermarkSizeWidth"; +PCSTR g_pszWMSizeHeight = "PageWatermarkSizeHeight"; +PCSTR g_pszWMFontSize = "PageWatermarkTextFontSize"; +PCSTR g_pszWMFontColor = "PageWatermarkTextColor"; +PCSTR g_pszWMText = "PageWatermarkTextText"; + +/*++ + +Routine Name: + + CUIProperties::CUIProperties + +Routine Description: + + CUIProperties default class constructor. + +Arguments: + + None. + +Return Value: + + None + Throws CXDException(HRESULT) on an error + +--*/ +CUIProperties::CUIProperties(): + m_pOEMDev(NULL) +{ + HRESULT hr = InitialiseMap(); + + if (FAILED(hr)) + { + throw CXDException(hr); + } +} + +/*++ + +Routine Name: + + CUIProperties::CUIProperties + +Routine Description: + + CUIProperties class constructor. + +Arguments: + + pOEMDM - Pointer to an OEMDEV structure. + +Return Value: + + None + Throws CXDException(HRESULT) on an error + +--*/ +CUIProperties::CUIProperties( + POEMDEV pOEMDM): + m_pOEMDev(pOEMDM) +{ + HRESULT hr = InitialiseMap(); + + if (FAILED(hr)) + { + throw CXDException(hr); + } +} + +/*++ + +Routine Name: + + CUIProperties::~CUIProperties + +Routine Description: + + CUIProperties class destructor. + +Arguments: + + None + +Return Value: + + None + +--*/ +CUIProperties::~CUIProperties() +{ +} + +/*++ + +Routine Name: + + CUIProperties::InitialiseMap + +Routine Description: + + Creates a map of GPD names and private OEM devmode properties that will be used by the driver. + +Arguments: + + None + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CUIProperties::InitialiseMap( + VOID + ) +{ + HRESULT hr = S_OK; + + try + { + // + // Initialise the OEM devmode entries + // + m_PropertyMap[g_pszPSScaleWidth] = UIPropertyPair(sizeof(DWORD), offsetof(OEMDEV, dwPgScaleX)); + m_PropertyMap[g_pszPSScaleHeight] = UIPropertyPair(sizeof(DWORD), offsetof(OEMDEV, dwPgScaleY)); + m_PropertyMap[g_pszOffsetWidth] = UIPropertyPair(sizeof(INT), offsetof(OEMDEV, iPgOffsetX)); + m_PropertyMap[g_pszOffsetHeight] = UIPropertyPair(sizeof(INT), offsetof(OEMDEV, iPgOffsetY)); + m_PropertyMap[g_pszWMTransparency] = UIPropertyPair(sizeof(INT), offsetof(OEMDEV, iWMTransparency)); + m_PropertyMap[g_pszWMAngle] = UIPropertyPair(sizeof(INT), offsetof(OEMDEV, iWMAngle)); + m_PropertyMap[g_pszWMFontSize] = UIPropertyPair(sizeof(INT), offsetof(OEMDEV, iWMFontSize)); + m_PropertyMap[g_pszWMFontColor] = UIPropertyPair(sizeof(DWORD), offsetof(OEMDEV, dwColText)); + m_PropertyMap[g_pszWMOffsetWidth] = UIPropertyPair(sizeof(INT), offsetof(OEMDEV, iWMOffsetX)); + m_PropertyMap[g_pszWMOffsetHeight] = UIPropertyPair(sizeof(INT), offsetof(OEMDEV, iWMOffsetY)); + m_PropertyMap[g_pszWMSizeWidth] = UIPropertyPair(sizeof(INT), offsetof(OEMDEV, iWMWidth)); + m_PropertyMap[g_pszWMSizeHeight] = UIPropertyPair(sizeof(INT), offsetof(OEMDEV, iWMHeight)); + m_PropertyMap[g_pszWMText] = UIPropertyPair(sizeof(TCHAR) * MAX_WATERMARK_TEXT, offsetof(OEMDEV, strWMText)); + + // + // Initialise the GPD OptItem entries. + // NOTE: These options will be removed from the standard Unidrv UI Treeview. + // + m_OptItemList.push_back("JobBindAllDocuments"); + m_OptItemList.push_back("DocumentBinding"); + m_OptItemList.push_back("PageColorManagement"); + m_OptItemList.push_back("PageSourceColorProfile"); + m_OptItemList.push_back("PageICMRenderingIntent"); + m_OptItemList.push_back("PageScaling"); + m_OptItemList.push_back("ScaleOffsetAlignment"); + m_OptItemList.push_back("PageWatermarkType"); + m_OptItemList.push_back("PageWatermarkLayering"); + m_OptItemList.push_back("JobNUpAllDocumentsContiguously"); + m_OptItemList.push_back("JobNUpContiguouslyPresentationOrder"); + m_OptItemList.push_back("DocumentNUp"); + m_OptItemList.push_back("DocumentNUpPresentationOrder"); + m_OptItemList.push_back("PageBorderless"); + m_OptItemList.push_back("PagePhotoPrintingIntent"); + m_OptItemList.push_back("DocumentDuplex"); + } + catch (exception& DBG_ONLY(e)) + { + ERR(e.what()); + hr = E_FAIL; + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CUIProperties::SetItem + +Routine Description: + + This method is used to set properties in the private OEM devmode. + +Arguments: + + pFeatureName - Pointer to the property name. + pUIProperty - Pointer to the property value. + cbSize - Size of the buffer pointed to by pUIProperty. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CUIProperties::SetItem( + _In_ PCSTR pFeatureName, + _In_reads_bytes_(cbSize) CONST UIProperty* pUIProperty, + _In_ SIZE_T cbSize + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(m_pOEMDev, E_PENDING))) + { + try + { + UIPropertyMap::const_iterator iterItem = m_PropertyMap.find(pFeatureName); + + if (iterItem != m_PropertyMap.end()) + { + if (iterItem->second.first >= cbSize) + { + memcpy(reinterpret_cast(m_pOEMDev) + iterItem->second.second, pUIProperty, cbSize); + } + else + { + hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); + } + } + else + { + hr = E_INVALIDARG; + } + } + catch (exception& DBG_ONLY(e)) + { + ERR(e.what()); + hr = E_FAIL; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CUIProperties::GetItem + + +Routine Description: + + This method is used to get properties in the private OEM devmode. + +Arguments: + + pFeatureName - Pointer to the property name. + pUIProperty - Pointer to the property value. + cbSize - Size of the buffer pointed to by pUIProperty. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CUIProperties::GetItem( + _In_ PCSTR pFeatureName, + _Out_writes_bytes_(cbSize) UIProperty* pUIProperty, + _In_ SIZE_T cbSize + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(m_pOEMDev, E_PENDING))) + { + try + { + UIPropertyMap::const_iterator iterItem = m_PropertyMap.find(pFeatureName); + + if (iterItem != m_PropertyMap.end()) + { + if (iterItem->second.first == cbSize) + { + memcpy(pUIProperty, reinterpret_cast(m_pOEMDev) + iterItem->second.second, cbSize); + } + else + { + hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); + } + } + else + { + hr = E_INVALIDARG; + } + } + catch (exception& DBG_ONLY(e)) + { + ERR(e.what()); + hr = E_FAIL; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CUIProperties::SetHeader + +Routine Description: + + Initialises the Unidrv private header portion of the OEM devmode. + +Arguments: + + None + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CUIProperties::SetHeader() +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(m_pOEMDev, E_PENDING))) + { + // + //OEM_DMEXTRAHEADER Members + // + m_pOEMDev->dmOEMExtra.dwSize = sizeof(OEMDEV); + m_pOEMDev->dmOEMExtra.dwSignature = OEM_SIGNATURE; + m_pOEMDev->dmOEMExtra.dwVersion = OEM_VERSION; + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CUIProperties::SetDefaults + +Routine Description: + + Initialises the OEM devmode with default values. + +Arguments: + + None + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CUIProperties::SetDefaults() +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(m_pOEMDev, E_PENDING))) + { + if (SUCCEEDED(hr = SetHeader())) + { + // + //Private members + // + + // + // Page Scaling + // + m_pOEMDev->dwPgScaleX = pgscParamDefIntegers[ePageScalingScaleWidth].default_value; + m_pOEMDev->dwPgScaleY = pgscParamDefIntegers[ePageScalingScaleHeight].default_value; + m_pOEMDev->iPgOffsetX = MICRON_TO_HUNDREDTH_OFINCH(pgscParamDefIntegers[ePageScalingOffsetWidth].default_value); + m_pOEMDev->iPgOffsetY = MICRON_TO_HUNDREDTH_OFINCH(pgscParamDefIntegers[ePageScalingOffsetHeight].default_value); + + // + // Page Watermark + // + m_pOEMDev->iWMTransparency = wmParamDefIntegers[ePageWatermarkTransparency].default_value; + m_pOEMDev->iWMAngle = wmParamDefIntegers[ePageWatermarkAngle].default_value; + m_pOEMDev->iWMOffsetX = MICRON_TO_HUNDREDTH_OFINCH(wmParamDefIntegers[ePageWatermarkOriginWidth].default_value); + m_pOEMDev->iWMOffsetY = MICRON_TO_HUNDREDTH_OFINCH(wmParamDefIntegers[ePageWatermarkOriginHeight].default_value); + + m_pOEMDev->iWMFontSize = wmParamDefIntegers[ePageWatermarkTextFontSize].default_value; + m_pOEMDev->dwColText = wmParamDefIntegers[ePageWatermarkTextColor].default_value; + + try + { + CStringXD cstrWMText(wmParamDefStrings[ePageWatermarkTextText].default_value); + hr = StringCchCopyN(m_pOEMDev->strWMText, MAX_WATERMARK_TEXT, cstrWMText.GetBuffer(), cstrWMText.GetLength()); + } + catch (CXDException& e) + { + hr = e; + } + + m_pOEMDev->iWMWidth = MICRON_TO_HUNDREDTH_OFINCH(wmParamDefIntegers[ePageWatermarkSizeWidth].default_value); + m_pOEMDev->iWMHeight = MICRON_TO_HUNDREDTH_OFINCH(wmParamDefIntegers[ePageWatermarkSizeHeight].default_value); + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CUIProperties::Convert + +Routine Description: + + This method is used to convert the OEM private devmode portion of this IUIProperty interface + given another interface as input. + +Arguments: + + pUIProperties - Pointer to the source IUIProperty interface to be converted. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CUIProperties::Convert( + _In_ CUIProperties * pUIProperties + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pUIProperties, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pUIProperties->m_pOEMDev, E_PENDING)) && + SUCCEEDED(hr = CHECK_POINTER(m_pOEMDev, E_PENDING))) + { + // + // Check OEM Signature, if it doesn't match ours, + // then just assume DMIn is bad and use defaults. + // + if (m_pOEMDev->dmOEMExtra.dwSignature == pUIProperties->m_pOEMDev->dmOEMExtra.dwSignature) + { + if (SUCCEEDED(hr = SetDefaults())) + { + // Copy the old structure in to the new using which ever size is the smaller. + // Devmode maybe from newer Devmode (not likely since there is only one), or + // Devmode maybe a newer Devmode, in which case it maybe larger, + // but the first part of the structure should be the same. + + // DESIGN ASSUMPTION: the private DEVMODE structure only gets added to; + // the fields that are in the DEVMODE never change only new fields get added to the end. + + DWORD dwSize = __min(m_pOEMDev->dmOEMExtra.dwSize, pUIProperties->m_pOEMDev->dmOEMExtra.dwSize); + memcpy(m_pOEMDev, pUIProperties->m_pOEMDev, dwSize); + + // Re-fill in the size and version fields to indicated + // that the DEVMODE is the current private DEVMODE version. + hr = SetHeader(); + } + } + else + { + hr = SetDefaults(); + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CUIProperties::Validate + +Routine Description: + + This method is used to ensure that the OEM private devmode is validated. + +Arguments: + + None + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CUIProperties::Validate() +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(m_pOEMDev, E_PENDING))) + { + // + // ASSUMPTION: pOEMDevmode is large enough to contain OEMDEV structure. + // Make sure that dmOEMExtra indicates the current OEMDEV structure. + // + if (SUCCEEDED(hr = SetHeader())) + { + // + // Page Scaling Members + // + if (m_pOEMDev->dwPgScaleX < static_cast(pgscParamDefIntegers[ePageScalingScaleWidth].min_length) || + m_pOEMDev->dwPgScaleX > static_cast(pgscParamDefIntegers[ePageScalingScaleWidth].max_length)) + { + m_pOEMDev->dwPgScaleX = static_cast(pgscParamDefIntegers[ePageScalingScaleWidth].default_value); + } + + if (m_pOEMDev->dwPgScaleY < static_cast(pgscParamDefIntegers[ePageScalingScaleHeight].min_length) || + m_pOEMDev->dwPgScaleY > static_cast(pgscParamDefIntegers[ePageScalingScaleHeight].max_length)) + { + m_pOEMDev->dwPgScaleY = static_cast(pgscParamDefIntegers[ePageScalingScaleHeight].default_value); + } + + if (m_pOEMDev->iPgOffsetX < MICRON_TO_HUNDREDTH_OFINCH(pgscParamDefIntegers[ePageScalingOffsetWidth].min_length) || + m_pOEMDev->iPgOffsetX > MICRON_TO_HUNDREDTH_OFINCH(pgscParamDefIntegers[ePageScalingOffsetWidth].max_length)) + { + m_pOEMDev->iPgOffsetX = MICRON_TO_HUNDREDTH_OFINCH(pgscParamDefIntegers[ePageScalingOffsetWidth].default_value); + } + + if (m_pOEMDev->iPgOffsetY < MICRON_TO_HUNDREDTH_OFINCH(pgscParamDefIntegers[ePageScalingOffsetHeight].min_length) || + m_pOEMDev->iPgOffsetY > MICRON_TO_HUNDREDTH_OFINCH(pgscParamDefIntegers[ePageScalingOffsetHeight].max_length)) + { + m_pOEMDev->iPgOffsetY = MICRON_TO_HUNDREDTH_OFINCH(pgscParamDefIntegers[ePageScalingOffsetHeight].default_value); + } + + // + // Watermark Members + // + if (m_pOEMDev->iWMTransparency < wmParamDefIntegers[ePageWatermarkTransparency].min_length || + m_pOEMDev->iWMTransparency > wmParamDefIntegers[ePageWatermarkTransparency].max_length) + { + m_pOEMDev->iWMTransparency = wmParamDefIntegers[ePageWatermarkTransparency].default_value; + } + + if (m_pOEMDev->iWMAngle < wmParamDefIntegers[ePageWatermarkAngle].min_length || + m_pOEMDev->iWMAngle > wmParamDefIntegers[ePageWatermarkAngle].max_length) + { + m_pOEMDev->iWMAngle = wmParamDefIntegers[ePageWatermarkAngle].default_value; + } + + if (m_pOEMDev->iWMOffsetX < MICRON_TO_HUNDREDTH_OFINCH(wmParamDefIntegers[ePageWatermarkOriginWidth].min_length) || + m_pOEMDev->iWMOffsetX > MICRON_TO_HUNDREDTH_OFINCH(wmParamDefIntegers[ePageWatermarkOriginWidth].max_length)) + { + m_pOEMDev->iWMOffsetX = MICRON_TO_HUNDREDTH_OFINCH(wmParamDefIntegers[ePageWatermarkOriginWidth].default_value); + } + + if (m_pOEMDev->iWMOffsetY < MICRON_TO_HUNDREDTH_OFINCH(wmParamDefIntegers[ePageWatermarkOriginHeight].min_length) || + m_pOEMDev->iWMOffsetY > MICRON_TO_HUNDREDTH_OFINCH(wmParamDefIntegers[ePageWatermarkOriginHeight].max_length)) + { + m_pOEMDev->iWMOffsetY = MICRON_TO_HUNDREDTH_OFINCH(wmParamDefIntegers[ePageWatermarkOriginHeight].default_value); + } + + if (m_pOEMDev->iWMFontSize < wmParamDefIntegers[ePageWatermarkTextFontSize].min_length || + m_pOEMDev->iWMFontSize > wmParamDefIntegers[ePageWatermarkTextFontSize].max_length) + { + m_pOEMDev->iWMFontSize = wmParamDefIntegers[ePageWatermarkTextFontSize].default_value; + } + + if (m_pOEMDev->dwColText < static_cast(wmParamDefIntegers[ePageWatermarkTextColor].min_length) || + m_pOEMDev->dwColText > static_cast(wmParamDefIntegers[ePageWatermarkTextColor].max_length)) + { + m_pOEMDev->dwColText = wmParamDefIntegers[ePageWatermarkTextColor].default_value; + } + + if (m_pOEMDev->iWMWidth < MICRON_TO_HUNDREDTH_OFINCH(wmParamDefIntegers[ePageWatermarkSizeWidth].min_length) || + m_pOEMDev->iWMWidth > MICRON_TO_HUNDREDTH_OFINCH(wmParamDefIntegers[ePageWatermarkSizeWidth].max_length)) + { + m_pOEMDev->iWMWidth = MICRON_TO_HUNDREDTH_OFINCH(wmParamDefIntegers[ePageWatermarkSizeWidth].default_value); + } + + if (m_pOEMDev->iWMHeight < MICRON_TO_HUNDREDTH_OFINCH(wmParamDefIntegers[ePageWatermarkSizeHeight].min_length) || + m_pOEMDev->iWMHeight > MICRON_TO_HUNDREDTH_OFINCH(wmParamDefIntegers[ePageWatermarkSizeHeight].max_length)) + { + m_pOEMDev->iWMHeight = MICRON_TO_HUNDREDTH_OFINCH(wmParamDefIntegers[ePageWatermarkSizeHeight].default_value); + } + + // + // Valid text is a NULL terminated string of length < MAX_WATERMARK_TEXT + // + size_t cch = 0; + if (FAILED(StringCchLength(m_pOEMDev->strWMText, MAX_WATERMARK_TEXT, &cch))) + { + try + { + CStringXD cstrWMText(wmParamDefStrings[ePageWatermarkTextText].default_value); + hr = StringCchCopyN(m_pOEMDev->strWMText, MAX_WATERMARK_TEXT, cstrWMText.GetBuffer(), cstrWMText.GetLength()); + } + catch (CXDException& e) + { + hr = e; + } + } + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CUIProperties::GetOptItem + +Routine Description: + + This method is used to get properties in the GPD. + +Arguments: + + pOemCUIPParam - Pointer to the POEMCUIPPARAM function. + pFeatureName - Pointer to a GPD property name. + ppOptItem - Address of a pointer that will be filled out with an OPTITEM structure. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CUIProperties::GetOptItem( + _In_ POEMCUIPPARAM pOemCUIPParam, + _In_ PCSTR pFeatureName, + _Outptr_result_maybenull_ POPTITEM* ppOptItem + ) +{ + HRESULT hr = S_OK; + POPTITEM pOIResult = NULL; + + if (SUCCEEDED(hr = CHECK_POINTER(pOemCUIPParam, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pOemCUIPParam->pDrvOptItems, E_PENDING)) && + SUCCEEDED(hr = CHECK_POINTER(pFeatureName, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(ppOptItem, E_POINTER))) + { + *ppOptItem = NULL; + + for (DWORD indexOptItem = 0; indexOptItem < pOemCUIPParam->cDrvOptItems; indexOptItem++) + { + pOIResult = &(pOemCUIPParam->pDrvOptItems[indexOptItem]); + + if (pOIResult->UserData != NULL) + { + PUSERDATA pUserData = reinterpret_cast(pOIResult->UserData); + if (SUCCEEDED(hr = CHECK_POINTER(pUserData->pKeyWordName, E_FAIL))) + { + if (strncmp(pUserData->pKeyWordName, pFeatureName, strlen(pFeatureName)) == 0) + { + hr = S_OK; + *ppOptItem = pOIResult; + break; + } + else + { + hr = E_ELEMENT_NOT_FOUND; + } + } + } + else + { + hr = E_FAIL; + } + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CUIProperties::HideOptItems + +Routine Description: + + Ensures that all GPD settings managed by the UI Plug-in are removed from the main Unidrv driver UI. + +Arguments: + + pOemCUIPParam - Pointer to the POEMCUIPPARAM function. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CUIProperties::HideOptItems( + _In_ POEMCUIPPARAM pOemCUIPParam + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pOemCUIPParam, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pOemCUIPParam->pDrvOptItems, E_PENDING))) + { + POPTITEM pOptItem = NULL; + + try + { + UIOptItemList::const_iterator iterOptItem = m_OptItemList.begin(); + + for (; iterOptItem != m_OptItemList.end() && SUCCEEDED(hr); iterOptItem++) + { + if (SUCCEEDED(hr = GetOptItem(pOemCUIPParam, *iterOptItem, &pOptItem)) && + SUCCEEDED(hr = CHECK_POINTER(pOptItem, E_FAIL))) + { + pOptItem->Flags |= OPTIF_HIDE; + } + } + } + catch (exception& DBG_ONLY(e)) + { + ERR(e.what()); + hr = E_FAIL; + } + } + + ERR_ON_HR(hr); + return hr; +} + + diff --git a/print/XPSDrvSmpl/src/ui/uiproperties.h b/print/XPSDrvSmpl/src/ui/uiproperties.h new file mode 100644 index 00000000..7fe0ab85 --- /dev/null +++ b/print/XPSDrvSmpl/src/ui/uiproperties.h @@ -0,0 +1,111 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + uiproperties.h + +Abstract: + + This class encapsulates all handling of GPD and OEM private devmode settings + used in the XPSDrv feature sample UI. + +--*/ + +#pragma once + +#include "devmode.h" + +extern PCSTR g_pszPSScaleWidth; +extern PCSTR g_pszPSScaleHeight; +extern PCSTR g_pszOffsetWidth; +extern PCSTR g_pszOffsetHeight; +extern PCSTR g_pszWMTransparency; +extern PCSTR g_pszWMAngle; +extern PCSTR g_pszWMOffsetWidth; +extern PCSTR g_pszWMOffsetHeight; +extern PCSTR g_pszWMSizeWidth; +extern PCSTR g_pszWMSizeHeight; +extern PCSTR g_pszWMFontSize; +extern PCSTR g_pszWMFontColor; +extern PCSTR g_pszWMText; + +// +// Forward declaration +// +class CUIProperties; + +typedef VOID UIProperty; + +typedef pair UIPropertyPair; +typedef map UIPropertyMap; + +typedef vector UIOptItemList; + +class CUIProperties +{ +public: + CUIProperties(); + + CUIProperties(POEMDEV pOEMDev); + + virtual ~CUIProperties(); + + HRESULT + GetItem( + _In_ PCSTR pFeatureName, + _Out_writes_bytes_(cbSize) UIProperty* pUIProperty, + _In_ SIZE_T cbSize + ); + + HRESULT + SetItem( + _In_ PCSTR pFeatureName, + _In_reads_bytes_(cbSize) CONST UIProperty* pUIProperty, + _In_ SIZE_T cbSize + ); + + HRESULT + SetDefaults(); + + HRESULT + Validate(); + + HRESULT + Convert( + _In_ CUIProperties* pUIProperties + ); + + HRESULT + GetOptItem( + _In_ POEMCUIPPARAM pOemCUIPParam, + _In_ PCSTR pFeatureName, + _Outptr_result_maybenull_ POPTITEM* ppOptItem + ); + + HRESULT + HideOptItems( + _In_ POEMCUIPPARAM pOemCUIPParam + ); + +private: + HRESULT SetHeader(); + + HRESULT InitialiseMap(); + +private: + POEMDEV m_pOEMDev; + + UIPropertyMap m_PropertyMap; + + UIOptItemList m_OptItemList; +}; + diff --git a/print/XPSDrvSmpl/src/ui/wmctrls.cpp b/print/XPSDrvSmpl/src/ui/wmctrls.cpp new file mode 100644 index 00000000..66647cc3 --- /dev/null +++ b/print/XPSDrvSmpl/src/ui/wmctrls.cpp @@ -0,0 +1,1381 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + wmctrls.cpp + +Abstract: + + Implementation of the watermark specific UI controls. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdstring.h" +#include "resource.h" +#include "wmctrls.h" +#include "privatedefs.h" + +PCSTR CUICtrlWMTypeCombo::m_pszWMType = "PageWatermarkType"; + +PCSTR CUICtrlWMLayeringCombo::m_pszWMLayering = "PageWatermarkLayering"; +PCSTR CUICtrlWMTransparencyEdit::m_pszWMTransparency = "PageWatermarkTransparency"; +PCSTR CUICtrlWMTransparencySpin::m_pszWMTransparency = "PageWatermarkTransparency"; +PCSTR CUICtrlWMAngleEdit::m_pszWMAngle = "PageWatermarkTextAngle"; +PCSTR CUICtrlWMAngleSpin::m_pszWMAngle = "PageWatermarkTextAngle"; +PCSTR CUICtrlWMOffsetXEdit::m_pszWMOffsetX = "PageWatermarkOriginWidth"; +PCSTR CUICtrlWMOffsetXSpin::m_pszWMOffsetX = "PageWatermarkOriginWidth"; +PCSTR CUICtrlWMOffsetYEdit::m_pszWMOffsetY = "PageWatermarkOriginHeight"; +PCSTR CUICtrlWMOffsetYSpin::m_pszWMOffsetY = "PageWatermarkOriginHeight"; + +PCSTR CUICtrlWMWidthEdit::m_pszWMWidth = "PageWatermarkSizeWidth"; +PCSTR CUICtrlWMWidthSpin::m_pszWMWidth = "PageWatermarkSizeWidth"; +PCSTR CUICtrlWMHeightEdit::m_pszWMHeight = "PageWatermarkSizeHeight"; +PCSTR CUICtrlWMHeightSpin::m_pszWMHeight = "PageWatermarkSizeHeight"; + +PCSTR CUICtrlWMTextEdit::m_pszWMText = "PageWatermarkTextText"; + +PCSTR CUICtrlWMFontSizeEdit::m_pszWMFontSize = "PageWatermarkTextFontSize"; +PCSTR CUICtrlWMFontSizeSpin::m_pszWMFontSize = "PageWatermarkTextFontSize"; + +PCSTR CUICtrlColorBtn::m_pszWMFontColor = "PageWatermarkTextColor"; + +#define WMTYPE_NONE_SEL 0 +#define WMTYPE_TEXT_SEL 1 +#define WMTYPE_RAST_SEL 2 +#define WMTYPE_VECT_SEL 3 + +// +// Watermark type combo box control +// +/*++ + +Routine Name: + + CUICtrlWMTypeCombo::CUICtrlWMTypeCombo + +Routine Description: + + CUICtrlWMTypeCombo class constructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlWMTypeCombo::CUICtrlWMTypeCombo() : + CUICtrlDefaultCombo(m_pszWMType, IDC_COMBO_WMTYPE) +{ +} + +/*++ + +Routine Name: + + CUICtrlWMTypeCombo::~CUICtrlWMTypeCombo + +Routine Description: + + CUICtrlWMTypeCombo class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlWMTypeCombo::~CUICtrlWMTypeCombo() +{ +} + +/*++ + +Routine Name: + + CUICtrlWMTypeCombo::OnInit + +Routine Description: + + This is responsible for initialising the control and is called when + the WM_INITDIALOG message is recieved. This method populates the combo + box with the appropriate option strings. + +Arguments: + + hDlg - handle to the parent window + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CUICtrlWMTypeCombo::OnInit( + _In_ CONST HWND hDlg + ) +{ + HRESULT hr = S_OK; + + // + // Populate the combo box + // + if (SUCCEEDED(hr = AddString(hDlg, g_hInstance, IDS_GPD_NONE)) && + SUCCEEDED(hr = AddString(hDlg, g_hInstance, IDS_GPD_TEXT)) && + SUCCEEDED(hr = AddString(hDlg, g_hInstance, IDS_GPD_RASTERIMAGE))) + { + hr = AddString(hDlg, g_hInstance, IDS_GPD_VECTORIMAGE); + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CUICtrlWMTypeCombo::EnableDependentCtrls + +Routine Description: + + This method is used to enable or disable other controls in the UI based on the + current combo box selection. + +Arguments: + + hDlg - handle to the parent window + lSel - current combo box selection + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CUICtrlWMTypeCombo::EnableDependentCtrls( + _In_ CONST HWND hDlg, + _In_ CONST LONG lSel + ) +{ + HRESULT hr = S_OK; + HWND hWnd = NULL; + + BOOL bWatermarkEnabled = (lSel != WMTYPE_NONE_SEL); + BOOL bRasterType = (lSel == WMTYPE_RAST_SEL); + BOOL bVectorType = (lSel == WMTYPE_VECT_SEL); + BOOL bTextType = (lSel == WMTYPE_TEXT_SEL); + + // + // Common Watermark Properties + // + // Here we are enabling/disabling common watermark controls based off the current + // watermark option. + // + // If a watermark is selected we enable the layering, transparentcy offset and angle controls + // + if (SUCCEEDED(hr) && + SUCCEEDED(hr = CHECK_HANDLE(hWnd = GetDlgItem(hDlg, IDC_COMBO_WMLAYERING), E_HANDLE))) + { + EnableWindow(hWnd, bWatermarkEnabled); + } + + if (SUCCEEDED(hr) && + SUCCEEDED(hr = CHECK_HANDLE(hWnd = GetDlgItem(hDlg, IDC_TXT_WMLAYERING), E_HANDLE))) + { + EnableWindow(hWnd, bWatermarkEnabled); + } + + if (SUCCEEDED(hr) && + SUCCEEDED(hr = CHECK_HANDLE(hWnd = GetDlgItem(hDlg, IDC_EDIT_WMTRANSPARENCY), E_HANDLE))) + { + EnableWindow(hWnd, bWatermarkEnabled); + } + + if (SUCCEEDED(hr) && + SUCCEEDED(hr = CHECK_HANDLE(hWnd = GetDlgItem(hDlg, IDC_SPIN_WMTRANSPARENCY), E_HANDLE))) + { + EnableWindow(hWnd, bWatermarkEnabled); + } + + if (SUCCEEDED(hr) && + SUCCEEDED(hr = CHECK_HANDLE(hWnd = GetDlgItem(hDlg, IDC_TXT_WMTRANSPARENCY), E_HANDLE))) + { + EnableWindow(hWnd, bWatermarkEnabled); + } + + if (SUCCEEDED(hr) && + SUCCEEDED(hr = CHECK_HANDLE(hWnd = GetDlgItem(hDlg, IDC_EDIT_WMANGLE), E_HANDLE))) + { + EnableWindow(hWnd, bWatermarkEnabled); + } + + if (SUCCEEDED(hr) && + SUCCEEDED(hr = CHECK_HANDLE(hWnd = GetDlgItem(hDlg, IDC_SPIN_WMANGLE), E_HANDLE))) + { + EnableWindow(hWnd, bWatermarkEnabled); + } + + if (SUCCEEDED(hr) && + SUCCEEDED(hr = CHECK_HANDLE(hWnd = GetDlgItem(hDlg, IDC_TXT_WMANGLE), E_HANDLE))) + { + EnableWindow(hWnd, bWatermarkEnabled); + } + + if (SUCCEEDED(hr) && + SUCCEEDED(hr = CHECK_HANDLE(hWnd = GetDlgItem(hDlg, IDC_EDIT_WMOFFX), E_HANDLE))) + { + EnableWindow(hWnd, bWatermarkEnabled); + } + + if (SUCCEEDED(hr) && + SUCCEEDED(hr = CHECK_HANDLE(hWnd = GetDlgItem(hDlg, IDC_SPIN_WMOFFX), E_HANDLE))) + { + EnableWindow(hWnd, bWatermarkEnabled); + } + + if (SUCCEEDED(hr) && + SUCCEEDED(hr = CHECK_HANDLE(hWnd = GetDlgItem(hDlg, IDC_TXT_WMOFFX), E_HANDLE))) + { + EnableWindow(hWnd, bWatermarkEnabled); + } + + if (SUCCEEDED(hr) && + SUCCEEDED(hr = CHECK_HANDLE(hWnd = GetDlgItem(hDlg, IDC_EDIT_WMOFFY), E_HANDLE))) + { + EnableWindow(hWnd, bWatermarkEnabled); + } + + if (SUCCEEDED(hr) && + SUCCEEDED(hr = CHECK_HANDLE(hWnd = GetDlgItem(hDlg, IDC_SPIN_WMOFFY), E_HANDLE))) + { + EnableWindow(hWnd, bWatermarkEnabled); + } + + if (SUCCEEDED(hr) && + SUCCEEDED(hr = CHECK_HANDLE(hWnd = GetDlgItem(hDlg, IDC_TXT_WMOFFY), E_HANDLE))) + { + EnableWindow(hWnd, bWatermarkEnabled); + } + + // + // Vector / Bitmap Watermark Properties + // + // Here we are enabling/disabling vector/bitmap watermark controls based off the current + // watermark option. + // + // If a vector or bitmap watermark is selected we enable the width and height controls + // + if (SUCCEEDED(hr) && + SUCCEEDED(hr = CHECK_HANDLE(hWnd = GetDlgItem(hDlg, IDC_EDIT_WMWIDTH), E_HANDLE))) + { + EnableWindow(hWnd, (bRasterType || bVectorType)); + ShowWindow(hWnd, (bRasterType || bVectorType) ? SW_SHOW : SW_HIDE); + } + + if (SUCCEEDED(hr) && + SUCCEEDED(hr = CHECK_HANDLE(hWnd = GetDlgItem(hDlg, IDC_SPIN_WMWIDTH), E_HANDLE))) + { + EnableWindow(hWnd, (bRasterType || bVectorType)); + ShowWindow(hWnd, (bRasterType || bVectorType) ? SW_SHOW : SW_HIDE); + } + + if (SUCCEEDED(hr) && + SUCCEEDED(hr = CHECK_HANDLE(hWnd = GetDlgItem(hDlg, IDC_TXT_WMWIDTH), E_HANDLE))) + { + EnableWindow(hWnd, (bRasterType || bVectorType)); + ShowWindow(hWnd, (bRasterType || bVectorType) ? SW_SHOW : SW_HIDE); + } + + if (SUCCEEDED(hr) && + SUCCEEDED(hr = CHECK_HANDLE(hWnd = GetDlgItem(hDlg, IDC_EDIT_WMHEIGHT), E_HANDLE))) + { + EnableWindow(hWnd, (bRasterType || bVectorType)); + ShowWindow(hWnd, (bRasterType || bVectorType) ? SW_SHOW : SW_HIDE); + } + + if (SUCCEEDED(hr) && + SUCCEEDED(hr = CHECK_HANDLE(hWnd = GetDlgItem(hDlg, IDC_SPIN_WMHEIGHT), E_HANDLE))) + { + EnableWindow(hWnd, (bRasterType || bVectorType)); + ShowWindow(hWnd, (bRasterType || bVectorType) ? SW_SHOW : SW_HIDE); + } + + if (SUCCEEDED(hr) && + SUCCEEDED(hr = CHECK_HANDLE(hWnd = GetDlgItem(hDlg, IDC_TXT_WMHEIGHT), E_HANDLE))) + { + EnableWindow(hWnd, (bRasterType || bVectorType)); + ShowWindow(hWnd, (bRasterType || bVectorType) ? SW_SHOW : SW_HIDE); + } + + // + // Text Watermark Properties + // + // Here we are enabling/disabling text watermark controls based off the current + // watermark option. + // + // If a text watermark is selected we enable the text and font controls + // + if (SUCCEEDED(hr = CHECK_HANDLE(hWnd = GetDlgItem(hDlg, IDC_EDIT_WMTEXT), E_HANDLE))) + { + EnableWindow(hWnd, bTextType); + ShowWindow(hWnd, bTextType ? SW_SHOW : SW_HIDE); + } + + if (SUCCEEDED(hr) && + (SUCCEEDED(hr = CHECK_HANDLE(hWnd = GetDlgItem(hDlg, IDC_TXT_WMTEXT), E_HANDLE)))) + { + EnableWindow(hWnd, bTextType); + ShowWindow(hWnd, bTextType ? SW_SHOW : SW_HIDE); + } + + if (SUCCEEDED(hr) && + (SUCCEEDED(hr = CHECK_HANDLE(hWnd = GetDlgItem(hDlg, IDC_EDIT_WMSIZE), E_HANDLE)))) + { + EnableWindow(hWnd, bTextType); + ShowWindow(hWnd, bTextType ? SW_SHOW : SW_HIDE); + } + + if (SUCCEEDED(hr) && + (SUCCEEDED(hr = CHECK_HANDLE(hWnd = GetDlgItem(hDlg, IDC_SPIN_WMSIZE), E_HANDLE)))) + { + EnableWindow(hWnd, bTextType); + ShowWindow(hWnd, bTextType ? SW_SHOW : SW_HIDE); + } + + if (SUCCEEDED(hr) && + (SUCCEEDED(hr = CHECK_HANDLE(hWnd = GetDlgItem(hDlg, IDC_TXT_WMSIZE), E_HANDLE)))) + { + EnableWindow(hWnd, bTextType); + ShowWindow(hWnd, bTextType ? SW_SHOW : SW_HIDE); + } + + if (SUCCEEDED(hr) && + (SUCCEEDED(hr = CHECK_HANDLE(hWnd = GetDlgItem(hDlg, IDC_BUTTON_WMCOLOR), E_HANDLE)))) + { + EnableWindow(hWnd, bTextType); + ShowWindow(hWnd, bTextType ? SW_SHOW : SW_HIDE); + } + + if (FAILED(hr)) + { + hr = HRESULT_FROM_WIN32(GetLastError()); + } + + ERR_ON_HR(hr); + return hr; +} + +// +// Watermark Layering combo box control +// +/*++ + +Routine Name: + + CUICtrlWMLayeringCombo::CUICtrlWMLayeringCombo + +Routine Description: + + CUICtrlWMLayeringCombo class constructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlWMLayeringCombo::CUICtrlWMLayeringCombo() : + CUICtrlDefaultCombo(m_pszWMLayering, IDC_COMBO_WMLAYERING) +{ +} + +/*++ + +Routine Name: + + CUICtrlWMLayeringCombo::~CUICtrlWMLayeringCombo + +Routine Description: + + CUICtrlWMLayeringCombo class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlWMLayeringCombo::~CUICtrlWMLayeringCombo() +{ +} + +/*++ + +Routine Name: + + CUICtrlWMLayeringCombo::OnInit + +Routine Description: + + This is responsible for initialising the control and is called when + the WM_INITDIALOG message is recieved. This method populates the combo + box with the appropriate option strings. + +Arguments: + + hDlg - handle to the parent window + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CUICtrlWMLayeringCombo::OnInit( + _In_ CONST HWND hDlg + ) +{ + HRESULT hr = S_OK; + + // + // Populate the combo box + // + if (SUCCEEDED (hr = AddString(hDlg, g_hInstance, IDS_GPD_OVERLAYED))) + { + hr = AddString(hDlg, g_hInstance, IDS_GPD_UNDERLAYED); + } + + ERR_ON_HR(hr); + return hr; +} + +// +// Watermark text combo box control +// +/*++ + +Routine Name: + + CUICtrlWMTextEdit::CUICtrlWMTextEdit + +Routine Description: + + CUICtrlWMTextEdit class constructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlWMTextEdit::CUICtrlWMTextEdit() : + CUICtrlDefaultEditText(m_pszWMText, + IDC_EDIT_WMTEXT, + MAX_WATERMARK_TEXT) +{ +} + +/*++ + +Routine Name: + + CUICtrlWMTextEdit::~CUICtrlWMTextEdit + +Routine Description: + + CUICtrlWMTextEdit class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlWMTextEdit::~CUICtrlWMTextEdit() +{ +} + +// +// Page Watermark Transparency +// + +/*++ + +Routine Name: + + CUICtrlWMTransparencyEdit::CUICtrlWMTransparencyEdit + +Routine Description: + + CUICtrlWMTransparencyEdit class constructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlWMTransparencyEdit::CUICtrlWMTransparencyEdit() : + CUICtrlDefaultEditNum(m_pszWMTransparency, + IDC_EDIT_WMTRANSPARENCY, + wmParamDefIntegers[ePageWatermarkTransparency].min_length, + wmParamDefIntegers[ePageWatermarkTransparency].max_length, + IDC_SPIN_WMTRANSPARENCY) +{ +} + +/*++ + +Routine Name: + + CUICtrlWMTransparencyEdit::~CUICtrlWMTransparencyEdit + +Routine Description: + + CUICtrlWMTransparencyEdit class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlWMTransparencyEdit::~CUICtrlWMTransparencyEdit() +{ +} + +/*++ + +Routine Name: + + CUICtrlWMTransparencySpin::CUICtrlWMTransparencySpin + +Routine Description: + + CUICtrlWMTransparencySpin class constructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlWMTransparencySpin::CUICtrlWMTransparencySpin( + _In_ CUICtrlDefaultEditNum* pEdit + ) : + CUICtrlDefaultSpin(pEdit) +{ +} + +/*++ + +Routine Name: + + CUICtrlWMTransparencySpin::~CUICtrlWMTransparencySpin + +Routine Description: + + CUICtrlWMTransparencySpin class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlWMTransparencySpin::~CUICtrlWMTransparencySpin() +{ +} + +// +// Page Watermark Angle +// + +/*++ + +Routine Name: + + CUICtrlWMAngleEdit::CUICtrlWMAngleEdit + +Routine Description: + + CUICtrlWMAngleEdit class constructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlWMAngleEdit::CUICtrlWMAngleEdit() : + CUICtrlDefaultEditNum(m_pszWMAngle, + IDC_EDIT_WMANGLE, + wmParamDefIntegers[ePageWatermarkAngle].min_length, + wmParamDefIntegers[ePageWatermarkAngle].max_length, + IDC_SPIN_WMANGLE) +{ +} + +/*++ + +Routine Name: + + CUICtrlWMAngleEdit::~CUICtrlWMAngleEdit + +Routine Description: + + CUICtrlWMAngleEdit class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlWMAngleEdit::~CUICtrlWMAngleEdit() +{ +} + +/*++ + +Routine Name: + + CUICtrlWMAngleSpin::CUICtrlWMAngleSpin + +Routine Description: + + CUICtrlWMAngleSpin class constructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlWMAngleSpin::CUICtrlWMAngleSpin( + _In_ CUICtrlDefaultEditNum* pEdit + ) : + CUICtrlDefaultSpin(pEdit) +{ +} + +/*++ + +Routine Name: + + CUICtrlWMAngleSpin::~CUICtrlWMAngleSpin + +Routine Description: + + CUICtrlWMAngleSpin class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlWMAngleSpin::~CUICtrlWMAngleSpin() +{ +} + +// +// Page Watermark Offset X +// + +/*++ + +Routine Name: + + CUICtrlWMOffsetXEdit::CUICtrlWMOffsetXEdit + +Routine Description: + + CUICtrlWMOffsetXEdit class constructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlWMOffsetXEdit::CUICtrlWMOffsetXEdit() : + CUICtrlDefaultEditNum(m_pszWMOffsetX, + IDC_EDIT_WMOFFX, + MICRON_TO_HUNDREDTH_OFINCH(wmParamDefIntegers[ePageWatermarkOriginWidth].min_length), + MICRON_TO_HUNDREDTH_OFINCH(wmParamDefIntegers[ePageWatermarkOriginWidth].max_length), + IDC_SPIN_WMOFFX) +{ +} + +/*++ + +Routine Name: + + CUICtrlWMOffsetXEdit::~CUICtrlWMOffsetXEdit + +Routine Description: + + CUICtrlWMOffsetXEdit class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlWMOffsetXEdit::~CUICtrlWMOffsetXEdit() +{ +} + +/*++ + +Routine Name: + + CUICtrlWMOffsetXSpin::CUICtrlWMOffsetXSpin + +Routine Description: + + CUICtrlWMOffsetXSpin class constructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlWMOffsetXSpin::CUICtrlWMOffsetXSpin( + _In_ CUICtrlDefaultEditNum* pEdit + ) : + CUICtrlDefaultSpin(pEdit) +{ +} + +/*++ + +Routine Name: + + CUICtrlWMOffsetXSpin::~CUICtrlWMOffsetXSpin + +Routine Description: + + CUICtrlWMOffsetXSpin class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlWMOffsetXSpin::~CUICtrlWMOffsetXSpin() +{ +} + +// +// Page Watermark Offset Y +// + +/*++ + +Routine Name: + + CUICtrlWMOffsetYEdit::CUICtrlWMOffsetYEdit + +Routine Description: + + CUICtrlWMOffsetYEdit class constructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlWMOffsetYEdit::CUICtrlWMOffsetYEdit() : + CUICtrlDefaultEditNum(m_pszWMOffsetY, + IDC_EDIT_WMOFFY, + MICRON_TO_HUNDREDTH_OFINCH(wmParamDefIntegers[ePageWatermarkOriginHeight].min_length), + MICRON_TO_HUNDREDTH_OFINCH(wmParamDefIntegers[ePageWatermarkOriginHeight].max_length), + IDC_SPIN_WMOFFY) +{ +} + +/*++ + +Routine Name: + + CUICtrlWMOffsetYEdit::~CUICtrlWMOffsetYEdit + +Routine Description: + + CUICtrlWMOffsetYEdit class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlWMOffsetYEdit::~CUICtrlWMOffsetYEdit() +{ +} + +/*++ + +Routine Name: + + CUICtrlWMOffsetYSpin::CUICtrlWMOffsetYSpin + +Routine Description: + + CUICtrlWMOffsetYSpin class constructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlWMOffsetYSpin::CUICtrlWMOffsetYSpin( + _In_ CUICtrlDefaultEditNum* pEdit + ) : + CUICtrlDefaultSpin(pEdit) +{ +} + +/*++ + +Routine Name: + + CUICtrlWMOffsetYSpin::~CUICtrlWMOffsetYSpin + +Routine Description: + + CUICtrlWMOffsetYSpin class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlWMOffsetYSpin::~CUICtrlWMOffsetYSpin() +{ +} + +// +// Page Watermark Width +// + +/*++ + +Routine Name: + + CUICtrlWMWidthEdit::CUICtrlWMWidthEdit + +Routine Description: + + CUICtrlWMWidthEdit class constructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlWMWidthEdit::CUICtrlWMWidthEdit() : + CUICtrlDefaultEditNum(m_pszWMWidth, + IDC_EDIT_WMWIDTH, + MICRON_TO_HUNDREDTH_OFINCH(wmParamDefIntegers[ePageWatermarkSizeWidth].min_length), + MICRON_TO_HUNDREDTH_OFINCH(wmParamDefIntegers[ePageWatermarkSizeWidth].max_length), + IDC_SPIN_WMWIDTH) +{ +} + +/*++ + +Routine Name: + + CUICtrlWMWidthEdit::~CUICtrlWMWidthEdit + +Routine Description: + + CUICtrlWMWidthEdit class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlWMWidthEdit::~CUICtrlWMWidthEdit() +{ +} + +/*++ + +Routine Name: + + CUICtrlWMWidthSpin::CUICtrlWMWidthSpin + +Routine Description: + + CUICtrlWMWidthSpin class constructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlWMWidthSpin::CUICtrlWMWidthSpin( + _In_ CUICtrlDefaultEditNum* pEdit + ) : + CUICtrlDefaultSpin(pEdit) +{ +} + +/*++ + +Routine Name: + + CUICtrlWMWidthSpin::~CUICtrlWMWidthSpin + +Routine Description: + + CUICtrlWMWidthSpin class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlWMWidthSpin::~CUICtrlWMWidthSpin() +{ +} + +// +// Page Watermark Height +// + +/*++ + +Routine Name: + + CUICtrlWMHeightEdit::CUICtrlWMHeightEdit + +Routine Description: + + CUICtrlWMHeightEdit class constructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlWMHeightEdit::CUICtrlWMHeightEdit() : + CUICtrlDefaultEditNum(m_pszWMHeight, + IDC_EDIT_WMHEIGHT, + MICRON_TO_HUNDREDTH_OFINCH(wmParamDefIntegers[ePageWatermarkSizeHeight].min_length), + MICRON_TO_HUNDREDTH_OFINCH(wmParamDefIntegers[ePageWatermarkSizeHeight].max_length), + IDC_SPIN_WMHEIGHT) +{ +} + +/*++ + +Routine Name: + + CUICtrlWMHeightEdit::~CUICtrlWMHeightEdit + +Routine Description: + + CUICtrlWMHeightEdit class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlWMHeightEdit::~CUICtrlWMHeightEdit() +{ +} + +/*++ + +Routine Name: + + CUICtrlWMHeightSpin::CUICtrlWMHeightSpin + +Routine Description: + + CUICtrlWMHeightSpin class constructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlWMHeightSpin::CUICtrlWMHeightSpin( + _In_ CUICtrlDefaultEditNum* pEdit + ) : + CUICtrlDefaultSpin(pEdit) +{ +} + +/*++ + +Routine Name: + + CUICtrlWMHeightSpin::~CUICtrlWMHeightSpin + +Routine Description: + + CUICtrlWMHeightSpin class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlWMHeightSpin::~CUICtrlWMHeightSpin() +{ +} + +// +// Page Watermark Font Size +// + +/*++ + +Routine Name: + + CUICtrlWMFontSizeEdit::CUICtrlWMFontSizeEdit + +Routine Description: + + CUICtrlWMFontSizeEdit class constructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlWMFontSizeEdit::CUICtrlWMFontSizeEdit() : + CUICtrlDefaultEditNum(m_pszWMFontSize, + IDC_EDIT_WMSIZE, + wmParamDefIntegers[ePageWatermarkTextFontSize].min_length, + wmParamDefIntegers[ePageWatermarkTextFontSize].max_length, + IDC_SPIN_WMSIZE) +{ +} + +/*++ + +Routine Name: + + CUICtrlWMFontSizeEdit::~CUICtrlWMFontSizeEdit + +Routine Description: + + CUICtrlWMFontSizeEdit class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlWMFontSizeEdit::~CUICtrlWMFontSizeEdit() +{ +} + +/*++ + +Routine Name: + + CUICtrlWMHeightSpin::CUICtrlWMHeightSpin + +Routine Description: + + CUICtrlWMHeightSpin class constructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlWMFontSizeSpin::CUICtrlWMFontSizeSpin( + _In_ CUICtrlDefaultEditNum* pEdit + ) : + CUICtrlDefaultSpin(pEdit) +{ +} + +/*++ + +Routine Name: + + CUICtrlWMFontSizeSpin::~CUICtrlWMFontSizeSpin + +Routine Description: + + CUICtrlWMFontSizeSpin class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlWMFontSizeSpin::~CUICtrlWMFontSizeSpin() +{ +} + +/*++ + +Routine Name: + + CUICtrlWMFontSizeSpin::~CUICtrlWMFontSizeSpin + +Routine Description: + + CUICtrlWMFontSizeSpin class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlColorBtn::CUICtrlColorBtn() : + CUICtrlDefaultBtn(m_pszWMFontColor, IDC_BUTTON_WMCOLOR) +{ +} + +/*++ + +Routine Name: + + CUICtrlColorBtn::~CUICtrlColorBtn + +Routine Description: + + CUICtrlColorBtn class constructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CUICtrlColorBtn::~CUICtrlColorBtn() +{ +} + +/*++ + +Routine Name: + + CUICtrlColorBtn::OnBnClicked + +Routine Description: + + Color button clicked handler + +Arguments: + + hDlg - handle to the parent window + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CUICtrlColorBtn::OnBnClicked( + _In_ CONST HWND hDlg + ) +{ + HRESULT hr = S_OK; + + ASSERTMSG(m_pUIProperties != NULL, "NULL pointer to UI properties interface.\n"); + + DWORD colorText = 0; + if (SUCCEEDED(hr = CHECK_HANDLE(hDlg, E_HANDLE)) && + SUCCEEDED(hr = CHECK_POINTER(m_pUIProperties, E_PENDING)) && + SUCCEEDED(hr = m_pUIProperties->GetItem(m_szPropertyString, reinterpret_cast(&colorText), sizeof(colorText)))) + { + PBYTE pChannels = reinterpret_cast(&colorText); + + COLORREF colorsCust[16] = {0}; + COLORREF rgbIn = RGB(pChannels[2], pChannels[1], pChannels[0]); + + colorsCust[0] = rgbIn; + + CHOOSECOLOR chooseColor = { + sizeof(CHOOSECOLOR), + hDlg, + NULL, + colorText, + colorsCust, + CC_RGBINIT | CC_SOLIDCOLOR, + NULL, + NULL, + NULL + }; + + if (ChooseColor(&chooseColor) && + chooseColor.rgbResult != rgbIn) + { + pChannels[2] = GetRValue(chooseColor.rgbResult); + pChannels[1] = GetGValue(chooseColor.rgbResult); + pChannels[0] = GetBValue(chooseColor.rgbResult); + + if (SUCCEEDED(hr = m_pUIProperties->SetItem(m_szPropertyString, reinterpret_cast(&colorText), sizeof(colorText)))) + { + PropSheet_Changed(GetParent(hDlg), hDlg); + } + } + } + + ERR_ON_HR(hr); + return hr; +} + + diff --git a/print/XPSDrvSmpl/src/ui/wmctrls.h b/print/XPSDrvSmpl/src/ui/wmctrls.h new file mode 100644 index 00000000..ed5e7d98 --- /dev/null +++ b/print/XPSDrvSmpl/src/ui/wmctrls.h @@ -0,0 +1,259 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + wmctrls.h + +Abstract: + + Definition of the watermark specific UI controls. + +--*/ + +#pragma once + +#include "uictrl.h" + +class CUICtrlWMTypeCombo : public CUICtrlDefaultCombo +{ +public: + CUICtrlWMTypeCombo(); + + virtual ~CUICtrlWMTypeCombo(); + + HRESULT + OnInit( + _In_ CONST HWND hDlg + ); + +private: + HRESULT + EnableDependentCtrls( + _In_ CONST HWND hDlg, + _In_ CONST LONG lSel + ); + +private: + static PCSTR m_pszWMType; +}; + +class CUICtrlWMLayeringCombo : public CUICtrlDefaultCombo +{ +public: + CUICtrlWMLayeringCombo(); + + virtual ~CUICtrlWMLayeringCombo(); + + HRESULT + OnInit( + _In_ CONST HWND hDlg + ); + +private: + static PCSTR m_pszWMLayering; +}; + +class CUICtrlWMTextEdit : public CUICtrlDefaultEditText +{ +public: + CUICtrlWMTextEdit(); + + virtual ~CUICtrlWMTextEdit(); + +private: + static PCSTR m_pszWMText; +}; + +class CUICtrlWMTransparencyEdit : public CUICtrlDefaultEditNum +{ +public: + CUICtrlWMTransparencyEdit(); + + virtual ~CUICtrlWMTransparencyEdit(); + +private: + static PCSTR m_pszWMTransparency; +}; + +class CUICtrlWMTransparencySpin : public CUICtrlDefaultSpin +{ +public: + CUICtrlWMTransparencySpin( + _In_ CUICtrlDefaultEditNum* pEdit + ); + + virtual ~CUICtrlWMTransparencySpin(); + +private: + static PCSTR m_pszWMTransparency; +}; + +class CUICtrlWMAngleEdit : public CUICtrlDefaultEditNum +{ +public: + CUICtrlWMAngleEdit(); + + virtual ~CUICtrlWMAngleEdit(); + +private: + static PCSTR m_pszWMAngle; +}; + +class CUICtrlWMAngleSpin : public CUICtrlDefaultSpin +{ +public: + CUICtrlWMAngleSpin( + _In_ CUICtrlDefaultEditNum* pEdit + ); + + virtual ~CUICtrlWMAngleSpin(); + +private: + static PCSTR m_pszWMAngle; +}; + +class CUICtrlWMOffsetXEdit : public CUICtrlDefaultEditNum +{ +public: + CUICtrlWMOffsetXEdit(); + + virtual ~CUICtrlWMOffsetXEdit(); + +private: + static PCSTR m_pszWMOffsetX; +}; + +class CUICtrlWMOffsetXSpin : public CUICtrlDefaultSpin +{ +public: + CUICtrlWMOffsetXSpin( + _In_ CUICtrlDefaultEditNum* pEdit + ); + + virtual ~CUICtrlWMOffsetXSpin(); + +private: + static PCSTR m_pszWMOffsetX; +}; + +class CUICtrlWMOffsetYEdit : public CUICtrlDefaultEditNum +{ +public: + CUICtrlWMOffsetYEdit(); + + virtual ~CUICtrlWMOffsetYEdit(); + +private: + static PCSTR m_pszWMOffsetY; +}; + +class CUICtrlWMOffsetYSpin : public CUICtrlDefaultSpin +{ +public: + CUICtrlWMOffsetYSpin( + _In_ CUICtrlDefaultEditNum* pEdit + ); + + virtual ~CUICtrlWMOffsetYSpin(); + +private: + static PCSTR m_pszWMOffsetY; +}; + +class CUICtrlWMWidthEdit : public CUICtrlDefaultEditNum +{ +public: + CUICtrlWMWidthEdit(); + + virtual ~CUICtrlWMWidthEdit(); + +private: + static PCSTR m_pszWMWidth; +}; + +class CUICtrlWMWidthSpin : public CUICtrlDefaultSpin +{ +public: + CUICtrlWMWidthSpin( + _In_ CUICtrlDefaultEditNum* pEdit + ); + + virtual ~CUICtrlWMWidthSpin(); + +private: + static PCSTR m_pszWMWidth; +}; + +class CUICtrlWMHeightEdit : public CUICtrlDefaultEditNum +{ +public: + CUICtrlWMHeightEdit(); + + virtual ~CUICtrlWMHeightEdit(); + +private: + static PCSTR m_pszWMHeight; +}; + +class CUICtrlWMHeightSpin : public CUICtrlDefaultSpin +{ +public: + CUICtrlWMHeightSpin( + _In_ CUICtrlDefaultEditNum* pEdit + ); + + virtual ~CUICtrlWMHeightSpin(); + +private: + static PCSTR m_pszWMHeight; +}; + +class CUICtrlWMFontSizeEdit : public CUICtrlDefaultEditNum +{ +public: + CUICtrlWMFontSizeEdit(); + + virtual ~CUICtrlWMFontSizeEdit(); + +private: + static PCSTR m_pszWMFontSize; +}; + +class CUICtrlWMFontSizeSpin : public CUICtrlDefaultSpin +{ +public: + CUICtrlWMFontSizeSpin( + _In_ CUICtrlDefaultEditNum* pEdit + ); + + virtual ~CUICtrlWMFontSizeSpin(); + +private: + static PCSTR m_pszWMFontSize; +}; + +class CUICtrlColorBtn : public CUICtrlDefaultBtn +{ +public: + CUICtrlColorBtn(); + + ~CUICtrlColorBtn(); + + HRESULT + OnBnClicked( + _In_ CONST HWND hDlg + ); + +private: + static PCSTR m_pszWMFontColor; +}; + diff --git a/print/XPSDrvSmpl/src/ui/wmdmptcnv.cpp b/print/XPSDrvSmpl/src/ui/wmdmptcnv.cpp new file mode 100644 index 00000000..22cfde42 --- /dev/null +++ b/print/XPSDrvSmpl/src/ui/wmdmptcnv.cpp @@ -0,0 +1,591 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + wmdmptcnv.cpp + +Abstract: + + PageWatermark devmode <-> PrintTicket conversion class implementation. + The class defines a common data representation between the DevMode (GPD) and PrintTicket + representations and implements the conversion and validation methods required + by CFeatureDMPTConvert. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdstring.h" +#include "wmdmptcnv.h" +#include "wmpchndlr.h" + +using XDPrintSchema::PageWatermark::WatermarkData; +using XDPrintSchema::PageWatermark::EWatermarkOption; +using XDPrintSchema::PageWatermark::NoWatermark; +using XDPrintSchema::PageWatermark::TextWatermark; +using XDPrintSchema::PageWatermark::BitmapWatermark; +using XDPrintSchema::PageWatermark::VectorWatermark; +using XDPrintSchema::PageWatermark::WatermarkData; +using XDPrintSchema::PageWatermark::WatermarkData; +using XDPrintSchema::PageWatermark::WatermarkData; +using XDPrintSchema::PageWatermark::WatermarkData; + +using XDPrintSchema::PageWatermark::Layering::ELayeringOption; +using XDPrintSchema::PageWatermark::Layering::Overlay; +using XDPrintSchema::PageWatermark::Layering::Underlay; + +// +// Look-up data converting GPD PageWatermarkType feature options to +// watermark type enumeration +// +PCSTR g_pszWatermarkTypeFeature = "PageWatermarkType"; +static GPDStringToOption g_watermarkTypeOption[] = { + {"None", NoWatermark}, + {"Text", TextWatermark}, + {"Raster", BitmapWatermark}, + {"Vector", VectorWatermark}, +}; +UINT g_cWatermarkTypeOption = sizeof(g_watermarkTypeOption)/sizeof(GPDStringToOption); + +// +// Look-up data converting GPD PageWatermarkLayering feature options to +// watermark layering enumeration +// +PCSTR g_pszLayeringFeature = "PageWatermarkLayering"; +static GPDStringToOption g_watermarkLayeringOption[] = { + {"Overlay", Overlay}, + {"Underlay", Underlay}, +}; +UINT g_cLayeringOption = sizeof(g_watermarkLayeringOption)/sizeof(GPDStringToOption); + +/*++ + +Routine Name: + + CWatermarkDMPTConv::CWatermarkDMPTConv + +Routine Description: + + CWatermarkDMPTConv class constructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CWatermarkDMPTConv::CWatermarkDMPTConv() +{ +} + +/*++ + +Routine Name: + + CWatermarkDMPTConv::~CWatermarkDMPTConv + +Routine Description: + + CWatermarkDMPTConv class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CWatermarkDMPTConv::~CWatermarkDMPTConv() +{ +} + +/*++ + +Routine Name: + + CWatermarkDMPTConv::GetPTDataSettingsFromDM + +Routine Description: + + Populates the watermark data structure from the Devmode passed in. + +Arguments: + + pDevmode - pointer to input devmode buffer. + cbDevmode - size in bytes of full input devmode. + pPrivateDevmode - pointer to input private devmode buffer. + cbDrvPrivateSize - size in bytes of private devmode. + pDataSettings - Pointer to watermark data structure to be updated. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CWatermarkDMPTConv::GetPTDataSettingsFromDM( + _In_ PDEVMODE pDevmode, + _In_ ULONG cbDevmode, + _In_ PVOID pPrivateDevmode, + _In_ ULONG cbDrvPrivateSize, + _Out_ WatermarkData* pDataSettings + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pDevmode, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pPrivateDevmode, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pDataSettings, E_POINTER))) + { + if (cbDevmode < sizeof(DEVMODE) || + cbDrvPrivateSize == 0) + { + hr = E_INVALIDARG; + } + } + + // + // Retrieve the GPD and devmode controlled settings + // + CUIProperties uiProperties(static_cast(pPrivateDevmode)); + + DWORD dwTextColor = 0; + if (SUCCEEDED(hr) && + SUCCEEDED(hr = GetOptionFromGPDString(pDevmode, + cbDevmode, + g_pszWatermarkTypeFeature, + g_watermarkTypeOption, + g_cWatermarkTypeOption, + pDataSettings->type)) && + SUCCEEDED(hr = GetOptionFromGPDString(pDevmode, + cbDevmode, + g_pszLayeringFeature, + g_watermarkLayeringOption, + g_cLayeringOption, + pDataSettings->layering)) && + SUCCEEDED(hr = uiProperties.GetItem(g_pszWMOffsetWidth, &pDataSettings->widthOrigin, sizeof(pDataSettings->widthOrigin))) && + SUCCEEDED(hr = uiProperties.GetItem(g_pszWMOffsetHeight, &pDataSettings->heightOrigin, sizeof(pDataSettings->heightOrigin))) && + SUCCEEDED(hr = uiProperties.GetItem(g_pszWMSizeWidth, &pDataSettings->widthExtent, sizeof(pDataSettings->widthExtent))) && + SUCCEEDED(hr = uiProperties.GetItem(g_pszWMSizeHeight, &pDataSettings->heightExtent, sizeof(pDataSettings->heightExtent))) && + SUCCEEDED(hr = uiProperties.GetItem(g_pszWMTransparency, &pDataSettings->transparency, sizeof(pDataSettings->transparency))) && + SUCCEEDED(hr = uiProperties.GetItem(g_pszWMAngle, &pDataSettings->angle, sizeof(pDataSettings->angle))) && + SUCCEEDED(hr = uiProperties.GetItem(g_pszWMFontSize, &pDataSettings->txtData.fontSize, sizeof(pDataSettings->txtData.fontSize))) && + SUCCEEDED(hr = uiProperties.GetItem(g_pszWMFontColor, &dwTextColor, sizeof(dwTextColor)))) + { + // + // Convert the color to the txtData BSTR + // + try + { + CStringXDW cstrColor; + cstrColor.Format(L"#%08X", dwTextColor); + pDataSettings->txtData.bstrFontColor.Empty(); + pDataSettings->txtData.bstrFontColor.Attach(cstrColor.AllocSysString()); + } + catch (CXDException& e) + { + hr = e; + } + + TCHAR text[MAX_WATERMARK_TEXT + 1] = {0}; + + if (SUCCEEDED(hr) && + SUCCEEDED(hr = uiProperties.GetItem(g_pszWMText, text, MAX_WATERMARK_TEXT * sizeof(TCHAR)))) + { + pDataSettings->txtData.bstrText = text; + + // + // Convert measurements from 100ths of an inch to microns + // + pDataSettings->widthOrigin = HUNDREDTH_OFINCH_TO_MICRON(pDataSettings->widthOrigin); + pDataSettings->heightOrigin = HUNDREDTH_OFINCH_TO_MICRON(pDataSettings->heightOrigin); + pDataSettings->widthExtent = HUNDREDTH_OFINCH_TO_MICRON(pDataSettings->widthExtent); + pDataSettings->heightExtent = HUNDREDTH_OFINCH_TO_MICRON(pDataSettings->heightExtent); + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CWatermarkDMPTConv::MergePTDataSettingsWithPT + +Routine Description: + + This method updates the watermark data structure from a PrintTicket description. + +Arguments: + + pPrintTicket - Pointer to the input PrintTicket. + pDataSettings - Pointer to the watermark data structure + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CWatermarkDMPTConv::MergePTDataSettingsWithPT( + _In_ IXMLDOMDocument2* pPrintTicket, + _Inout_ WatermarkData* pDataSettings + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr) && + SUCCEEDED(hr = CHECK_POINTER(pPrintTicket, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pDataSettings, E_POINTER))) + { + try + { + // + // Get the watermark settings from the PrintTicket and set the options in + // the input Watermark data structure + // + WatermarkData wmData; + CWMPTHandler wmPTHndlr(pPrintTicket); + + if (SUCCEEDED(hr = wmPTHndlr.GetData(&wmData))) + { + // + // Only update settings relevant to the feature so that we do not unset + // other watermark settings in the devmode + // + pDataSettings->type = NoWatermark; + switch (wmData.type) + { + case TextWatermark: + { + pDataSettings->type = TextWatermark; + pDataSettings->widthOrigin = wmData.widthOrigin; + pDataSettings->heightOrigin = wmData.heightOrigin; + pDataSettings->transparency = wmData.transparency; + pDataSettings->angle = wmData.angle; + pDataSettings->layering = wmData.layering; + pDataSettings->txtData.bstrFontColor = wmData.txtData.bstrFontColor; + pDataSettings->txtData.fontSize = wmData.txtData.fontSize; + pDataSettings->txtData.bstrText = wmData.txtData.bstrText; + } + break; + + case BitmapWatermark: + { + pDataSettings->type = BitmapWatermark; + pDataSettings->widthOrigin = wmData.widthOrigin; + pDataSettings->heightOrigin = wmData.heightOrigin; + pDataSettings->widthExtent = wmData.widthExtent; + pDataSettings->heightExtent = wmData.heightExtent; + pDataSettings->transparency = wmData.transparency; + pDataSettings->angle = wmData.angle; + pDataSettings->layering = wmData.layering; + } + break; + + case VectorWatermark: + { + pDataSettings->type = VectorWatermark; + pDataSettings->widthOrigin = wmData.widthOrigin; + pDataSettings->heightOrigin = wmData.heightOrigin; + pDataSettings->widthExtent = wmData.widthExtent; + pDataSettings->heightExtent = wmData.heightExtent; + pDataSettings->transparency = wmData.transparency; + pDataSettings->angle = wmData.angle; + pDataSettings->layering = wmData.layering; + } + break; + + case NoWatermark: + break; + + default: + { + WARNING("Unrecognized watermark feature - setting to default\n"); + } + break; + } + } + else if (hr == E_ELEMENT_NOT_FOUND) + { + // + // Watermark setting not in the PT - this is not an error. Just + // leave the type as NoWatermark and reset the HRESULT to S_OK + // + hr = S_OK; + } + } + catch (CXDException& e) + { + hr = e; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CWatermarkDMPTConv::SetPTDataInDM + +Routine Description: + + This method updates the watermark options in the devmode from the UI Settings. + +Arguments: + + dataSettings - Reference to watermark data settings to be updated. + pDevmode - pointer to devmode to be updated. + cbDevmode - size in bytes of full devmode. + pPrivateDevmode - pointer to input private devmode buffer. + cbDrvPrivateSize - size in bytes of private devmode. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CWatermarkDMPTConv::SetPTDataInDM( + _In_ CONST WatermarkData& dataSettings, + _Inout_ PDEVMODE pDevmode, + _In_ ULONG cbDevmode, + _Inout_ PVOID pPrivateDevmode, + _In_ ULONG cbDrvPrivateSize + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pDevmode, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pPrivateDevmode, E_POINTER))) + { + if (cbDevmode < sizeof(DEVMODE) || + cbDrvPrivateSize == 0) + { + hr = E_INVALIDARG; + } + } + + // + // Convert from microns to 100ths of an inch before writing to the DevMode + // + if (SUCCEEDED(hr)) + { + INT widthOrigin = MICRON_TO_HUNDREDTH_OFINCH(dataSettings.widthOrigin); + INT heightOrigin = MICRON_TO_HUNDREDTH_OFINCH(dataSettings.heightOrigin); + INT widthExtent = MICRON_TO_HUNDREDTH_OFINCH(dataSettings.widthExtent); + INT heightExtent = MICRON_TO_HUNDREDTH_OFINCH(dataSettings.heightExtent); + + // + // Set the GPD and devmode controlled settings + // + CUIProperties uiProperties(static_cast(pPrivateDevmode)); + if (SUCCEEDED(hr = SetGPDStringFromOption(pDevmode, + cbDevmode, + g_pszWatermarkTypeFeature, + g_watermarkTypeOption, + g_cWatermarkTypeOption, + dataSettings.type)) && + SUCCEEDED(hr = SetGPDStringFromOption(pDevmode, + cbDevmode, + g_pszLayeringFeature, + g_watermarkLayeringOption, + g_cLayeringOption, + dataSettings.layering)) && + SUCCEEDED(hr = uiProperties.SetItem(g_pszWMOffsetWidth, &widthOrigin, sizeof(widthOrigin))) && + SUCCEEDED(hr = uiProperties.SetItem(g_pszWMOffsetHeight, &heightOrigin, sizeof(heightOrigin))) && + SUCCEEDED(hr = uiProperties.SetItem(g_pszWMSizeWidth, &widthExtent, sizeof(widthExtent))) && + SUCCEEDED(hr = uiProperties.SetItem(g_pszWMSizeHeight, &heightExtent, sizeof(heightExtent))) && + SUCCEEDED(hr = uiProperties.SetItem(g_pszWMTransparency, &dataSettings.transparency, sizeof(dataSettings.transparency))) && + SUCCEEDED(hr = uiProperties.SetItem(g_pszWMAngle, &dataSettings.angle, sizeof(dataSettings.angle))) && + SUCCEEDED(hr = uiProperties.SetItem(g_pszWMFontSize, &dataSettings.txtData.fontSize, sizeof(dataSettings.txtData.fontSize)))) + { + try + { + // + // Convert the font color to a channel array + // + BYTE fontColor[4] = {0}; + CStringXDW cstrFontColor(dataSettings.txtData.bstrFontColor); + cstrFontColor.Trim(); + if (cstrFontColor.Find(L"#") == 0) + { + cstrFontColor.Delete(0); + cstrFontColor.Trim(); + } + + cstrFontColor.Truncate(8); + INT cChannel = 3; + while (cstrFontColor.GetLength() > 0 && + cChannel < sizeof(DWORD) && + cChannel >= 0) + { + // + // Add the data a channel at a time so we dont overflow wcstol + // +#pragma prefast(suppress:__WARNING_MUST_USE, "All possible two-digit hex numbers are valid.") + fontColor[cChannel] = static_cast(wcstol(cstrFontColor.Left(2), NULL, 16)); + + // + // Delete the channel from the color ref string + // + cstrFontColor.Delete(0, 2); + + // + // Traverse array in reverse to correct for endianness + // + cChannel--; + } + + hr = uiProperties.SetItem(g_pszWMFontColor, fontColor, sizeof(DWORD)); + + // + // Set the text string + // + if (SUCCEEDED(hr)) + { + CStringXD text(dataSettings.txtData.bstrText); + text.Truncate(MAX_WATERMARK_TEXT); + + hr = uiProperties.SetItem(g_pszWMText, text.GetBuffer(), (text.GetLength() + 1) * sizeof(TCHAR)); + } + } + catch (CXDException& e) + { + hr = e; + } + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CWatermarkDMPTConv::SetPTDataInPT + +Routine Description: + + This method updates the watemark PrintTicket description from watermark data structure. + +Arguments: + + drvSettings - Reference to watermark data structure to update from. + pPrintTicket - Pointer to the PrintTicket to be updated. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CWatermarkDMPTConv::SetPTDataInPT( + _In_ CONST WatermarkData& dataSettings, + _Inout_ IXMLDOMDocument2* pPrintTicket + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pPrintTicket, E_POINTER))) + { + try + { + CWMPTHandler wmPTHndlr(pPrintTicket); + hr = wmPTHndlr.SetData(&dataSettings); + } + catch (CXDException& e) + { + hr = e; + } + } + else + { + hr = E_POINTER; + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CWatermarkDMPTConv::CompletePrintCapabilities + +Routine Description: + + Unidrv calls this routine with an input Device Capabilities Document + that is partially populated with Device capabilities information + filled in by Unidrv for features that it understands. The plug-in + needs to read any private features in the input PrintTicket, delete + them and add them back under Printschema namespace so that higher + level applications can understand them and make use of them. + +Arguments: + + pPrintTicket - pointer to input PrintTicket + pCapabilities - pointer to Device Capabilities Document. + +Return Value: + + HRESULT + S_OK - Always + +--*/ +HRESULT STDMETHODCALLTYPE +CWatermarkDMPTConv::CompletePrintCapabilities( + _In_opt_ IXMLDOMDocument2*, + _Inout_ IXMLDOMDocument2* pPrintCapabilities + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pPrintCapabilities, E_POINTER))) + { + try + { + CWMPCHandler watermarkpcHandler(pPrintCapabilities); + watermarkpcHandler.SetCapabilities(); + } + catch(CXDException& e) + { + hr = e; + } + } + + ERR_ON_HR(hr); + return hr; +} + diff --git a/print/XPSDrvSmpl/src/ui/wmdmptcnv.h b/print/XPSDrvSmpl/src/ui/wmdmptcnv.h new file mode 100644 index 00000000..37b8a8ae --- /dev/null +++ b/print/XPSDrvSmpl/src/ui/wmdmptcnv.h @@ -0,0 +1,75 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + wmdmptcnv.h + +Abstract: + + PageWatermark devmode <-> PrintTicket conversion class definition. + The class defines a common data representation between the DevMode (GPD) and PrintTicket + representations and implements the conversion and validation methods required + by CFeatureDMPTConvert. + +--*/ + +#pragma once + +#include "ftrdmptcnv.h" +#include "wmpthndlr.h" +#include "uiproperties.h" + +class CWatermarkDMPTConv : public CFeatureDMPTConvert +{ +public: + CWatermarkDMPTConv(); + + ~CWatermarkDMPTConv(); + +private: + HRESULT + GetPTDataSettingsFromDM( + _In_ PDEVMODE pDevmode, + _In_ ULONG cbDevmode, + _In_ PVOID pPrivateDevmode, + _In_ ULONG cbDrvPrivateSize, + _Out_ XDPrintSchema::PageWatermark::WatermarkData* pDataSettings + ); + + HRESULT + MergePTDataSettingsWithPT( + _In_ IXMLDOMDocument2* pPrintTicket, + _Inout_ XDPrintSchema::PageWatermark::WatermarkData* pDrvSettings + ); + + HRESULT + SetPTDataInDM( + _In_ CONST XDPrintSchema::PageWatermark::WatermarkData& drvSettings, + _Inout_ PDEVMODE pDevmode, + _In_ ULONG cbDevmode, + _Inout_ PVOID pPrivateDevmode, + _In_ ULONG cbDrvPrivateSize + ); + + HRESULT + SetPTDataInPT( + _In_ CONST XDPrintSchema::PageWatermark::WatermarkData& drvSettings, + _Inout_ IXMLDOMDocument2* pPrintTicket + ); + + HRESULT STDMETHODCALLTYPE + CompletePrintCapabilities( + _In_opt_ IXMLDOMDocument2*, + _Inout_ IXMLDOMDocument2* pPrintCapabilities + ); +}; + diff --git a/print/XPSDrvSmpl/src/ui/wmppg.cpp b/print/XPSDrvSmpl/src/ui/wmppg.cpp new file mode 100644 index 00000000..64faee63 --- /dev/null +++ b/print/XPSDrvSmpl/src/ui/wmppg.cpp @@ -0,0 +1,268 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + wmppg.cpp + +Abstract: + + Implementation of the watermark property page. This class is + responsible for initialising and registering the color management + property page and its controls. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdexcept.h" +#include "xdstring.h" +#include "resource.h" +#include "wmppg.h" +#include "wmctrls.h" + +/*++ + +Routine Name: + + CWatermarkPropPage::CWatermarkPropPage + +Routine Description: + + CWatermarkPropPage class constructor. + Creates a handler class object for every control on the watermark property page. + Each of these handlers is stored in a collection. + +Arguments: + + None + +Return Value: + + None + Throws CXDException(HRESULT) on an error + +--*/ +CWatermarkPropPage::CWatermarkPropPage() +{ + HRESULT hr = S_OK; + + try + { + CUIControl* pControl = new(std::nothrow) CUICtrlWMTypeCombo(); + + if (SUCCEEDED(hr = CHECK_POINTER(pControl, E_OUTOFMEMORY))) + { + hr = AddUIControl(IDC_COMBO_WMTYPE, pControl); + } + + if (SUCCEEDED(hr)) + { + pControl = new(std::nothrow) CUICtrlWMLayeringCombo(); + if (SUCCEEDED(hr = CHECK_POINTER(pControl, E_OUTOFMEMORY))) + { + hr = AddUIControl(IDC_COMBO_WMLAYERING, pControl); + } + } + + if (SUCCEEDED(hr)) + { + pControl = new(std::nothrow) CUICtrlWMTextEdit(); + if (SUCCEEDED(hr = CHECK_POINTER(pControl, E_OUTOFMEMORY))) + { + hr = AddUIControl(IDC_EDIT_WMTEXT, pControl); + } + } + + if (SUCCEEDED(hr)) + { + pControl = new(std::nothrow) CUICtrlWMTransparencyEdit(); + if (SUCCEEDED(hr = CHECK_POINTER(pControl, E_OUTOFMEMORY)) && + SUCCEEDED(hr = AddUIControl(IDC_EDIT_WMTRANSPARENCY, pControl))) + { + pControl = new(std::nothrow) CUICtrlWMTransparencySpin(reinterpret_cast(pControl)); + if (SUCCEEDED(hr = CHECK_POINTER(pControl, E_OUTOFMEMORY))) + { + hr = AddUIControl(IDC_SPIN_WMTRANSPARENCY, pControl); + } + } + } + + if (SUCCEEDED(hr)) + { + pControl = new(std::nothrow) CUICtrlWMAngleEdit(); + if (SUCCEEDED(hr = CHECK_POINTER(pControl, E_OUTOFMEMORY)) && + SUCCEEDED(hr = AddUIControl(IDC_EDIT_WMANGLE, pControl))) + { + pControl = new(std::nothrow) CUICtrlWMAngleSpin(reinterpret_cast(pControl)); + if (SUCCEEDED(hr = CHECK_POINTER(pControl, E_OUTOFMEMORY))) + { + hr = AddUIControl(IDC_SPIN_WMANGLE, pControl); + } + } + } + + if (SUCCEEDED(hr)) + { + pControl = new(std::nothrow) CUICtrlWMOffsetXEdit(); + if (SUCCEEDED(hr = CHECK_POINTER(pControl, E_OUTOFMEMORY)) && + SUCCEEDED(hr = AddUIControl(IDC_EDIT_WMOFFX, pControl))) + { + pControl = new(std::nothrow) CUICtrlWMOffsetXSpin(reinterpret_cast(pControl)); + if (SUCCEEDED(hr = CHECK_POINTER(pControl, E_OUTOFMEMORY))) + { + hr = AddUIControl(IDC_SPIN_WMOFFX, pControl); + } + } + } + + if (SUCCEEDED(hr)) + { + pControl = new(std::nothrow) CUICtrlWMOffsetYEdit(); + if (SUCCEEDED(hr = CHECK_POINTER(pControl, E_OUTOFMEMORY)) && + SUCCEEDED(hr = AddUIControl(IDC_EDIT_WMOFFY, pControl))) + { + pControl = new(std::nothrow) CUICtrlWMOffsetYSpin(reinterpret_cast(pControl)); + if (SUCCEEDED(hr = CHECK_POINTER(pControl, E_OUTOFMEMORY))) + { + hr = AddUIControl(IDC_SPIN_WMOFFY, pControl); + } + } + } + + if (SUCCEEDED(hr)) + { + pControl = new(std::nothrow) CUICtrlWMWidthEdit(); + if (SUCCEEDED(hr = CHECK_POINTER(pControl, E_OUTOFMEMORY)) && + SUCCEEDED(hr = AddUIControl(IDC_EDIT_WMWIDTH, pControl))) + { + pControl = new(std::nothrow) CUICtrlWMWidthSpin(reinterpret_cast(pControl)); + if (SUCCEEDED(hr = CHECK_POINTER(pControl, E_OUTOFMEMORY))) + { + hr = AddUIControl(IDC_SPIN_WMWIDTH, pControl); + } + } + } + + if (SUCCEEDED(hr)) + { + pControl = new(std::nothrow) CUICtrlWMHeightEdit(); + if (SUCCEEDED(hr = CHECK_POINTER(pControl, E_OUTOFMEMORY)) && + SUCCEEDED(hr = AddUIControl(IDC_EDIT_WMHEIGHT, pControl))) + { + pControl = new(std::nothrow) CUICtrlWMHeightSpin(reinterpret_cast(pControl)); + if (SUCCEEDED(hr = CHECK_POINTER(pControl, E_OUTOFMEMORY))) + { + hr = AddUIControl(IDC_SPIN_WMHEIGHT, pControl); + } + } + } + + if (SUCCEEDED(hr)) + { + pControl = new(std::nothrow) CUICtrlWMFontSizeEdit(); + if (SUCCEEDED(hr = CHECK_POINTER(pControl, E_OUTOFMEMORY)) && + SUCCEEDED(hr = AddUIControl(IDC_EDIT_WMSIZE, pControl))) + { + pControl = new(std::nothrow) CUICtrlWMFontSizeSpin(reinterpret_cast(pControl)); + if (SUCCEEDED(hr = CHECK_POINTER(pControl, E_OUTOFMEMORY))) + { + hr = AddUIControl(IDC_SPIN_WMSIZE, pControl); + } + } + } + + if (SUCCEEDED(hr)) + { + pControl = new(std::nothrow) CUICtrlColorBtn(); + if (SUCCEEDED(hr = CHECK_POINTER(pControl, E_OUTOFMEMORY))) + { + hr = AddUIControl(IDC_BUTTON_WMCOLOR, pControl); + } + } + } + catch (CXDException& e) + { + hr = e; + } + + if (FAILED(hr)) + { + DestroyUIComponents(); + throw CXDException(hr); + } +} + +/*++ + +Routine Name: + + CWatermarkPropPage::~CWatermarkPropPage + +Routine Description: + + CWatermarkPropPage class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CWatermarkPropPage::~CWatermarkPropPage() +{ +} + +/*++ + +Routine Name: + + CWatermarkPropPage::InitDlgBox + +Routine Description: + + Provides the base class with the data required to intialise the dialog box. + +Arguments: + + ppszTemplate - Pointer to dialog box template to be intialised. + ppszTitle - Pointer to dialog box title to be intialised. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CWatermarkPropPage::InitDlgBox( + _Out_ LPCTSTR* ppszTemplate, + _Out_ LPCTSTR* ppszTitle + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(ppszTemplate, E_POINTER)) || + SUCCEEDED(hr = CHECK_POINTER(ppszTitle, E_POINTER))) + { + *ppszTemplate = MAKEINTRESOURCE(IDD_WATERMARK); + *ppszTitle = MAKEINTRESOURCE(IDS_WMARK); + } + + ERR_ON_HR(hr); + return hr; +} + diff --git a/print/XPSDrvSmpl/src/ui/wmppg.h b/print/XPSDrvSmpl/src/ui/wmppg.h new file mode 100644 index 00000000..e28d5ea5 --- /dev/null +++ b/print/XPSDrvSmpl/src/ui/wmppg.h @@ -0,0 +1,42 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + wmppg.h + +Abstract: + + Definiiion of the watermark property page. This class is + responsible for initialising and registering the color management + property page and its controls. + +--*/ + +#pragma once + +#include "precomp.h" +#include "docppg.h" + +class CWatermarkPropPage : public CDocPropPage +{ +public: + CWatermarkPropPage(); + + virtual ~CWatermarkPropPage(); + + HRESULT + InitDlgBox( + _Out_ LPCTSTR* ppszTemplate, + _Out_ LPCTSTR* ppszTitle + ); +}; + diff --git a/print/XPSDrvSmpl/src/ui/xdsmplcf.cpp b/print/XPSDrvSmpl/src/ui/xdsmplcf.cpp new file mode 100644 index 00000000..abbdb3e4 --- /dev/null +++ b/print/XPSDrvSmpl/src/ui/xdsmplcf.cpp @@ -0,0 +1,192 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + xdsmplcf.cpp + +Abstract: + + XPSDrv feature sample class factory implementation. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdexcept.h" +#include "xdstring.h" +#include "xdsmplcf.h" +#include "xdsmplui.h" +#include "xdsmplptprov.h" + +/*++ + +Routine Name: + + CXDSmplUICF::CreateInstance + +Routine Description: + + Creates an object of the specified CLSID and retrieves an interface pointer to this object. + The supported class objects are currently IPrintOemUI and IPrintOemPrintTicketProvider. + +Arguments: + + pUnkOuter - This must be NULL, as aggregare object creation is not supported. + riid - The IID of the requested interface. + ppvObject - A pointer to the interface pointer identified by riid. + If the object does not support this interface, ppvObj is set to NULL. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CXDSmplUICF::CreateInstance( + _In_opt_ LPUNKNOWN pUnkOuter, + _In_ REFIID riid, + _Outptr_ PVOID* ppvObject + ) +{ + HRESULT hr = S_OK; + + if (ppvObject == NULL) + { + hr = E_POINTER; + goto Exit; + } + *ppvObject = NULL; + + if (pUnkOuter == NULL) + { + // + // Create UI component + // + CXDSmplUI* pXDSmplUI = NULL; + + try + { + pXDSmplUI = new(std::nothrow) CXDSmplUI; + hr = CHECK_POINTER(pXDSmplUI, E_OUTOFMEMORY); + } + catch (CXDException& e) + { + hr = e; + } + catch (...) + { + hr = E_FAIL; + } + + if (SUCCEEDED(hr)) + { + // + // Get the requested interface + // + hr = pXDSmplUI->QueryInterface(riid, ppvObject) ; + + // + // Release the IUnknown pointer. If QueryInterface failed + // the Release() call will clean up + // + pXDSmplUI->Release(); + + // + // If QueryInterface failed this could be a request for the + // PTProvider Interface + // + if (FAILED(hr)) + { + CXDSmplPTProvider* pXDSmplPT = NULL; + + try + { + pXDSmplPT = new(std::nothrow) CXDSmplPTProvider; + hr = CHECK_POINTER(pXDSmplPT, E_OUTOFMEMORY); + } + catch (CXDException& e) + { + _Analysis_assume_((*ppvObject) == NULL); + hr = e; + } + catch (...) + { + hr = E_FAIL; + } + + if (SUCCEEDED(hr)) + { + hr = pXDSmplPT->QueryInterface(riid, ppvObject) ; + + // + // Release the IUnknown pointer. + // (If QueryInterface failed, component will delete itself.) + // + pXDSmplPT->Release(); + } + } + } + } + else + { + // + // Cannot aggregate + // + hr = CLASS_E_NOAGGREGATION; + } + +Exit: + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CXDSmplUICF::LockServer + +Routine Description: + + Increments and decrements the UI Plug-in Module lock count. + +Arguments: + + bLock - If TRUE, the lock count is incremented; otherwise, the lock count is decremented. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CXDSmplUICF::LockServer( + BOOL bLock + ) +{ + if (bLock) + { + InterlockedIncrement(&g_cServerLocks); + } + else + { + InterlockedDecrement(&g_cServerLocks); + } + + return S_OK; +} + diff --git a/print/XPSDrvSmpl/src/ui/xdsmplcf.h b/print/XPSDrvSmpl/src/ui/xdsmplcf.h new file mode 100644 index 00000000..ae1a78c8 --- /dev/null +++ b/print/XPSDrvSmpl/src/ui/xdsmplcf.h @@ -0,0 +1,56 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + xdsmplcf.cpp + +Abstract: + + XPSDrv feature sample class factory definition. + +--*/ + +#pragma once + +#include "cunknown.h" + +class CXDSmplUICF : public CUnknown +{ +public: + // + // Constructor and Destruction + // + CXDSmplUICF() : + CUnknown(IID_IClassFactory) + { + } + + virtual ~CXDSmplUICF() + { + } + + // + // IClassFactory methods + // + virtual HRESULT STDMETHODCALLTYPE + CreateInstance( + _In_opt_ LPUNKNOWN pUnkOuter, + _In_ REFIID riid, + _Outptr_ PVOID* ppvObject + ); + + virtual HRESULT STDMETHODCALLTYPE + LockServer( + BOOL bLock + ); +}; + diff --git a/print/XPSDrvSmpl/src/ui/xdsmpldlg.rc b/print/XPSDrvSmpl/src/ui/xdsmpldlg.rc new file mode 100644 index 00000000..bfbdee3f --- /dev/null +++ b/print/XPSDrvSmpl/src/ui/xdsmpldlg.rc @@ -0,0 +1,326 @@ +// +// Copyright (c) 2005 Microsoft Corporation +// +// All rights reserved. +// +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +// PARTICULAR PURPOSE. +// +// File Name: +// +// xdsmpldlg.rc +// +// Abstract: +// +// XPSDrv sample driver UI plug-in resource file. +// +// + +#include "winres.h" +#include "resource.h" +#include + +#define VER_FILETYPE VFT_DLL +#define VER_FILESUBTYPE VFT2_UNKNOWN +#define VER_FILEDESCRIPTION_STR "XPSDrv Sample UI Plug-In" +#define VER_INTERNALNAME_STR "PrintFeatureFilters" + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// + +#include "common.ver" + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_COL_MANAGE DIALOGEX 0, 0, 296, 200 +STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | WS_CHILD | WS_DISABLED +FONT 8, "MS Shell Dlg", 0, 0, 0x0 +BEGIN + LISTBOX IDC_LIST_COLPROF,21,63,252,82,LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP + LTEXT "Select color profile",IDC_TEXT_COLPROF,22,51,89,8 + GROUPBOX "",IDC_GRP_COLPROF,4,4,288,192 + COMBOBOX IDC_COMBO_COL_MANAGE,137,28,135,88,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "Select Color Management Method",IDC_TXT_COL_MANAGE,24,31,108,8 + LTEXT "Select ICM Rendering Intent",IDC_TXT_COL_INTENT,24,164,92,8 + COMBOBOX IDC_COMBO_COL_INTENT,137,162,135,88,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP +END + +IDD_WATERMARK DIALOGEX 0, 0, 296, 200 +STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | WS_CHILD | WS_DISABLED +FONT 8, "MS Shell Dlg", 0, 0, 0x0 +BEGIN + COMBOBOX IDC_COMBO_WMTYPE,14,32,107,88,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "Watermark Type",IDC_TXT_WMTYPE,14,21,65,8 + COMBOBOX IDC_COMBO_WMLAYERING,14,66,75,88,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "Layering",IDC_TXT_WMLAYERING,14,55,65,8 + GROUPBOX "Settings",IDC_GRP_WM,4,4,284,192 + EDITTEXT IDC_EDIT_WMTEXT,14,131,107,14, ES_AUTOHSCROLL + LTEXT "Text",IDC_TXT_WMTEXT,14,120,65,8 + EDITTEXT IDC_EDIT_WMTRANSPARENCY,236,65,33,14,ES_AUTOHSCROLL | ES_NUMBER + CONTROL "",IDC_SPIN_WMTRANSPARENCY,"msctls_updown32",UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,260,65,11,14 + EDITTEXT IDC_EDIT_WMANGLE,133,66,33,14,ES_AUTOHSCROLL | ES_NUMBER + CONTROL "",IDC_SPIN_WMANGLE,"msctls_updown32",UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,157,66,11,14 + EDITTEXT IDC_EDIT_WMOFFX,70,96,50,14,ES_AUTOHSCROLL | ES_NUMBER + CONTROL "",IDC_SPIN_WMOFFX,"msctls_updown32",UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,109,96,11,14 + EDITTEXT IDC_EDIT_WMOFFY,190,96,50,14,ES_AUTOHSCROLL | ES_NUMBER + CONTROL "",IDC_SPIN_WMOFFY,"msctls_updown32",UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,229,96,11,14 + LTEXT "Transparency",IDC_TXT_WMTRANSPARENCY,186,68,45,8 + LTEXT "Angle",IDC_TXT_WMANGLE,104,68,23,8 + LTEXT "Offset X .01""",IDC_TXT_WMOFFX,17,99,43,8 + LTEXT "Offset Y .01""",IDC_TXT_WMOFFY,140,98,43,8 + EDITTEXT IDC_EDIT_WMWIDTH,70,125,50,14,ES_AUTOHSCROLL | ES_NUMBER + CONTROL "",IDC_SPIN_WMWIDTH,"msctls_updown32",UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,108,125,11,14 + EDITTEXT IDC_EDIT_WMHEIGHT,190,125,50,14,ES_AUTOHSCROLL | ES_NUMBER + CONTROL "",IDC_SPIN_WMHEIGHT,"msctls_updown32",UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,229,125,11,14 + LTEXT "Width .01""",IDC_TXT_WMWIDTH,17,128,51,8 + LTEXT "Height .01""",IDC_TXT_WMHEIGHT,140,127,37,8 + EDITTEXT IDC_EDIT_WMSIZE,129,163,33,14,ES_AUTOHSCROLL | ES_NUMBER + CONTROL "",IDC_SPIN_WMSIZE,"msctls_updown32",UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,158,163,11,14 + LTEXT "Size",IDC_TXT_WMSIZE,104,166,18,8 + PUSHBUTTON "Color",IDC_BUTTON_WMCOLOR,27,163,50,14 +END + +IDD_FEATURES DIALOGEX 0, 0, 296, 200 +STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | WS_CHILD | WS_DISABLED +FONT 8, "MS Shell Dlg", 0, 0, 0x0 +BEGIN + GROUPBOX "Page Scaling",IDC_GRP_PGSCALE,4,2,285,56 + GROUPBOX "Document Multi-Up",IDC_GRP_DOCNUP,4,61,285,45 + COMBOBOX IDC_COMBO_PGSCALE,11,28,88,88,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "Scaling Option",IDC_TXT_PGSCALE,11,18,46,8 + COMBOBOX IDC_COMBO_SCALEOFF,144,28,114,88,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "Scale Offset Alignment",IDC_TXT_SCALEOFF,144,17,88,8 + EDITTEXT IDC_EDIT_PGSCALEX,138,14,40,14,ES_AUTOHSCROLL | ES_NUMBER + CONTROL "",IDC_SPIN_PGSCALEX,"msctls_updown32",UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,168,14,10,14 + EDITTEXT IDC_EDIT_PGOFFX,234,14,50,14,ES_AUTOHSCROLL | ES_NUMBER + CONTROL "",IDC_SPIN_PGOFFX,"msctls_updown32",UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,273,14,10,14 + EDITTEXT IDC_EDIT_PGSCALEY,138,38,40,14,ES_AUTOHSCROLL | ES_NUMBER + CONTROL "",IDC_SPIN_PGSCALEY,"msctls_updown32",UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,168,38,10,14 + EDITTEXT IDC_EDIT_PGOFFY,234,38,50,14,ES_AUTOHSCROLL | ES_NUMBER + CONTROL "",IDC_SPIN_PGOFFY,"msctls_updown32",UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,273,38,10,14 + LTEXT "Scale X",IDC_TXT_PGSCALEX,108,18,25,8 + LTEXT "Scale Y",IDC_TXT_PGSCALEY,108,40,25,8 + LTEXT "Offset X .01""",IDC_TXT_PGOFFX,187,17,42,8 + LTEXT "Offset Y .01""",IDC_TXT_PGOFFY,187,40,42,8 + COMBOBOX IDC_COMBO_NUP,11,81,114,88,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_COMBO_NUP_ORDER,155,81,114,88,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "Number Up",IDC_TXT_NUP,11,70,36,8 + LTEXT "Presentation Order",IDC_TXT_NUP_ORDER,155,70,88,8 + COMBOBOX IDC_COMBO_PHOTO_INTENT,93,176,83,88,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "Page Photo Printing Intent",IDC_TXT_PHOTO_INTENT,93,165,86,8 + CONTROL "Enable Borderless Pages",IDC_CHECK_BORDERLESS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,187,177,94,10 + COMBOBOX IDC_COMBO_DOCDUPLEX,11,176,68,88,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "Duplex Option",IDC_TXT_DOCDUPLEX,11,165,46,8 + GROUPBOX "Other",IDC_STATIC,4,157,285,38 + LTEXT "Job Binding (all documents)",IDC_TXT_JOBBIND,11,118,100,8 + COMBOBOX IDC_COMBO_JOBBIND,11,129,115,88,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + GROUPBOX "Binding Option",IDC_STATIC,4,109,285,45 + LTEXT "Document Binding",IDC_TXT_DOCBIND,155,118,100,8 + COMBOBOX IDC_COMBO_DOCBIND,155,129,114,88,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP +END + + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE +BEGIN + IDS_COLMAN "Color Management" + IDS_WMARK "Watermarks" + IDS_FEATURE "Features" +END + +STRINGTABLE +BEGIN + IDS_GPD_1PPS "1 Page per Sheet" + IDS_GPD_2PPS "2 Page per Sheet" + IDS_GPD_4PPS "4 Page per Sheet" + IDS_GPD_6PPS "6 Page per Sheet" + IDS_GPD_8PPS "8 Page per Sheet" + IDS_GPD_9PPS "9 Page per Sheet" + IDS_GPD_16PPS "16 Page per Sheet" + IDS_GPD_RES1200 "1200 x 1200 dpi" + IDS_GPD_RES600 "600 x 600 dpi" + IDS_GPD_AUTOMATIC "Automatic" + IDS_GPD_BORDERED "Bordered" + IDS_GPD_BORDERLESS "Borderless" + IDS_GPD_BTOT "Bottom to Top" + IDS_GPD_BTOTLTOR "Bottom to Top, Left to Right" + IDS_GPD_BTOTRTOL "Bottom to Top, Right to Left" + IDS_GPD_CMYK "CMYK" +END + +STRINGTABLE +BEGIN + IDS_GPD_COLOR "Color" + IDS_GPD_CONFIDENTIAL "Confidential" + IDS_GPD_CUSTSQUARE "Custom Square" + IDS_GPD_CUSTOM "Custom" + IDS_GPD_SRCCOLPROF "Source Color Profile" + IDS_GPD_DEVICE "Device" + IDS_GPD_DOCBIND "Document Binding" + IDS_GPD_PAGECOLMAN "Page Color Management" + IDS_GPD_PAGEPHOTINTENT "Page Photo Printing Intent" + IDS_GPD_DOCDUPLEX "Document Duplex" + IDS_GPD_DOCNUP "Document NUp" + IDS_GPD_DOCNUPPRESENTORDER "Document NUp Presentation Order" + IDS_GPD_DRAFT "Draft" + IDS_GPD_DRIVER "Driver" + IDS_GPD_DUPLEX "Duplex" + IDS_GPD_FAX "Fax" +END + +STRINGTABLE +BEGIN + IDS_GPD_FITBLEED "Fit Bleed Size" + IDS_GPD_FITCONTENT "Fit Content Size" + IDS_GPD_FITPAGE "Fit Page Size" + IDS_GPD_GLOSSY "Glossy" + IDS_GPD_GRAYSCALE "Grayscale" + IDS_GPD_HIGH "High" + IDS_GPD_HORIZONTAL "Horizontal" + IDS_GPD_JOBBINDING "Job Binding (all documents)" + IDS_GPD_JOBNUPPRESENTORDER "Job NUp Presentation Order" + IDS_GPD_JOBNUP "Job NUp (contigously)" + IDS_GPD_JOBPAGEORDER "Job Page Order" + IDS_GPD_LANDSCAPE "Landscape" + IDS_GPD_LTOR "Left to Right" + IDS_GPD_LTORBTOT "Left to Right, Bottom to Top" + IDS_GPD_LTORTTOB "Left to Right, Top to Bottom" + IDS_GPD_MEDIATYPE "Media Type" +END + +STRINGTABLE +BEGIN + IDS_GPD_MONO "Mono" + IDS_GPD_NONE "None" + IDS_GPD_NORMAL "Normal" + IDS_GPD_OFF "Off" + IDS_GPD_ON "On" + IDS_GPD_ORIENATION "Orientation" + IDS_GPD_OVERLAYED "Overlaid" + IDS_GPD_PAGEBORDER "Page Border" + IDS_GPD_PAGEQUALITY "Page Output Quality" + IDS_GPD_PAGESCALING "Page Scaling" + IDS_GPD_PAPERSOURCE "Paper Source" + IDS_GPD_PHOTOGRAPHIC "Photographic" + IDS_GPD_PORTRAIT "Portrait" + IDS_GPD_RASTERIMAGE "Raster Image" + IDS_GPD_RESOLUTION "Resolution" + IDS_GPD_REVERSELANDSCAPE "Reverse Landscape" +END + +STRINGTABLE +BEGIN + IDS_GPD_REVERSE "Reverse" + IDS_GPD_RTOL "Right to Left" + IDS_GPD_RTOLBTOT "Right to Left, Bottom to Top" + IDS_GPD_RTOLTTOB "Right to Left, Top to Bottom" + IDS_GPD_SCALEPAGETOPAGE "Scale Page to Page" + IDS_GPD_SCRGB "scRGB" + IDS_GPD_STANDARD "Standard" + IDS_GPD_TEXT "Text" + IDS_GPD_TTOB "Top to Bottom" + IDS_GPD_TTOBLTOR "Top to Bottom, Left to Right" + IDS_GPD_TTOBRTOL "Top to Bottom, Right to Left" + IDS_GPD_TRANSPARENCY "Transparency" + IDS_GPD_TRANSPARENT "Transparent" + IDS_GPD_UNDERLAYED "Underlayed" + IDS_GPD_UPPER "Upper" + IDS_GPD_VECTORIMAGE "Vector Image" +END + +STRINGTABLE +BEGIN + IDS_GPD_VERTICAL "Vertical" + IDS_GPD_WATERMARKLAYERING "Watermark Layering" + IDS_GPD_WATERMARKTEXT "Watermark Text" + IDS_GPD_WATERMARKTYPE "Watermark Type" + IDS_GPD_BEST "Best" + IDS_GPD_PAGEICMINTENT "Page ICM Rendering Intent" + IDS_GPD_ABSCOLINTENT "Absolute Colorimetric" + IDS_GPD_RELCOLINTENT "Relative Colorimetric" + IDS_GPD_PHOTOINTENT "Photographs" + IDS_GPD_BIZINTENT "Business Graphics" + IDS_GPD_SYSTEM "System" + IDS_GPD_WATERMARKTEXTCOLOR "Watermark Text Color" + IDS_GPD_RED "Red" + IDS_GPD_GREEN "Green" + IDS_GPD_BLUE "Blue" + IDS_GPD_MAGENTA "Magenta" + IDS_GPD_CYAN "Cyan" + IDS_GPD_YELLOW "Yellow" + IDS_GPD_BLACK "Black" +END + +STRINGTABLE +BEGIN + IDS_GPD_SCALE_ALIGN "Scale Offset Alignment" + IDS_GPD_SCALE_ALIGN_BC "Bottom Centre" + IDS_GPD_SCALE_ALIGN_BL "Bottom Left" + IDS_GPD_SCALE_ALIGN_BR "Bottom Right" + IDS_GPD_SCALE_ALIGN_CC "Centre" + IDS_GPD_SCALE_ALIGN_LC "Centre Left" + IDS_GPD_SCALE_ALIGN_CR "Centre Right" + IDS_GPD_SCALE_ALIGN_CT "Centre Top" + IDS_GPD_SCALE_ALIGN_TL "Top Left" + IDS_GPD_SCALE_ALIGN_TR "Top Right" +END + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/print/XPSDrvSmpl/src/ui/xdsmplptprov.cpp b/print/XPSDrvSmpl/src/ui/xdsmplptprov.cpp new file mode 100644 index 00000000..5e0f521f --- /dev/null +++ b/print/XPSDrvSmpl/src/ui/xdsmplptprov.cpp @@ -0,0 +1,891 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + xdsmplptprov.cpp + +Abstract: + + Implementation of the PrintTicket provider plugin. This is responsible for + handling PrintTicket features that are too complex for the GPD->PrintTicket + automapping facility. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdexcept.h" +#include "xdstring.h" +#include "xdsmplptprov.h" +#include "wmdmptcnv.h" +#include "pgscdmptcnv.h" +#include "bkdmptcnv.h" +#include "nupptcnv.h" +#include "coldmptcnv.h" +#include "pthndlr.h" +#include "pchndlr.h" + +static LPCWSTR PRIVATE_URI = L"http://schemas.microsoft.com/windows/2003/08/printing/XPSDrv_Feature_Sample"; + + +/*++ + +Routine Name: + + CXDSmplPTProvider::CXDSmplPTProvider + +Routine Description: + + CXDSmplPTProvider class constructor + +Arguments: + + None + +Return Value: + + None + Throws CXDException(HRESULT) on an error + +--*/ +CXDSmplPTProvider::CXDSmplPTProvider() : + CUnknown(IID_IPrintOemPrintTicketProvider), + m_hPrinterCached(NULL), + m_pCoreHelper(NULL), + m_bstrPrivateNS(PRIVATE_URI) +{ + HRESULT hr = S_OK; + IFeatureDMPTConvert* pHandler = NULL; + +// +// This Prefast warning indicates that memory could be leaked +// in the event of an exception. We suppress this false positive because we +// know that the local try/catch block will clean up a single +// IFeatureDMPTConvert, and the destructor will clean up any that are +// successfully added to the vector. +// +#pragma prefast(push) +#pragma prefast(disable:__WARNING_ALIASED_MEMORY_LEAK_EXCEPTION) + try + { + // + // Populate the feature DM<->PT conversion vector + // + pHandler = new(std::nothrow) CWatermarkDMPTConv(); + + hr = AddConverter(pHandler); + + if (SUCCEEDED(hr)) + { + pHandler = new(std::nothrow) CPageScalingDMPTConv(); + + hr = AddConverter(pHandler); + } + + if (SUCCEEDED(hr)) + { + pHandler = new(std::nothrow) CBookletDMPTConv(); + + hr = AddConverter(pHandler); + } + + if (SUCCEEDED(hr)) + { + pHandler = new(std::nothrow) CNUpDMPTConv(); + + hr = AddConverter(pHandler); + } + + if (SUCCEEDED(hr)) + { + pHandler = new(std::nothrow) CColorProfileDMPTConv(); + + hr = AddConverter(pHandler); + } + } + catch (exception& DBG_ONLY(e)) + { + ERR(e.what()); + + hr = E_FAIL; + } + + if (FAILED(hr)) + { + // + // If we successfully created a handler but failed to push it onto + // the handler vector we need to free the allocated handler + // + if (pHandler != NULL) + { + delete pHandler; + pHandler = NULL; + } + + // + // Delete any DM<->PT converters that were successfully instantiated + // + DeleteConverters(); + + throw CXDException(hr); + } +#pragma prefast(pop) +} + +/*++ + +Routine Name: + + CXDSmplPTProvider::~CXDSmplPTProvider + +Routine Description: + + CXDSmplPTProvider class destructor + +Arguments: + + None + +Return Value: + + None + +--*/ +CXDSmplPTProvider::~CXDSmplPTProvider() +{ + // + // Clean up all DM<->PT converters + // + DeleteConverters(); +} + +/*++ + +Routine Name: + + CXDSmplPTProvider::GetSupportedVersions + +Routine Description: + + The routine returns major versions of Printschema schema supported by the plug-in Provider. + +Arguments: + + hPrinter - Printer Handle + ppVersions - OUT pointer to array of version numbers to be filled in by the plug-in + cVersions - OUT pointer to count of Number of versions supported by plug-in + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT STDMETHODCALLTYPE +CXDSmplPTProvider::GetSupportedVersions( + _In_ HANDLE, + _Outptr_result_buffer_(*pcVersions) INT* ppVersions[], + _Out_ INT* pcVersions + ) +{ + HRESULT hr = S_OK; + + // + // Check if input parameters are valid + // + if (SUCCEEDED(hr = CHECK_POINTER(ppVersions, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pcVersions, E_POINTER))) + { + *pcVersions = 0; + + // + // The Plug-in Provider need to allocate memory for the input version array and + // then fill it with version information + // + *ppVersions = static_cast(CoTaskMemAlloc(sizeof(INT))); + + if (*ppVersions != NULL) + { + // + // version number 1 is the only version supported currently + // + *pcVersions = 1; + (*ppVersions)[0] = PRINTSCHEMA_VERSION_NUMBER; + } + else + { + hr = E_OUTOFMEMORY; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CXDSmplPTProvider::BindPrinter + +Routine Description: + + Bind Printer is the part of the Unidrv's activity to bind to a device. It allows the plug-in to cache + certain information that can be used later on such as the private namespaces used by the plug-in. + +Arguments: + + hPrinter - Printer Handle supplied by Unidrv + version - version of Printschema + pOptions - Flags passed out to set configurable options supported by caller + cNamespaces - Count of private namespaces of plug-in + ppNamespaces - OUT pointer to the array of Namespace URIs filled in by plug-in + +Return Value: + + HRESULT + S_OK - On success + E_VERSION_NOT_SUPPORTED - if printer version specified is not supported by plug-in + E_* - On any other failure + +--*/ +HRESULT STDMETHODCALLTYPE +CXDSmplPTProvider::BindPrinter( + _In_ HANDLE hPrinter, + INT version, + _Out_ POEMPTOPTS pOptions, + _Out_ INT* pcNamespaces, + _Outptr_result_buffer_maybenull_(*pcNamespaces) BSTR** ppNamespaces + ) +{ + HRESULT hr = S_OK; + + // + // Printer Handle should be provided by Unidrv in this call, which is cached by plug-in provider and + // is later on used while making calls to Plug-in Helper Interface methods. + // + if (SUCCEEDED(hr = CHECK_POINTER(pOptions, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pcNamespaces, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(ppNamespaces, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(hPrinter, E_HANDLE))) + { + *ppNamespaces = NULL; + *pcNamespaces = 0; + + // + // Agree on the Printschema version with Unidrv Version 1 is the only + // version currently supported + // + if (PRINTSCHEMA_VERSION_NUMBER == version) + { + // + // Cache the printer handle for further use + // + m_hPrinterCached = hPrinter; + + // + // Flags to set configurable options, OEMPT_DEFAULT defined in prcomoem.h + // + *pOptions = OEMPT_NOSNAPSHOT; + + // + // Publish the private namespace + // + *pcNamespaces = 1; + *ppNamespaces = static_cast(CoTaskMemAlloc(sizeof(BSTR))); + + if (SUCCEEDED(hr = CHECK_POINTER(*ppNamespaces, E_OUTOFMEMORY))) + { + hr = m_bstrPrivateNS.CopyTo(*ppNamespaces); + } + } + else + { + hr = E_VERSION_NOT_SUPPORTED; + } + } + + ERR_ON_HR_EXC(hr, E_VERSION_NOT_SUPPORTED); + return hr; +} + +/*++ + +Routine Name: + + CXDSmplPTProvider::PublishPrintTicketHelperInterface + +Routine Description: + + For a number of operations, the plug-in needs to use the Helper Interface utilities provided by + Unidrv. Unidrv uses this method to publish the PrintTicket Helper Interface, IPrintCoreHelper. + Plug-in should return SUCCESS after successfully incrementing the reference count of the interface. + +Arguments: + + pHelper - IPrintCoreHelper interface pointer + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT STDMETHODCALLTYPE +CXDSmplPTProvider::PublishPrintTicketHelperInterface( + _In_ IUnknown *pHelper + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pHelper, E_POINTER))) + { + // + // Need to store pointer to Driver Helper functions, if we already haven't. + // + if (m_pCoreHelper == NULL) + { + hr = pHelper->QueryInterface(IID_IPrintCoreHelperUni, reinterpret_cast(&m_pCoreHelper)); + } + + // + // It's possible that this routine will publish other interfaces in the future. + // If the object published did not support the desired interface, this routine + // should still succeed. + // + // If the helper interface is needed, but for some reason was not published + // (this would be an error on the OS's part), you should detect this and fail + // during the call-back where you intended to use the helper interface. + // + if (E_NOINTERFACE == hr) + { + hr = S_OK; + } + else + { + try + { + // + // Iterate over all PrintTicket feature converters publishing the helper interface + // + DMPTConvCollection::iterator iterConverters = m_vectFtrDMPTConverters.begin(); + + for (; iterConverters != m_vectFtrDMPTConverters.end() && SUCCEEDED(hr); iterConverters++) + { + hr = (*iterConverters)->PublishPrintTicketHelperInterface(m_pCoreHelper); + } + } + catch (exception& DBG_ONLY(e)) + { + ERR(e.what()); + hr = E_FAIL; + } + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CXDSmplPTProvider::QueryDeviceDefaultNamespace + +Routine Description: + + This method provides the plug-in with the opportunity to specify the name of the + Private namespace URI that Unidrv should be using to handle any features defined + in the GPD that Unidrv does not recognize. The plug-in may specify a set of + namespaces as a result of the call to BindPrinter method, and Unidrv needs to know + which of them is to be used as default namespace so that, for all the features that + Unidrv does not recognize, it will put them under this namespace in the PrintTicket. + + Note: It is Unidrv's responsibility to add the private namespace URI that plug-in + has specified through this call in the root node of the DOM document, and also define + a prefix for it so that plug-in should use the prefix defined by Unidrv when it wishes + to add any new node to the PrintTicket under its private namespace. Plug-in should + not define its own prefix for this default private namespace URI. + +Arguments: + + pbstrNamespaceUri - OUT Pointer to namespace URI to be filled in and returned by plug-in + +Return Value: + + HRESULT + S_OK - On success + E_NOTIMPL - The plugin does not require a private namespace + E_* - On error + +--*/ +HRESULT STDMETHODCALLTYPE +CXDSmplPTProvider::QueryDeviceDefaultNamespace( + _Out_ BSTR* pbstrNamespaceUri + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pbstrNamespaceUri, E_POINTER))) + { + hr = m_bstrPrivateNS.CopyTo(pbstrNamespaceUri); + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CXDSmplPTProvider::ConvertPrintTicketToDevMode + +Routine Description: + + Unidrv will call this routine before it performs its part of PT->DM + conversion. The plug-in is passed with an input PrintTicket that is + fully populated, and Devmode which has default settings in it. + + This routine merely passes the call on to the individual feature handlers. + +Arguments: + + pPrintTicket - pointer to input PrintTicket + cbDevmode - size in bytes of input full devmode + pDevmode - pointer to input full devmode buffer + cbDrvPrivateSize - buffer size in bytes of plug-in private devmode + pPrivateDevmode - pointer to plug-in private devmode buffer + + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT STDMETHODCALLTYPE +CXDSmplPTProvider::ConvertPrintTicketToDevMode( + _In_ IXMLDOMDocument2* pPrintTicket, + ULONG cbDevmode, + _Inout_updates_bytes_(cbDevmode) + PDEVMODE pDevmode, + ULONG cbDrvPrivateSize, + _Inout_ PVOID pPrivateDevmode + ) +{ + HRESULT hr = S_OK; + + // + // Validate parameters + // + if (SUCCEEDED(hr = CHECK_POINTER(pDevmode, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pPrivateDevmode, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pPrintTicket, E_POINTER))) + { + if (cbDevmode < sizeof(DEVMODE) || + cbDrvPrivateSize == 0) + { + hr = E_INVALIDARG; + } + } + + try + { + if (SUCCEEDED(hr)) + { + // + // Iterate over all PrintTicket feature converters letting them + // provide the conversion + // + DMPTConvCollection::iterator iterConverters = m_vectFtrDMPTConverters.begin(); + + for (; iterConverters != m_vectFtrDMPTConverters.end() && SUCCEEDED(hr); iterConverters++) + { + hr = (*iterConverters)->ConvertPrintTicketToDevMode(pPrintTicket, cbDevmode, pDevmode, cbDrvPrivateSize, pPrivateDevmode); + } + } + } + catch (exception& DBG_ONLY(e)) + { + ERR(e.what()); + hr = E_FAIL; + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CXDSmplPTProvider::ConvertDevModeToPrintTicket + +Routine Description: + + Unidrv will call the routine with an Input PrintTicket that is populated + with public and Unidrv private features. For those features in the GPD that + Unidrv does not understand, it puts them in the PT under the private namespace + (either specified by the plug-in through QueryDeviceDefaultNamespace or created + by itself). It is the plug-in's responsibility to read the corresponding features + from the input PT and put them in public printschema namespace, so that any higher + level application making use of a PrintTicket can read and interpret these settings. + + This routine merely passes the call on to the individual feature handlers. + + +Arguments: + + cbDevmode - size in bytes of input full devmode + pDevmode - pointer to input full devmode buffer + cbDrvPrivateSize - buffer size in bytes of plug-in private devmode + pPrivateDevmode - pointer to plug-in private devmode buffer + pPrintTicket - pointer to input PrintTicket + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT STDMETHODCALLTYPE +CXDSmplPTProvider::ConvertDevModeToPrintTicket( + ULONG cbDevmode, + _Inout_updates_bytes_(cbDevmode) + PDEVMODE pDevmode, + ULONG cbDrvPrivateSize, + _Inout_ PVOID pPrivateDevmode, + _Inout_ IXMLDOMDocument2* pPrintTicket + ) +{ + HRESULT hr = S_OK; + + // + // Validate parameters + // + if (SUCCEEDED(hr = CHECK_POINTER(pDevmode, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pPrivateDevmode, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pPrintTicket, E_POINTER))) + { + if (cbDevmode < sizeof(DEVMODE) || + cbDrvPrivateSize == 0) + { + hr = E_INVALIDARG; + } + } + + try + { + if (SUCCEEDED(hr)) + { + // + // Iterate over all PrintTicket feature converters letting them + // provide the conversion + // + DMPTConvCollection::iterator iterConverters = m_vectFtrDMPTConverters.begin(); + + for (; iterConverters != m_vectFtrDMPTConverters.end() && SUCCEEDED(hr); iterConverters++) + { + hr = (*iterConverters)->ConvertDevModeToPrintTicket(cbDevmode, pDevmode, cbDrvPrivateSize, pPrivateDevmode, pPrintTicket); + } + + // + // Delete all the private features generated by the Unidrv parser from the GPD. + // These are not required in the PrintTicket as they are only used to control + // features in the public PrintSchema and have no meaning outside the config + // module. + // + if (SUCCEEDED(hr)) + { + CPTHandler ptHandler(pPrintTicket); + hr = ptHandler.DeletePrivateFeatures(m_bstrPrivateNS); + } + } + } + catch (exception& DBG_ONLY(e)) + { + ERR(e.what()); + hr = E_FAIL; + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CXDSmplPTProvider::CompletePrintCapabilities + +Routine Description: + + Unidrv calls this routine with an input Device Capabilities Document + that is partially populated with Device capabilities information + filled in by Unidrv for features that it understands. The plug-in + needs to read any private features in the input PrintTicket, delete + them and add them back under Printschema namespace so that higher + level applications can understand them and make use of them. + + The XPSDrv sample driver does not define any private device capabilities + so this method merely returns S_OK + +Arguments: + + pPrintTicket - pointer to input PrintTicket + pCapabilities - pointer to Device Capabilities Document. + +Return Value: + + HRESULT + S_OK - Always + +--*/ +HRESULT STDMETHODCALLTYPE +CXDSmplPTProvider::CompletePrintCapabilities( + _In_opt_ IXMLDOMDocument2* pPrintTicket, + _Inout_ IXMLDOMDocument2* pPrintCapabilities + ) +{ + HRESULT hr = S_OK; + + // + // Validate parameters + // + if (SUCCEEDED(hr = CHECK_POINTER(pPrintCapabilities, E_POINTER))) + { + try + { + // + // Iterate over all PrintTicket feature converters letting them + // provide the conversion + // + DMPTConvCollection::iterator iterConverters = m_vectFtrDMPTConverters.begin(); + + for (; iterConverters != m_vectFtrDMPTConverters.end() && SUCCEEDED(hr); iterConverters++) + { + hr = (*iterConverters)->CompletePrintCapabilities(pPrintTicket, pPrintCapabilities); + } + + // + // Delete all the private features generated by the Unidrv parser from the GPD. + // These are not required in the PrintCapabilities as they are only used to control + // features in the public PrintSchema and have no meaning outside the config + // module. + // + if (SUCCEEDED(hr)) + { + CPCHandler pcHandler(pPrintCapabilities); + hr = pcHandler.DeletePrivateFeatures(m_bstrPrivateNS); + } + } + catch (exception& DBG_ONLY(e)) + { + ERR(e.what()); + hr = E_FAIL; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CXDSmplPTProvider::ExpandIntentOptions + +Routine Description: + + As part of its Merge and Validate Procedure, the Unidrv/Postscript driver + will call this routine to give the plug-in a chance to expand options + which represent intent into their individual settings in other features + in the PrintTicket. This has two important effects: the client sees the + results of the intent expansion, and unidrv resolves constraints against + the individual features which are affected by the intent. + + The XPSDrv sample driver plug-in does not support any intent features, therefore + simply returns S_OK. + +Arguments: + + pPrintTicket - Pointer to input PrintTicket. + +Return Value: + + HRESULT + S_OK - Always + +--*/ +HRESULT STDMETHODCALLTYPE +CXDSmplPTProvider::ExpandIntentOptions( + _Inout_ IXMLDOMDocument2 * + ) +{ + return S_OK; +} + +/*++ + +Routine Name: + + CXDSmplPTProvider::ValidatePrintTicket + +Routine Description: + + The plug-in might need to delete any feature under private namespace + from input PT that are also in the public namespace because of Merge + and Validate. + + The Validate method should also perform any conflict resolution if + necessary looking at the settings made in public and unidrv private + part of PrintTicket, to make sure that the resultant PrintTicket is a + valid one, and has all constraints resolved. + + This routine merely passes the validate call on to the feature handlers + +Arguments: + + pPrintTicket - Pointer to input PrintTicket. + +Return Value: + + HRESULT + S_NO_CONFLICT/S_CONFLICT_RESOLVED - On success + E_* - On error + +--*/ +HRESULT STDMETHODCALLTYPE +CXDSmplPTProvider::ValidatePrintTicket( + _Inout_ IXMLDOMDocument2* pPrintTicket + ) +{ + HRESULT hr = S_NO_CONFLICT; + + // + // Validate parameters + // + if (pPrintTicket != NULL) + { + try + { + // + // Iterate over all PrintTicket feature converters letting them + // provide the validation + // + DMPTConvCollection::iterator iterConverters = m_vectFtrDMPTConverters.begin(); + + for (; iterConverters != m_vectFtrDMPTConverters.end() && SUCCEEDED(hr); iterConverters++) + { + HRESULT hrConverter = (*iterConverters)->ValidatePrintTicket(pPrintTicket); + + if (FAILED(hrConverter) || + hrConverter == static_cast(S_CONFLICT_RESOLVED)) + { + hr = hrConverter; + } + } + } + catch (...) + { + hr = E_FAIL; + } + } + else + { + hr = E_POINTER; + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CXDSmplPTProvider::DeleteConverters + +Routine Description: + + This routine cleans up the vector of DM <-> PT converters. + +Arguments: + + NONE + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CXDSmplPTProvider::DeleteConverters( + VOID + ) +{ + HRESULT hr = S_OK; + + try + { + while (!m_vectFtrDMPTConverters.empty()) + { + if (m_vectFtrDMPTConverters.back() != NULL) + { + delete m_vectFtrDMPTConverters.back(); + m_vectFtrDMPTConverters.back() = NULL; + } + + m_vectFtrDMPTConverters.pop_back(); + } + } + catch (exception& DBG_ONLY(e)) + { + ERR(e.what()); + hr = E_FAIL; + } + + ERR_ON_HR(hr); + return hr; +} + +// +// Use __drv_aliasesMem annotation to avoid PREfast warning 28197: Possibly leaking memory, +// +HRESULT +// Prefast warning 28194: The function was declared as aliasing the value in variable and exited without doing so. +// We suppress this false positive because STL vector does not have annotation, and we know the pointer has been saved +// to STL vector, which is released in DeleteConverters(). +#pragma warning(suppress: 28194) +CXDSmplPTProvider::AddConverter( + _In_opt_ __drv_aliasesMem IFeatureDMPTConvert *pHandler + ) +{ + HRESULT hr = CHECK_POINTER(pHandler, E_OUTOFMEMORY); + + if (SUCCEEDED(hr)) + { + m_vectFtrDMPTConverters.push_back(pHandler); + } + + return hr; +} diff --git a/print/XPSDrvSmpl/src/ui/xdsmplptprov.h b/print/XPSDrvSmpl/src/ui/xdsmplptprov.h new file mode 100644 index 00000000..3286944f --- /dev/null +++ b/print/XPSDrvSmpl/src/ui/xdsmplptprov.h @@ -0,0 +1,124 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + xdsmplptprov.h + +Abstract: + + Definition of the PrintTicket provider plugin. This is responsible for + handling PrintTicket features that are too complex for the GPD->PrintTicket + automapping facility. + +--*/ + +#pragma once + +#include "cunknown.h" +#include "schema.h" +#include "ftrdmptcnv.h" + +typedef vector DMPTConvCollection; + +class CXDSmplPTProvider : public CUnknown +{ +public: + CXDSmplPTProvider(); + + virtual ~CXDSmplPTProvider(); + + // + // IPrintOemPrintTicketProvider methods + // + virtual HRESULT STDMETHODCALLTYPE + GetSupportedVersions( + _In_ HANDLE hPrinter, + _Outptr_result_buffer_(*pcVersions) INT* ppVersions[], + _Out_ INT* pcVersions + ); + + virtual HRESULT STDMETHODCALLTYPE + BindPrinter( + _In_ HANDLE hPrinter, + INT version, + _Out_ POEMPTOPTS pOptions, + _Out_ INT* pcNamespaces, + _Outptr_result_buffer_maybenull_(*pcNamespaces) BSTR** ppNamespaces + ); + + virtual HRESULT STDMETHODCALLTYPE + PublishPrintTicketHelperInterface( + _In_ IUnknown* pHelper + ); + + virtual HRESULT STDMETHODCALLTYPE + QueryDeviceDefaultNamespace( + _Out_ BSTR* pbstrNamespaceUri + ); + + virtual HRESULT STDMETHODCALLTYPE + ConvertPrintTicketToDevMode( + _In_ IXMLDOMDocument2* pPrintTicket, + ULONG cbDevmode, + _Inout_updates_bytes_(cbDevmode) + PDEVMODE pDevmode, + ULONG cbDrvPrivateSize, + _Inout_ PVOID pPrivateDevmode + ); + + virtual HRESULT STDMETHODCALLTYPE + ConvertDevModeToPrintTicket( + ULONG cbDevmode, + _Inout_updates_bytes_(cbDevmode) + PDEVMODE pDevmode, + ULONG cbDrvPrivateSize, + _Inout_ PVOID pPrivateDevmode, + _Inout_ IXMLDOMDocument2* pPrintTicket + ); + + virtual HRESULT STDMETHODCALLTYPE + CompletePrintCapabilities( + _In_opt_ IXMLDOMDocument2* pPrintTicket, + _Inout_ IXMLDOMDocument2* pCapabilities + ); + + virtual HRESULT STDMETHODCALLTYPE + ExpandIntentOptions( + _Inout_ IXMLDOMDocument2* pPrintTicket + ); + + virtual HRESULT STDMETHODCALLTYPE + ValidatePrintTicket( + _Inout_ IXMLDOMDocument2* pPrintTicket + ); + +private: + HRESULT + DeleteConverters( + VOID + ); + + HRESULT + AddConverter( + _In_opt_ __drv_aliasesMem IFeatureDMPTConvert* pHandler + ); + +private: + HANDLE m_hPrinterCached; + + CComPtr m_pCoreHelper; + + DMPTConvCollection m_vectFtrDMPTConverters; + + CComBSTR m_bstrPrivateNS; +}; + diff --git a/print/XPSDrvSmpl/src/ui/xdsmplui.cpp b/print/XPSDrvSmpl/src/ui/xdsmplui.cpp new file mode 100644 index 00000000..b41116a6 --- /dev/null +++ b/print/XPSDrvSmpl/src/ui/xdsmplui.cpp @@ -0,0 +1,1018 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + xdsmplui.cpp + +Abstract: + + Implementation of the UI plugin. This is responsible for initialising and maintaining + the property pages used in the XPSDrv feature sample UI. + +--*/ + +#include "precomp.h" +#include "debug.h" +#include "globals.h" +#include "xdexcept.h" +#include "xdstring.h" +#include "xdsmplui.h" +#include "colppg.h" +#include "wmppg.h" +#include "ftrppg.h" +#include "UIProperties.h" + +/*++ + +Routine Name: + + CXDSmplUI::CXDSmplUI + +Routine Description: + + CXDSmplUI class constructor. + Creates a handler class object for every property page added in Unidrv UI Plug-in. + Each of these handlers is stored in a collection. + + +Arguments: + + None + +Return Value: + + None + +--*/ +CXDSmplUI::CXDSmplUI() : + CUnknown(IID_IPrintOemUI), + m_pDriverUIHelp(NULL), + m_pOemCUIPParam(NULL), + m_pUIProperties(NULL) +{ +} + +/*++ + +Routine Name: + + CXDSmplUI::~CXDSmplUI + +Routine Description: + + CXDSmplUI class destructor. + +Arguments: + + None + +Return Value: + + None. + +--*/ +CXDSmplUI::~CXDSmplUI() +{ + DestroyPropPages(); +} + +/*++ + +Routine Name: + + CXDSmplUI::PublishDriverInterface + +Routine Description: + + The PublishDriverInterface method allows a user interface plug-in to obtain + the Unidrv driver's IPrintOemDriverUI interface. + +Arguments: + + pIUnknown - Caller-supplied pointer to the IUnknown interface of the driver's + IPrintOemDriverUI COM Interface. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CXDSmplUI::PublishDriverInterface( + _In_ IUnknown* pIUnknown + ) +{ + HRESULT hr = E_FAIL; + PVOID pInterface = NULL; + + if (m_pDriverUIHelp == NULL && + SUCCEEDED(hr = pIUnknown->QueryInterface(IID_IPrintOemDriverUI, &pInterface))) + { + m_pDriverUIHelp = reinterpret_cast(pInterface); + hr = S_OK; + } + + return hr; +} + +/*++ + +Routine Name: + + CXDSmplUI::GetInfo + +Routine Description: + + Unidrv will call this routine to obtain identification information. + +Arguments: + + dwMode - Supported modes are OEMGI_GETSIGNATURE and OEMGI_GETVERSION. + pBuffer - Caller-supplied pointer to memory allocated to receive the information specified by dwMode. + cbSize - Caller-supplied size of the buffer pointed to by pBuffer. + pcbNeeded - Caller-supplied pointer to a location to receive the number of bytes written into the buffer pointed to by pBuffer. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CXDSmplUI::GetInfo( + _In_ DWORD dwMode, + _Out_writes_bytes_(cbSize) PVOID pBuffer, + _In_ DWORD cbSize, + _Out_ PDWORD pcbNeeded + ) +{ + HRESULT hr = S_OK; + + if ((NULL == pcbNeeded) || + ((OEMGI_GETSIGNATURE != dwMode) && + (OEMGI_GETVERSION != dwMode) && + (OEMGI_GETREQUESTEDHELPERINTERFACES != dwMode))) + { + SetLastError(ERROR_INVALID_PARAMETER); + hr = E_INVALIDARG; + } + else + { + *pcbNeeded = sizeof(DWORD); + + if ((cbSize < *pcbNeeded) || + (NULL == pBuffer)) + { + SetLastError(ERROR_INSUFFICIENT_BUFFER); + hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); + } + else + { + switch (dwMode) + { + case OEMGI_GETSIGNATURE: + { + *reinterpret_cast(pBuffer) = OEM_SIGNATURE; + } + break; + + case OEMGI_GETVERSION: + { + *reinterpret_cast(pBuffer) = OEM_VERSION; + } + break; + + default: + { + *pcbNeeded = 0; + hr = E_NOTIMPL; + } + break; + } + } + } + + ERR_ON_HR_EXC(hr, E_NOTIMPL); + return hr; +} + +/*++ + +Routine Name: + + CXDSmplUI::DevMode + +Routine Description: + + Performs operation on UI Plugins Private DevMode Members. + Called via IPrintOemUI::DevMode + +Arguments: + + dwMode - Supported modes are OEMDM_SIZE, OEMDM_DEFAULT, OEMDM_CONVERT and OEMDM_MERGE. + pOemDMParam - Caller-supplied pointer to an OEMDMPARAM structure. + Dependent on which dwMode is set. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CXDSmplUI::DevMode( + _In_ DWORD dwMode, + _In_ POEMDMPARAM pOemDMParam + ) +{ + HRESULT hr = S_OK; + + if (SUCCEEDED(hr = CHECK_POINTER(pOemDMParam, E_POINTER))) + { + if ((OEMDM_SIZE != dwMode) && + (OEMDM_DEFAULT != dwMode) && + (OEMDM_CONVERT != dwMode)&& + (OEMDM_MERGE != dwMode)) + { + hr = E_INVALIDARG; + } + } + + if (SUCCEEDED(hr)) + { + switch (dwMode) + { + // + // The method should return the size of the memory allocation needed to store the UI plugin Private DEVMODE. + // + case OEMDM_SIZE: + { + pOemDMParam->cbBufSize = sizeof(OEMDEV); + } + break; + + // + // Should fill the Private DEVMODE with the default values. + // + case OEMDM_DEFAULT: + { + try + { + if (SUCCEEDED(hr = CHECK_POINTER(pOemDMParam->pOEMDMOut, E_POINTER))) + { + CUIProperties oemDevOut = CUIProperties(reinterpret_cast(pOemDMParam->pOEMDMOut)); + + hr = oemDevOut.SetDefaults(); + } + } + catch (CXDException &e) + { + hr = e; + } + catch (...) + { + hr = E_FAIL; + } + } + break; + + // + // The method should convert private DEVMODE members to the current version, if necessary. + // + case OEMDM_CONVERT: + { + try + { + if (SUCCEEDED(hr = CHECK_POINTER(pOemDMParam->pOEMDMOut, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pOemDMParam->pOEMDMIn, E_POINTER))) + { + CUIProperties oemDevIn = CUIProperties(reinterpret_cast(pOemDMParam->pOEMDMIn)); + CUIProperties oemDevOut = CUIProperties(reinterpret_cast(pOemDMParam->pOEMDMOut)); + + hr = oemDevOut.Convert(&oemDevIn); + } + } + catch (CXDException &e) + { + hr = e; + } + catch (...) + { + hr = E_FAIL; + } + } + break; + + // + //The method should validate the information contained in private DEVMODE members and merge validated values into a private DEVMODE structure containing default values + // + case OEMDM_MERGE: + { + try + { + if (SUCCEEDED(hr = CHECK_POINTER(pOemDMParam->pOEMDMOut, E_POINTER)) && + SUCCEEDED(hr = CHECK_POINTER(pOemDMParam->pOEMDMIn, E_POINTER))) + { + CUIProperties oemDevIn = CUIProperties(reinterpret_cast(pOemDMParam->pOEMDMIn)); + CUIProperties oemDevOut = CUIProperties(reinterpret_cast(pOemDMParam->pOEMDMOut)); + + if (SUCCEEDED(hr = oemDevOut.Convert(&oemDevIn))) + { + hr = oemDevOut.Validate(); + } + } + } + catch (CXDException &e) + { + hr = e; + } + catch (...) + { + hr = E_FAIL; + } + } + break; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CXDSmplUI::CommonUIProp + +Routine Description: + + This method allows a user interface plug-in to modify an existing printer property sheet page. + +Arguments: + + dwMode - Supported modes are OEMCUIP_DOCPROP and OEMCUIP_PRNPROP. + pOemCUIPParam - Caller-supplied pointer to an OEMCUIPPARAM structure. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CXDSmplUI::CommonUIProp( + _In_ DWORD dwMode, + _In_ POEMCUIPPARAM pOemCUIPParam + ) +{ + HRESULT hr = S_OK; + + if (dwMode == OEMCUIP_PRNPROP) + { + // + // We do not implement any printer property sheets + // + hr = E_NOTIMPL; + } + else if (dwMode != OEMCUIP_DOCPROP) + { + // + // Unknown mode encountered + // + hr = E_INVALIDARG; + } + + if (SUCCEEDED(hr) && + SUCCEEDED(hr = CHECK_POINTER(pOemCUIPParam, E_POINTER))) + { + // + // Store the OEMCUIPPARAM pointer so we can modify data and OPTITEMS. + // + m_pOemCUIPParam = pOemCUIPParam; + + // + // The pDrvOptItems member is NULL on the first call through to CommonUIProp(). + // + if (pOemCUIPParam->pDrvOptItems != NULL) + { + try + { + CUIProperties uiProperties; + hr = uiProperties.HideOptItems(pOemCUIPParam); + } + catch (CXDException& e) + { + hr = e; + } + catch (...) + { + hr = E_FAIL; + } + } + } + + ERR_ON_HR_EXC(hr, E_NOTIMPL); + return hr; +} + +/*++ + +Routine Name: + + CXDSmplUI::DocumentPropertySheets + +Routine Description: + + This method allows a user interface plug-in to append a new page to a printer device's + document property sheet. + +Arguments: + + pPSUIInfo - Caller-supplied pointer to a PROPSHEETUI_INFO structure. + lParam - Caller-supplied value that depends on the reason value in pPSUIInfo->Reason. + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CXDSmplUI::DocumentPropertySheets( + _In_ PPROPSHEETUI_INFO pPSUIInfo, + _In_ LPARAM lParam + ) +{ + HRESULT hr = S_OK; + + if (pPSUIInfo == NULL || + pPSUIInfo->Version != PROPSHEETUI_INFO_VERSION) + { + SetLastError(ERROR_INVALID_PARAMETER); + hr = E_INVALIDARG; + } + else + { + switch (pPSUIInfo->Reason) + { + case PROPSHEETUI_REASON_INIT: + { + // + // We need to report the OEMCUIPPARAM structure to the prop sheet + // so ASSERT it is valid. We will let the prop sheet decide if it + // is critical to have a valid pointer or not + // + ASSERTMSG(m_pOemCUIPParam != NULL, "NULL pointer to OEMCUIPPARAM structure.\n"); + + try + { + // + // Create the UI properties object + // + m_pUIProperties = new(std::nothrow) CUIProperties(reinterpret_cast(m_pOemCUIPParam->pOEMDM)); + + // + // Create the property pages for the document property sheet + // + if (SUCCEEDED(hr = CHECK_POINTER(m_pUIProperties, E_OUTOFMEMORY)) && + SUCCEEDED(hr = CreatePropertyPages())) + { + DocPropertyPageMap::iterator iterPropSheets = m_vectPropPages.begin(); + + // + // Make sure the helper interfaces and the OEMCUIPPARAM structure + // are published to the page first. This allows the prop sheet to + // propogate these interfaces to the UI control objects when initializing + // + while (iterPropSheets != m_vectPropPages.end() && + SUCCEEDED(hr = CHECK_POINTER(*iterPropSheets, E_FAIL)) && + SUCCEEDED(hr = (*iterPropSheets)->SetPrintOemDriverUI(m_pDriverUIHelp)) && + SUCCEEDED(hr = (*iterPropSheets)->SetOemCUIPParam(m_pOemCUIPParam))&& + SUCCEEDED(hr = (*iterPropSheets)->SetUIProperties(m_pUIProperties))&& + SUCCEEDED(hr = (*iterPropSheets)->PropPageInit(pPSUIInfo))) + { + iterPropSheets++; + } + } + } + catch (CXDException &e) + { + hr = e; + } + catch (exception& DBG_ONLY(e)) + { + ERR(e.what()); + hr = E_FAIL; + } + } + break; + + case PROPSHEETUI_REASON_GET_INFO_HEADER: + { + if (SUCCEEDED(hr = CHECK_POINTER(pPSUIInfo, E_POINTER))) + { + pPSUIInfo->Result = TRUE; + } + } + break; + + case PROPSHEETUI_REASON_DESTROY: + { + if (SUCCEEDED(hr = CHECK_POINTER(pPSUIInfo, E_POINTER))) + { + pPSUIInfo->Result = TRUE; + } + } + break; + + case PROPSHEETUI_REASON_SET_RESULT: + { + if (SUCCEEDED(hr = CHECK_POINTER(pPSUIInfo, E_POINTER))) + { + pPSUIInfo->Result = reinterpret_cast(lParam)->Result; + } + } + break; + + case PROPSHEETUI_REASON_GET_ICON: + { + if (SUCCEEDED(hr = CHECK_POINTER(pPSUIInfo, E_POINTER))) + { + // + // No icon + // + pPSUIInfo->Result = FALSE; + } + } + break; + + default: + { + hr = E_FAIL; + } + break; + } + } + + ERR_ON_HR(hr); + return hr; +} + +/*++ + +Routine Name: + + CXDSmplUI::DevicePropertySheets + +Routine Description: + + This method allows a user interface plug-in to append a new page to a printer device's + printer property sheet. + +Arguments: + + None referenced. + +Return Value: + + HRESULT + E_NOTIMPL - Method not implemented + +--*/ +HRESULT +CXDSmplUI::DevicePropertySheets( + _In_ PPROPSHEETUI_INFO, + _In_ LPARAM + ) +{ + return E_NOTIMPL; +} + +/*++ + +Routine Name: + + CXDSmplUI::DevQueryPrintEx + +Routine Description: + + This method allows a user interface plug-in to help determine if a print job is printable. + +Arguments: + + None referenced. + +Return Value: + + HRESULT + E_NOTIMPL - Method not implemented + +--*/ +HRESULT +CXDSmplUI::DevQueryPrintEx( + _In_ POEMUIOBJ, + _In_ PDEVQUERYPRINT_INFO, + _In_ PDEVMODE, + _In_ PVOID + ) +{ + return E_NOTIMPL; +} + +/*++ + +Routine Name: + + CXDSmplUI::DeviceCapabilities + +Routine Description: + + This method enables a user interface plug-in to specify customized device capabilities. + +Arguments: + + None referenced. + +Return Value: + + HRESULT + E_NOTIMPL - Method not implemented + +--*/ +HRESULT +CXDSmplUI::DeviceCapabilities( + _In_ POEMUIOBJ, + _In_ HANDLE, + _In_z_ PWSTR, + _In_ WORD, + _In_ PVOID, + _In_ PDEVMODE, + _In_ PVOID, + _In_ DWORD, + _In_ DWORD* + ) +{ + return E_NOTIMPL; +} + +/*++ + +Routine Name: + + CXDSmplUI::UpgradePrinter + +Routine Description: + + This method allows a user interface plug-in to upgrade device option values + that are stored in the registry. + +Arguments: + + None referenced. + +Return Value: + + HRESULT + E_NOTIMPL - Method not implemented + +--*/ +HRESULT +CXDSmplUI::UpgradePrinter( + _In_ DWORD, + _In_ PBYTE + ) +{ + return E_NOTIMPL; +} + +/*++ + +Routine Name: + + CXDSmplUI::PrinterEvent + +Routine Description: + + This method allows a user interface plug-in to process printer events. + +Arguments: + + None referenced. + +Return Value: + + HRESULT + E_NOTIMPL - Method not implemented + +--*/ +HRESULT +CXDSmplUI::PrinterEvent( + _In_ PWSTR , + _In_ INT , + _In_ DWORD , + _In_ LPARAM + ) +{ + return E_NOTIMPL; +} + +/*++ + +Routine Name: + + CXDSmplUI::DriverEvent + +Routine Description: + + The printer driver's DrvDriverEvent function calls a user interface plug-in's + IPrintOemUI::DriverEvent method for additional processing of printer driver events. + +Arguments: + + None referenced. + +Return Value: + + HRESULT + E_NOTIMPL - Method not implemented + +--*/ +HRESULT +CXDSmplUI::DriverEvent( + _In_ DWORD , + _In_ DWORD , + _In_reads_(_Inexpressible_("varies")) PBYTE , + _In_ LPARAM + ) +{ + return E_NOTIMPL; +} + +/*++ + +Routine Name: + + CXDSmplUI::QueryColorProfile + +Routine Description: + + This method allows a user interface plug-in to specify an ICC profile to use for color management. + +Arguments: + + None referenced. + +Return Value: + + HRESULT + E_NOTIMPL - Method not implemented + +--*/ +HRESULT +CXDSmplUI::QueryColorProfile( + _In_ HANDLE , + _In_ POEMUIOBJ , + _In_ PDEVMODE , + _In_ PVOID , + _In_ ULONG , + _Out_writes_(*pcbProfileData) VOID* , + _Inout_ ULONG* pcbProfileData, + _Out_ FLONG* + ) +{ + UNREFERENCED_PARAMETER(pcbProfileData); + return E_NOTIMPL; +} + +/*++ + +Routine Name: + + CXDSmplUI::FontInstallerDlgProc + +Routine Description: + + A user interface plug-in's IPrintOemUI::FontInstallerDlgProc method replaces + the Unidrv font installer's user interface. + +Arguments: + + None referenced. + +Return Value: + + HRESULT + E_NOTIMPL - Method not implemented + +--*/ +HRESULT +CXDSmplUI::FontInstallerDlgProc( + _In_ HWND , + _In_ UINT , + _In_ WPARAM , + _In_ LPARAM + ) +{ + return E_NOTIMPL; +} + +/*++ + +Routine Name: + + CXDSmplUI::UpdateExternalFonts + +Routine Description: + + This allows a user interface plug-in to update a printer's Unidrv Font Format Files (.uff file). + +Arguments: + + None referenced. + +Return Value: + + HRESULT + E_NOTIMPL - Method not implemented + +--*/ +HRESULT +CXDSmplUI::UpdateExternalFonts( + _In_ HANDLE, + _In_ HANDLE, + _In_z_ PWSTR + ) +{ + return E_NOTIMPL; +} + +/*++ + +Routine Name: + + CXDSmplUI::CreatePropertyPages + +Routine Description: + + Creates all property page handler objects. + +Arguments: + + None + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +HRESULT +CXDSmplUI::CreatePropertyPages( + VOID + ) +{ + HRESULT hr = S_OK; + CDocPropPage* pPropPage = NULL; + +// +// This Prefast warning indicates that memory could be leaked +// in the event of an exception. We suppress this false positive because we +// know that the local try/catch block will clean up a single +// CDocPropPage, and the destructor will clean up any that are +// successfully added to the vector. +// +#pragma prefast(push) +#pragma prefast(disable:__WARNING_ALIASED_MEMORY_LEAK_EXCEPTION) + + try + { + // + // Populate the property page vector + // + pPropPage = new(std::nothrow) CColorPropPage(); + + hr = AddPropPage(pPropPage); + + if (SUCCEEDED(hr)) + { + pPropPage = new(std::nothrow) CWatermarkPropPage(); + hr = AddPropPage(pPropPage); + } + + if (SUCCEEDED(hr)) + { + pPropPage = new(std::nothrow) CFeaturePropPage(); + hr = AddPropPage(pPropPage); + } + } + catch (CXDException &e) + { + hr = e; + } + catch (exception& DBG_ONLY(e)) + { + ERR(e.what()); + hr = E_FAIL; + } + + if (FAILED(hr)) + { + // + // If we successfully created a property page but failed to push it onto + // the vector we need to free the allocated property page + // + if (pPropPage != NULL) + { + delete pPropPage; + pPropPage = NULL; + } + } + +#pragma prefast(pop) + + return hr; +} + +/*++ + +Routine Name: + + CXDSmplUI::DestroyPropPages + +Routine Description: + + Destroy all property page handler classes that have been added into the collection. + +Arguments: + + None + +Return Value: + + HRESULT + S_OK - On success + E_* - On error + +--*/ +inline VOID +CXDSmplUI::DestroyPropPages( + VOID + ) +{ + while (!m_vectPropPages.empty()) + { + if (m_vectPropPages.back() != NULL) + { + delete m_vectPropPages.back(); + m_vectPropPages.back() = NULL; + } + + m_vectPropPages.pop_back(); + } + + if (m_pUIProperties != NULL) + { + delete m_pUIProperties; + m_pUIProperties = NULL; + } +} + +// +// Use __drv_aliasesMem annotation to avoid PREfast warning 28197: Possibly leaking memory, +// +HRESULT +// Prefast warning 28194: The function was declared as aliasing the value in variable and exited without doing so. +// We suppress this false positive because STL vector does not have annotation, and we know the pointer has been saved +// to STL vector, which is released in DestroyPropPages(). +#pragma warning(suppress: 28194) +CXDSmplUI::AddPropPage( + _In_opt_ __drv_aliasesMem CDocPropPage* pPropPage + ) +{ + HRESULT hr = CHECK_POINTER(pPropPage, E_OUTOFMEMORY); + + if (SUCCEEDED(hr)) + { + m_vectPropPages.push_back(pPropPage); + } + + return hr; +} + diff --git a/print/XPSDrvSmpl/src/ui/xdsmplui.def b/print/XPSDrvSmpl/src/ui/xdsmplui.def new file mode 100644 index 00000000..dccec9d5 --- /dev/null +++ b/print/XPSDrvSmpl/src/ui/xdsmplui.def @@ -0,0 +1,23 @@ +; +; Copyright (c) 2005 Microsoft Corporation +; +; All rights reserved. +; +; THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +; ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +; THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +; PARTICULAR PURPOSE. +; +; File Name: +; +; xdsmplui.def +; +; Abstract: +; +; XPSDrv feature sample config plugin module definition file +; + +LIBRARY XDSmplUI +EXPORTS DllGetClassObject PRIVATE + DllCanUnloadNow PRIVATE + diff --git a/print/XPSDrvSmpl/src/ui/xdsmplui.h b/print/XPSDrvSmpl/src/ui/xdsmplui.h new file mode 100644 index 00000000..c175de88 --- /dev/null +++ b/print/XPSDrvSmpl/src/ui/xdsmplui.h @@ -0,0 +1,161 @@ +/*++ + +Copyright (c) 2005 Microsoft Corporation + +All rights reserved. + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +File Name: + + xdsmplui.h + +Abstract: + + Definition of the UI plugin. This is responsible for initialising and maintining + the property pages used in the XPSDrv feature sample UI. + +--*/ + +#pragma once + +#include "cunknown.h" +#include "docppg.h" + +typedef std::vector DocPropertyPageMap; + +class CXDSmplUI : public CUnknown +{ +public: + // + // Construction and Destruction + // + CXDSmplUI(); + + virtual ~CXDSmplUI(); + + // + // IPrintOemUI methods + // + STDMETHOD(PublishDriverInterface)(THIS_ + _In_ IUnknown* pIUnknown + ); + + STDMETHOD(GetInfo)(THIS_ + _In_ DWORD dwMode, + _Out_writes_bytes_(cbSize) PVOID pBuffer, + _In_ DWORD cbSize, + _Out_ PDWORD pcbNeeded + ); + + STDMETHOD(DevMode)(THIS_ + _In_ DWORD dwMode, + _In_ POEMDMPARAM pOemDMParam + ); + + STDMETHOD(CommonUIProp)(THIS_ + _In_ DWORD dwMode, + _In_ POEMCUIPPARAM pOemCUIPParam + ); + + STDMETHOD(DocumentPropertySheets)(THIS_ + _In_ PPROPSHEETUI_INFO pPSUIInfo, + _In_ LPARAM lParam + ); + + STDMETHOD(DevicePropertySheets)(THIS_ + _In_ PPROPSHEETUI_INFO pPSUIInfo, + _In_ LPARAM lParam + ); + + STDMETHOD(DevQueryPrintEx)(THIS_ + _In_ POEMUIOBJ poemuiobj, + _In_ PDEVQUERYPRINT_INFO pDQPInfo, + _In_ PDEVMODE pPublicDM, + _In_ PVOID pOEMDM + ); + + STDMETHOD(DeviceCapabilities)(THIS_ + _In_ POEMUIOBJ poemuiobj, + _In_ HANDLE hPrinter, + _In_z_ PWSTR pDeviceName, + _In_ WORD wCapability, + _In_ PVOID pOutput, + _In_ PDEVMODE pPublicDM, + _In_ PVOID pOEMDM, + _In_ DWORD dwOld, + _In_ DWORD* dwResult + ); + + STDMETHOD(UpgradePrinter)(THIS_ + _In_ DWORD dwLevel, + _In_ PBYTE pDriverUpgradeInfo + ); + + STDMETHOD(PrinterEvent)(THIS_ + _In_ PWSTR pPrinterName, + _In_ INT iDriverEvent, + _In_ DWORD dwFlags, + _In_ LPARAM lParam + ); + + STDMETHOD(DriverEvent)(THIS_ + _In_ DWORD dwDriverEvent, + _In_ DWORD dwLevel, + _In_reads_(_Inexpressible_("varies")) PBYTE pDriverInfo, + _In_ LPARAM lParam + ); + + STDMETHOD(QueryColorProfile)(THIS_ + _In_ HANDLE hPrinter, + _In_ POEMUIOBJ poemuiobj, + _In_ PDEVMODE pPublicDM, + _In_ PVOID pOEMDM, + _In_ ULONG ulReserved, + _Out_writes_(*pcbProfileData) VOID* pvProfileData, + _Inout_ ULONG* pcbProfileData, + _Out_ FLONG* pflProfileData + ); + + STDMETHOD(FontInstallerDlgProc)(THIS_ + _In_ HWND hWnd, + _In_ UINT usMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + + STDMETHOD(UpdateExternalFonts)(THIS_ + _In_ HANDLE hPrinter, + _In_ HANDLE hHeap, + _In_z_ PWSTR pwstrCartridges + ); + +private: + HRESULT + CreatePropertyPages( + VOID + ); + + HRESULT + AddPropPage( + _In_opt_ __drv_aliasesMem CDocPropPage* pPropPage + ); + + inline VOID + DestroyPropPages( + VOID + ); + +private: + POEMCUIPPARAM m_pOemCUIPParam; + + CUIProperties* m_pUIProperties; + + CComPtr m_pDriverUIHelp; + + DocPropertyPageMap m_vectPropPages; +}; + diff --git a/print/XPSDrvSmpl/src/ui/xdsmplui.vcxproj b/print/XPSDrvSmpl/src/ui/xdsmplui.vcxproj new file mode 100644 index 00000000..3183440c --- /dev/null +++ b/print/XPSDrvSmpl/src/ui/xdsmplui.vcxproj @@ -0,0 +1,367 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {20DDD6AA-CA85-46F3-8446-EDA619839273} + $(MSBuildProjectName) + false + true + Debug + Win32 + {8254BBF3-16D5-4993-9FDA-F4BD174AD743} + + + + Windows10 + False + Desktop + + WindowsApplicationForDrivers10.0 + DynamicLibrary + + + Windows10 + True + Desktop + + WindowsApplicationForDrivers10.0 + DynamicLibrary + + + Windows10 + False + Desktop + + WindowsApplicationForDrivers10.0 + DynamicLibrary + + + Windows10 + True + Desktop + + WindowsApplicationForDrivers10.0 + DynamicLibrary + + + + $(IntDir) + + + + + + + + + + + + + + + + + _DllMainCRTStartup@12 + _DllMainCRTStartup + + + + + _DllMainCRTStartup@12 + _DllMainCRTStartup + + + + + _DllMainCRTStartup@12 + _DllMainCRTStartup + + + + + _DllMainCRTStartup@12 + _DllMainCRTStartup + + + + + MultiThreaded + MultiThreadedDebug + true + Level4 + Sync + + + + + MultiThreaded + MultiThreadedDebug + true + Level4 + Sync + + + + + MultiThreaded + MultiThreadedDebug + true + Level4 + Sync + + + + + MultiThreaded + MultiThreadedDebug + true + Level4 + Sync + + + + xdsmplui + + + xdsmplui + + + xdsmplui + + + xdsmplui + + + + %(PreprocessorDefinitions);USERMODE_DRIVER;_UNICODE;UNICODE + %(PreprocessorDefinitions);PLUGIN_PRINTTICKET + %(AdditionalIncludeDirectories);..\inc;..\debug;..\common;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + %(PreprocessorDefinitions);USERMODE_DRIVER;_UNICODE;UNICODE + %(PreprocessorDefinitions);PLUGIN_PRINTTICKET + %(AdditionalIncludeDirectories);..\inc;..\debug;..\common;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + %(PreprocessorDefinitions);USERMODE_DRIVER;_UNICODE;UNICODE + %(PreprocessorDefinitions);PLUGIN_PRINTTICKET + %(AdditionalIncludeDirectories);..\inc;..\debug;..\common;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + %(AdditionalDependencies);kernel32.lib;user32.lib;winspool.lib;ole32.lib;oleaut32.lib;advapi32.lib;msxml6.lib;uuid.lib;Comdlg32.lib;.\..\debug\$(IntDir)\xdsdbg.lib;.\..\common\$(IntDir)\xdsmplcmn.lib + xdsmplui.def + + + + + %(PreprocessorDefinitions);USERMODE_DRIVER;_UNICODE;UNICODE + %(PreprocessorDefinitions);PLUGIN_PRINTTICKET + %(AdditionalIncludeDirectories);..\inc;..\debug;..\common;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + %(PreprocessorDefinitions);USERMODE_DRIVER;_UNICODE;UNICODE + %(PreprocessorDefinitions);PLUGIN_PRINTTICKET + %(AdditionalIncludeDirectories);..\inc;..\debug;..\common;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + %(PreprocessorDefinitions);USERMODE_DRIVER;_UNICODE;UNICODE + %(PreprocessorDefinitions);PLUGIN_PRINTTICKET + %(AdditionalIncludeDirectories);..\inc;..\debug;..\common;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + %(AdditionalDependencies);kernel32.lib;user32.lib;winspool.lib;ole32.lib;oleaut32.lib;advapi32.lib;msxml6.lib;uuid.lib;Comdlg32.lib;.\..\debug\$(IntDir)\xdsdbg.lib;.\..\common\$(IntDir)\xdsmplcmn.lib + xdsmplui.def + + + + + %(PreprocessorDefinitions);USERMODE_DRIVER;_UNICODE;UNICODE + %(PreprocessorDefinitions);PLUGIN_PRINTTICKET + %(AdditionalIncludeDirectories);..\inc;..\debug;..\common;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + %(PreprocessorDefinitions);USERMODE_DRIVER;_UNICODE;UNICODE + %(PreprocessorDefinitions);PLUGIN_PRINTTICKET + %(AdditionalIncludeDirectories);..\inc;..\debug;..\common;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + %(PreprocessorDefinitions);USERMODE_DRIVER;_UNICODE;UNICODE + %(PreprocessorDefinitions);PLUGIN_PRINTTICKET + %(AdditionalIncludeDirectories);..\inc;..\debug;..\common;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + %(AdditionalDependencies);kernel32.lib;user32.lib;winspool.lib;ole32.lib;oleaut32.lib;advapi32.lib;msxml6.lib;uuid.lib;Comdlg32.lib;.\..\debug\$(IntDir)\xdsdbg.lib;.\..\common\$(IntDir)\xdsmplcmn.lib + xdsmplui.def + + + + + %(PreprocessorDefinitions);USERMODE_DRIVER;_UNICODE;UNICODE + %(PreprocessorDefinitions);PLUGIN_PRINTTICKET + %(AdditionalIncludeDirectories);..\inc;..\debug;..\common;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + %(PreprocessorDefinitions);USERMODE_DRIVER;_UNICODE;UNICODE + %(PreprocessorDefinitions);PLUGIN_PRINTTICKET + %(AdditionalIncludeDirectories);..\inc;..\debug;..\common;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + %(PreprocessorDefinitions);USERMODE_DRIVER;_UNICODE;UNICODE + %(PreprocessorDefinitions);PLUGIN_PRINTTICKET + %(AdditionalIncludeDirectories);..\inc;..\debug;..\common;$(DDK_INC_PATH);$(SDK_INC_PATH)\gdiplus + + + %(AdditionalDependencies);kernel32.lib;user32.lib;winspool.lib;ole32.lib;oleaut32.lib;advapi32.lib;msxml6.lib;uuid.lib;Comdlg32.lib;.\..\debug\$(IntDir)\xdsdbg.lib;.\..\common\$(IntDir)\xdsmplcmn.lib + xdsmplui.def + + + + + ;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ;%(AdditionalIncludeDirectories) + precomp.h + Create + $(IntDir)\precomp.h.pch + + + ;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + ;%(AdditionalIncludeDirectories) + precomp.h + Use + $(IntDir)\precomp.h.pch + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/print/XPSDrvSmpl/src/ui/xdsmplui.vcxproj.Filters b/print/XPSDrvSmpl/src/ui/xdsmplui.vcxproj.Filters new file mode 100644 index 00000000..33559735 --- /dev/null +++ b/print/XPSDrvSmpl/src/ui/xdsmplui.vcxproj.Filters @@ -0,0 +1,84 @@ + + + + + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* + {7ABCDA75-F2B6-43F8-9F0C-5C23F4A47C6B} + + + h;hpp;hxx;hm;inl;inc;xsd + {C1E80132-1D96-4658-94D3-6D189ABDA762} + + + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml + {EFFEF9F4-65D8-4348-BF3A-8F4E00BA8219} + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Resource Files + + + \ No newline at end of file diff --git a/print/XpsRasFilter/XpsRasFilter.sln b/print/XpsRasFilter/XpsRasFilter.sln index 4adc144d..db7de92c 100644 --- a/print/XpsRasFilter/XpsRasFilter.sln +++ b/print/XpsRasFilter/XpsRasFilter.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xpsrasfilter", "src\xpsrasfilter.vcxproj", "{41965435-F4B0-495B-B669-2291F27F56B5}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xpsrasfilter", "src\xpsrasfilter.vcxproj", "{7D6A9E48-4B15-454E-846E-580BD64DDAF9}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +13,14 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {41965435-F4B0-495B-B669-2291F27F56B5}.Debug|Win32.ActiveCfg = Debug|Win32 - {41965435-F4B0-495B-B669-2291F27F56B5}.Debug|Win32.Build.0 = Debug|Win32 - {41965435-F4B0-495B-B669-2291F27F56B5}.Release|Win32.ActiveCfg = Release|Win32 - {41965435-F4B0-495B-B669-2291F27F56B5}.Release|Win32.Build.0 = Release|Win32 - {41965435-F4B0-495B-B669-2291F27F56B5}.Debug|x64.ActiveCfg = Debug|x64 - {41965435-F4B0-495B-B669-2291F27F56B5}.Debug|x64.Build.0 = Debug|x64 - {41965435-F4B0-495B-B669-2291F27F56B5}.Release|x64.ActiveCfg = Release|x64 - {41965435-F4B0-495B-B669-2291F27F56B5}.Release|x64.Build.0 = Release|x64 + {7D6A9E48-4B15-454E-846E-580BD64DDAF9}.Debug|Win32.ActiveCfg = Debug|Win32 + {7D6A9E48-4B15-454E-846E-580BD64DDAF9}.Debug|Win32.Build.0 = Debug|Win32 + {7D6A9E48-4B15-454E-846E-580BD64DDAF9}.Release|Win32.ActiveCfg = Release|Win32 + {7D6A9E48-4B15-454E-846E-580BD64DDAF9}.Release|Win32.Build.0 = Release|Win32 + {7D6A9E48-4B15-454E-846E-580BD64DDAF9}.Debug|x64.ActiveCfg = Debug|x64 + {7D6A9E48-4B15-454E-846E-580BD64DDAF9}.Debug|x64.Build.0 = Debug|x64 + {7D6A9E48-4B15-454E-846E-580BD64DDAF9}.Release|x64.ActiveCfg = Release|x64 + {7D6A9E48-4B15-454E-846E-580BD64DDAF9}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/print/XpsRasFilter/src/xpsrasfilter.vcxproj b/print/XpsRasFilter/src/xpsrasfilter.vcxproj index 48f9b603..94c791b0 100644 --- a/print/XpsRasFilter/src/xpsrasfilter.vcxproj +++ b/print/XpsRasFilter/src/xpsrasfilter.vcxproj @@ -19,11 +19,11 @@
- {41965435-F4B0-495B-B669-2291F27F56B5} + {7D6A9E48-4B15-454E-846E-580BD64DDAF9} $(MSBuildProjectName) Debug Win32 - {47DD7292-F334-4FEC-B539-B5D84A74585B} + {05F4D921-7C2D-4B7E-92D8-44E0887DBD76} diff --git a/print/XpsRasFilter/src/xpsrasfilter.vcxproj.Filters b/print/XpsRasFilter/src/xpsrasfilter.vcxproj.Filters index fdfc8758..e42cec79 100644 --- a/print/XpsRasFilter/src/xpsrasfilter.vcxproj.Filters +++ b/print/XpsRasFilter/src/xpsrasfilter.vcxproj.Filters @@ -3,15 +3,15 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {10F00C97-F803-43B8-994A-022AE3AA52E4} + {9A48947D-56D1-4B56-A0D9-6405186AF999} h;hpp;hxx;hm;inl;inc;xsd - {0422AF40-0146-47B2-BF48-C80A11C4F7F2} + {CE57A622-98E6-419C-A031-506952D9F0B2} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {1F07CF73-346E-4FF4-80B6-BC92C1A72B62} + {F6700635-AB37-4734-B021-AAA6C38430A0} diff --git a/print/autoconfig/ACnfgPS.gdl b/print/autoconfig/ACnfgPS.gdl new file mode 100644 index 00000000..e2fb2eb0 --- /dev/null +++ b/print/autoconfig/ACnfgPS.gdl @@ -0,0 +1,100 @@ +*%****************************************************************************************** +*% ACnfgPS.GDL +*% This file implements the *BidiQuery, *BidiResponse and *Option elements that correspond to +*% the InstalledMemory, DuplexUnit and HardDisk features in AutoCnfg.PPD file. The feature +*% name in the GDL file should exaclty match the corresponding feature and option names in the PPD. +*%****************************************************************************************** + + +%******************************************************************************************* +*% Memory +*% +*%****************************************************************************************** + +*Feature: InstalledMemory +{ + *FeatureType: PRINTER_PROPERTY + *BidiQuery: InstalledMemory + { + *QueryString: "\Printer.Configuration.Memory:Size" + } + + *BidiResponse: InstalledMemory + { + *ResponseType: BIDI_INT + *ResponseData: ENUM_OPTION(Memory) + } + *Option: 32Meg + { + *BidiValue: INT(32768) + } + *Option: 64Meg + { + *BidiValue: INT(65536) + } + *Option: 128Meg + { + *BidiValue: INT(131072) + } + *Option: 256Meg + { + *BidiValue: INT(262144) + } + +} + + +*%****************************************************************************************** +*% Duplex Unit +*%****************************************************************************************** + +*Feature: DuplexUnit +{ + *FeatureType: PRINTER_PROPERTY + *BidiQuery: DuplexUnit + { + *QueryString: "\Printer.Configuration.DuplexUnit:Installed" + } + + *BidiResponse: DuplexUnit + { + *ResponseType: BIDI_BOOL + *ResponseData: ENUM_OPTION(DuplexUnit) + } + + *Option: False + { + *BidiValue: BOOL(FALSE) + } + + *Option: True + { + *BidiValue: BOOL(TRUE) + } +} + +*%****************************************************************************************** +*% Hard Disk +*%****************************************************************************************** + +*Feature: HardDisk +{ + *FeatureType: PRINTER_PROPERTY + *BidiQuery:HardDisk + { + *QueryString: "\Printer.Configuration.HardDisk:Installed" + } + *BidiResponse: HardDisk + { + *ResponseType: BIDI_BOOL + *ResponseData: ENUM_OPTION(PrinterHardDisk) + } + *Option: False + { + *BidiValue: BOOL(FALSE) + } + *Option: True + { + *BidiValue: BOOL(TRUE) + } +} diff --git a/print/autoconfig/ACnfgUni.GDL b/print/autoconfig/ACnfgUni.GDL new file mode 100644 index 00000000..655b4cb2 --- /dev/null +++ b/print/autoconfig/ACnfgUni.GDL @@ -0,0 +1,111 @@ +*%****************************************************************************************** +*% ACnfgUni.GDL +*% This file implements the *BidiQuery, *BidiResponse and *Option elements that correspond +*% to the Memory,DuplexUnit and PrinterHardDisk features in AutoCnfg.GPD file. The feature +*% name in the GDL file should exaclty match the corresponding feature and option names in the GPD. +*%****************************************************************************************** + + +%******************************************************************************************* +*% Memory +*% +*%****************************************************************************************** + +*Feature: Memory +{ + *FeatureType: PRINTER_PROPERTY + *BidiQuery: Memory + { + *QueryString: "\Printer.Configuration.Memory:Size" + } + + *BidiResponse: Memory + { + *ResponseType: BIDI_INT + *ResponseData: ENUM_OPTION(Memory) + } + *Option: 16384KB + { + *BidiValue: INT(16384) + } + *Option: 24576KB + { + *BidiValue: INT(24576) + } + *Option: 32768KB + { + *BidiValue: INT(32768) + } + *Option: 49152KB + { + *BidiValue: INT(49152) + } + *Option: 65536KB + { + *BidiValue: INT(65536) + } + *Option: 98304KB + { + *BidiValue: INT(98304) + } + *Option: 131072KB + { + *BidiValue: INT(131072) + } +} + + +*%****************************************************************************************** +*% Duplex Unit +*%****************************************************************************************** + +*Feature: DuplexUnit +{ + *FeatureType: PRINTER_PROPERTY + *BidiQuery: DuplexUnit + { + *QueryString: "\Printer.Configuration.DuplexUnit:Installed" + } + + *BidiResponse: DuplexUnit + { + *ResponseType: BIDI_BOOL + *ResponseData: ENUM_OPTION(DuplexUnit) + } + + *Option: FALSE + { + *BidiValue: BOOL(FALSE) + } + + *Option: TRUE + { + *BidiValue: BOOL(TRUE) + } +} + +*%****************************************************************************************** +*% Hard Disk +*%****************************************************************************************** + +*Feature: PrinterHardDisk +{ + *FeatureType: PRINTER_PROPERTY + *BidiQuery:PrinterHardDisk + { + *QueryString: "\Printer.Configuration.HardDisk:Installed" + } + *BidiResponse: PrinterHardDisk + { + *ResponseType: BIDI_BOOL + *ResponseData: ENUM_OPTION(PrinterHardDisk) + } + *Option: FALSE + { + *BidiValue: BOOL(FALSE) + } + *Option: TRUE + { + *BidiValue: BOOL(TRUE) + } +} diff --git a/print/autoconfig/AutoCnfg.GPD b/print/autoconfig/AutoCnfg.GPD new file mode 100644 index 00000000..a9eb8b6f --- /dev/null +++ b/print/autoconfig/AutoCnfg.GPD @@ -0,0 +1,733 @@ +*Include: "stdnames.gpd" +*Include: "ttfsub.gpd" + +*ModelName: "Unidrv AutoConfiguration Sample" +*PrinterType: PAGE +*GPDSpecVersion: "1.0" + +*MasterUnits: PAIR(1200, 1200) +*ResourceDLL: "pcl5eres.dll" +*MaxCopies: 32767 + + +*GPDFileName: "autocnfg.gpd" +*GPDFileVersion: "1.0" +*Personality: =PERSONALITY_PCL_DISPLAY +*PrintRatePPM: 16 + +*%****************************************************************************************** +*% Common Resources +*%****************************************************************************************** +*ResourceDLL: "pcl5eres.dll" +*ResourceDLL: "unires.dll" + +*Feature: RESDLL +{ + *Option: PCL5ERES + { + *Name: "pcl5eres.dll" + } +} + + +*rcInstalledOptionNameID: RESDLL.PCL5ERES.443 *% Installed +*rcNotInstalledOptionNameID: RESDLL.PCL5ERES.444 *% Not Installed + +*%****************************************************************************************** +*% Specify ACnfgUni.GDL as the Bidi query file which has the GDL extensions for +*% Autoconfig corresponding to the Memory,DuplexUnit and PrinterHardDisk features. The +*% GDL extensions can also be put in the GPD file itself instead of in a separate GDL +*% file. Using a separate GDL file reduces the amount of change in the original GPD +*% file, thereby reducing the chances for unintended alteration of the existing GPD data. +*%****************************************************************************************** + +*Ifdef: WINNT_60 +*BidiQueryFile: "ACnfgUni.GDL" +*Endif: WINNT_60 + +*%****************************************************************************************** +*% HP-GL/2 Graphics Support +*%****************************************************************************************** +*Ifdef: WINNT_51 +*Personality: =PERSONALITY_HPGL2 +*Feature: GraphicsMode +{ + *rcNameID: =GRAPHICSMODE_DISPLAY + *DefaultOption: RASTERMODE + *Option: HPGL2MODE + { + *rcNameID: =GRAPHICSMODE_HPGL2_DISPLAY + } + *Option: RASTERMODE + { + *rcNameID: =GRAPHICSMODE_RASTER_DISPLAY + *Command: CmdSelect + { + *Order: DOC_SETUP.3 + *Cmd: "@PJL SET LIMAGEENHANCE=OFF<0A>" + } + } +} +*Endif: + + + +*%****************************************************************************************** +*% Orientation +*%****************************************************************************************** +*Feature: Orientation +{ + *rcNameID: =ORIENTATION_DISPLAY + *DefaultOption: PORTRAIT + *Option: PORTRAIT + { + *rcNameID: =PORTRAIT_DISPLAY + *Command: CmdSelect + { + *Order: DOC_SETUP.8 + *NoPageEject?: TRUE + *Cmd: "<1B>&l0o1E" + } + } + *Option: LANDSCAPE_CC90 + { + *rcNameID: =LANDSCAPE_DISPLAY + *Command: CmdSelect + { + *Order: DOC_SETUP.8 + *NoPageEject?: TRUE + *Cmd: "<1B>&l1o1E" + } + } +} + +*%****************************************************************************************** +*% Input Bin +*%****************************************************************************************** +*Feature: InputBin +{ + *rcNameID: =PAPER_SOURCE_DISPLAY + *DefaultOption: AUTO + *Option: AUTO + { + *rcNameID: =AUTO_DISPLAY + *Command: CmdSelect + { + *Order: DOC_SETUP.11 + *Cmd: "<1B>&l7H" + } + } + *Option: UPPER + { + *rcNameID: =UPPER_TRAY_DISPLAY + *Command: CmdSelect + { + *Order: DOC_SETUP.11 + *Cmd: "<1B>&l1H" + } + } + *Option: LOWER + { + *rcNameID: =LOWER_TRAY_DISPLAY + *Command: CmdSelect + { + *Order: DOC_SETUP.11 + *Cmd: "<1B>&l1H" + } + } + *Option: ENVELOPE + { + *rcNameID: =ENV_FEED_DISPLAY + *Command: CmdSelect + { + *Order: DOC_SETUP.11 + *Cmd: "<1B>&l6H" + } + } + *Option: MANUAL + { + *rcNameID: =MANUAL_FEED_DISPLAY + *Command: CmdSelect + { + *Order: DOC_SETUP.11 + *Cmd: "<1B>&l2H" + } + } +} + +*%****************************************************************************************** +*% Resolution +*%****************************************************************************************** +*Feature: Resolution +{ + *rcNameID: =RESOLUTION_DISPLAY + *DefaultOption: 600_DPI + *Option: 600_DPI + { + *Name: "600 x 600 " =DOTS_PER_INCH + *DPI: PAIR(600, 600) + *TextDPI: PAIR(600, 600) + *MinStripBlankPixels: 32 + EXTERN_GLOBAL: *StripBlanks: LIST(ENCLOSED,TRAILING) + *SpotDiameter: 100 + *Command: CmdBeginRaster { *Cmd : "<1B>*r1A" } + *Command: CmdEndRaster { *Cmd : "<1B>*rB" } + *Command: CmdSendBlockData { *Cmd : "<1B>*b" %d{NumOfDataBytes}"W" } + *Command: CmdSelect + { + *Order: DOC_SETUP.5 + *Cmd: "@PJL SET RESOLUTION=600<0A>@PJL ENTER LANGUAGE=PCL<0A0D1B>E<1B>*t600R" + } + } + *Option: 300_DPI + { + *Name: "300 x 300 " =DOTS_PER_INCH + *DPI: PAIR(300, 300) + *TextDPI: PAIR(300, 300) + *MinStripBlankPixels: 32 + EXTERN_GLOBAL: *StripBlanks: LIST(ENCLOSED, TRAILING) + *SpotDiameter: 100 + *Command: CmdBeginRaster { *Cmd : "<1B>*r1A" } + *Command: CmdEndRaster { *Cmd : "<1B>*rB" } + *Command: CmdSendBlockData { *Cmd : "<1B>*b" %d{NumOfDataBytes}"W" } + *Command: CmdSelect + { + *Order: DOC_SETUP.5 + *Cmd: "@PJL SET RESOLUTION=300<0A>@PJL ENTER LANGUAGE=PCL<0A0D1B>E<1B>*t300R" + } + } + *Option: 150_DPI + { + *Name: "150 x 150 " =DOTS_PER_INCH + *DPI: PAIR(150, 150) + *TextDPI: PAIR(150, 150) + *MinStripBlankPixels: 32 + EXTERN_GLOBAL: *StripBlanks: LIST(ENCLOSED, TRAILING) + *SpotDiameter: 100 + *Command: CmdBeginRaster { *Cmd : "<1B>*r1A" } + *Command: CmdEndRaster { *Cmd : "<1B>*rB" } + *Command: CmdSendBlockData { *Cmd : "<1B>*b" %d{NumOfDataBytes}"W" } + *Command: CmdSelect + { + *Order: DOC_SETUP.5 + *Cmd: "@PJL SET RESOLUTION=150<0A>@PJL ENTER LANGUAGE=PCL<0A0D1B>E<1B>*t150R" + } + } +} + +*%****************************************************************************************** +*% Paper Size +*%****************************************************************************************** +*Feature: PaperSize +{ + *rcNameID: =PAPER_SIZE_DISPLAY + *DefaultOption: LETTER + *Option: LETTER + { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *PageProtectMem: 1028 + *switch: Orientation + { + *case: PORTRAIT + { + *PrintableArea: PAIR(9500, 12500) + *PrintableOrigin: PAIR(400, 400) + *CursorOrigin: PAIR(300, 300) + *Command: CmdSelect + { + *Order: DOC_SETUP.12 + *Cmd: "<1B>&l2a8c1E<1B>*p0x0Y<1B>*c0t5260x7704Y" + } + } + *case: LANDSCAPE_CC90 + { + *PrintableArea: PAIR(9500, 12200) + *PrintableOrigin: PAIR(450, 300) + *CursorOrigin: PAIR(200, 12900) + *Command: CmdSelect + { + *Order: DOC_SETUP.12 + *Cmd: "<1B>&l2a8c1E<1B>*p0x0Y<1B>*c0t7332x5880Y" + } + } + } + } + *Option: LEGAL + { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *PageProtectMem: 1692 + *switch: Orientation + { + *case: PORTRAIT + { + *PrintableArea: PAIR(9000, 15500) + *PrintableOrigin: PAIR(400, 600) + *CursorOrigin: PAIR(180, 300) + *Command: CmdSelect + { + *Order: DOC_SETUP.12 + *Cmd: "<1B>&l3a8c1E<1B>*p0x0Y<1B>*c0t5880x8900Y" + } + } + *case: LANDSCAPE_CC90 + { + *PrintableArea: PAIR(9000, 15500) + *PrintableOrigin: PAIR(400, 900) + *CursorOrigin: PAIR(180, 16500) + *Command: CmdSelect + { + *Order: DOC_SETUP.12 + *Cmd: "<1B>&l3a8c1E<1B>*p0x0Y<1B>*c0t8900x5880Y" + } + } + } + } + *Option: EXECUTIVE + { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *PageProtectMem: 4109 + *switch: Orientation + { + *case: PORTRAIT + { + *PrintableArea: PAIR(8100, 11500) + *PrintableOrigin: PAIR(300, 300) + *CursorOrigin: PAIR(300, 200) + *Command: CmdSelect + { + *Order: DOC_SETUP.12 + *Cmd: "<1B>&l1a8c1E<1B>*p0x0Y<1B>*c0t4860x7344Y" + } + } + *case: LANDSCAPE_CC90 + { + *PrintableArea: PAIR(8300, 11500) + *PrintableOrigin: PAIR(200, 300) + *CursorOrigin: PAIR(200, 12300) + *Command: CmdSelect + { + *Order: DOC_SETUP.12 + *Cmd: "<1B>&l1a8c1E<1B>*p0x0Y<1B>*c0t7272x4980Y" + } + } + } + } + *Option: A4 + { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *PageProtectMem: 4249 + *switch: Orientation + { + *case: PORTRAIT + { + *PrintableArea: PAIR(9100, 13200) + *PrintableOrigin: PAIR(400, 300) + *CursorOrigin: PAIR(288, 180) + *Command: CmdSelect + { + *Order: DOC_SETUP.12 + *Cmd: "<1B>&l26a8c1E<1B>*p0x0Y<1B>*c0t5594x8201Y" + } + } + *case: LANDSCAPE_CC90 + { + *PrintableArea: PAIR(9100, 13200) + *PrintableOrigin: PAIR(400, 300) + *CursorOrigin: PAIR(204, 13824) + *Command: CmdSelect + { + *Order: DOC_SETUP.12 + *Cmd: "<1B>&l26a8c1E<1B>*p0x0Y<1B>*c0t8129x5714Y" + } + } + } + } + *Option: B5 + { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *PageProtectMem: 3198 + *switch: Orientation + { + *case: PORTRAIT + { + *PrintableArea: PAIR(7900, 11140) + *PrintableOrigin: PAIR(352, 300) + *CursorOrigin: PAIR(300, 100) + *Command: CmdSelect + { + *Order: DOC_SETUP.12 + *Cmd: "<1B>&l12a8c1E<1B>*p0x0Y<1B>*c0t4970x7040Y" + } + } + *case: LANDSCAPE_CC90 + { + *PrintableArea: PAIR(7760, 11140) + *PrintableOrigin: PAIR(300, 400) + *CursorOrigin: PAIR(100, 11940) + *Command: CmdSelect + { + *Order: DOC_SETUP.12 + *Cmd: "<1B>&l12a8c1E<1B>*p0x0Y<1B>*c0t6780x4970Y" + } + } + } + } +} + +*%****************************************************************************************** +*% Media Type +*%****************************************************************************************** +*Feature: MediaType +{ + *rcNameID: =MEDIA_TYPE_DISPLAY + *DefaultOption: PLAIN + *Option: PLAIN + { + *rcNameID: =PLAIN_PAPER_DISPLAY + *Command: CmdSelect + { + *Order: DOC_SETUP.15 + *Cmd: "<1B>&n6WdPlain" + } + } + *Option: TRANSPARENCY + { + *rcNameID: =TRANSPARENCY_DISPLAY + *Command: CmdSelect + { + *Order: DOC_SETUP.15 + *Cmd: "<1B>&n13WdTransparency" + } + } +} + +*%****************************************************************************************** +*% Color Mode +*%****************************************************************************************** +*Feature: ColorMode +{ + *rcNameID: =COLOR_PRINTING_MODE_DISPLAY + *DefaultOption: 24bpp + *Option: Mono + { + *rcNameID: =MONO_DISPLAY + *DevNumOfPlanes: 1 + *DevBPP: 1 + *Color?: FALSE + } + *Option: 24bpp + { + *rcNameID: =24BPP_DISPLAY + *DevNumOfPlanes: 1 + *DevBPP: 24 + *DrvBPP: 24 +*% *Command: CmdEnableDRC { *Cmd : "<1B>*b3M" } + *PaletteSize: 256 + *PaletteProgrammable? : TRUE + *Command: CmdDefinePaletteEntry + { + *Cmd : "<1B>*v" %d{RedValue}"a" ++ %d{GreenValue}"b" ++ %d{BlueValue}"c" ++ %d{PaletteIndexToProgram}"I" + } + *Command: CmdSelectPaletteEntry { *Cmd : "<1B>*v" %d{CurrentPaletteIndex}"S" } + *Command: CmdSetSrcBmpWidth { *Cmd : "<1B>*r" %d{RasterDataWidthInBytes / 3}"S" } + *Command: CmdSelect + { + *Order: PAGE_SETUP.16 + *Cmd: "<1B>*v1N<1B>*v1O<1B>*l184O<1B>*v6W<000308080808><1B>*v0a0b0c7i255a255b255c0I<1B>*o3W<060406>" + } + } +} + +*%****************************************************************************************** +*% HalfTone +*%****************************************************************************************** +*Feature: Halftone +{ + *rcNameID: =HALFTONING_DISPLAY + *DefaultOption: HT_PATSIZE_AUTO + *Option: HT_PATSIZE_AUTO + { + *rcNameID: =HT_AUTO_SELECT_DISPLAY + } + *Option: HT_PATSIZE_SUPERCELL_M + { + *rcNameID: =HT_SUPERCELL_DISPLAY + } + *Option: HT_PATSIZE_6x6_M + { + *rcNameID: =HT_DITHER6X6_DISPLAY + } + *Option: HT_PATSIZE_8x8_M + { + *rcNameID: =HT_DITHER8X8_DISPLAY + } +} + +*%****************************************************************************************** +*% Memory +*% +*% Note: Unidrv uses the font memory information to estimate when it needs to stop +*% downloading fonts for a page, and thus driver writers should err on the conservative +*% side. Otherwise, printers will generate "out of memory" device errors for pages with +*% a large number of fonts / unique glyphs. +*%****************************************************************************************** +*Feature: Memory +{ + *rcNameID: =PRINTER_MEMORY_DISPLAY + *FeatureType: PRINTER_PROPERTY + *DefaultOption: 32768KB + *Option: 16384KB + { + *Name: "16MB" + *MemoryConfigKB: PAIR(16384, 13950) + } + *Option: 24576KB + { + *Name: "24MB" + *MemoryConfigKB: PAIR(24576, 21150) + } + *Option: 32768KB + { + *Name: "32MB" + *MemoryConfigKB: PAIR(32768, 28350) + } + *Option: 49152KB + { + *Name: "48MB" + *MemoryConfigKB: PAIR(49152, 43050) + } + *Option: 65536KB + { + *Name: "64MB" + *MemoryConfigKB: PAIR(65536, 57150) + } + *Option: 98304KB + { + *Name: "96MB" + *MemoryConfigKB: PAIR(98304, 85950) + } + *Option: 131072KB + { + *Name: "128MB" + *MemoryConfigKB: PAIR(131072, 116250) + } +} + + +*%****************************************************************************************** +*% Duplex Unit +*%****************************************************************************************** +*Feature: DuplexUnit +{ + *rcNameID: RESDLL.PCL5ERES.429 + *FeatureType: PRINTER_PROPERTY + *DefaultOption: FALSE + *Option: FALSE + { + *rcNameID: RESDLL.PCL5ERES.444 + *DisabledFeatures: LIST(Duplex) + *Constraints: LIST(Duplex.VERTICAL, Duplex.HORIZONTAL) + } + *Option: TRUE + { + *rcNameID: RESDLL.PCL5ERES.443 + } +} + + +*%****************************************************************************************** +*% Duplex Type +*%****************************************************************************************** +*Feature: Duplex +{ + *rcNameID: =TWO_SIDED_PRINTING_DISPLAY + *DefaultOption: NONE + *Option: NONE + { + *rcNameID: =NONE_DISPLAY + *Command: CmdSelect + { + *Order: DOC_SETUP.9 + *Cmd: "<1B>&l0S" + } + } + *Option: VERTICAL + { + *rcNameID: =FLIP_ON_LONG_EDGE_DISPLAY + *Command: CmdSelect + { + *Order: DOC_SETUP.9 + *Cmd: "<1B>&l1S" + } + } + *Option: HORIZONTAL + { + *rcNameID: =FLIP_ON_SHORT_EDGE_DISPLAY + *Command: CmdSelect + { + *Order: DOC_SETUP.9 + *Cmd: "<1B>&l2S" + } + } +} + +*%****************************************************************************************** +*% Hard Disk +*%****************************************************************************************** +*Feature: PrinterHardDisk +{ + *rcNameID: RESDLL.PCL5ERES.430 + *FeatureType: PRINTER_PROPERTY + *DefaultOption: FALSE + *Option: FALSE + { + *rcNameID: RESDLL.PCL5ERES.444 + } + *Option: TRUE + { + *rcNameID: RESDLL.PCL5ERES.443 + } +} + + +*%****************************************************************************************** +*% Page Protect +*%****************************************************************************************** +*Feature: PageProtect +{ + *rcNameID: =PAGE_PROTECTION_DISPLAY + *DefaultOption: OFF + *Option: ON + { + *rcNameID: =ON_DISPLAY + *Command: CmdSelect + { + *Order: DOC_SETUP.1 + *Cmd: "@PJL SET PAGEPROTECT=ON<0A>" + } + } + *Option: OFF + { + *rcNameID: =OFF_DISPLAY + *Command: CmdSelect + { + *Order: DOC_SETUP.1 + *Cmd: "@PJL SET PAGEPROTECT=OFF<0A>" + } + } +} + +*%****************************************************************************************** +*% Doc setup commands +*%****************************************************************************************** +*Command: CmdStartDoc +{ + *Order: DOC_SETUP.7 + *Cmd: "<1B>&u1200D<1B>*r0F" +} +*Command: CmdStartPage +{ + *Order: PAGE_SETUP.1 + *Cmd: "<1B>*b0M<0D>" +} +*Command: CmdEndJob +{ + *Order: JOB_FINISH.1 + *Cmd: "<1B>E<1B>%%-12345X@PJL<20>LPORTROTATE<0A><1B>%%-12345X" +} +*Command: CmdCopies +{ + *Order: DOC_SETUP.13 + *Cmd: "<1B>&l" %d{NumOfCopies}"X" +} + +*%****************************************************************************************** +*% Cursor, Page and Color Commands +*%****************************************************************************************** +*RotateCoordinate?: TRUE +*RotateRaster?: TRUE +*RotateFont?: TRUE +*TextCaps: LIST(TC_CR_90,TC_UA_ABLE) +*MemoryUsage: LIST(FONT, RASTER, VECTOR) +*CursorXAfterCR: AT_PRINTABLE_X_ORIGIN +*BadCursorMoveInGrxMode: LIST(X_PORTRAIT,Y_LANDSCAPE) +*XMoveThreshold: 0 +*YMoveThreshold: 0 +*XMoveUnit: 300 +*YMoveUnit: 300 +*Command: CmdXMoveAbsolute { *Cmd : "<1B>*p" %d{(DestX) }"X" } +*Command: CmdXMoveRelRight { *Cmd : "<1B>*p+" %d[0,9600]{max_repeat((DestXRel) )}"X" } +*Command: CmdXMoveRelLeft { *Cmd : "<1B>*p-" %d[0,9600]{max_repeat((DestXRel) )}"X" } +*Command: CmdYMoveAbsolute { *Cmd : "<1B>*p" %d{(DestY) }"Y" } +*Command: CmdYMoveRelDown { *Cmd : "<1B>*p+" %d{(DestYRel) }"Y" } +*Command: CmdYMoveRelUp { *Cmd : "<1B>*p-" %d{(DestYRel) }"Y" } +*Command: CmdDefinePaletteEntry { *Cmd : "<1B>*v" %d{RedValue}"a" %d{GreenValue}"b" %d{BlueValue}"c" ++ %d{PaletteIndexToProgram} "I" } +*Command: CmdSelectPaletteEntry { *Cmd : "<1B>*v" %d{CurrentPaletteIndex}"S" } +*Command: CmdCR { *Cmd : "<0D>" } +*Command: CmdLF { *Cmd : "<0A>" } +*Command: CmdFF { *Cmd : "<0C>" } +*Command: CmdBackSpace { *Cmd : "<08>" } +*Command: CmdUniDirectionOn { *Cmd : "<00>" } +*Command: CmdUniDirectionOff { *Cmd : "<00>" } +*Command: CmdPushCursor { *Cmd : "<1B>&f0S" } +*Command: CmdPopCursor { *Cmd : "<1B>&f1S" } +*Command: CmdSetSimpleRotation { *Cmd : "<1B>&a" %d{PrintDirInCCDegrees}"P" } +*EjectPageWithFF?: TRUE +*Command: CmdEnableTIFF4 { *Cmd : "<1B>*b2M" } +*Command: CmdDisableCompression { *Cmd : "<1B>*b0M" } +*OutputDataFormat: H_BYTE +*OptimizeLeftBound?: TRUE +*CursorXAfterSendBlockData: AT_GRXDATA_ORIGIN +*CursorYAfterSendBlockData: AUTO_INCREMENT + +*%****************************************************************************************** +*% Font Descriptions and Commands +*%****************************************************************************************** +*TTFSEnabled?: TRUE +*DefaultFont: 136 +*DefaultCTT: 0 +*CharPosition: BASELINE +*DeviceFonts: LIST(136,138,146,147,148,149,150,151,152,153,154,155,156,157, ++ 163,164,165,166,196,197,198,199,200,201,202,203,209,210, ++ 211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226, ++ 227,228,229,230) +*MinFontID: 16534 +*MaxFontID: 32768 +*switch: Resolution +{ + *case: 600_DPI + { + *FontFormat: HPPCL_OUTLINE + } + *case: 300_DPI + { + *FontFormat: HPPCL_OUTLINE + } + *case: 150_DPI + { + *FontFormat: HPPCL_RES + } +} +*Command: CmdSetFontID { *Cmd : "<1B>*c" %d{NextFontID}"D" } +*Command: CmdSelectFontID { *Cmd : "<1B>(" %d{CurrentFontID}"X" } +*Command: CmdSetCharCode { *Cmd : "<1B>*c" %d{NextGlyph}"E" } +*Command: CmdUnderlineOn { *Cmd : "<1B>&dD" } +*Command: CmdUnderlineOff { *Cmd : "<1B>&d@" } +*Command: CmdWhiteTextOn { *Cmd : "<1B>*v1o1T" } +*Command: CmdWhiteTextOff { *Cmd : "<1B>*v0o0T" } + + +*%******************************************************************************************** +*%* Vector Commands. +*%******************************************************************************************** +*MinGrayFill: 1 +*MaxGrayFill: 100 +*Command: CmdSetRectWidth { *Cmd : "<1B>*c" %d{(RectXSize) }"A" } +*Command: CmdSetRectHeight { *Cmd : "<1B>*c" %d{(RectYSize) }"B" } +*Command: CmdRectGrayFill { *Cmd : "<1B>*c" %d{GrayPercentage }"g2P" } +*Command: CmdRectWhiteFill { *Cmd : "<1B>*c1P" } +*Command: CmdRectBlackFill { *Cmd : "<1B>*c0P" } diff --git a/print/autoconfig/AutoCnfg.PPD b/print/autoconfig/AutoCnfg.PPD new file mode 100644 index 00000000..e6591b8c --- /dev/null +++ b/print/autoconfig/AutoCnfg.PPD @@ -0,0 +1,479 @@ +*PPD-Adobe: "4.3" +*% Adobe Systems PostScript(R) Printer Description File +*% Copyright (c) 2005 Microsoft Corp. All rights reserved. + +*FormatVersion: "4.3" +*FileVersion: "2.0" +*LanguageEncoding: ISOLatin1 +*LanguageVersion: English +*Product: "(PostScript AutoConfiguration)" +*PSVersion: "(2015.105) 9" +*Manufacturer: "Microsoft" +*ModelName: "PostScript AutoConfiguration Sample" +*ShortNickName: "PostScript AutoConfiguration" +*NickName: "PostScript AutoConfiguration" +*PCFileName: "AutoCnfg.PPD" + +*MSBidiQueryFile: "ACnfgPS.GDL" + +*% === Installable Options =========== +*OpenGroup: InstallableOptions/Options Installed + +*OpenUI *DuplexUnit/Duplex Unit: Boolean +*DefaultDuplexUnit: False +*DuplexUnit True/Installed: "" +*DuplexUnit False/Not Installed: "" +*CloseUI: *DuplexUnit + +*OpenUI *HardDisk/Printer Hard Disk: Boolean +*DefaultHardDisk: False +*HardDisk True/Installed: "" +*HardDisk False/Not Installed: "" +*CloseUI: *HardDisk + +*OpenUI *InstalledMemory/Printer Memory: PickOne +*DefaultInstalledMemory: 32Meg +*InstalledMemory 32Meg/32 MB: "" +*InstalledMemory 64Meg/64 MB: "" +*InstalledMemory 128Meg/128 MB: "" +*InstalledMemory 256Meg/256 MB: "" +*CloseUI: *InstalledMemory + +*CloseGroup: InstallableOptions + +*% === Constraints =================== + + +*% === Basic Device Capabilities ============ + +*LanguageLevel: "2" +*Protocols: BCP + +*FreeVM: "6666752" +*VMOption 32Meg/32 MB: "6609408" +*VMOption 64Meg/64 MB: "6666752" +*VMOption 128Meg/128 MB: "9705984" +*VMOption 256Meg/256 MB: "13736448" + + +*ColorDevice: True +*DefaultColorSpace: CMYK +*AccurateScreensSupport: True +*SuggestedJobTimeout: "0" +*SuggestedWaitTimeout: "300" +*SuggestedManualFeedTimeout: "60" +*End +*TTRasterizer: Type42 +*?TTRasterizer: " + save + 42 /FontType resourcestatus + { pop pop (Type42)} {pop pop (None)} ifelse = flush + restore" +*End + +*Emulators: hpgl +*StartEmulator_hpgl: "currentfile /hpgl statusdict /emulate get exec " +*StopEmulator_hpgl: "<1B7F>0" + +*FileSystem: True +*?FileSystem: " + save false + (%disk?%) + { currentdevparams dup /Writeable known + { /Writeable get {pop true} if } {pop} ifelse + } 10 string /IODevice resourceforall + {(True)}{(False)} ifelse = flush + restore" +*End +*Throughput: "14" +*Password: "(0)" +*ExitServer: " + count 0 eq + { false } { true exch startjob } ifelse + not + { (WARNING: Cannot modify initial VM.) = + (Missing or invalid password.) = + (Please contact the author of this software.) = flush quit + } if" +*End +*Reset: " + count 0 eq + { false } { true exch startjob } ifelse + not + { (WARNING: Cannot reset printer.) = + (Missing or invalid password.) = + (Please contact the author of this software.) = flush quit + } if + systemdict /quit get exec + (WARNING : Printer Reset Failed.) = flush" +*End + +*DefaultResolution: 600x600dpi +*?Resolution: " + save currentpagedevice + /HWResolution get + aload pop exch ( ) cvs print (x) print ( ) cvs print (dpi) + = flush + restore" +*End + +*% Halftone Information ================= + +*DefaultHalftoneType: 9 +*ScreenFreq: "60.0" +*ScreenAngle: "0.0" +*DefaultScreenProc: Null +*ScreenProc Null: "{}" + +*DefaultTransfer: Null +*Transfer Null: "{ }" +*Transfer Null.Inverse: "{ 1 exch sub }" + + +*% Tray Selection ============ + +*OpenUI *InputSlot: PickOne +*OrderDependency: 10 AnySetup *InputSlot +*DefaultInputSlot: Paper +*InputSlot Upper: " + (<<) cvx exec + /MediaPosition 0 + /MediaType null + /TraySwitch false + /ManualFeed false + (>>) cvx exec setpagedevice" +*End +*InputSlot Middle: " + (<<) cvx exec + /MediaPosition 1 + /MediaType null + /TraySwitch false + /ManualFeed false + (>>) cvx exec setpagedevice" +*End +*InputSlot Lower: " + (<<) cvx exec + /MediaPosition 2 + /MediaType null + /TraySwitch false + /ManualFeed false + (>>) cvx exec setpagedevice" +*End +*InputSlot Paper: " + (<<) cvx exec + /MediaPosition null + /MediaType (Paper) + /TraySwitch true + /ManualFeed false + (>>) cvx exec setpagedevice" +*End +*InputSlot Transparency: " + (<<) cvx exec + /MediaPosition null + /MediaType (Transparency) + /TraySwitch true + /ManualFeed false + (>>) cvx exec setpagedevice" +*End +*InputSlot ManualPaper/Manual Paper: " + (<<) cvx exec + /MediaPosition null + /MediaType (Paper) + /TraySwitch false + /ManualFeed true + (>>) cvx exec setpagedevice" +*End +*InputSlot ManualTransparency/Manual Transparency: " + (<<) cvx exec + /MediaPosition null + /MediaType (Transparency) + /TraySwitch false + /ManualFeed true + (>>) cvx exec setpagedevice" +*End +*?InputSlot: " + save + currentpagedevice /MediaPosition get + dup null eq + { pop currentpagedevice /MediaType get + dup null eq + { pop (Upper) } + { dup (Paper) eq + { pop currentpagedevice /ManualFeed get + { (ManualPaper) } + { (Paper) } ifelse + } + { + (Transparency) eq + { currentpagedevice /ManualFeed get + { (ManualTransparency) } + { (Transparency) } ifelse + } + { (Unknown) } ifelse + } ifelse + } ifelse + } + { + dup 0 eq + { pop (Upper) } + { dup 1 eq + { pop (Middle) } + { 2 eq + { (Lower) } + { (Unknown) } ifelse + } ifelse + } ifelse + } ifelse + = flush restore" +*End +*CloseUI: *InputSlot + +*% Paper Handling =================== + +*% Use these entries to set paper size most of the time, unless there is +*% specific reason to use PageRegion. +*OpenUI *PageSize: PickOne +*OrderDependency: 20 AnySetup *PageSize +*DefaultPageSize: Letter +*PageSize Letter: "(<<) cvx exec /PageSize [612 792] /ImagingBBox null + (>>) cvx exec setpagedevice" +*End +*PageSize Legal: "(<<) cvx exec /PageSize [612 1008] /ImagingBBox null + (>>) cvx exec setpagedevice" +*End +*PageSize A4: "(<<) cvx exec /PageSize [595 842] /ImagingBBox null + (>>) cvx exec setpagedevice" +*End +*?PageSize: " + save currentpagedevice /PageSize get aload pop + 2 copy gt {exch} if (Unknown) + (<<) cvx exec + [612 792] (Letter) + [612 1008] (Legal) + [595 842] (A4) (>>) cvx exec + { exch aload pop 4 index sub abs 5 le exch 5 index sub abs 5 le and + { exch pop exit } { pop } ifelse + } bind forall = flush pop pop + restore" +*End +*CloseUI: *PageSize + +*% These entries will set up the frame buffer. Usually used with manual feed. +*OpenUI *PageRegion: PickOne +*OrderDependency: 30 AnySetup *PageRegion +*DefaultPageRegion: Letter +*PageRegion Letter: "(<<) cvx exec /PageSize [612 792] /ImagingBBox null + (>>) cvx exec setpagedevice" +*End +*PageRegion Legal: "(<<) cvx exec /PageSize [612 1008] /ImagingBBox null + (>>) cvx exec setpagedevice" +*End +*PageRegion A4: "(<<) cvx exec /PageSize [595 842] /ImagingBBox null + (>>) cvx exec setpagedevice" +*End +*CloseUI: *PageRegion + +*% The following entries provide information about specific paper keywords. +*DefaultImageableArea: Letter +*ImageableArea Letter: "10.32 15.9 601.68 776.22" +*ImageableArea Legal: "10.32 16.3801 601.68 991.74" +*ImageableArea A4: "13.44 14.46 581.76 828.54" +*?ImageableArea: " + save + /cvp { ( ) cvs print ( ) print } bind def + /upperright {10000 mul floor 10000 div} bind def + /lowerleft {10000 mul ceiling 10000 div} bind def + newpath clippath pathbbox + 4 -2 roll exch 2 {lowerleft cvp} repeat + exch 2 {upperright cvp} repeat flush + restore" +*End + +*% These provide the physical dimensions of the paper (by keyword) +*DefaultPaperDimension: Letter +*PaperDimension Letter: "612 792" +*PaperDimension Legal: "612 1008" +*PaperDimension A4: "595 842" + +*RequiresPageRegion All: True + +*% Print Quality Selection =================== + +*OpenUI *OutputMode/Print Quality: PickOne +*OrderDependency: 50 AnySetup *OutputMode +*DefaultOutputMode: Standard +*OutputMode Fast/Fast Color 600x600 dpi: " + (<<) cvx exec + /HWResolution [600 600] + /ProcessColorModel /DeviceCMY + (>>) cvx exec setpagedevice" +*End +*OutputMode Standard/Standard 600x600 dpi: " + (<<) cvx exec + /HWResolution [600 600] + /ProcessColorModel /DeviceCMYK + (>>) cvx exec setpagedevice" +*End +*OutputMode Enhanced/Enhanced 1200x600 dpi: " + (<<) cvx exec + /HWResolution [1200 600] + /ProcessColorModel /DeviceCMYK + (>>) cvx exec setpagedevice" +*End +*OutputMode Premium/Premium 1200x1200 dpi: " + (<<) cvx exec + /HWResolution [1200 1200] + /ProcessColorModel /DeviceCMYK + (>>) cvx exec setpagedevice" +*End +*?OutputMode: " + save + currentpagedevice /ProcessColorModel get /DeviceCMY eq + { (Fast) } + { currentpagedevice /HWResolution get + aload pop 1200 eq + { pop (Premium) } + { 1200 eq + { (Enhanced) } + { (Standard) } ifelse + } ifelse + } ifelse + = flush restore" +*End +*CloseUI: *OutputMode + +*OpenUI *OutputOrder/Output Order: PickOne +*OrderDependency: 60 AnySetup *OutputOrder +*DefaultOutputOrder: Reverse +*OutputOrder Normal/Face Down: " + (<<) cvx exec + /OutputFaceUp false + (>>) cvx exec setpagedevice" +*End +*OutputOrder Reverse/Face Up: " + (<<) cvx exec + /OutputFaceUp true + (>>) cvx exec setpagedevice" +*End +*?OutputOrder: " + save + currentpagedevice /OutputFaceUp get {(Reverse)}{(Normal)}ifelse + = flush restore" +*End +*CloseUI: *OutputOrder + +*OpenUI *Collate/Quick Collate: Boolean +*OrderDependency: 70 AnySetup *Collate +*DefaultCollate: False +*Collate False: " + (<<) cvx exec + /Collate false + (>>) cvx exec setpagedevice" +*End +*Collate True: " + (<<) cvx exec + /Collate true + (>>) cvx exec setpagedevice" +*End +*?Collate: " + save + currentpagedevice /Collate get {(True)}{(False)}ifelse + = flush restore" +*End +*CloseUI: *Collate + +*%================================ +*% Two-sided Printing (Duplex) +*%================================ + +*OpenUI *Duplex/Duplex: PickOne +*OrderDependency: 50 AnySetup *Duplex +*DefaultDuplex: None +*Duplex None/Off: " + <> setpagedevice" +*End +*Duplex DuplexNoTumble/Flip on Long Edge (Standard): " + <> setpagedevice" +*End +*Duplex DuplexTumble/Flip on Short Edge: " + <> setpagedevice" +*End +*?Duplex: "save + currentpagedevice dup /Duplex known + {dup /Duplex get + {/Tumble get{(DuplexTumble)}{(DuplexNoTumble)}ifelse} + {pop (None)} ifelse + } + {(None)} ifelse = flush +restore +" +*End +*CloseUI: *Duplex + +*% ================================= +*% User Interface Constraints +*% ================================= + +*% If the duplex unit is not installed disable duplex modes. + +*UIConstraints: *DuplexUnit NotInstalled *Duplex DuplexNoTumble +*UIConstraints: *DuplexUnit NotInstalled *Duplex DuplexTumble + + +*% Font Information ===================== +*DefaultFont: Courier +*Font Courier: Standard "(002.003)" Standard ROM +*Font Courier-Bold: Standard "(002.003)" Standard ROM +*Font Courier-BoldOblique: Standard "(002.003)" Standard ROM +*Font Courier-Oblique: Standard "(002.003)" Standard ROM +*Font Helvetica: Standard "(001.006)" Standard ROM +*Font Helvetica-Bold: Standard "(001.007)" Standard ROM +*Font Helvetica-BoldOblique: Standard "(001.007)" Standard ROM +*Font Helvetica-Condensed: Standard "(001.001)" Standard ROM +*Font Helvetica-Condensed-Bold: Standard "(001.002)" Standard ROM +*Font Helvetica-Condensed-BoldObl: Standard "(001.002)" Standard ROM +*Font Helvetica-Condensed-Oblique: Standard "(001.001)" Standard ROM +*Font Helvetica-Narrow: Standard "(001.006)" Standard ROM +*Font Helvetica-Narrow-Bold: Standard "(001.007)" Standard ROM +*Font Helvetica-Narrow-BoldOblique: Standard "(001.007)" Standard ROM +*Font Helvetica-Narrow-Oblique: Standard "(001.006)" Standard ROM +*Font Helvetica-Oblique: Standard "(001.006)" Standard ROM +*Font Symbol: Special "(001.007)" Special ROM +*Font Times-Bold: Standard "(001.007)" Standard ROM +*Font Times-BoldItalic: Standard "(001.009)" Standard ROM +*Font Times-Italic: Standard "(001.007)" Standard ROM +*Font Times-Roman: Standard "(001.007)" Standard ROM +*Font ZapfChancery-MediumItalic: Standard "(001.006)" Standard ROM +*Font ZapfDingbats: Special "(001.004)" Special ROM +*?FontQuery: " + save + { count 1 gt + { exch dup 127 string cvs (/) print print (:) print + /Font resourcestatus {pop pop (Yes)} {(No)} ifelse = + } { exit } ifelse + } bind loop + (*) = flush restore" +*End + +*?FontList: " + save (*) {cvn ==} 128 string /Font resourceforall + (*) = flush restore" +*End + +*DefaultColorSep: ProcessBlack.60lpi.600x600dpi/60 lpi / 600x600 dpi + +*% For 60 lpi / 600x600dpi ================================ + +*ColorSepScreenAngle ProcessBlack.60lpi.600x600dpi/60 lpi / 600x600 dpi: "0.0" +*ColorSepScreenAngle CustomColor.60lpi.600x600dpi/60 lpi / 600x600 dpi: "0.0" +*ColorSepScreenAngle ProcessCyan.60lpi.600x600dpi/60 lpi / 600x600 dpi: "0.0" +*ColorSepScreenAngle ProcessMagenta.60lpi.600x600dpi/60 lpi / 600x600 dpi: "0.0" +*ColorSepScreenAngle ProcessYellow.60lpi.600x600dpi/60 lpi / 600x600 dpi: "0.0" + +*ColorSepScreenFreq ProcessBlack.60lpi.600x600dpi/60 lpi / 600x600 dpi: "60.0" +*ColorSepScreenFreq CustomColor.60lpi.600x600dpi/60 lpi / 600x600 dpi: "60.0" +*ColorSepScreenFreq ProcessCyan.60lpi.600x600dpi/60 lpi / 600x600 dpi: "60.0" +*ColorSepScreenFreq ProcessMagenta.60lpi.600x600dpi/60 lpi / 600x600 dpi: "60.0" +*ColorSepScreenFreq ProcessYellow.60lpi.600x600dpi/60 lpi / 600x600 dpi: "60.0" + +*% end of PPD file for MS PS5 OEM Custimization diff --git a/print/autoconfig/AutoCnfg.inf b/print/autoconfig/AutoCnfg.inf new file mode 100644 index 00000000..c76422e9 --- /dev/null +++ b/print/autoconfig/AutoCnfg.inf @@ -0,0 +1,111 @@ +; AutoCnfg.INF +; +; INF file for AutoConfiguration samples +; +; Copyright 1999-2005 Microsoft Corporation + + +[Version] +Signature="$Windows NT$" +Provider=%MS% +LayoutFile=ntprint.inf +ClassGUID={4D36E979-E325-11CE-BFC1-08002BE10318} +Class=Printer +DriverVer=11/17/2005,1.0.0.2 +CatalogFile=AutoCnfg.cat + +; +; Manufacturer section. +; +; This section lists all of the manufacturers +; that we will display in the Dialog box +; +[Manufacturer] +"Microsoft"=Microsoft, NTx86, NTamd64, NTia64 + +; +; Model sections. +; +; Each section here corresponds with an entry listed in the +; [Manufacturer] section, above. The models will be displayed in the order +; that they appear in the INF file. +; +[Microsoft.NTx86] +"Unidrv AutoConfiguration Sample" = INSTALL_AUTO_CONFIG.UNI,DO_NOT_USE_THIS_HWID1 +"PScript5 AutoConfiguration Sample" = INSTALL_AUTO_CONFIG.PS,DO_NOT_USE_THIS_HWID2 + +[Microsoft.NTamd64] +"Unidrv AutoConfiguration Sample" = INSTALL_AUTO_CONFIG.UNI,DO_NOT_USE_THIS_HWID1 +"PScript5 AutoConfiguration Sample" = INSTALL_AUTO_CONFIG.PS,DO_NOT_USE_THIS_HWID2 + +[Microsoft.NTia64] +"Unidrv AutoConfiguration Sample" = INSTALL_AUTO_CONFIG.UNI,DO_NOT_USE_THIS_HWID1 +"PScript5 AutoConfiguration Sample" = INSTALL_AUTO_CONFIG.PS,DO_NOT_USE_THIS_HWID2 + + + +; +; Installer Sections +; +; These sections control file installation, and reference all files that +; need to be copied. The section name will be assumed to be the driver +; file, unless there is an explicit DriverFile section listed. +; +[INSTALL_AUTO_CONFIG.UNI] +CopyFiles=AUTO_CONFIG.UNI +DataFile=AutoCnfg.GPD +DataSection=UNIDRV_DATA +Include=NTPRINT.INF +Needs=UNIDRV.OEM,UNIDRV_DATA,TTFSUB.OEM,PCL5ERES.OEM + +[INSTALL_AUTO_CONFIG.PS] +CopyFiles=AUTO_CONFIG.PS +DataFile=AutoCnfg.PPD +DataSection=PSCRIPT_DATA +Include=NTPRINT.INF +Needs=PSCRIPT.OEM,PSCRIPT_DATA + +; Copy Sections +; +; Lists of files that are actually copied. These sections are referenced +; from the installer sections, above. Only create a section if it contains +; two or more files (if we only copy a single file, identify it in the +; installer section, using the @filename notation) or if it's a color +; profile (since the DestinationDirs can only handle sections, and not +; individual files). +; +[AUTO_CONFIG.UNI] +AutoCnfg.GPD +ACnfgUni.GDL + +[AUTO_CONFIG.PS] +AutoCnfg.PPD +ACnfgPS.GDL + +; +; Location of source files not in Layout.inf. +; +[SourceDisksNames] +100 = %AutoConfigSample% + +[SourceDisksFiles] +AutoCnfg.GPD = 100 +AutoCnfg.PPD = 100 +ACnfgUni.GDL = 100 +ACnfgPS.GDL = 100 + + +; +; Call SetupSetDirectoryId with 66000 to set the target directory at runtime +; (depending on which environment drivers are getting installed) +; + +[DestinationDirs] +DefaultDestDir=66000 + +; +; Localizable Strings +; +[Strings] +MS="Microsoft DDK Sample" +AutoConfigSample="AutoConfiguration Samples" diff --git a/print/autoconfig/AutoConfig.htm b/print/autoconfig/AutoConfig.htm new file mode 100644 index 00000000..5a32268c --- /dev/null +++ b/print/autoconfig/AutoConfig.htm @@ -0,0 +1,367 @@ + + + + +Auto-Configuration Samples + + + + + +

Auto-Configuration Samples

+

Summary

+

+AutoConfig sample +demonstrates how to implement Unidrv-based and PScript5-based drivers to +leverage the inbox support for auto-configuration.

+

+The sample +works only when used with the standard TCP/IP port monitor or the +Network-Connected Device (NCD) port monitor.

+

 

+

+Note: The +sample is provided here only as a proof of concept.

+

 

+

The +table shown below identifies which operating systems this sample will build and +work on.

+

 

+

 

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

+ Operating System

+

+ Can sample be + built in the OS? +

+

+ Does sample work + in the OS?

+

+ + Can sample be used in a production environment for the OS?

+

+ Windows Vista

+

+ Yes

+

+ Yes

+

+ No

+

+ Windows Server + 2003

+

+ No

+

+ No

+

+ No

+

+ Windows XP

+

+ No

+

+ No

+

+ No

+

+ Windows 2000

+

+ No

+

+ No

+

+ No

+

+ Windows Me

+

+ No

+

+ No

+

+ No

+

+ Windows 98 SE

+

+ No

+

+ No

+

+ No

+

 

+

Auto-Configuration +Basics

+

Prior +to Microsoft® Windows® Vista, the settings of a print queue are set initially to +the driver's default settings, rather than to the appropriate settings based on +the device. For Unidrv or Pscript5, this means that static default values +specified in the GPD or PPD file are used for the initial print queue setup. +This static set of defaults necessarily must represent the minimum configuration +that a printer can ship with. For instance, if a stapling unit is optional for a +device, then by default, such a device cannot have stapling capability enabled, +otherwise the user interface for devices without the stapling unit would show +stapling as an option. A customer who selected the stapling option but found +that it did not work would likely be confused.

+

For any device that +comes with features not present in the basic model, a user or administrator must +manually configure these features on the print queue after installation. This +can at times be a confusing and non-intuitive experience. The configuration +process is easy to get wrong, particularly with regard to internal parameters +such as memory and hard disk size, which significantly can affect printing speed +and quality.

+

Auto-configuration +solves this problem by +automatically configuring the print queue according to the installable features +on the device, rather than simply using the driver's static default settings. +The main target for auto-configuration is network printers. They are the most +likely ones to have multiple optional features and require more manual +configuration.

+

Auto-configuration +works by means of +bi-directional printer communication (also known as bidi communication) between +the print subsystem and the printer. In order for auto-configuration to work, +the printer must be able to:

+

+·                  + +Understand a +query sent by the port monitor.

+

+·                  + +Generate the +appropriate response to the query.

+

To support +auto-configuration, both the printer driver and the port monitor must be +modified.

+

A printer driver +must:

+

+·                  + +Be aware of +the Bidi Notification Schema.

+

+·                  + +Be able to +receive notifications about device configuration changes using the Bidi +Notification Schema.

+

+·                  + +Be able to +solicit configuration data from the printer using the Bidi Communication +Interfaces, and specifically the IBidiSpl2 COM interface (described in +the Platform SDK documentation).

+

A port monitor +must:

+

+·                  + +Support a +device protocol capable of querying the printer's configuration.

+

+·                  + +Be able to +receive unsolicited status messages from the printer.

+

+·                  + +Convert +unsolicited status messages to an appropriate driver notification.

+

+·                  + +Keep all of +the device status and configuration data up-to date by means of polling or +alerts.

+

+·                  + +Inform the +driver or application of any configuration changes in the device.

+

Unidrv-based and +PScript5-based drivers using the standard TCP/IP port monitor or the +Network-Connected Device (NCD) port monitor provide support for +auto-configuration.

+

CODE TOUR

+

 

+

+Unidrv + +Auto-Configuration Sample

+

+ 

+

The main part of the +sample is the auto-configuration GDL file ACnfgUni.GDL. This file implements +the  *BidiQuery, *BidiResponse and *Option elements that correspond to the +Memory, DuplexUnit and PrinterHardDisk features in AutoCnfg.GPD file. The +Feature and Option names in the auto-configuration GDL file should exaclty match +the corresponding Feature and Option names in the GPD file. The +auto-configuration GDL file is specified in the GPD file using the *BidiQueryFile +keyword. The auto-configuration GDL content can also be contained directly +inside the GPD file itself instead of in a separate GDL file, in which case the +*BidiQueryFile keyword should specify the GPD file name.

+

 

+

+PScript5 Auto-Configuration +Sample

+

 

+

The +main part of the sample is the auto-configuration GDL file ACnfgPS.GDL. This +file implements the *BidiQuery, *BidiResponse and *Option elements that +corresponds to the InstalledMemory, DuplexUnit and HardDisk features in +AutoCnfg.PPD file. As mentioned for the Unidrv sample, the Feature and Option +names should exactly match. Please note that the GPD and PPD files do not have +the same Feature and Option names. That is why the two GDL files are not +identical. The auto-configuration GDL file is specified in the PPD file using +the *MSBidiQueryFile keyword.

+

INSTALLING/TESTING THE SAMPLE

+

The samples don’t have +any binaries to be built. They may be installed by using Add Printer Wizard and +supplying the AutoCnfg.INF as the INF file. To test the auto-configuration +feature you need to install the driver to a Standard TCP/IP port.  You need a +printer, which understands and responds to the bidi SNMP queries, connected to +the port. The tcpbidi.xml file located in system32 directory has information +about the SNMP OIDs used for each query. The installable options in the device +settings will reflect the information obtained by querying the printer. +

+

File Manifest 

+
 
+
Root:
+
 
+
Files                  Description
+
 
+

AutoConfig.htm      The documentation for this sample +(this file)

+

AutoCnfg.INF        The printer INF that will install +Unidrv and PScript5 auto-configuration samples

+

AutoCnfg.GPD        The GPD file for the Unidrv +auto-configuration sample

+

AutoCnfg.PPD        The PPD file for the PScript5 +auto-configuration sample

+

ACnfgUni.GDL        The GDL file for the Unidrv +auto-configuration sample

+

ACnfgPS.GDL         The GDL file for the PScript5 +auto-configuration sample

+

Resources

+

For +the latest release of the Windows Device Driver Development Kit, see + +http://www.microsoft.com/whdc/ddk/winddk.mspx.

+

 

+

If +you have questions on using or adapting this sample for your project, you can +either contact + +Microsoft Technical Support or post your questions in the + +Microsoft driver development newsgroup.

+ + + + diff --git a/print/autoconfig/AutoConfig.sln b/print/autoconfig/AutoConfig.sln new file mode 100644 index 00000000..bf0ee61f --- /dev/null +++ b/print/autoconfig/AutoConfig.sln @@ -0,0 +1,47 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0 +MinimumVisualStudioVersion = 12.0 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Package", "Package", "{4259D226-70CB-4CC3-A9C5-6BE1F4A92C76}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "AutoConfig", "AutoConfig", "{05648001-0846-4B8A-BC4C-C2B1099A81ED}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "package", "Package\package.VcxProj", "{2413CDC5-F87A-4C93-A58F-E7AB497C9863}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AutoConfig", "AutoConfig.vcxproj", "{3AC4649E-0746-4815-BE4D-CA5F491BA78C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {2413CDC5-F87A-4C93-A58F-E7AB497C9863}.Debug|Win32.ActiveCfg = Debug|Win32 + {2413CDC5-F87A-4C93-A58F-E7AB497C9863}.Debug|Win32.Build.0 = Debug|Win32 + {2413CDC5-F87A-4C93-A58F-E7AB497C9863}.Release|Win32.ActiveCfg = Release|Win32 + {2413CDC5-F87A-4C93-A58F-E7AB497C9863}.Release|Win32.Build.0 = Release|Win32 + {2413CDC5-F87A-4C93-A58F-E7AB497C9863}.Debug|x64.ActiveCfg = Debug|x64 + {2413CDC5-F87A-4C93-A58F-E7AB497C9863}.Debug|x64.Build.0 = Debug|x64 + {2413CDC5-F87A-4C93-A58F-E7AB497C9863}.Release|x64.ActiveCfg = Release|x64 + {2413CDC5-F87A-4C93-A58F-E7AB497C9863}.Release|x64.Build.0 = Release|x64 + {3AC4649E-0746-4815-BE4D-CA5F491BA78C}.Debug|Win32.ActiveCfg = Debug|Win32 + {3AC4649E-0746-4815-BE4D-CA5F491BA78C}.Debug|Win32.Build.0 = Debug|Win32 + {3AC4649E-0746-4815-BE4D-CA5F491BA78C}.Release|Win32.ActiveCfg = Release|Win32 + {3AC4649E-0746-4815-BE4D-CA5F491BA78C}.Release|Win32.Build.0 = Release|Win32 + {3AC4649E-0746-4815-BE4D-CA5F491BA78C}.Debug|x64.ActiveCfg = Debug|x64 + {3AC4649E-0746-4815-BE4D-CA5F491BA78C}.Debug|x64.Build.0 = Debug|x64 + {3AC4649E-0746-4815-BE4D-CA5F491BA78C}.Release|x64.ActiveCfg = Release|x64 + {3AC4649E-0746-4815-BE4D-CA5F491BA78C}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {2413CDC5-F87A-4C93-A58F-E7AB497C9863} = {4259D226-70CB-4CC3-A9C5-6BE1F4A92C76} + {3AC4649E-0746-4815-BE4D-CA5F491BA78C} = {05648001-0846-4B8A-BC4C-C2B1099A81ED} + {4259D226-70CB-4CC3-A9C5-6BE1F4A92C76} = {05648001-0846-4B8A-BC4C-C2B1099A81ED} + EndGlobalSection +EndGlobal diff --git a/print/autoconfig/AutoConfig.vcxproj b/print/autoconfig/AutoConfig.vcxproj new file mode 100644 index 00000000..2a0d4922 --- /dev/null +++ b/print/autoconfig/AutoConfig.vcxproj @@ -0,0 +1,160 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {3AC4649E-0746-4815-BE4D-CA5F491BA78C} + $(MSBuildProjectName) + false + true + Debug + Win32 + {5361FE42-60AC-4D05-AA79-9928B15AD552} + + + + Windows10 + False + Desktop + None + WindowsKernelModeDriver10.0 + Utility + + + Windows10 + True + Desktop + None + WindowsKernelModeDriver10.0 + Utility + + + Windows10 + False + Desktop + None + WindowsKernelModeDriver10.0 + Utility + + + Windows10 + True + Desktop + None + WindowsKernelModeDriver10.0 + Utility + + + + $(IntDir) + + + + + + + + + + + + + + + + AutoConfig + + + AutoConfig + + + AutoConfig + + + AutoConfig + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/print/autoconfig/AutoConfig.vcxproj.Filters b/print/autoconfig/AutoConfig.vcxproj.Filters new file mode 100644 index 00000000..3b9f54c4 --- /dev/null +++ b/print/autoconfig/AutoConfig.vcxproj.Filters @@ -0,0 +1,21 @@ + + + + + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* + {CC0020D1-88BF-4AA4-8E5C-08FA0FC25EB2} + + + h;hpp;hxx;hm;inl;inc;xsd + {125816B7-55A7-4B3D-AD8D-27FC65BA0320} + + + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml + {207C912A-A306-4C9E-8530-7D55313903B7} + + + inf;inv;inx;mof;mc; + {9174D187-924B-4401-A505-E3744534AA84} + + + \ No newline at end of file diff --git a/print/autoconfig/Package/package.VcxProj b/print/autoconfig/Package/package.VcxProj new file mode 100644 index 00000000..fe3b9df5 --- /dev/null +++ b/print/autoconfig/Package/package.VcxProj @@ -0,0 +1,88 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + WindowsKernelModeDriver10.0 + Utility + Package + true + Debug + + + + {2413CDC5-F87A-4C93-A58F-E7AB497C9863} + {721ABA50-F9B7-47C3-AE46-D758904898FE} + $(MSBuildProjectName) + + + Windows10 + true + + + Windows10 + false + + + Windows10 + true + + + Windows10 + false + + + + + + + + + + + DbgengKernelDebugger + False + None + + + + + + %PathToInf% + False + False + True + + 133563 + + + + + + + + + + {3AC4649E-0746-4815-BE4D-CA5F491BA78C} + + + + + + \ No newline at end of file diff --git a/print/autoconfig/Package/package.VcxProj.Filters b/print/autoconfig/Package/package.VcxProj.Filters new file mode 100644 index 00000000..cca2dd89 --- /dev/null +++ b/print/autoconfig/Package/package.VcxProj.Filters @@ -0,0 +1,21 @@ + + + + + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* + {B8DF1233-DF16-44AA-9934-5E306B564E71} + + + h;hpp;hxx;hm;inl;inc;xsd + {252924E9-6243-4097-8F0E-531E56389AE2} + + + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml + {98522D6D-8655-4174-8A06-C4BA5DFE1A53} + + + inf;inv;inx;mof;mc; + {57663FE0-B30B-4B3E-929F-05EEDA920360} + + + \ No newline at end of file diff --git a/print/autoconfig/ReadMe.md b/print/autoconfig/ReadMe.md new file mode 100644 index 00000000..28c454b1 --- /dev/null +++ b/print/autoconfig/ReadMe.md @@ -0,0 +1,62 @@ +Print Auto Configuration Sample +=============================== + +The auto configuration sample demonstrates how to implement Unidrv-based and PScript5-based drivers to leverage the inbox support for auto-configuration. The sample works only when used with the standard TCP/IP port monitor or the Network-Connected Device (NCD) port monitor. + +**Auto-Configuration Basics** + +Prior to Microsoft® Windows® Vista, the settings of a print queue were set initially to the driver's default settings, rather than to the appropriate settings based on the device. For Unidrv or Pscript5, this means that static default values specified in the GPD or PPD file are used for the initial print queue setup. This static set of defaults must, necessarily, represent the minimum configuration that a printer can ship with. For instance, if a stapling unit is optional for a device, then by default, such a device cannot have stapling capability enabled, otherwise the user interface for devices without the stapling unit would show stapling as an option. A customer who selected the stapling option but found that it did not work would likely be confused. + +For any device that comes with features not present in the basic model, a user or administrator must manually configure these features on the print queue after installation. This can at times be a confusing and non-intuitive experience. The configuration process is easy to get wrong, particularly with regard to internal parameters such as memory and hard disk size, which significantly can affect printing speed and quality. + +Auto-configuration solves this problem by automatically configuring the print queue according to the installable features on the device, rather than simply using the driver's static default settings. The main target for auto-configuration is network printers. They are the most likely ones to have multiple optional features and require more manual configuration. For more information, see [Printer Autoconfiguration](http://msdn.microsoft.com/en-us/library/windows/hardware/ff560774(v=vs.85).aspx). + + +Build the sample +---------------- + +The auto configuration sample doesn’t have any binaries to be built. It may be installed by using **Add Printer Wizard** and supplying the AutoCnfg.INF as the INF file. + +But to build a signed driver package using Windows 8.1 driver kit (Windows Driver Kit (WDK)) and Visual Studio 2013, for the project file (csproj) that ships with the auto configuration sample, perform the following steps. + +1. Open the solution file in Visual Studio 2013 + +2. Add all non-binary files (usually located in the \\install directory of the sample) to the Package project + +a. In the **Solution Explorer**, right click **Driver Files** + +b. Select **Add**, then click **Existing Item** + +c. Navigate to the location to which you downloaded the sample, and select all the files in the install directory, or the equivalent set of non-binary files such as INFs, INIs, GPD, PPD files, etc. + +d. Click **Add** + +3. Configure these files to be added into the driver package + +a. In the **Solution Explorer**, right click the Package project and select **Properties** + +b. In the left pane, click **Configuration Properties** \> **Driver Install** \> **Package Files**. + +c. In the right pane, use the ellipsis button (...) to browse to the set of files that needs to be added to the driver package. All the data files that you added in **Step 2-c**, except the INF file, should be added. + +**Note**  This configuration is per-architecture, so this configuration must be repeated for each architecture that will be built. + +d. Click **OK** + +4. Open the INF file and edit it to match the built output + +a. Open the INF file + +b. In the Version section, add a reference to a catalog file like this: CatalogFile=XpsDrvSmpl.cat + +c. In the SourceDisksFiles section, change the location of the DLL files you are building, to =1. This indicates that there is no architecture specific directory in this driver. If you ship multiple architectures simultaneously, you will need to collate the driver INF manually. + +At this point, Visual Studio 2013 will be able to build a driver package and output the files to disk. In order to configure driver signing and deployment, see [Developing, Testing, and Deploying Drivers](http://msdn.microsoft.com/en-us/library/windows/hardware/ff554651(v=vs.85).aspx). + +For more information about how to build a driver solution using Microsoft Visual Studio, see [Building a Driver](http://msdn.microsoft.com/en-us/library/windows/hardware/ff554644). + +Run the sample +-------------- + +To test the auto-configuration feature you need to install the driver to a Standard TCP/IP port. You need a printer, which understands and responds to the bidi SNMP queries, connected to the port. The tcpbidi.xml file located in system32 directory has information about the SNMP OIDs used for each query. The installable options in the device settings will reflect the information obtained by querying the printer. + diff --git a/print/cpsuisam/cpsui.htm b/print/cpsuisam/cpsui.htm new file mode 100644 index 00000000..a79cb228 --- /dev/null +++ b/print/cpsuisam/cpsui.htm @@ -0,0 +1,236 @@ + + + + + + + + +CPSUI + + + + + + + + + +
+ +

CPSUI

+ +

SUMMARY

+ +

The Common Property Sheet +User Interface (CPSUI) is a user-mode dynamic link library that enables +developers to create property sheet pages that have a standard appearance.

+ +

This application causes +CPSUI to call the Windows® 2000/Windows® XP/Windows® Server 2003 print spooler +to create property sheet pages for the system's default printer. Note that printer +interface DLLs should not do this. The application then creates an additional +property sheet page to illustrate some of the techniques that can be employed when +using CPSUI to create a new page.

+ +

BUILDING THE SAMPLE

+ +

This sample requires that +the Windows® 2000/Windows® XP/Windows® Server 2003 Software Development Kit and +Driver Development Kit be installed so that the required headers and libs are available.

+ +

To build the samples, run +build from this directory. The DLL will be placed in the appropriate +platform directory.

+ +

Once built, the sample +produces one binary: Cpsuisam.exe. The sample is 64-bit compliant and compiles +properly with Microsoft® Visual C® 6.0.

+ +

CODE TOUR

+ +

File Manifest

+ +
 
 
Files          Description
Apple.ico      The resource file for a sample icon
Cpsuidat.cpp   The source file that contains all the predefined data
Cpsuidat.h     The header file for CPSUIDAT.cpp
Cpsuisam.c     The source file that implements the sample for the Windows 2000 CPSUI
Cpsuisam.def   The file that lists the exported functions
Cpsuisam.dlg   The resource file for the dialogs
Cpsuisam.h     The header file for CPSUISAM.c
Cpsuisam.ico   The resource file for a sample icon
Debug.c        The source file for debugging functions
Debug.h        The header for Debug.c
Makefile       The generic file for building the code sample
Precomp.h      The header that includes the headers to pre-compile
Cpsui.htm      The documentation for this sample (this file)
Res.rc         The resource file for the module
Sources        The generic file for building the code sample
+ +

Top of page

+ + + + + +
+

 

+
+ +

© 2004 Microsoft +Corporation

+ +
+ + + + diff --git a/print/cpsuisam/cpsuisam.sln b/print/cpsuisam/cpsuisam.sln index 334867da..b5112f28 100644 --- a/print/cpsuisam/cpsuisam.sln +++ b/print/cpsuisam/cpsuisam.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cpsuisam", "cpsuisam.vcxproj", "{F7BAD220-8095-4F67-A75B-0250FCB2B670}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cpsuisam", "cpsuisam.vcxproj", "{A0AB72F8-43E4-4DF9-9BF8-5BE5943F5087}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +13,14 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {F7BAD220-8095-4F67-A75B-0250FCB2B670}.Debug|Win32.ActiveCfg = Debug|Win32 - {F7BAD220-8095-4F67-A75B-0250FCB2B670}.Debug|Win32.Build.0 = Debug|Win32 - {F7BAD220-8095-4F67-A75B-0250FCB2B670}.Release|Win32.ActiveCfg = Release|Win32 - {F7BAD220-8095-4F67-A75B-0250FCB2B670}.Release|Win32.Build.0 = Release|Win32 - {F7BAD220-8095-4F67-A75B-0250FCB2B670}.Debug|x64.ActiveCfg = Debug|x64 - {F7BAD220-8095-4F67-A75B-0250FCB2B670}.Debug|x64.Build.0 = Debug|x64 - {F7BAD220-8095-4F67-A75B-0250FCB2B670}.Release|x64.ActiveCfg = Release|x64 - {F7BAD220-8095-4F67-A75B-0250FCB2B670}.Release|x64.Build.0 = Release|x64 + {A0AB72F8-43E4-4DF9-9BF8-5BE5943F5087}.Debug|Win32.ActiveCfg = Debug|Win32 + {A0AB72F8-43E4-4DF9-9BF8-5BE5943F5087}.Debug|Win32.Build.0 = Debug|Win32 + {A0AB72F8-43E4-4DF9-9BF8-5BE5943F5087}.Release|Win32.ActiveCfg = Release|Win32 + {A0AB72F8-43E4-4DF9-9BF8-5BE5943F5087}.Release|Win32.Build.0 = Release|Win32 + {A0AB72F8-43E4-4DF9-9BF8-5BE5943F5087}.Debug|x64.ActiveCfg = Debug|x64 + {A0AB72F8-43E4-4DF9-9BF8-5BE5943F5087}.Debug|x64.Build.0 = Debug|x64 + {A0AB72F8-43E4-4DF9-9BF8-5BE5943F5087}.Release|x64.ActiveCfg = Release|x64 + {A0AB72F8-43E4-4DF9-9BF8-5BE5943F5087}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/print/cpsuisam/cpsuisam.vcxproj b/print/cpsuisam/cpsuisam.vcxproj index 91f302ef..8303081a 100644 --- a/print/cpsuisam/cpsuisam.vcxproj +++ b/print/cpsuisam/cpsuisam.vcxproj @@ -19,11 +19,11 @@
- {F7BAD220-8095-4F67-A75B-0250FCB2B670} + {A0AB72F8-43E4-4DF9-9BF8-5BE5943F5087} $(MSBuildProjectName) Debug Win32 - {67BF1D0E-F90D-414D-A13C-543092176A80} + {9796197E-B5DF-412B-B5C7-53D2157DAEA4} diff --git a/print/cpsuisam/cpsuisam.vcxproj.Filters b/print/cpsuisam/cpsuisam.vcxproj.Filters index 44bbac68..84a24cc9 100644 --- a/print/cpsuisam/cpsuisam.vcxproj.Filters +++ b/print/cpsuisam/cpsuisam.vcxproj.Filters @@ -3,15 +3,15 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {50DC862B-95AC-4892-B963-876111462136} + {B311EA89-CEDD-4A4B-8E38-ED0D084243BD} h;hpp;hxx;hm;inl;inc;xsd - {5A8D8E11-1C44-4DD6-8615-57E54DDD4C6C} + {2F9561F0-63CF-4857-87E0-DA7247F9B6D3} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {44FF2C70-58D4-464D-B774-C6C44F8E380B} + {C6380BED-A054-4AB8-85AE-2990733CF187} diff --git a/print/v4PrintDriverSamples/PrinterExtensionSample/PrinterExtensionSample.sln b/print/v4PrintDriverSamples/PrinterExtensionSample/PrinterExtensionSample.sln index 5573b670..355378ea 100644 --- a/print/v4PrintDriverSamples/PrinterExtensionSample/PrinterExtensionSample.sln +++ b/print/v4PrintDriverSamples/PrinterExtensionSample/PrinterExtensionSample.sln @@ -3,9 +3,9 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ExtensionSample", "ExtensionSample", "{EAF81F7A-957C-4C1F-A2ED-5A9FE3DAEA77}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ExtensionSample", "ExtensionSample", "{46FA638A-C5E2-4257-9A15-1E0AD088D8C7}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "PrinterExtensionLibrary", "PrinterExtensionLibrary", "{D86B51AE-7E8E-4A5B-947B-02BD9CA9A176}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "PrinterExtensionLibrary", "PrinterExtensionLibrary", "{7996DD32-8A65-4596-877B-804470DCCAE6}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PrinterExtensionSample", "ExtensionSample\PrinterExtensionSample.csproj", "{CF554A99-6889-4B86-934F-B6AADBFEFC01}" EndProject @@ -80,7 +80,7 @@ Global HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {CF554A99-6889-4B86-934F-B6AADBFEFC01} = {EAF81F7A-957C-4C1F-A2ED-5A9FE3DAEA77} - {D8DA0C4D-F972-4546-9068-8EB256F222F7} = {D86B51AE-7E8E-4A5B-947B-02BD9CA9A176} + {CF554A99-6889-4B86-934F-B6AADBFEFC01} = {46FA638A-C5E2-4257-9A15-1E0AD088D8C7} + {D8DA0C4D-F972-4546-9068-8EB256F222F7} = {7996DD32-8A65-4596-877B-804470DCCAE6} EndGlobalSection EndGlobal diff --git a/print/v4PrintDriverSamples/v4PrintDriver-ConstraintScript/ConstraintScript.sln b/print/v4PrintDriverSamples/v4PrintDriver-ConstraintScript/ConstraintScript.sln index 16309c48..c767c9bb 100644 --- a/print/v4PrintDriverSamples/v4PrintDriver-ConstraintScript/ConstraintScript.sln +++ b/print/v4PrintDriverSamples/v4PrintDriver-ConstraintScript/ConstraintScript.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ConstraintScript", "ConstraintScript.vcxproj", "{3743F253-48F5-4E35-9158-87A7A4B21BAD}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ConstraintScript", "ConstraintScript.vcxproj", "{CB1E04C7-6B76-4C0D-8022-9C8DDCA2CAF7}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +13,14 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {3743F253-48F5-4E35-9158-87A7A4B21BAD}.Debug|Win32.ActiveCfg = Debug|Win32 - {3743F253-48F5-4E35-9158-87A7A4B21BAD}.Debug|Win32.Build.0 = Debug|Win32 - {3743F253-48F5-4E35-9158-87A7A4B21BAD}.Release|Win32.ActiveCfg = Release|Win32 - {3743F253-48F5-4E35-9158-87A7A4B21BAD}.Release|Win32.Build.0 = Release|Win32 - {3743F253-48F5-4E35-9158-87A7A4B21BAD}.Debug|x64.ActiveCfg = Debug|x64 - {3743F253-48F5-4E35-9158-87A7A4B21BAD}.Debug|x64.Build.0 = Debug|x64 - {3743F253-48F5-4E35-9158-87A7A4B21BAD}.Release|x64.ActiveCfg = Release|x64 - {3743F253-48F5-4E35-9158-87A7A4B21BAD}.Release|x64.Build.0 = Release|x64 + {CB1E04C7-6B76-4C0D-8022-9C8DDCA2CAF7}.Debug|Win32.ActiveCfg = Debug|Win32 + {CB1E04C7-6B76-4C0D-8022-9C8DDCA2CAF7}.Debug|Win32.Build.0 = Debug|Win32 + {CB1E04C7-6B76-4C0D-8022-9C8DDCA2CAF7}.Release|Win32.ActiveCfg = Release|Win32 + {CB1E04C7-6B76-4C0D-8022-9C8DDCA2CAF7}.Release|Win32.Build.0 = Release|Win32 + {CB1E04C7-6B76-4C0D-8022-9C8DDCA2CAF7}.Debug|x64.ActiveCfg = Debug|x64 + {CB1E04C7-6B76-4C0D-8022-9C8DDCA2CAF7}.Debug|x64.Build.0 = Debug|x64 + {CB1E04C7-6B76-4C0D-8022-9C8DDCA2CAF7}.Release|x64.ActiveCfg = Release|x64 + {CB1E04C7-6B76-4C0D-8022-9C8DDCA2CAF7}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/print/v4PrintDriverSamples/v4PrintDriver-ConstraintScript/ConstraintScript.vcxproj b/print/v4PrintDriverSamples/v4PrintDriver-ConstraintScript/ConstraintScript.vcxproj index 32f2e007..0ceaac0e 100644 --- a/print/v4PrintDriverSamples/v4PrintDriver-ConstraintScript/ConstraintScript.vcxproj +++ b/print/v4PrintDriverSamples/v4PrintDriver-ConstraintScript/ConstraintScript.vcxproj @@ -19,12 +19,12 @@ - {3743F253-48F5-4E35-9158-87A7A4B21BAD} + {CB1E04C7-6B76-4C0D-8022-9C8DDCA2CAF7} $(MSBuildProjectName) false Debug Win32 - {9E99443A-A160-4CFF-B9B7-86E42C9F6352} + {817B63FA-2B1C-4CBD-9CA7-7BCEECDA4B4F} diff --git a/print/v4PrintDriverSamples/v4PrintDriver-ConstraintScript/ConstraintScript.vcxproj.Filters b/print/v4PrintDriverSamples/v4PrintDriver-ConstraintScript/ConstraintScript.vcxproj.Filters index dc898596..f711c36b 100644 --- a/print/v4PrintDriverSamples/v4PrintDriver-ConstraintScript/ConstraintScript.vcxproj.Filters +++ b/print/v4PrintDriverSamples/v4PrintDriver-ConstraintScript/ConstraintScript.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {13816FE7-E5E7-44C3-A1BC-C290ADE11E77} + {32D0EF97-FC2B-4E1F-9E36-6AD986687F61} h;hpp;hxx;hm;inl;inc;xsd - {1B9F5A82-93F9-43BB-9206-07B44A903E65} + {29FB739F-C9CC-464B-A7B5-42F18A18F286} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {97FFF924-8790-432D-B7FB-620D32F06728} + {D3DA9AC3-690E-42E3-8BE5-002D7099D700} inf;inv;inx;mof;mc; - {37982029-F9B3-4A61-8379-A5CE0AE7F8B5} + {F90BC5C4-C6B9-417A-AD02-5507849101EF} \ No newline at end of file diff --git a/print/v4PrintDriverSamples/v4PrintDriver-HostBasedSampleDriver/HostBasedSampleDriver.sln b/print/v4PrintDriverSamples/v4PrintDriver-HostBasedSampleDriver/HostBasedSampleDriver.sln new file mode 100644 index 00000000..e08b4c01 --- /dev/null +++ b/print/v4PrintDriverSamples/v4PrintDriver-HostBasedSampleDriver/HostBasedSampleDriver.sln @@ -0,0 +1,43 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0 +MinimumVisualStudioVersion = 12.0 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Package", "Package", "{29C54707-CBCF-4EE7-8664-5A8809CD30D9}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "package", "Package\package.VcxProj", "{F1081D0D-31B7-4B48-9AD6-6C7336ADEA61}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HostBasedSampleDriver", "HostBasedSampleDriver.vcxproj", "{C4923416-0CA0-4D73-98F2-BC10C70C6689}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {F1081D0D-31B7-4B48-9AD6-6C7336ADEA61}.Debug|Win32.ActiveCfg = Debug|Win32 + {F1081D0D-31B7-4B48-9AD6-6C7336ADEA61}.Debug|Win32.Build.0 = Debug|Win32 + {F1081D0D-31B7-4B48-9AD6-6C7336ADEA61}.Release|Win32.ActiveCfg = Release|Win32 + {F1081D0D-31B7-4B48-9AD6-6C7336ADEA61}.Release|Win32.Build.0 = Release|Win32 + {F1081D0D-31B7-4B48-9AD6-6C7336ADEA61}.Debug|x64.ActiveCfg = Debug|x64 + {F1081D0D-31B7-4B48-9AD6-6C7336ADEA61}.Debug|x64.Build.0 = Debug|x64 + {F1081D0D-31B7-4B48-9AD6-6C7336ADEA61}.Release|x64.ActiveCfg = Release|x64 + {F1081D0D-31B7-4B48-9AD6-6C7336ADEA61}.Release|x64.Build.0 = Release|x64 + {C4923416-0CA0-4D73-98F2-BC10C70C6689}.Debug|Win32.ActiveCfg = Debug|Win32 + {C4923416-0CA0-4D73-98F2-BC10C70C6689}.Debug|Win32.Build.0 = Debug|Win32 + {C4923416-0CA0-4D73-98F2-BC10C70C6689}.Release|Win32.ActiveCfg = Release|Win32 + {C4923416-0CA0-4D73-98F2-BC10C70C6689}.Release|Win32.Build.0 = Release|Win32 + {C4923416-0CA0-4D73-98F2-BC10C70C6689}.Debug|x64.ActiveCfg = Debug|x64 + {C4923416-0CA0-4D73-98F2-BC10C70C6689}.Debug|x64.Build.0 = Debug|x64 + {C4923416-0CA0-4D73-98F2-BC10C70C6689}.Release|x64.ActiveCfg = Release|x64 + {C4923416-0CA0-4D73-98F2-BC10C70C6689}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {F1081D0D-31B7-4B48-9AD6-6C7336ADEA61} = {29C54707-CBCF-4EE7-8664-5A8809CD30D9} + EndGlobalSection +EndGlobal diff --git a/print/v4PrintDriverSamples/v4PrintDriver-HostBasedSampleDriver/HostBasedSampleDriver.vcxproj b/print/v4PrintDriverSamples/v4PrintDriver-HostBasedSampleDriver/HostBasedSampleDriver.vcxproj new file mode 100644 index 00000000..4056d79e --- /dev/null +++ b/print/v4PrintDriverSamples/v4PrintDriver-HostBasedSampleDriver/HostBasedSampleDriver.vcxproj @@ -0,0 +1,162 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {C4923416-0CA0-4D73-98F2-BC10C70C6689} + $(MSBuildProjectName) + false + true + Debug + Win32 + {192B3507-9B3B-4F9D-8757-FB236A173A4C} + + + + Windows10 + False + Desktop + None + WindowsKernelModeDriver10.0 + Utility + + + Windows10 + True + Desktop + None + WindowsKernelModeDriver10.0 + Utility + + + Windows10 + False + Desktop + None + WindowsKernelModeDriver10.0 + Utility + + + Windows10 + True + Desktop + None + WindowsKernelModeDriver10.0 + Utility + + + + $(IntDir) + + + + + + + + + + + + + + + + HostBasedSampleDriver + + + HostBasedSampleDriver + + + HostBasedSampleDriver + + + HostBasedSampleDriver + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/print/v4PrintDriverSamples/v4PrintDriver-HostBasedSampleDriver/HostBasedSampleDriver.vcxproj.Filters b/print/v4PrintDriverSamples/v4PrintDriver-HostBasedSampleDriver/HostBasedSampleDriver.vcxproj.Filters new file mode 100644 index 00000000..32c3897e --- /dev/null +++ b/print/v4PrintDriverSamples/v4PrintDriver-HostBasedSampleDriver/HostBasedSampleDriver.vcxproj.Filters @@ -0,0 +1,41 @@ + + + + + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* + {805C7C5E-A9EF-42CA-8F3A-175C6CCDFD53} + + + h;hpp;hxx;hm;inl;inc;xsd + {A2CB3D9E-1732-4426-8E35-7341BE09E5BD} + + + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml + {71B188DF-173E-402E-9FB3-D936E33C3F93} + + + inf;inv;inx;mof;mc; + {7A9313F9-BD09-46CB-8B04-D289D34FFDE0} + + + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + \ No newline at end of file diff --git a/print/v4PrintDriverSamples/v4PrintDriver-HostBasedSampleDriver/Package/package.VcxProj b/print/v4PrintDriverSamples/v4PrintDriver-HostBasedSampleDriver/Package/package.VcxProj new file mode 100644 index 00000000..d1f97a31 --- /dev/null +++ b/print/v4PrintDriverSamples/v4PrintDriver-HostBasedSampleDriver/Package/package.VcxProj @@ -0,0 +1,88 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + WindowsKernelModeDriver10.0 + Utility + Package + true + Debug + + + + {F1081D0D-31B7-4B48-9AD6-6C7336ADEA61} + {6D0283E4-148C-44BA-98FA-A3D4EEBF561E} + $(MSBuildProjectName) + + + Windows10 + true + + + Windows10 + false + + + Windows10 + true + + + Windows10 + false + + + + + + + + + + + DbgengKernelDebugger + False + None + + + + + + %PathToInf% + False + False + True + + 133563 + + + + + + + + + + {C4923416-0CA0-4D73-98F2-BC10C70C6689} + + + + + + \ No newline at end of file diff --git a/print/v4PrintDriverSamples/v4PrintDriver-HostBasedSampleDriver/Package/package.VcxProj.Filters b/print/v4PrintDriverSamples/v4PrintDriver-HostBasedSampleDriver/Package/package.VcxProj.Filters new file mode 100644 index 00000000..a9ed8cc6 --- /dev/null +++ b/print/v4PrintDriverSamples/v4PrintDriver-HostBasedSampleDriver/Package/package.VcxProj.Filters @@ -0,0 +1,21 @@ + + + + + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* + {82BBB724-F089-4441-8ECE-61571F0CD9ED} + + + h;hpp;hxx;hm;inl;inc;xsd + {24C56EA9-2A47-4CDD-ADAF-AC403C6FDDD1} + + + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml + {C7204588-58DE-470B-B532-39199F0C5930} + + + inf;inv;inx;mof;mc; + {40292FDA-3C17-4357-8861-B57A7A726884} + + + \ No newline at end of file diff --git a/print/v4PrintDriverSamples/v4PrintDriver-HostBasedSampleDriver/ReadMe.md b/print/v4PrintDriverSamples/v4PrintDriver-HostBasedSampleDriver/ReadMe.md new file mode 100644 index 00000000..4a438be7 --- /dev/null +++ b/print/v4PrintDriverSamples/v4PrintDriver-HostBasedSampleDriver/ReadMe.md @@ -0,0 +1,60 @@ +USB Host-Based Print Driver Sample +================================== + +This driver sample demonstrates how to support host-based devices that use the v4 print driver model, and are connected via USB. + +**Note**  This sample is for the v4 print driver model. + +Windows enables manufacturers to support Bidirectional Communication (Bidi) for USB devices, by using a combination of both a Bidi XML file and a Javascript file known as a USB Bidi extender. The *usb\_host\_based\_sample.js* file that is included with the sample, plays the role of the USB Bidi extender. + +The USB Bidi extender allows apps to use Bidi with USB as the transport mechanism. The Javascript implementation does not support any device flow control, or any multiplexing of control information with print jobs during printing. + +By default, Bidi queries and status requests are routed over the USB device interface that is used for printing. + +In addition to extending Bidi communication, this driver sample also specifies the schema elements that it supports. The *usb\_host\_based\_sample\_extension.xml* file that is included with the sample, provides information about the supported schema elements. + +The Bidi schema is a hierarchy of printer attributes, some of which are properties and others that are values (or value entries). + +*Property* + +A property is a node in the schema hierarchy. A property can have one or more children, and these children can be other properties or values. + +*Value* + +A value is a leaf in the schema hierarchy that represents either a single data item or a list of related data items. A value has a name, a data type, and a data value. A value cannot have child elements. + +For more information, see [USB Bidi Extender](http://msdn.microsoft.com/en-us/library/windows/hardware/jj659903(v=vs.85).aspx) and [Bidi Communication Schema](http://msdn.microsoft.com/en-us/library/windows/hardware/ff545169(v=vs.85).aspx). + +Here are the core files that you will find in this sample: + +File name + +Description + +usb\_host\_based\_sample.js + +A USB Bidi Extension JavaScript file which includes support for controlling printing for host-based devices. This is the only code in the driver sample. It is invoked by USBMon and it communicates with the device to do the following: + +- Determine if the device is ready to receive data +- Check to see if there is an error condition +- Read the device status + +usb\_host\_based\_sample\_events.xml + +A 'driver events' XML file that specifies an event which detects when the user needs to flip over the paper in the tray. + +usb\_host\_based\_sample\_extension.xml + +A USB Bidi Extension XML file that specifies the supported Bidi Schema elements for this driver. + + +Build the sample +---------------- + +For information and instructions about how to test and deploy drivers, see [Developing, Testing, and Deploying Drivers](http://msdn.microsoft.com/en-us/library/windows/hardware/ff554651(v=vs.85).aspx). + +Run the sample +-------------- + +To understand how to run this sample as a Windows driver, see the [v4 Printer Driver](http://msdn.microsoft.com/en-us/library/windows/hardware/hh706306(v=vs.85).aspx) collection of topics. + diff --git a/print/v4PrintDriverSamples/v4PrintDriver-HostBasedSampleDriver/usb_host_based_sample-manifest.ini b/print/v4PrintDriverSamples/v4PrintDriver-HostBasedSampleDriver/usb_host_based_sample-manifest.ini new file mode 100644 index 00000000..3205ffcf --- /dev/null +++ b/print/v4PrintDriverSamples/v4PrintDriver-HostBasedSampleDriver/usb_host_based_sample-manifest.ini @@ -0,0 +1,13 @@ +[DriverConfig] +DriverCategory=PrintFax.Printer +DataFile=usb_host_based_sample.gpd + +; Note: Please replace the GUID below when building a production driver. +PrinterDriverID={00000000-0000-0000-0000-000000000000} +Flags=HostBasedDevice +EventFile=usb_host_based_sample_events.xml +RequiredFiles=UNIRES.DLL,STDNAMES.GPD,MSXPSINC.GPD + +[BidiFiles] +BidiUSBFile=usb_host_based_sample_extension.xml +BidiUSBJSFile=usb_host_based_sample.js diff --git a/print/v4PrintDriverSamples/v4PrintDriver-HostBasedSampleDriver/usb_host_based_sample-pipelineconfig.xml b/print/v4PrintDriverSamples/v4PrintDriver-HostBasedSampleDriver/usb_host_based_sample-pipelineconfig.xml new file mode 100644 index 00000000..905358a2 --- /dev/null +++ b/print/v4PrintDriverSamples/v4PrintDriver-HostBasedSampleDriver/usb_host_based_sample-pipelineconfig.xml @@ -0,0 +1 @@ + diff --git a/print/v4PrintDriverSamples/v4PrintDriver-HostBasedSampleDriver/usb_host_based_sample.gpd b/print/v4PrintDriverSamples/v4PrintDriver-HostBasedSampleDriver/usb_host_based_sample.gpd new file mode 100644 index 00000000..1f37334c --- /dev/null +++ b/print/v4PrintDriverSamples/v4PrintDriver-HostBasedSampleDriver/usb_host_based_sample.gpd @@ -0,0 +1,138 @@ +*% +*% This file is a sample GPD demonstrating basic printer features/options +*% +*% + +*%****************************************************************************** +*%: The following root-level attributes should be modified to suit your printer +*%****************************************************************************** +*GPDFileName: "usb_host_based.GPD" +*GPDFileVersion: "1.0" +*GPDSpecVersion: "1.0" +*Include: "StdNames.gpd" +*%************************************************** +*% V4 GPD-based printer drivers must include msxpsinc.GPD file +*%************************************************** +*Include: "msxpsinc.gpd" +*ModelName: "Microsft USB Host Based Sample Driver" +*MasterUnits: PAIR(1200, 1200) +*PrinterType: PAGE +*MaxCopies: 1 +*Command: CmdSendBlockData { *Cmd : "" } + +*PrintSchemaPrivateNamespaceURI: "http://www.microsoft.com/USBHostBasedSample" + +*%****************************************************************************** +*% Orientation +*%****************************************************************************** +*Feature: Orientation +{ + *rcNameID: =ORIENTATION_DISPLAY + *DefaultOption: PORTRAIT + + *Option: PORTRAIT + { + *rcNameID: =PORTRAIT_DISPLAY + } + + *Option: LANDSCAPE_CC270 + { + *rcNameID: =LANDSCAPE_DISPLAY + } +} + + +*%****************************************************************************** +*% Resolution +*%****************************************************************************** +*Feature: Resolution +{ + *rcNameID: =RESOLUTION_DISPLAY + *DefaultOption: Option1 + + *Option: Option1 + { + *Name: "600 x 600 " =DOTS_PER_INCH + *DPI: PAIR(600, 600) + *TextDPI: PAIR(600, 600) + *SpotDiameter: 100 + } +} + +*%****************************************************************************** +*% Input Bin +*%****************************************************************************** +*Feature: InputBin +{ + *rcNameID: =PAPER_SOURCE_DISPLAY + *DefaultOption: FORMSOURCE + + *Option: FORMSOURCE + { + *rcNameID: =AUTO_DISPLAY + } + *Option: UPPER + { + *rcNameID: =UPPER_TRAY_DISPLAY + } +} + +*%****************************************************************************** +*% Paper Size +*%****************************************************************************** +*Feature: PaperSize +{ + *rcNameID: =PAPER_SIZE_DISPLAY + *DefaultOption: LETTER + + *Option: LETTER + { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME *% 1000 + *switch: Orientation + { + *case: PORTRAIT + { + *PrintableArea: PAIR(9000, 12600) + *PrintableOrigin: PAIR(200, 200) + *CursorOrigin: PAIR(0, 0) + } + *case: LANDSCAPE_CC270 + { + *PrintableArea: PAIR(9000, 12600) + *PrintableOrigin: PAIR(200, 200) + *CursorOrigin: PAIR(0, 0) + } + } + } + + *Option: A4 + { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME *% 1008 + *switch: Orientation + { + *case: PORTRAIT + { + *PrintableArea: PAIR(9000, 12600) + *PrintableOrigin: PAIR(200, 200) + *CursorOrigin: PAIR(0, 0) + } + *case: LANDSCAPE_CC270 + { + *PrintableArea: PAIR(9000, 12600) + *PrintableOrigin: PAIR(200, 200) + *CursorOrigin: PAIR(0, 0) + } + } + } +} + +*%****************************************************************************** +*% Cursor Commands +*% The following cursor commands are mandatory +*% +*% Learn more: Cursor Commands +*% http://msdn.microsoft.com/en-us/library/ff547223(VS.85).aspx +*%****************************************************************************** +*Command: CmdCR { *Cmd : "" } +*Command: CmdLF { *Cmd : "" } +*Command: CmdFF { *Cmd : "" } diff --git a/print/v4PrintDriverSamples/v4PrintDriver-HostBasedSampleDriver/usb_host_based_sample.inf b/print/v4PrintDriverSamples/v4PrintDriver-HostBasedSampleDriver/usb_host_based_sample.inf new file mode 100644 index 00000000..4297a35a --- /dev/null +++ b/print/v4PrintDriverSamples/v4PrintDriver-HostBasedSampleDriver/usb_host_based_sample.inf @@ -0,0 +1,108 @@ +; +; usb_host_based_sample.inf +; +; Microsoft USB Host Based Sample Driver +; +; Copyright Microsoft Corporation +; +[Version] +Signature="$Windows NT$" +Provider=%MS% +CatalogFile=usb_host_based_sample.cat +ClassGUID={4D36E979-E325-11CE-BFC1-08002BE10318} +Class=Printer +DriverVer=03/12/2013,1.0.0.1 +ClassVer=4.0 + +; +; Manufacturer section. +; +; This section lists all of the manufacturers +; that we will display in the Dialog box +; +[Manufacturer] +%MS%=Microsoft, NTx86, NTamd64, NTarm, NTarm64 + +; +; Model sections +; +; Each section here corresponds with an entry listed in the +; [Manufacturer] section above. The models will be displayed in the order +; that they appear in the INF file. +; + +[Microsoft.NTx86] +"Microsoft USB Host Based Sample Driver" = USB_HOST_BASED_SAMPLE, DO_NOT_USE_THIS_HWID1, + +[Microsoft.NTamd64] +"Microsoft USB Host Based Sample Driver" = USB_HOST_BASED_SAMPLE, DO_NOT_USE_THIS_HWID1 + +[Microsoft.NTarm] +"Microsoft USB Host Based Sample Driver" = USB_HOST_BASED_SAMPLE, DO_NOT_USE_THIS_HWID1 + +[Microsoft.NTarm64] +"Microsoft USB Host Based Sample Driver" = USB_HOST_BASED_SAMPLE, DO_NOT_USE_THIS_HWID1 + +; +; Installer Sections +; +; These sections control file installation, and reference all files that +; need to be copied. The section name will be assumed to be the driver +; file, unless there is an explicit DriverFile section listed. +; +[USB_HOST_BASED_SAMPLE] +CopyFiles=USB_HOST_BASED_SAMPLE_FILES + +; +; Copy Sections +; +; Lists of files that are actually copied. These sections are referenced +; from the installer sections, above. Only create a section if it contains +; two or more files (if we only copy a single file, identify it in the +; installer section, using the @filename notation) or if it's a color +; profile (since the DestinationDirs can only handle sections, and not +; individual files). +; + +[USB_HOST_BASED_SAMPLE_FILES] +usb_host_based_sample.gpd +usb_host_based_sample-pipelineconfig.xml +usb_host_based_sample_extension.xml +usb_host_based_sample-manifest.ini +usb_host_based_sample.js +usb_host_based_sample_events.xml + +[DestinationDirs] +DefaultDestDir=66000 + +; +; Source Disk Section +; Location of source files +; + +[SourceDisksFiles] +usb_host_based_sample.gpd = 1 +usb_host_based_sample-pipelineconfig.xml = 1 +usb_host_based_sample-manifest.ini = 1 +usb_host_based_sample.js = 1 +usb_host_based_sample_extension.xml = 1 +usb_host_based_sample_events.xml = 1 + +[SourceDisksNames.x86] +1 = %Disk1%,,, + +[SourceDisksNames.amd64] +1 = %Disk1%,,, + +[SourceDisksNames.arm] +1 = %Disk1%,,, + +[SourceDisksNames.arm64] +1 = %Disk1%,,, + +; +; Localizable Strings +; +[Strings] +Disk1="." +MS="Microsoft" diff --git a/print/v4PrintDriverSamples/v4PrintDriver-HostBasedSampleDriver/usb_host_based_sample.js b/print/v4PrintDriverSamples/v4PrintDriver-HostBasedSampleDriver/usb_host_based_sample.js new file mode 100644 index 00000000..f7131583 Binary files /dev/null and b/print/v4PrintDriverSamples/v4PrintDriver-HostBasedSampleDriver/usb_host_based_sample.js differ diff --git a/print/v4PrintDriverSamples/v4PrintDriver-HostBasedSampleDriver/usb_host_based_sample_events.xml b/print/v4PrintDriverSamples/v4PrintDriver-HostBasedSampleDriver/usb_host_based_sample_events.xml new file mode 100644 index 00000000..bf6953df --- /dev/null +++ b/print/v4PrintDriverSamples/v4PrintDriver-HostBasedSampleDriver/usb_host_based_sample_events.xml @@ -0,0 +1,11 @@ + + + + USB + \Printer.Extension + + + + + + \ No newline at end of file diff --git a/print/v4PrintDriverSamples/v4PrintDriver-HostBasedSampleDriver/usb_host_based_sample_extension.xml b/print/v4PrintDriverSamples/v4PrintDriver-HostBasedSampleDriver/usb_host_based_sample_extension.xml new file mode 100644 index 00000000..7d892878 --- /dev/null +++ b/print/v4PrintDriverSamples/v4PrintDriver-HostBasedSampleDriver/usb_host_based_sample_extension.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/print/v4PrintDriverSamples/v4PrintDriver-HostBasedSampleDriver/v4PrintDriver-Intellisense-Windows8.1.js b/print/v4PrintDriverSamples/v4PrintDriver-HostBasedSampleDriver/v4PrintDriver-Intellisense-Windows8.1.js new file mode 100644 index 00000000..bbbc31a0 --- /dev/null +++ b/print/v4PrintDriverSamples/v4PrintDriver-HostBasedSampleDriver/v4PrintDriver-Intellisense-Windows8.1.js @@ -0,0 +1,126 @@ +/// + +v4PrintDriverIntellisense.appendInterfaceMethods( + IPrintSchemaTicket, + { + GetParameterInitializer: function (name, namespaceUri) { + /// + /// Method maps to COM IPrintSchemaTicket2::GetParameterInitializer. + /// + /// + /// + /// + } + }); + +v4PrintDriverIntellisense.appendInterfaceMethods( + IPrintSchemaCapabilities, + { + GetParameterDefinition: function (name, namespaceUri) { + /// + /// Method maps to COM IPrintSchemaCapabilities2::GetParameterDefinition. + /// + /// + /// + /// + } + }); + +IPrintSchemaParameterInitializer = function () { } +v4PrintDriverIntellisense.createInterface( + IPrintSchemaParameterInitializer, + IPrintSchemaElement, + { + /// + /// Property-get/set maps to COM IPrintSchemaParameterInitializer::Value. + /// + Value: null, + }); + +IPrintSchemaParameterDefinition = function () { } +v4PrintDriverIntellisense.createInterface( + IPrintSchemaParameterDefinition, + IPrintSchemaDisplayableElement, + { + /// + /// Property-get maps to COM IPrintSchemaParameterDefinition::UserInputRequired. + /// + UserInputRequired: null, + /// + /// Property-get maps to COM IPrintSchemaParameterDefinition::UnitType. + /// + UnitType: null, + /// + /// Property-get maps to COM IPrintSchemaParameterDefinition::DataType. + /// + DataType: null, + /// + /// Property-get maps to COM IPrintSchemaParameterDefinition::RangeMin. + /// + RangeMin: null, + /// + /// Property-get maps to COM IPrintSchemaParameterDefinition::RangeMax. + /// + RangeMax: null + }); + +IPrinterScriptUsbJobContextReturnCodes = function () { } +v4PrintDriverIntellisense.createInterface( + IPrinterScriptUsbJobContextReturnCodes, + null, + { + /// + /// Property-get maps to COM IPrinterScriptUsbJobContextReturnCodes::Success. + /// + Success: null, + /// + /// Property-get maps to COM IPrinterScriptUsbJobContextReturnCodes::Failure. + /// + Failure: null, + /// + /// Property-get maps to COM IPrinterScriptUsbJobContextReturnCodes::Retry. + /// + Retry: null, + /// + /// Property-get maps to COM IPrinterScriptUsbJobContextReturnCodes::DeviceBusy. + /// + DeviceBusy: null, + /// + /// Property-get maps to COM IPrinterScriptUsbJobContextReturnCodes::AbortTheJob. + /// + AbortTheJob: null + }); + +IPrinterScriptUsbWritePrintDataProgress = function () { } +v4PrintDriverIntellisense.createInterface( + IPrinterScriptUsbWritePrintDataProgress, + null, + { + /// + /// Property-get/set maps to COM IPrinterScriptUsbWritePrintDataProgress::ProcessedByteCount. + /// + ProcessedByteCount: null + }); + +IPrinterScriptUsbJobContext = function () { } +v4PrintDriverIntellisense.createInterface( + IPrinterScriptUsbJobContext, + null, + { + /// + /// Property-get maps to COM IPrinterScriptUsbJobContext::JobPropertyBag. + /// + JobPropertyBag: null, + /// + /// Property-get maps to COM IPrinterScriptUsbJobContext::ReturnCodes. + /// + ReturnCodes: null, + /// + /// Property-get maps to COM IPrinterScriptUsbJobContext::TemporaryStreams. Provides an array of IPrinterScriptableSequentialStream. + /// + TemporaryStreams: null, + /// + /// Property-get/set maps to COM IPrinterScriptUsbJobContext::PrintedPageCount. + /// + PrintedPageCount: null + }); \ No newline at end of file diff --git a/print/v4PrintDriverSamples/v4PrintDriver-HostBasedSampleDriver/v4PrintDriver-Intellisense.js b/print/v4PrintDriverSamples/v4PrintDriver-HostBasedSampleDriver/v4PrintDriver-Intellisense.js new file mode 100644 index 00000000..2386541d --- /dev/null +++ b/print/v4PrintDriverSamples/v4PrintDriver-HostBasedSampleDriver/v4PrintDriver-Intellisense.js @@ -0,0 +1,513 @@ +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +// PARTICULAR PURPOSE. +// +// Copyright (c) Microsoft Corporation. All rights reserved +// +// File Name: +// +// v4PrintDriver-Intellisense.js +// +// Abstract: +// +// This file defines intellisense to be used by JavaScript extensions in v4 print drivers. + +var v4PrintDriverIntellisense = { + /// Intended for use by v4 print driver JavaScript Intellisense. + createInterface: function (childInterface, baseType, prototype) { + /// Intended for use by v4 print driver JavaScript Intellisense. + childInterface.__class = true; + + if (prototype) { + childInterface.prototype = prototype; + } + + if (baseType) { + childInterface.__baseType = baseType; + childInterface.__basePrototypePending = true; + v4PrintDriverIntellisense.resolveInheritance(childInterface); + } + }, + appendInterfaceMethods: function (baseType, prototype) { + /// Intended for use by v4 print driver JavaScript Intellisense. + for (var memberName in prototype) { + baseType.prototype[memberName] = prototype[memberName]; + } + }, + resolveInheritance: function (childInterface) { + /// Intended for use by v4 print driver JavaScript Intellisense. + var baseType = childInterface.__baseType; + if (!baseType) { + return; + } + + if (baseType.__baseType) { + resolveInheritance(baseType); + } + + if (!childInterface.__basePrototypePending) { + return; + } + + for (var memberName in baseType.prototype) { + var memberValue = baseType.prototype[memberName]; + if (!childInterface.prototype[memberName]) { + childInterface.prototype[memberName] = memberValue; + } + } + + delete childInterface.__basePrototypePending; + } +} + +IPrintSchemaElement = function () { } +v4PrintDriverIntellisense.createInterface( + IPrintSchemaElement, + null, + { + /// + /// Property-get maps to COM IPrintSchemaElement::XmlNode. + /// + XmlNode: null, + /// + /// Property-get maps to COM IPrintSchemaElement::Name. + /// + Name: null, + /// + /// Property-get maps to COM IPrintSchemaElement::NamespaceUri. + /// + NamespaceUri: null + }); + +IPrintSchemaDisplayableElement = function () { } +v4PrintDriverIntellisense.createInterface( + IPrintSchemaDisplayableElement, + IPrintSchemaElement, + { + /// + /// Property-get maps to COM IPrintSchemaDisplayableElement::DisplayName. + /// + DisplayName: null + }); + + +IPrintSchemaOption = function () { } +v4PrintDriverIntellisense.createInterface( + IPrintSchemaOption, + IPrintSchemaDisplayableElement, + { + /// + /// Property-get maps to COM IPrintSchemaOption::Selected. + /// + Selected: null, + /// + /// Property-get maps to COM IPrintSchemaOption::Constrained. + /// + Constrained: null, + GetPropertyValue: function (name, namespaceUri) { + /// + /// Method maps to COM IPrintSchemaOption::GetPropertyValue. + /// + /// + /// + /// + }, + /// + /// Property-get maps to COM IPrintSchemaNUpOption::PagesPerSheet. Valid for NUp option only. + /// + PagesPerSheet: null, + /// + /// Property-get maps to COM IPrintSchemaPageMediaSizeOption::WidthInMicrons. Valid for PageMediaSize option only. + /// + WidthInMicrons: null, + /// + /// Property-get maps to COM IPrintSchemaPageMediaSizeOption::HeightInMicrons. Valid for PageMediaSize option only. + /// + HeightInMicrons: null + + }); + +IPrintSchemaOptionCollection = function () { } +v4PrintDriverIntellisense.createInterface( + IPrintSchemaOptionCollection, + null, + { + /// + /// Property-get maps to COM IPrintSchemaOptionCollection::Count. + /// + Count: null, + GetAt: function (index) { + /// + /// Property-get maps to COM IPrintSchemaOptionCollection::GetAt. + /// + /// + /// + } + }); + + +IPrintSchemaFeature = function () { } +v4PrintDriverIntellisense.createInterface( + IPrintSchemaFeature, + IPrintSchemaDisplayableElement, + { + /// + /// Property-set/get maps to COM IPrintSchemaFeature::SelectedOption. + /// + SelectedOption: null, + /// + /// Property-get maps to COM IPrintSchemaFeature::SelectionType. + /// + SelectionType: null, + GetOption: function (name, namespaceUri) { + /// + /// Method maps to COM IPrintSchemaFeature::GetOption. + /// + /// + /// + /// + }, + /// + /// Property-get maps to COM IPrintSchemaFeature::DisplayUI. + /// + DisplayUI: null + }); + + +IPrintSchemaPageImageableSize = function () { } +v4PrintDriverIntellisense.createInterface( + IPrintSchemaPageImageableSize, + IPrintSchemaElement, + { + /// + /// Property-get maps to COM IPrintSchemaPageImageableSize::ImageableSizeWidthInMicrons. + /// + ImageableSizeWidthInMicrons: null, + /// + /// Property-get maps to COM IPrintSchemaPageImageableSize::ImageableSizeHeightInMicrons. + /// + ImageableSizeHeightInMicrons: null, + /// + /// Property-get maps to COM IPrintSchemaPageImageableSize::OriginWidthInMicrons. + /// + OriginWidthInMicrons: null, + /// + /// Property-get maps to COM IPrintSchemaPageImageableSize::OriginHeightInMicrons. + /// + OriginHeightInMicrons: null, + /// + /// Property-get maps to COM IPrintSchemaPageImageableSize::ExtentWidthInMicrons. + /// + ExtentWidthInMicrons: null, + /// + /// Property-get maps to COM IPrintSchemaPageImageableSize::ExtentHeightInMicrons. + /// + ExtentHeightInMicrons: null + }); + + +IPrintSchemaCapabilities = function () { } +v4PrintDriverIntellisense.createInterface( + IPrintSchemaCapabilities, + IPrintSchemaElement, + { + GetFeatureByKeyName: function (keyName) { + /// + /// Method maps to COM IPrintSchemaCapabilities::GetFeatureByKeyName. + /// + /// + /// + }, + GetFeature: function (name, namespaceUri) { + /// + /// Method maps to COM IPrintSchemaCapabilities::GetFeature. + /// + /// + /// + /// + }, + /// + /// Property-get maps to COM IPrintSchemaCapabilities::PageImageableSize. + /// + PageImageableSize: null, + /// + /// Property-get maps to COM IPrintSchemaCapabilities::JobCopiesAllDocumentsMinValue. + /// + JobCopiesAllDocumentsMinValue: null, + /// + /// Property-get maps to COM IPrintSchemaCapabilities::JobCopiesAllDocumentsMaxValue. + /// + JobCopiesAllDocumentsMaxValue: null, + GetSelectedOptionInPrintTicket: function (feature) { + /// + /// Method maps to COM IPrintSchemaCapabilities::GetSelectedOptionInPrintTicket. + /// + /// + /// + }, + GetOptions: function (feature) { + /// + /// Method maps to COM IPrintSchemaCapabilities::GetOptions. + /// + /// + /// + } + }); + + +IPrintSchemaTicket = function () { } +v4PrintDriverIntellisense.createInterface( + IPrintSchemaTicket, + IPrintSchemaElement, + { + GetFeatureByKeyName: function (keyName) { + /// + /// Method maps to COM IPrintSchemaTicket::GetFeatureByKeyName. + /// + /// + /// + }, + GetFeature: function (name, namespaceUri) { + /// + /// Method maps to COM IPrintSchemaTicket::GetFeature. + /// + /// + /// + /// + }, + NotifyXmlChanged: function () { + /// + /// Method maps to COM IPrintSchemaTicket::NotifyXmlChanged. + /// + }, + GetCapabilities: function () { + /// + /// Method maps to COM IPrintSchemaTicket::GetCapabilities. + /// + /// + }, + /// + /// Property-get/put maps to IPrintSchemaTicket::JobCopiesAllDocuments. + /// + JobCopiesAllDocuments: null + }); + + +IPrinterScriptableSequentialStream = function () { } +v4PrintDriverIntellisense.createInterface( + IPrinterScriptableSequentialStream, + null, + { + Read: function (count) { + /// + /// Method maps to COM IPrinterScriptableSequentialStream::Read. + /// + /// + /// + }, + Write: function (array) { + /// + /// Method maps to COM IPrinterScriptableSequentialStream::Write. + /// + /// + /// + } + }); + +IPrinterScriptableStream = function () { } +v4PrintDriverIntellisense.createInterface( + IPrinterScriptableStream, + IPrinterScriptableSequentialStream, + { + Commit: function () { + /// + /// Method maps to COM IPrinterScriptableStream::Commit. + /// + }, + Seek: function (offset, streamSeek) { + /// + /// Method maps to COM IPrinterScriptableStream::Seek + /// + /// + /// + /// + }, + SetSize: function (size) { + /// + /// Method maps to COM IPrinterScriptableStream::SetSize. + /// + /// + } + }); + + +IPrinterScriptablePropertyBag = function () { } +v4PrintDriverIntellisense.createInterface( + IPrinterScriptablePropertyBag, + null, + { + GetBool: function (name) { + /// + /// Method maps to COM IPrinterScriptablePropertyBag::GetBool. + /// + /// + /// + }, + SetBool: function (name, value) { + /// + /// Method maps to COM IPrinterScriptablePropertyBag::SetBool. + /// + /// + /// + }, + GetInt32: function (name) { + /// + /// Method maps to COM IPrinterScriptablePropertyBag::GetInt32. + /// + /// + /// + }, + SetInt32: function (name, value) { + /// + /// Method maps to COM IPrinterScriptablePropertyBag::SetInt32. + /// + /// + /// + }, + GetString: function (name) { + /// + /// Method maps to COM IPrinterScriptablePropertyBag::GetString. + /// + /// + /// + }, + SetString: function (name, value) { + /// + /// Method maps to COM IPrinterScriptablePropertyBag::SetString. + /// + /// + /// + }, + GetReadStream: function (name) { + /// + /// Method maps to COM IPrinterScriptablePropertyBag::GetReadStream. + /// + /// + /// + }, + GetWriteStream: function (name) { + /// + /// Method maps to COM IPrinterScriptablePropertyBag::GetWriteStream. + /// + /// + /// + } + }); + + +IPrinterScriptContext = function () { } +v4PrintDriverIntellisense.createInterface( + IPrinterScriptContext, + null, + { + /// + /// Property-get maps to COM IPrinterScriptContext::DriverProperties. + /// + DriverProperties: null, + /// + /// Property-get maps to COM IPrinterScriptContext::QueueProperties. + /// + QueueProperties: null, + /// + /// Property-get maps to COM IPrinterScriptContext::UserProperties. + /// + UserProperties: null + }); + +IPrinterBidiSchemaElement = function () { } +v4PrintDriverIntellisense.createInterface( + IPrinterBidiSchemaElement, + null, + { + /// + /// Property-get maps to COM IPrinterBidiSchemaElement::Name. + /// + Name: null, + /// + /// Property-get maps to COM IPrinterBidiSchemaElement::BidiType. + /// + BidiType: null, + /// + /// Property-get maps to COM IPrinterBidiSchemaElement::Value. + /// + Value: null + }); + +IPrinterBidiSchemaResponses = function () { } +v4PrintDriverIntellisense.createInterface( + IPrinterBidiSchemaResponses, + null, + { + AddNull: function (schema) { + /// + /// Method maps to COM IPrinterBidiSchemaResponses::AddNull. + /// + /// + }, + AddString: function (schema, value) { + /// + /// Method maps to COM IPrinterBidiSchemaResponses::AddString. + /// + /// + /// + }, + AddText: function (schema, value) { + /// + /// Method maps to COM IPrinterBidiSchemaResponses::AddText. + /// + /// + /// + }, + AddEnum: function (schema, value) { + /// + /// Method maps to COM IPrinterBidiSchemaResponses::AddEnum. + /// + /// + /// + }, + AddInt32: function (schema, value) { + /// + /// Method maps to COM IPrinterBidiSchemaResponses::AddInt32. + /// + /// + /// + }, + AddBool: function (schema, value) { + /// + /// Method maps to COM IPrinterBidiSchemaResponses::AddBool. + /// + /// + /// + }, + AddFloat: function (schema, value) { + /// + /// Method maps to COM IPrinterBidiSchemaResponses::AddFloat. + /// + /// + /// + }, + AddBlob: function (schema, array) { + /// + /// Method maps to COM IPrinterBidiSchemaResponses::AddBlob. + /// + /// + /// + }, + AddRequeryKey: function (queryKey) { + /// + /// Method maps to COM IPrinterBidiSchemaResponses::AddRequeryKey. + /// + /// + } + }); diff --git a/print/v4PrintDriverSamples/v4PrintDriver-USBMon-Bidi-Extension/USBMon-Bidi-Extension.sln b/print/v4PrintDriverSamples/v4PrintDriver-USBMon-Bidi-Extension/USBMon-Bidi-Extension.sln index accd9781..d9dd00fb 100644 --- a/print/v4PrintDriverSamples/v4PrintDriver-USBMon-Bidi-Extension/USBMon-Bidi-Extension.sln +++ b/print/v4PrintDriverSamples/v4PrintDriver-USBMon-Bidi-Extension/USBMon-Bidi-Extension.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "USBMon-Bidi-Extension", "USBMon-Bidi-Extension.vcxproj", "{9ADDA646-6402-49C1-8DE3-5E8161501609}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "USBMon-Bidi-Extension", "USBMon-Bidi-Extension.vcxproj", "{AAFFC04F-26D7-4533-B15E-1E1687EB77D3}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +13,14 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {9ADDA646-6402-49C1-8DE3-5E8161501609}.Debug|Win32.ActiveCfg = Debug|Win32 - {9ADDA646-6402-49C1-8DE3-5E8161501609}.Debug|Win32.Build.0 = Debug|Win32 - {9ADDA646-6402-49C1-8DE3-5E8161501609}.Release|Win32.ActiveCfg = Release|Win32 - {9ADDA646-6402-49C1-8DE3-5E8161501609}.Release|Win32.Build.0 = Release|Win32 - {9ADDA646-6402-49C1-8DE3-5E8161501609}.Debug|x64.ActiveCfg = Debug|x64 - {9ADDA646-6402-49C1-8DE3-5E8161501609}.Debug|x64.Build.0 = Debug|x64 - {9ADDA646-6402-49C1-8DE3-5E8161501609}.Release|x64.ActiveCfg = Release|x64 - {9ADDA646-6402-49C1-8DE3-5E8161501609}.Release|x64.Build.0 = Release|x64 + {AAFFC04F-26D7-4533-B15E-1E1687EB77D3}.Debug|Win32.ActiveCfg = Debug|Win32 + {AAFFC04F-26D7-4533-B15E-1E1687EB77D3}.Debug|Win32.Build.0 = Debug|Win32 + {AAFFC04F-26D7-4533-B15E-1E1687EB77D3}.Release|Win32.ActiveCfg = Release|Win32 + {AAFFC04F-26D7-4533-B15E-1E1687EB77D3}.Release|Win32.Build.0 = Release|Win32 + {AAFFC04F-26D7-4533-B15E-1E1687EB77D3}.Debug|x64.ActiveCfg = Debug|x64 + {AAFFC04F-26D7-4533-B15E-1E1687EB77D3}.Debug|x64.Build.0 = Debug|x64 + {AAFFC04F-26D7-4533-B15E-1E1687EB77D3}.Release|x64.ActiveCfg = Release|x64 + {AAFFC04F-26D7-4533-B15E-1E1687EB77D3}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/print/v4PrintDriverSamples/v4PrintDriver-USBMon-Bidi-Extension/USBMon-Bidi-Extension.vcxproj b/print/v4PrintDriverSamples/v4PrintDriver-USBMon-Bidi-Extension/USBMon-Bidi-Extension.vcxproj index 5dac5ac6..d6ff88ca 100644 --- a/print/v4PrintDriverSamples/v4PrintDriver-USBMon-Bidi-Extension/USBMon-Bidi-Extension.vcxproj +++ b/print/v4PrintDriverSamples/v4PrintDriver-USBMon-Bidi-Extension/USBMon-Bidi-Extension.vcxproj @@ -19,12 +19,12 @@
- {9ADDA646-6402-49C1-8DE3-5E8161501609} + {AAFFC04F-26D7-4533-B15E-1E1687EB77D3} $(MSBuildProjectName) false Debug Win32 - {5233D70B-3962-4627-B29A-9C0A35610B5B} + {7DC67506-ED7D-464A-8950-91E1A3485356} diff --git a/print/v4PrintDriverSamples/v4PrintDriver-USBMon-Bidi-Extension/USBMon-Bidi-Extension.vcxproj.Filters b/print/v4PrintDriverSamples/v4PrintDriver-USBMon-Bidi-Extension/USBMon-Bidi-Extension.vcxproj.Filters index bdfa6e2f..bc347870 100644 --- a/print/v4PrintDriverSamples/v4PrintDriver-USBMon-Bidi-Extension/USBMon-Bidi-Extension.vcxproj.Filters +++ b/print/v4PrintDriverSamples/v4PrintDriver-USBMon-Bidi-Extension/USBMon-Bidi-Extension.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {779218F5-6AF7-428A-B095-7CBA5126C413} + {08A89D46-9794-49C4-A5DA-AED702601A98} h;hpp;hxx;hm;inl;inc;xsd - {7EE9AB0A-990F-4733-8072-4F30033D2B77} + {98EBFD2A-3A4F-479C-964C-8F3F91CF1ED9} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {404DBCB9-03F7-4AB9-A0D5-36D7DF44DCEE} + {827B912F-6627-485D-ACE9-ACF6A014186B} inf;inv;inx;mof;mc; - {B4AECD6D-977B-4925-90B0-28186A3AAFD2} + {C469AF55-3C55-4086-BC4C-7597B99B1528} diff --git a/print/v4PrintDriverSamples/v4PrintDriver-WSDMon-Bidi-Extension/WSDMon-Bidi-Extension.sln b/print/v4PrintDriverSamples/v4PrintDriver-WSDMon-Bidi-Extension/WSDMon-Bidi-Extension.sln index 7c7318e6..24a86e72 100644 --- a/print/v4PrintDriverSamples/v4PrintDriver-WSDMon-Bidi-Extension/WSDMon-Bidi-Extension.sln +++ b/print/v4PrintDriverSamples/v4PrintDriver-WSDMon-Bidi-Extension/WSDMon-Bidi-Extension.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WSDMon-Bidi-Extension", "WSDMon-Bidi-Extension.vcxproj", "{F3AE3A42-0F21-4E36-8E5D-F3C399060D3D}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WSDMon-Bidi-Extension", "WSDMon-Bidi-Extension.vcxproj", "{9629A925-8512-41CB-AD2E-F730F7D457AB}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +13,14 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {F3AE3A42-0F21-4E36-8E5D-F3C399060D3D}.Debug|Win32.ActiveCfg = Debug|Win32 - {F3AE3A42-0F21-4E36-8E5D-F3C399060D3D}.Debug|Win32.Build.0 = Debug|Win32 - {F3AE3A42-0F21-4E36-8E5D-F3C399060D3D}.Release|Win32.ActiveCfg = Release|Win32 - {F3AE3A42-0F21-4E36-8E5D-F3C399060D3D}.Release|Win32.Build.0 = Release|Win32 - {F3AE3A42-0F21-4E36-8E5D-F3C399060D3D}.Debug|x64.ActiveCfg = Debug|x64 - {F3AE3A42-0F21-4E36-8E5D-F3C399060D3D}.Debug|x64.Build.0 = Debug|x64 - {F3AE3A42-0F21-4E36-8E5D-F3C399060D3D}.Release|x64.ActiveCfg = Release|x64 - {F3AE3A42-0F21-4E36-8E5D-F3C399060D3D}.Release|x64.Build.0 = Release|x64 + {9629A925-8512-41CB-AD2E-F730F7D457AB}.Debug|Win32.ActiveCfg = Debug|Win32 + {9629A925-8512-41CB-AD2E-F730F7D457AB}.Debug|Win32.Build.0 = Debug|Win32 + {9629A925-8512-41CB-AD2E-F730F7D457AB}.Release|Win32.ActiveCfg = Release|Win32 + {9629A925-8512-41CB-AD2E-F730F7D457AB}.Release|Win32.Build.0 = Release|Win32 + {9629A925-8512-41CB-AD2E-F730F7D457AB}.Debug|x64.ActiveCfg = Debug|x64 + {9629A925-8512-41CB-AD2E-F730F7D457AB}.Debug|x64.Build.0 = Debug|x64 + {9629A925-8512-41CB-AD2E-F730F7D457AB}.Release|x64.ActiveCfg = Release|x64 + {9629A925-8512-41CB-AD2E-F730F7D457AB}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/print/v4PrintDriverSamples/v4PrintDriver-WSDMon-Bidi-Extension/WSDMon-Bidi-Extension.vcxproj b/print/v4PrintDriverSamples/v4PrintDriver-WSDMon-Bidi-Extension/WSDMon-Bidi-Extension.vcxproj index 960aff5b..136ac8d4 100644 --- a/print/v4PrintDriverSamples/v4PrintDriver-WSDMon-Bidi-Extension/WSDMon-Bidi-Extension.vcxproj +++ b/print/v4PrintDriverSamples/v4PrintDriver-WSDMon-Bidi-Extension/WSDMon-Bidi-Extension.vcxproj @@ -19,12 +19,12 @@ - {F3AE3A42-0F21-4E36-8E5D-F3C399060D3D} + {9629A925-8512-41CB-AD2E-F730F7D457AB} $(MSBuildProjectName) false Debug Win32 - {97755429-CC3C-4B58-BC51-A59C619F85C8} + {6B788CC8-550C-41A8-8182-DDD6FF0808F5} diff --git a/print/v4PrintDriverSamples/v4PrintDriver-WSDMon-Bidi-Extension/WSDMon-Bidi-Extension.vcxproj.Filters b/print/v4PrintDriverSamples/v4PrintDriver-WSDMon-Bidi-Extension/WSDMon-Bidi-Extension.vcxproj.Filters index a0f5371f..aafacd9e 100644 --- a/print/v4PrintDriverSamples/v4PrintDriver-WSDMon-Bidi-Extension/WSDMon-Bidi-Extension.vcxproj.Filters +++ b/print/v4PrintDriverSamples/v4PrintDriver-WSDMon-Bidi-Extension/WSDMon-Bidi-Extension.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {97DCB8DD-A2C7-4BC9-9BED-F52D4DEED9F8} + {011840BF-3888-4C28-B34B-DD44E4396358} h;hpp;hxx;hm;inl;inc;xsd - {4499D9A5-12C4-4DCA-863A-080346D0DF6A} + {F231759E-CDB4-470A-AEFE-E7D23D6E2882} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {7EC62C4F-BCD7-4890-A981-D5F8E1B06D6C} + {D3DF558A-B1AE-4E01-B213-14060FF647F1} inf;inv;inx;mof;mc; - {F8B1D5FC-4292-4BC7-8521-752BFB1BE306} + {B51D78AF-436E-453E-A710-1E92BC35C51F} diff --git a/sd/miniport/sdhc/README.md b/sd/miniport/sdhc/README.md new file mode 100644 index 00000000..b5c35093 --- /dev/null +++ b/sd/miniport/sdhc/README.md @@ -0,0 +1,13 @@ +Standard SD Host Controller Miniport +=================== + +This is a sample for a Secure Digital (SD) Host Controller miniport driver. The driver works in conjunction with sdport.sys, which implements SD/SDIO/eMMC protocol and WDM interfaces, to provide the host register interface. + +## Universal Compliant +This sample builds a Windows Universal driver. It uses only APIs and DDIs that are included in Windows Core. + +This driver, sdhc.sys, provides a functional miniport implementation for a standard SD host controller. However, it does not have support for many more recent features such as: + +- UHS-I speed modes. +- HS400 +- SD 4.0 \ No newline at end of file diff --git a/sd/miniport/sdhc/inbox/sdhc.vcxproj b/sd/miniport/sdhc/inbox/sdhc.vcxproj new file mode 100644 index 00000000..04459aa7 --- /dev/null +++ b/sd/miniport/sdhc/inbox/sdhc.vcxproj @@ -0,0 +1,156 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {696C1C9C-405C-4675-B344-B5FF53BAB93A} + $(MSBuildProjectName) + Debug + Win32 + {014CCC56-7545-4368-82D4-5DBD32E969C6} + + + + Windows10 + False + Desktop + WDM + WindowsKernelModeDriver10.0 + Driver + + + Windows10 + True + Desktop + WDM + WindowsKernelModeDriver10.0 + Driver + + + Windows10 + False + Desktop + WDM + WindowsKernelModeDriver10.0 + Driver + + + Windows10 + True + Desktop + WDM + WindowsKernelModeDriver10.0 + Driver + + + + $(IntDir) + + + + + + + + + + + + + + + + .\$(IntDir)\sdhc.inf + + + + sdhc + + + sdhc + + + sdhc + + + sdhc + + + + %(AdditionalDependencies);$(DDK_LIB_PATH)\sdport.lib;$(DDK_LIB_PATH)\ntoskrnl.lib + + + true + Level4 + + + + + + + %(AdditionalDependencies);$(DDK_LIB_PATH)\sdport.lib;$(DDK_LIB_PATH)\ntoskrnl.lib + + + true + Level4 + + + + + + + %(AdditionalDependencies);$(DDK_LIB_PATH)\sdport.lib;$(DDK_LIB_PATH)\ntoskrnl.lib + + + true + Level4 + + + + + + + %(AdditionalDependencies);$(DDK_LIB_PATH)\sdport.lib;$(DDK_LIB_PATH)\ntoskrnl.lib + + + true + Level4 + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/sd/miniport/sdhc/inbox/sdhc.vcxproj.Filters b/sd/miniport/sdhc/inbox/sdhc.vcxproj.Filters new file mode 100644 index 00000000..398abeab --- /dev/null +++ b/sd/miniport/sdhc/inbox/sdhc.vcxproj.Filters @@ -0,0 +1,39 @@ + + + + + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* + {9BCD4C03-CF88-47B5-BB78-F6C8FF86F96C} + + + h;hpp;hxx;hm;inl;inc;xsd + {BCF0B6A6-7B9C-4BF8-A56B-6FE9AEF11C02} + + + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml + {70DA8E30-872B-447B-8759-726797BFE240} + + + inf;inv;inx;mof;mc; + {428B9C34-C4C4-4109-B1A9-9054F8F7C20A} + + + + + Driver Files + + + Driver Files + + + + + Source Files + + + + + Resource Files + + + \ No newline at end of file diff --git a/sd/miniport/sdhc/sdhc.c b/sd/miniport/sdhc/sdhc.c new file mode 100644 index 00000000..c7d85274 --- /dev/null +++ b/sd/miniport/sdhc/sdhc.c @@ -0,0 +1,3291 @@ +/*++ + +Copyright (c) 2002-2014 Microsoft Corporation + +Module Name: + + sdhc.c + +Abstract: + + This file contains the code that interfaces with standard host controller + implementations. + +Author: + + Greg Garbern (greggar) 01-May-2014 + +Environment: + + Kernel mode only. + +Revision History: + + Greg Garbern (greggar) 12-June-2014 + +--*/ + +#include +#include +#include "sdhc.h" + +#ifdef ALLOC_PRAGMA + #pragma alloc_text(INIT, DriverEntry) +#endif + +//----------------------------------------------------------------------------- +// SlotExtension routines. +//----------------------------------------------------------------------------- + +NTSTATUS +DriverEntry( + _In_ PVOID DriverObject, + _In_ PVOID RegistryPath + ) + +/*++ + +Routine Description: + + This routine is the entry point for the standard sdhsot miniport driver. + +Arguments: + + DriverObject - DriverObject for the standard host controller. + + RegistryPath - Registry path for this standard host controller. + +Return Value: + + NTSTATUS + +--*/ + +{ + + SDPORT_INITIALIZATION_DATA InitializationData; + + RtlZeroMemory(&InitializationData, sizeof(InitializationData)); + InitializationData.StructureSize = sizeof(InitializationData); + + // + // Initialize the entry points/callbacks for the miniport interface. + // + + InitializationData.GetSlotCount = SdhcGetSlotCount; + InitializationData.GetSlotCapabilities = SdhcGetSlotCapabilities; + InitializationData.Initialize = SdhcSlotInitialize; + InitializationData.IssueBusOperation = SdhcSlotIssueBusOperation; + InitializationData.GetCardDetectState = SdhcSlotGetCardDetectState; + InitializationData.GetWriteProtectState = SdhcSlotGetWriteProtectState; + InitializationData.Interrupt = SdhcSlotInterrupt; + InitializationData.IssueRequest = SdhcSlotIssueRequest; + InitializationData.GetResponse = SdhcSlotGetResponse; + InitializationData.ToggleEvents = SdhcSlotToggleEvents; + InitializationData.ClearEvents = SdhcSlotClearEvents; + InitializationData.RequestDpc = SdhcRequestDpc; + InitializationData.SaveContext = SdhcSaveContext; + InitializationData.RestoreContext = SdhcRestoreContext; + + // + // Provide the number of slots and their size. + // + + InitializationData.PrivateExtensionSize = sizeof(SDHC_EXTENSION); + + // + // Hook up the IRP dispatch routines. + // + + return SdPortInitialize(DriverObject, RegistryPath, &InitializationData); +} + +NTSTATUS +SdhcGetSlotCount( + _In_ PSD_MINIPORT Miniport, + _Out_ PUCHAR SlotCount + ) + +/*++ + +Routine Description: + + Return the number of slots present on this controller. + +Arguments: + + Argument - Functional device object for this controller. + +Return value: + + STATUS_UNSUCCESSFUL - PCI config space was unable to be queried. + + STATUS_INVALID_PARAMETER - Invalid underlying bus type for the miniport. + + STATUS_SUCCESS - SlotCount returned properly. + +--*/ + +{ + + SDPORT_BUS_TYPE BusType; + UCHAR Data; + NTSTATUS Status; + + *SlotCount = 0; + BusType = Miniport->ConfigurationInfo.BusType; + switch (BusType) { + case SdBusTypeAcpi: + + // + // We don't currently have a mechanism to query the slot count for ACPI + // enumerated host controllers. Default to one slot. + // + + *SlotCount = 1; + Status = STATUS_SUCCESS; + break; + + case SdBusTypePci: + Data = 0; + Status = SdPortGetPciConfigSpace(Miniport, + SDHC_PCICFG_SLOT_INFORMATION, + &Data, + sizeof(Data)); + + if (!NT_SUCCESS(Status)) { + return Status; + } + + *SlotCount = (Data >> 4) + 1; + if ((*SlotCount) > 6) { + + NT_ASSERT((*SlotCount) <= 6); + + Status = STATUS_UNSUCCESSFUL; + } + + SdhcInitializePciConfigSpace(Miniport); + Status = STATUS_SUCCESS; + break; + + default: + + NT_ASSERT((BusType == SdBusTypeAcpi) || (BusType == SdBusTypePci)); + + *SlotCount = 1; + Status = STATUS_INVALID_PARAMETER; + break; + } + + return Status; +} + +VOID +SdhcGetSlotCapabilities( + _In_ PVOID PrivateExtension, + _Out_ PSDPORT_CAPABILITIES Capabilities + ) + +/*++ + +Routine Description: + + Override for miniport to provide host register mapping information if the + memory range provideed by the underlying bus isn't sufficient. + +Arguments: + + SlotExtension - SlotExtension interface between sdhost and this miniport. + + Capabilities - Miniport provided capabilities. + +Return value: + + STATUS_SUCCESS - Capabilities returned successfully. + +--*/ + +{ + + PSDHC_EXTENSION SdhcExtension; + + SdhcExtension = (PSDHC_EXTENSION) PrivateExtension; + RtlCopyMemory(Capabilities, + &SdhcExtension->Capabilities, + sizeof(SdhcExtension->Capabilities)); +} + +NTSTATUS +SdhcSlotInitialize( + _In_ PVOID PrivateExtension, + _In_ PHYSICAL_ADDRESS PhysicalBase, + _In_ PVOID VirtualBase, + _In_ ULONG Length + ) + +/*++ + +Routine Description: + + Initialize the miniport for standard host controllers. + +Arguments: + + SlotExtension - SlotExtension interface between sdhost and this miniport. + +Return value: + + NTSTATUS + +--*/ + +{ + + PSDPORT_CAPABILITIES Capabilities; + SDHC_CAPABILITIES_REGISTER CapabilitiesReg; + SDHC_CAPABILITIES2_REGISTER Capabilities2Reg; + ULONG CurrentLimits; + ULONG CurrentLimitMax; + ULONG CurrentLimitMask; + ULONG CurrentLimitShift; + UCHAR Index; + PSDHC_EXTENSION SdhcExtension; + USHORT SpecVersion; + + SdhcExtension = (PSDHC_EXTENSION) PrivateExtension; + + // + // Initialize the SDHC_EXTENSION register space. + // + + SdhcExtension->PhysicalBaseAddress = PhysicalBase; + SdhcExtension->BaseAddress = VirtualBase; + SdhcExtension->BaseAddressSpaceSize = Length; + SdhcExtension->BaseAddressDebug = + (PSD_HOST_CONTROLLER_REGISTERS) VirtualBase; + + // + // Initialize host capabilities. + // + + Capabilities = (PSDPORT_CAPABILITIES) &SdhcExtension->Capabilities; + CapabilitiesReg.AsUlong = + SdhcReadRegisterUlong(SdhcExtension, SDHC_CAPABILITIES); + + Capabilities2Reg.AsUlong = + SdhcReadRegisterUlong(SdhcExtension, SDHC_CAPABILITIES2); + + SpecVersion = SdhcReadRegisterUshort(SdhcExtension, SDHC_VERSION); + Capabilities->SpecVersion = SpecVersion & 0xFF; + Capabilities->MaximumOutstandingRequests = SDHC_MAX_OUTSTANDING_REQUESTS; + Capabilities->MaximumBlockSize = + (USHORT)(512 << CapabilitiesReg.MaxBlockLength); + + Capabilities->MaximumBlockCount = 0xFFFF; + Capabilities->BaseClockFrequencyKhz = + CapabilitiesReg.BaseClockFrequency * 1000; + + Capabilities->DmaDescriptorSize = + sizeof(SDHC_ADMA2_DESCRIPTOR_TABLE_ENTRY) + + (CapabilitiesReg.SystemBus64Support ? + sizeof(ULONGLONG) : sizeof(ULONG)); + + Capabilities->AlignmentRequirement = + (CapabilitiesReg.SystemBus64Support ? + sizeof(ULONGLONG) : sizeof(ULONG)) - 1; + + if (CapabilitiesReg.Adma2Support) { + Capabilities->Supported.ScatterGatherDma = 1; + } + + if (CapabilitiesReg.SystemBus64Support) { + Capabilities->Supported.Address64Bit = 1; + } + + if (CapabilitiesReg.Support8BitBus) { + Capabilities->Supported.BusWidth8Bit = 1; + } + + if (CapabilitiesReg.HighSpeedSupport) { + Capabilities->Supported.HighSpeed = 1; + } + + if (Capabilities2Reg.SDR50Support) { + Capabilities->Supported.SDR50 = 1; + Capabilities->Supported.SignalingVoltage18V = 1; + } + + if (Capabilities2Reg.DDR50Support) { + Capabilities->Supported.DDR50 = 1; + Capabilities->Supported.SignalingVoltage18V = 1; + } + + if (Capabilities2Reg.SDR104Support) { + Capabilities->Supported.SDR104 = 1; + Capabilities->Supported.SignalingVoltage18V = 1; + } + + Capabilities->Supported.HS200 = 0; + Capabilities->Supported.HS400 = 0; + + if (Capabilities2Reg.DriverTypeA) { + Capabilities->Supported.DriverTypeA = 1; + } + + if (Capabilities2Reg.DriverTypeC) { + Capabilities->Supported.DriverTypeC = 1; + } + + if (Capabilities2Reg.DriverTypeD) { + Capabilities->Supported.DriverTypeD = 1; + } + + Capabilities->Supported.DriverTypeB = 1; + + if (Capabilities2Reg.UseTuningForSDR50) { + Capabilities->Supported.TuningForSDR50 = 1; + } + + if (Capabilities2Reg.RetuningTimerCount != 0) { + Capabilities->TuningTimerCountInSeconds = + (1 << (Capabilities2Reg.RetuningTimerCount - 1)); + } + + if (Capabilities2Reg.RetuningModes == 0) { + Capabilities->Supported.SoftwareTuning = 1; + } + + if (SpecVersion >= SDHC_SPEC_VERSION_3) { + Capabilities->Supported.AutoCmd23 = 1; + } + + if (CapabilitiesReg.Voltage18) { + Capabilities->Supported.Voltage18V; + } + + if (CapabilitiesReg.Voltage30) { + Capabilities->Supported.Voltage30V; + } + + if (CapabilitiesReg.Voltage33) { + Capabilities->Supported.Voltage33V; + } + + // + // Find the current limits suppported by the controller. + // + + CurrentLimitMask = 0; + CurrentLimitShift = 0; + if (Capabilities->Supported.Voltage33V) { + CurrentLimitMask = 0xFF; + CurrentLimitShift = 0; + + } else if (Capabilities->Supported.Voltage30V) { + CurrentLimitMask = 0xFF00; + CurrentLimitShift = 8; + + } else if (Capabilities->Supported.Voltage18V) { + CurrentLimitMask = 0xFF0000; + CurrentLimitShift = 16; + } + + CurrentLimits = SdhcReadRegisterUlong(SdhcExtension, SDHC_MAXIMUM_CURRENT); + CurrentLimitMax = + ((CurrentLimits & CurrentLimitMask) >> CurrentLimitShift) * 4; + + if (CurrentLimitMax >= 800) { + Capabilities->Supported.Limit800mA; + } + + if (CurrentLimitMax >= 600) { + Capabilities->Supported.Limit600mA; + } + + if (CurrentLimitMax >= 400) { + Capabilities->Supported.Limit400mA; + } + + if (CurrentLimitMax >= 200) { + Capabilities->Supported.Limit200mA; + } + + // + // Initialize our array of outstanding requests to keep track + // of what operations are in flight. + // + + for (Index = 0; + Index < Capabilities->MaximumOutstandingRequests; + Index += 1) { + + RtlZeroMemory(&SdhcExtension->OutstandingRequests[Index], + sizeof(PSDPORT_REQUEST)); + } + + return STATUS_SUCCESS; +} + +NTSTATUS +SdhcSlotIssueBusOperation( + _In_ PVOID PrivateExtension, + _In_ PSDPORT_BUS_OPERATION BusOperation + ) + +/*++ + +Routine Description: + + Issue host bus operation specified by BusOperation. + +Arguments: + + SlotExtension - SlotExtension interface between sdhost and this miniport. + + BusOperation - Bus operation to perform. + +Return value: + + NTSTATUS - Return value of the bus operation performed. + +--*/ + +{ + + PSDHC_EXTENSION SdhcExtension; + NTSTATUS Status; + + Status = STATUS_INVALID_PARAMETER; + SdhcExtension = (PSDHC_EXTENSION) PrivateExtension; + switch (BusOperation->Type) { + case SdResetHost: + Status = SdhcResetHost(SdhcExtension, + BusOperation->Parameters.ResetType); + + break; + + case SdSetClock: + Status = SdhcSetClock(SdhcExtension, + BusOperation->Parameters.FrequencyKhz); + + break; + + case SdSetVoltage: + Status = SdhcSetVoltage(SdhcExtension, + BusOperation->Parameters.Voltage); + + break; + + case SdSetBusWidth: + Status = SdhcSetBusWidth(SdhcExtension, + BusOperation->Parameters.BusWidth); + + break; + + case SdSetBusSpeed: + Status = SdhcSetSpeed(SdhcExtension, BusOperation->Parameters.BusSpeed); + break; + + case SdSetSignalingVoltage: + Status = SdhcSetSignaling(SdhcExtension, + BusOperation->Parameters.SignalingVoltage); + + break; + + case SdSetDriveStrength: + //Status = SdhcSetDriveStrength(SdhcExtension, + // BusOperation->Parameters.DriveStrength); + break; + + case SdSetDriverType: + //Status = SdhcSetDriverType(SdhcExtension, + // BusOperation->Parameters.DriverType); + + break; + + case SdSetPresetValue: + Status = SdhcSetPresetValue( + SdhcExtension, + BusOperation->Parameters.PresetValueEnabled); + + break; + + case SdExecuteTuning: + Status = SdhcExecuteTuning(SdhcExtension); + break; + + default: + Status = STATUS_INVALID_PARAMETER; + break; + } + + return Status; +} + +BOOLEAN +SdhcSlotGetCardDetectState( + _In_ PVOID PrivateExtension + ) + +/*++ + +Routine Description: + + Determine whether a card is inserted in the slot. + +Arguments: + + SlotExtension - SlotExtension interface between sdhost and this miniport. + +Return value: + + TRUE - Card is inserted. + + FALSE - Slot is empty. + +--*/ + +{ + + PSDHC_EXTENSION SdhcExtension; + + SdhcExtension = (PSDHC_EXTENSION) PrivateExtension; + return SdhcIsCardInserted(SdhcExtension); +} + +BOOLEAN +SdhcSlotGetWriteProtectState( + _In_ PVOID PrivateExtension + ) + +/*++ + +Routine Description: + + Determine whether the slot write protection is engaged. + +Arguments: + + SlotExtension - SlotExtension interface between sdhost and this miniport. + +Return value: + + TRUE - Slot is write protected. + + FALSE - Slot is writable. + +--*/ + +{ + + PSDHC_EXTENSION SdhcExtension; + + SdhcExtension = (PSDHC_EXTENSION) PrivateExtension; + return SdhcIsWriteProtected(SdhcExtension); +} + +BOOLEAN +SdhcSlotInterrupt( + _In_ PVOID PrivateExtension, + _Out_ PULONG Events, + _Out_ PULONG Errors, + _Out_ PBOOLEAN NotifyCardChange, + _Out_ PBOOLEAN NotifySdioInterrupt, + _Out_ PBOOLEAN NotifyTuning + ) + +/*++ + +Routine Description: + + Level triggered DIRQL interrupt handler (ISR) for this controller. + +Arguments: + + SlotExtension - SlotExtension interface between sdhost and this miniport. + +Return value: + + Whether the interrupt is handled. + +--*/ + +{ + + PSDHC_EXTENSION SdhcExtension; + + SdhcExtension = (PSDHC_EXTENSION) PrivateExtension; + *Events = (ULONG) SdhcGetInterruptStatus(SdhcExtension); + + // + // If there aren't any events to handle, then we don't need to + // process anything. + // + + if (*Events == 0) { + return FALSE; + } + + if (*Events & SDHC_IS_ERROR_INTERRUPT) { + *Errors = (ULONG) SdhcGetErrorStatus(SdhcExtension); + } + + // + // If a card has changed, notify the port driver. + // + + if (*Events & SDHC_IS_CARD_DETECT) { + *NotifyCardChange = TRUE; + *Events &= ~SDHC_IS_CARD_DETECT; + } + + // + // If we have an external SDIO interrupt, notify the port driver. + // + + if (*Events & SDHC_IS_CARD_INTERRUPT) { + *NotifySdioInterrupt = TRUE; + *Events &= ~SDHC_IS_CARD_INTERRUPT; + } + + // + // If there's a tuning request, notify the port driver. + // + + if (*Events & SDHC_IS_TUNING_INTERRUPT) { + *NotifyTuning = TRUE; + *Events &= ~SDHC_IS_TUNING_INTERRUPT; + } + + // + // Acknowledge/clear interrupt status. Request completions will occur in + // the port driver's slot completion DPC. We need to make the members of + // SDPORT_REQUEST that only the port driver uses opaque to the miniport. + // See how Storport does this (if it does). + // + + SdhcAcknowledgeInterrupts(SdhcExtension, (USHORT) *Events); + return (*Events != 0); +} + +NTSTATUS +SdhcSlotIssueRequest( + _In_ PVOID PrivateExtension, + _In_ PSDPORT_REQUEST Request + ) + +/*++ + +Routine Description: + + Issue hardware request specified by Request. + +Arguments: + + PrivateExtension - This driver's device extension (SdhcExtension). + + Request - Request operation to perform. + +Return value: + + NTSTATUS - Return value of the request performed. + +--*/ + +{ + + ULONG Index; + PSDHC_EXTENSION SdhcExtension; + NTSTATUS Status; + + SdhcExtension = (PSDHC_EXTENSION) PrivateExtension; + + // + // Insert the request onto the outstanding requests list. + // + + for (Index = 0; + Index < SdhcExtension->Capabilities.MaximumOutstandingRequests; + Index += 1) { + + if (SdhcExtension->OutstandingRequests[Index] == NULL) { + SdhcExtension->OutstandingRequests[Index] = Request; + break; + } + } + + // + // Dispatch the request based off of the request type. + // + + switch (Request->Type) { + case SdRequestTypeCommandNoTransfer: + case SdRequestTypeCommandWithTransfer: + Status = SdhcSendCommand(SdhcExtension, Request); + break; + + case SdRequestTypeStartTransfer: + Status = SdhcStartTransfer(SdhcExtension, Request); + break; + + default: + Status = STATUS_NOT_SUPPORTED; + break; + } + + return Status; +} + +VOID +SdhcSlotGetResponse( + _In_ PVOID PrivateExtension, + _In_ PSDPORT_COMMAND Command, + _Out_ PVOID ResponseBuffer + ) + +/*++ + +Routine Description: + + Return the response data for a given command back to the port driver. + +Arguments: + + PrivateExtension - This driver's device extension (SdhcExtension). + + Command - Command for which we're getting the response. + + ResponseBuffer - Response data for the given command. + +Return value: + + None. + +--*/ + +{ + + PSDHC_EXTENSION SdhcExtension; + NTSTATUS Status; + + SdhcExtension = (PSDHC_EXTENSION) PrivateExtension; + Status = SdhcGetResponse(SdhcExtension, Command, ResponseBuffer); + NT_ASSERT(NT_SUCCESS(Status)); +} + +VOID +SdhcRequestDpc( + _In_ PVOID PrivateExtension, + _Inout_ PSDPORT_REQUEST Request, + _In_ ULONG Events, + _In_ ULONG Errors + ) + +/*++ + +Routine Description: + + DPC for interrupts associated with the given request. + +Arguments: + + PrivateExtension - This driver's device extension (SdhcExtension). + + Request - Request operation to perform. + +Return value: + + NTSTATUS - Return value of the request performed. + +--*/ + +{ + + ULONG Index; + PSDHC_EXTENSION SdhcExtension; + NTSTATUS Status; + + // + // Clear the request's required events if they have completed. + // + + Request->RequiredEvents &= ~Events; + + // + // Find the index of the request in the outstanding request list. + // + + SdhcExtension = (PSDHC_EXTENSION) PrivateExtension; + for (Index = 0; Index < SDHC_MAX_OUTSTANDING_REQUESTS; Index += 1) { + if (SdhcExtension->OutstandingRequests[Index] == Request) { + break; + } + } + + // + // If there are errors, we need to fail whatever outstanding request + // was on the bus. Otherwise, the request succeeded. + // + // TODO: There's a race condition here--it's possible for a request + // to get a transfer complete interrupt and then later receive an + // error interrupt for the same transfer. It might be mitigated by + // handling request completion in a DPC for ISR. + // + + if (Errors) { + Request->RequiredEvents = 0; + SdhcExtension->OutstandingRequests[Index] = NULL; + Status = SdhcConvertErrorToStatus((USHORT) Errors); + SdPortCompleteRequest(Request, Status); + + } else if (Request->RequiredEvents == 0) { + if (Request->Status != STATUS_MORE_PROCESSING_REQUIRED) { + Request->Status = STATUS_SUCCESS; + } + + SdhcExtension->OutstandingRequests[Index] = NULL; + SdPortCompleteRequest(Request, Request->Status); + } +} + +VOID +SdhcSlotToggleEvents( + _In_ PVOID PrivateExtension, + _In_ ULONG EventMask, + _In_ BOOLEAN Enable + ) + +/*++ + +Routine Description: + + Enable or disable the given event mask. + +Arguments: + + SlotExtension - SlotExtension interface between sdhost and this miniport. + + Events - The event mask to toggle. + + Enable - TRUE to enable, FALSE to disable. + +Return value: + + None. + +--*/ + +{ + + USHORT InterruptMask; + PSDHC_EXTENSION SdhcExtension; + + InterruptMask = SdhcConvertEventsToHwMask(EventMask); + SdhcExtension = (PSDHC_EXTENSION) PrivateExtension; + if (Enable) { + SdhcEnableInterrupt(SdhcExtension, + InterruptMask); + + } else { + SdhcDisableInterrupt(SdhcExtension, + InterruptMask); + } +} + +VOID +SdhcSlotClearEvents( + _In_ PVOID PrivateExtension, + _In_ ULONG EventMask + ) + +{ + + USHORT Interrupts; + PSDHC_EXTENSION SdhcExtension; + + SdhcExtension = (PSDHC_EXTENSION) PrivateExtension; + Interrupts = SdhcConvertEventsToHwMask(EventMask); + SdhcAcknowledgeInterrupts(SdhcExtension, Interrupts); +} + +VOID +SdhcSaveContext( + _In_ PVOID PrivateExtension + ) + +/*++ + +Routine Description: + + Save slot register context. + +Arguments: + + SlotExtension - SlotExtension interface between sdhost and this miniport. + +Return value: + + None. + +--*/ + +{ + UNREFERENCED_PARAMETER(PrivateExtension); +} + +VOID +SdhcRestoreContext( + _In_ PVOID PrivateExtension + ) + +/*++ + +Routine Description: + + Restore slot register context from a previously saved context. + +Arguments: + + SlotExtension - SlotExtension interface between sdhost and this miniport. + +Return value: + + None. + +--*/ + +{ + UNREFERENCED_PARAMETER(PrivateExtension); +} + +//----------------------------------------------------------------------------- +// Host routine implementations. +//----------------------------------------------------------------------------- + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +SdhcResetHost( + _In_ PSDHC_EXTENSION SdhcExtension, + _In_ UCHAR ResetType + ) + +/*++ + +Routine Description: + + Execute a soft reset to the socket specified. + +Arguments: + + SdhcExtension - Host controller specific driver context. + + ResetType - Either full, CMD, or DAT reset. + +Return value: + + STATUS_SUCCESS - Reset succeeded. + + STATUS_INVALID_PARAMETER - Invalid reset type chosen. + +--*/ + +{ + + UCHAR HostControl; + UCHAR Reset; + UCHAR Retries; + UCHAR Mask; + + switch (ResetType) { + case SdResetTypeAll: + Mask = SDHC_RESET_ALL; + break; + + case SdResetTypeCmd: + Mask = SDHC_RESET_CMD; + break; + + case SdResetTypeDat: + Mask = SDHC_RESET_DAT; + break; + + default: + return STATUS_INVALID_PARAMETER; + } + + // + // Reset the host controller. + // + + Retries = 100; + SdhcWriteRegisterUchar(SdhcExtension, SDHC_RESET, Mask); + do { + Retries -= 1; + if (Retries == 0) { + return STATUS_TIMEOUT; + } + + Reset = SdhcReadRegisterUchar(SdhcExtension, SDHC_RESET); + + if ((Reset & Mask) != 0) { + SdPortWait(1000); + } + + } while ((Reset & Mask) != 0); + + // + // Set the max HW timeout for bus operations. + // + + SdhcWriteRegisterUchar(SdhcExtension, + SDHC_TIMEOUT_CONTROL, + SDHC_TC_MAX_DATA_TIMEOUT); + + // + // Initialize DMA if the controller supports it. + // + + HostControl = SdhcReadRegisterUchar(SdhcExtension, SDHC_HOST_CONTROL); + HostControl &= ~SDHC_HC_DMA_SELECT_MASK; + if (SdhcExtension->Capabilities.Supported.ScatterGatherDma) { + if (SdhcExtension->Capabilities.Supported.Address64Bit) { + HostControl |= SDHC_HC_DMA_SELECT_ADMA64; + + } else { + HostControl |= SDHC_HC_DMA_SELECT_ADMA32; + } + } + + SdhcWriteRegisterUchar(SdhcExtension, SDHC_HOST_CONTROL, HostControl); + return STATUS_SUCCESS; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +SdhcSetClock( + _In_ PSDHC_EXTENSION SdhcExtension, + _In_ ULONG Frequency + ) + +/*++ + +Routine Description: + + Set the clock to a given frequency. + +Arguments: + + SdhcExtension - Host controller specific driver context. + + Frequency - The target frequency. + +Return value: + + STATUS_SUCCESS - The clock was successfuly set. + + STATUS_TIMEOUT - The clock did not stabilize in time. + +--*/ + +{ + + ULONG ActualFrequency; + USHORT ClockControl; + ULONG Delay; + USHORT Mask; + UCHAR Retries; + + UNREFERENCED_PARAMETER(Frequency); + + ClockControl = SdhcReadRegisterUshort(SdhcExtension, SDHC_CLOCK_CONTROL); + ClockControl &= ~(SDHC_CC_CLOCK_ENABLE | SDHC_CC_INTERNAL_CLOCK_ENABLE); + SdhcWriteRegisterUshort(SdhcExtension, SDHC_CLOCK_CONTROL, ClockControl); + ClockControl = SdhcCalcClockFrequency(SdhcExtension, + Frequency, + &ActualFrequency); + + ClockControl |= SDHC_CC_INTERNAL_CLOCK_ENABLE; + SdhcWriteRegisterUshort(SdhcExtension, SDHC_CLOCK_CONTROL, ClockControl); + + // + // Now the frequency is set, delay a few times to wait for it to become + // stable. + // + + Retries = 100; + Mask = SDHC_CC_CLOCK_STABLE; + do { + Retries -= 1; + if (Retries == 0) { + return STATUS_TIMEOUT; + } + + ClockControl = + SdhcReadRegisterUshort(SdhcExtension, SDHC_CLOCK_CONTROL); + + if ((ClockControl & Mask) == 0) { + SdPortWait(1000); + } + + } while ((ClockControl & Mask) == 0); + + // + // Clock is now stable, now enable it. + // + + ClockControl |= SDHC_CC_CLOCK_ENABLE; + SdhcWriteRegisterUshort(SdhcExtension, SDHC_CLOCK_CONTROL, ClockControl); + + // + // Some hardware need more time here to stabilize, but minimize latency + // for fixed eMMC devices during runtime Dx transitions. + // + + Delay = (SdhcExtension->Removable) ? (10 * 1000) : 50; + SdPortWait(Delay); + return STATUS_SUCCESS; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +SdhcSetVoltage( + _In_ PSDHC_EXTENSION SdhcExtension, + _In_ SDPORT_BUS_VOLTAGE Voltage + ) + +/*++ + +Routine Description: + + Set the slot's voltage profile. + +Arguments: + + SdhcExtension - Host controller specific driver context. + + VoltageProfile - Indicates which power voltage to use. If 0, turn off the + power + +Return value: + + STATUS_SUCCESS - The bus voltage was successfully switched. + + STATUS_INVALID_PARAMETER - The voltage profile provided was invalid. + + STATUS_TIMEOUT - The bus voltage did not stabilize in time. + +--*/ + +{ + + ULONG Delay; + UCHAR Mask; + UCHAR PowerControl; + UCHAR PowerControlCheck; + UCHAR Retries; + + // + // Wait 10ms if the slot is removable; otherwise, only wait 50us. + // + + Delay = (SdhcExtension->Removable) ? (10* 1000) : 50; + SdPortWait(Delay); + + // + // Use the highest voltage capable. + // + + switch (Voltage) { + case SdBusVoltage33: + PowerControl = SDHC_PC_3_3V; + break; + + case SdBusVoltage30: + PowerControl = SDHC_PC_3_0V; + break; + + case SdBusVoltage18: + PowerControl = SDHC_PC_1_8V; + break; + + case SdBusVoltageOff: + PowerControl = 0; + break; + + default: + + NT_ASSERTMSG("SDHC - Voltage profile invalid.", FALSE); + + return STATUS_INVALID_PARAMETER; + } + + Retries = 100; + Mask = SDHC_PC_VOLTAGE_MASK; + do { + Retries -= 1; + if (Retries == 0) { + return STATUS_TIMEOUT; + } + + SdhcWriteRegisterUchar(SdhcExtension, SDHC_POWER_CONTROL, PowerControl); + PowerControlCheck = + SdhcReadRegisterUchar(SdhcExtension, SDHC_POWER_CONTROL); + + if ((PowerControlCheck & Mask) != PowerControl) { + SdPortWait(1000); + } + + } while ((PowerControlCheck & Mask) != PowerControl); + + PowerControl |= SDHC_PC_BUS_POWER; + SdhcWriteRegisterUchar(SdhcExtension, SDHC_POWER_CONTROL, PowerControl); + SdPortWait(Delay); + + Retries = 100; + Mask = SDHC_PC_VOLTAGE_MASK | SDHC_PC_BUS_POWER; + do { + Retries -= 1; + if (Retries == 0) { + return STATUS_TIMEOUT; + } + + SdhcWriteRegisterUchar(SdhcExtension, SDHC_POWER_CONTROL, PowerControl); + PowerControlCheck = + SdhcReadRegisterUchar(SdhcExtension, SDHC_POWER_CONTROL); + + if ((PowerControlCheck & Mask) != PowerControl) { + SdPortWait(1000); + } + + } while ((PowerControlCheck & Mask) != PowerControl); + + return STATUS_SUCCESS; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +SdhcSetBusWidth( + _In_ PSDHC_EXTENSION SdhcExtension, + _In_ UCHAR Width + ) + +/*++ + +Routine Description: + + Set bus width for host controller. + +Arguments: + + SdhcExtension - Host controller specific driver context. + + Width - The data bus width of the slot. + +Return value: + + STATUS_SUCCESS - The bus width was properly changed. + +--*/ + +{ + + UCHAR HostControl; + + HostControl = SdhcReadRegisterUchar(SdhcExtension, SDHC_HOST_CONTROL); + HostControl &= ~(SDHC_HC_DATA_WIDTH_4BIT | SDHC_HC_DATA_WIDTH_8BIT); + switch (Width) { + case 1: + break; + + case 4: + HostControl |= SDHC_HC_DATA_WIDTH_4BIT; + break; + case 8: + HostControl |= SDHC_HC_DATA_WIDTH_8BIT; + break; + + default: + + NT_ASSERTMSG("SDHC - Provided bus width is invalid", FALSE); + + break; + } + + SdhcWriteRegisterUchar(SdhcExtension, SDHC_HOST_CONTROL, HostControl); + return STATUS_SUCCESS; +} + +NTSTATUS +SdhcSetSpeed( + _In_ PSDHC_EXTENSION SdhcExtension, + _In_ SDPORT_BUS_SPEED Speed + ) + +/*++ + +Routine Description: + + Based on the capabilities of card and host, turns on the maximum performing + speed mode for the host. Caller is expected to know the capabilities of the + card before setting the speed mode. + +Arguments: + + SdhcExtension - Host controller specific driver context. + + Speed - Bus speed to set. + +Return value: + + STATUS_SUCCESS - The selected speed mode was successfully set. + + STATUS_INVALID_PARAMETER - The speed mode selected is not valid. + +--*/ + +{ + + NTSTATUS Status; + USHORT UhsMode; + + switch (Speed) { + case SdBusSpeedNormal: + Status = SdhcSetHighSpeed(SdhcExtension, FALSE); + break; + + case SdBusSpeedHigh: + Status = SdhcSetHighSpeed(SdhcExtension, TRUE); + break; + + case SdBusSpeedSDR12: + case SdBusSpeedSDR25: + case SdBusSpeedSDR50: + case SdBusSpeedDDR50: + case SdBusSpeedSDR104: + case SdBusSpeedHS200: + case SdBusSpeedHS400: + UhsMode = SdhcGetHwUhsMode(Speed); + Status = SdhcSetUhsMode(SdhcExtension, UhsMode); + break; + + default: + + NT_ASSERTMSG("SDHC - Invalid speed mode selected.", FALSE); + + Status = STATUS_INVALID_PARAMETER; + break; + } + + return Status; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +SdhcSetHighSpeed( + _In_ PSDHC_EXTENSION SdhcExtension, + _In_ BOOLEAN Enable + ) + +/*++ + +Routine Description: + + Based on the capabilities of card and host, enables or disables high speed. + +Arguments: + + SdhcExtension - Host controller specific driver context. + + Enable - TRUE to enable high speed, FALSE to disable. + +Return value: + + STATUS_SUCCESS - High speed was successfully enabled. + +--*/ + +{ + + UCHAR HostControl; + + HostControl = SdhcReadRegisterUchar(SdhcExtension, SDHC_HOST_CONTROL); + HostControl &= ~SDHC_HC_ENABLE_HIGH_SPEED; + if (Enable) { + HostControl |= SDHC_HC_ENABLE_HIGH_SPEED; + } + + SdhcWriteRegisterUchar(SdhcExtension, SDHC_HOST_CONTROL, HostControl); + return STATUS_SUCCESS; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +SdhcSetUhsMode( + _In_ PSDHC_EXTENSION SdhcExtension, + _In_ USHORT Mode + ) + +/*++ + +Routine Description: + + Based on the capabilities of card and host, turns on the maximum performing + speed mode for the host. Caller is expected to know the capabilities of the + card before setting the speed mode. + +Arguments: + + SdhcExtension - Host controller specific driver context. + + Mode - UHS mode to set. + +Return value: + + STATUS_SUCCESS - Mode requested is set on the controller. + + STATUS_INVALID_PARAMETER - The mode selected is not a UHS mode. + +--*/ + +{ + + USHORT ClockControl; + USHORT HostControl2; + + HostControl2 = SdhcReadRegisterUshort(SdhcExtension, SDHC_HOST_CONTROL2); + + // + // If we're already in the requested mode, return. + // + + if ((HostControl2 & SDHC_HC2_UHS_MODES) == Mode) { + return STATUS_SUCCESS; + } + + ClockControl = SdhcReadRegisterUshort(SdhcExtension, SDHC_CLOCK_CONTROL); + ClockControl &= ~SDHC_CC_CLOCK_ENABLE; + SdhcWriteRegisterUshort(SdhcExtension, SDHC_CLOCK_CONTROL, ClockControl); + SdPortWait(10 * 1000); + + // + // Set the UHS mode. + // + + HostControl2 &= ~SDHC_HC2_UHS_MODES; + HostControl2 |= Mode; + SdhcWriteRegisterUshort(SdhcExtension, SDHC_HOST_CONTROL2, HostControl2); + ClockControl = SdhcReadRegisterUshort(SdhcExtension, SDHC_CLOCK_CONTROL); + ClockControl |= SDHC_CC_CLOCK_ENABLE; + SdhcWriteRegisterUshort(SdhcExtension, SDHC_CLOCK_CONTROL, ClockControl); + SdPortWait(10 * 1000); + return STATUS_SUCCESS; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +SdhcSetSignaling( + _In_ PSDHC_EXTENSION SdhcExtension, + _In_ BOOLEAN Enable + ) + +/*++ + +Routine Description: + + Set signaling voltage (1.8V or 3.3V). + +Arguments: + + SdhcExtension - Host controller specific driver context. + + Enable - TRUE for 1.8V signaling, FALSE for default 3.3V. + +Return value: + + STATUS_SUCCESS - Signaling voltage switch successful. + + STATUS_UNSUCCESSFUL - Signaling voltage switch unsuccessful. + +--*/ + +{ + + USHORT ClockControl; + ULONG DatLines; + USHORT HostControl2; + USHORT Mask; + + // + // Disable the bus clock. + // + + ClockControl = SdhcReadRegisterUshort(SdhcExtension, SDHC_CLOCK_CONTROL); + ClockControl &= ~SDHC_CC_CLOCK_ENABLE; + SdhcWriteRegisterUshort(SdhcExtension, SDHC_CLOCK_CONTROL, ClockControl); + SdPortWait(10 * 1000); + + // + // DAT[3:0] must be all zeroes. + // + + DatLines = 0; + DatLines = + SDHC_PS_DAT_3_0 & + SdhcReadRegisterUlong(SdhcExtension, SDHC_PRESENT_STATE); + + if (DatLines != 0) { + return STATUS_UNSUCCESSFUL; + } + + // + // Set the signaling voltage. + // + + HostControl2 = SdhcReadRegisterUshort(SdhcExtension, SDHC_HOST_CONTROL2); + Mask = SDHC_HC2_1_8V_SIGNALING; + if (Enable) { + HostControl2 |= Mask; + + } else { + HostControl2 &= ~Mask; + } + + SdhcWriteRegisterUshort(SdhcExtension, SDHC_HOST_CONTROL2, HostControl2); + SdPortWait(5 * 1000); + HostControl2 = SdhcReadRegisterUshort(SdhcExtension, SDHC_HOST_CONTROL2); + + // + // Make sure the signaling voltage latched. + // + + if (Enable) { + if ((HostControl2 & Mask) == 0) { + return STATUS_UNSUCCESSFUL; + } + + } else { + if ((HostControl2 & Mask) != 0) { + return STATUS_UNSUCCESSFUL; + } + } + + // + // Reenable the bus clock. + // + + ClockControl = SdhcReadRegisterUshort(SdhcExtension, SDHC_CLOCK_CONTROL); + SdPortWait(10000); + + // + // DAT[3:0] must be all ones. + // + + DatLines = 0; + DatLines = + SDHC_PS_DAT_3_0 & + SdhcReadRegisterUlong(SdhcExtension, SDHC_PRESENT_STATE); + + if (DatLines != SDHC_PS_DAT_3_0) { + return STATUS_UNSUCCESSFUL; + } + + return STATUS_SUCCESS; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +SdhcExecuteTuning( + _In_ PSDHC_EXTENSION SdhcExtension + ) + +/*++ + +Routine Description: + + Tune the bus sampling point due to variations in voltage, + temperature, and time. + + Caller guarantees that the bus is in a UHS mode that + requires tuning. + +Arguments: + + SdhcExtension - Host controller specific driver context. + +Return value: + + STATUS_SUCCESS - Tuning successful. + +--*/ + +{ + + USHORT HostControl2; + //UCHAR Retries; + SDPORT_REQUEST TuningRequest; + + HostControl2 = SdhcReadRegisterUshort(SdhcExtension, SDHC_HOST_CONTROL2); + + NT_ASSERT((HostControl2 & SDHC_HC2_EXECUTE_TUNING) == 0); + + // + // Disable controller events + // + // Technically, all controller events should be disabled at tuning execute + // time, but some controllers do not follow this requirement. + // + + if ((HostControl2 & SDHC_HC2_EXECUTE_TUNING) == 0) { + HostControl2 |= SDHC_HC2_EXECUTE_TUNING; + SdhcWriteRegisterUshort(SdhcExtension, + SDHC_HOST_CONTROL2, + HostControl2); + } + + RtlZeroMemory(&TuningRequest, sizeof(TuningRequest)); + TuningRequest.Command.TransferType = SdTransferTypeSingleBlock; + TuningRequest.Command.TransferDirection = SdTransferDirectionRead; + TuningRequest.Command.Class = SdCommandClassStandard; + TuningRequest.Command.ResponseType = SdResponseTypeR1; + if (SdhcExtension->SpeedMode == SdhcSpeedModeSDR104) { + TuningRequest.Command.Index = 19; + TuningRequest.Command.BlockSize = 64; + + } else { + TuningRequest.Command.Index = 21; + TuningRequest.Command.BlockSize = 128; + } + + // + // TODO: Implement rest of tuning logic as described in + // SD Host Controller Specification. This is needed for + // SDR104, HS200, and HS400 modes, and sometimes for SDR50. + // + + // + // Execute the data transfer. + // + + //Status = SdhcBuildTransfer() + + return STATUS_SUCCESS; +} + +VOID +SdhcSetLed( + _In_ PSDHC_EXTENSION SdhcExtension, + _In_ BOOLEAN Enable + ) + +/*++ + +Routine Description: + + Turn the controller activity LED on/off. + +Arguments: + + SdhcExtension - Host controller specific driver context. + + Enable - Indicate whether to enable or disable the LED. + +Return value: + + None. + +--*/ + +{ + + UCHAR HostControl; + + HostControl = SdhcReadRegisterUchar(SdhcExtension, SDHC_HOST_CONTROL); + if (Enable) { + HostControl |= SDHC_HC_LED_POWER; + + } else { + HostControl &= ~SDHC_HC_LED_POWER; + } + + SdhcWriteRegisterUchar(SdhcExtension, SDHC_HOST_CONTROL, HostControl); +} + +NTSTATUS +SdhcSetPresetValue( + _In_ PSDHC_EXTENSION SdhcExtension, + _In_ BOOLEAN Enable + ) + +/*++ + +Routine Description: + + Enable or disable setting of preset values. Caller must + ensure that the controller supports preset value. + +Arguments: + + SdhcExtension - Host controller specific driver context. + + Enable - Indicate whether to enable or disable preset values. + +Return value: + + None. + +--*/ + +{ + + USHORT HostControl2; + + HostControl2 = SdhcReadRegisterUshort(SdhcExtension, SDHC_HOST_CONTROL2); + + NT_ASSERT((HostControl2 & SDHC_HC2_ENABLE_PRESET_VALUE) != 0); + + HostControl2 &= ~SDHC_HC2_ENABLE_PRESET_VALUE; + if (Enable) { + HostControl2 |= SDHC_HC2_ENABLE_PRESET_VALUE; + } + + SdhcWriteRegisterUshort(SdhcExtension, SDHC_HOST_CONTROL2, HostControl2); + return STATUS_SUCCESS; +} + +VOID +SdhcSetBlockGapControl( + _In_ PSDHC_EXTENSION SdhcExtension, + _In_ BOOLEAN Continue, + _In_ BOOLEAN RequestStop + ) + +/*++ + +Routine Description: + + Enable block gap interrupt requests. + +Arguments: + + SdhcExtension - Host controller specific driver context. + + Continue - Continue after the next block gap. + + RequestStop - Request the block gap interrupt request. + +Return value: + + None. + +--*/ + +{ + + UCHAR BlockGapControl; + + BlockGapControl = SdhcReadRegisterUchar(SdhcExtension, + SDHC_BLOCKGAP_CONTROL); + + BlockGapControl &= ~SDHC_BGC_CONTINUE; + BlockGapControl &= ~SDHC_BGC_STOP_NEXT_GAP; + if (Continue) { + BlockGapControl |= SDHC_BGC_CONTINUE; + } + + if (RequestStop) { + BlockGapControl |= SDHC_BGC_STOP_NEXT_GAP; + } +} + +VOID +SdhcEnableInterrupt( + _In_ PSDHC_EXTENSION SdhcExtension, + _In_ ULONG NormalInterruptMask + ) + +/*++ + +Routine Description: + + Set the host event mask to the new value specified. + +Arguments: + + SdhcExtension - Host controller specific driver context. + + NormalInterruptMask - The new normal events to set. + +Return value: + + None. + +--*/ + +{ + + USHORT InterruptEnable; + + InterruptEnable = + SdhcReadRegisterUshort(SdhcExtension, SDHC_INTERRUPT_SIGNAL_ENABLE); + + InterruptEnable |= NormalInterruptMask; + + // + // Enable the interrupt signals from controller to OS. + // + + SdhcWriteRegisterUshort(SdhcExtension, + SDHC_INTERRUPT_SIGNAL_ENABLE, + InterruptEnable); + + SdhcWriteRegisterUshort(SdhcExtension, + SDHC_ERROR_SIGNAL_ENABLE, + 0xFFFF); + + // + // Enable the interrupt signals on the controller. + // + + SdhcWriteRegisterUshort(SdhcExtension, + SDHC_INTERRUPT_STATUS_ENABLE, + InterruptEnable); + + SdhcWriteRegisterUshort(SdhcExtension, + SDHC_ERROR_STATUS_ENABLE, + 0xFFFF); +} + +VOID +SdhcDisableInterrupt( + _In_ PSDHC_EXTENSION SdhcExtension, + _In_ ULONG NormalInterruptMask + ) + +/*++ + +Routine Description: + + Set the host event mask to the new value specified. + +Arguments: + + SdhcExtension - Host controller specific driver context. + + NormalInterruptMask - Normal Interrupts to disable. + +Return value: + + None. + +--*/ + +{ + + USHORT InterruptDisable; + + InterruptDisable = + SdhcReadRegisterUshort(SdhcExtension, SDHC_INTERRUPT_SIGNAL_ENABLE); + + InterruptDisable &= ~NormalInterruptMask; + + // + // Disable the interrupt signals on the controller. + // + + SdhcWriteRegisterUshort(SdhcExtension, + SDHC_INTERRUPT_STATUS_ENABLE, + InterruptDisable); + + SdhcWriteRegisterUshort(SdhcExtension, + SDHC_ERROR_STATUS_ENABLE, + 0); + + // + // Disable the interrupt signals from controller to OS. + // + + SdhcWriteRegisterUshort(SdhcExtension, + SDHC_INTERRUPT_SIGNAL_ENABLE, + InterruptDisable); + + SdhcWriteRegisterUshort(SdhcExtension, + SDHC_ERROR_SIGNAL_ENABLE, + 0); +} + +__forceinline +USHORT +SdhcGetInterruptStatus( + _In_ PSDHC_EXTENSION SdhcExtension + ) + +/*++ + +Routine Description: + + Get current pending events from the interrupt status. This function does + not acknowledge the interrupt. The caller should acknowledge or disable + the corresponding events. + +Arguments: + + SdhcExtension - Host controller specific driver context. + +Return value: + + The event mask. + +--*/ + +{ + + USHORT InterruptStatus; + + InterruptStatus = + SdhcReadRegisterUshort(SdhcExtension, SDHC_INTERRUPT_STATUS); + + // + // 0xFFFF means HC is no longer accessible. This interrupt does not belong + // to us. + // + + if (InterruptStatus == 0xFFFF) { + return 0; + } + + return InterruptStatus; +} + +__forceinline +USHORT +SdhcGetErrorStatus( + _In_ PSDHC_EXTENSION SdhcExtension + ) + +/*++ + +Routine Description: + + This routine returns the current error status, if any. + +Arguments: + + SdhcExtension - Host controller specific driver context. + +Return value: + + The error interrupt status. + +--*/ + +{ + + return SdhcReadRegisterUshort(SdhcExtension, SDHC_ERROR_STATUS); +} + +__forceinline +USHORT +SdhcGetAutoCmd12ErrorStatus( + _In_ PSDHC_EXTENSION SdhcExtension + ) + +/*++ + +Routine Description: + + This routine returns the current Auto CMD12 error status, if any. + +Arguments: + + SdhcExtension - Host controller specific driver context. + +Return value: + + The Auto CMD12 error status. + +--*/ + +{ + + return SdhcReadRegisterUshort(SdhcExtension, SDHC_AUTO_CMD12_ERROR_STATUS); +} + +USHORT +SdhcGetAdmaErrorStatus( + _In_ PSDHC_EXTENSION SdhcExtension + ) + +/*++ + +Routine Description: + + This routine returns the current ADMA error status, if any. + +Arguments: + + SdhcExtension - Host controller specific driver context. + +Return value: + + The ADMA error status. + +--*/ + +{ + + return SdhcReadRegisterUshort(SdhcExtension, SDHC_ADMA_ERROR_STATUS); +} + +VOID +SdhcAcknowledgeInterrupts( + _In_ PSDHC_EXTENSION SdhcExtension, + _In_ USHORT Interrupts + ) + +/*++ + +Routine Description: + + Acknowlege the interrupts specified. + +Arguments: + + SdhcExtension - Host controller specific driver context. + + Interrupts - event mask to acknowledge (single event only) + +Return value: + + None. + +--*/ + +{ + + if ((Interrupts & SDHC_IS_ERROR_INTERRUPT) != 0) { + + // + // The Auto CMD12 error interrupt status bit of some Ricoh controllers + // can't get cleared by writing to the error status register alone. + // Write all-ones and all-zeroes to the Auto CMD12 error status register + // first to work around this issue. This write should have no effect on + // other types of controllers since the register should be read-only + // according to the spec. + // + + SdhcWriteRegisterUshort(SdhcExtension, + SDHC_AUTO_CMD12_ERROR_STATUS, + 0xFFFF); + + SdhcWriteRegisterUshort(SdhcExtension, + SDHC_AUTO_CMD12_ERROR_STATUS, + 0x0); + + // + // Clear the error interrupt by writing all-ones. + // + + SdhcWriteRegisterUshort(SdhcExtension, SDHC_ERROR_STATUS, 0xFFFF); + Interrupts &= ~SDHC_IS_ERROR_INTERRUPT; + } + + // + // Clear other interrupts in the interrupt status register. + // + + SdhcWriteRegisterUshort(SdhcExtension, SDHC_INTERRUPT_STATUS, Interrupts); +} + +BOOLEAN +SdhcIsCardInserted( + _In_ PSDHC_EXTENSION SdhcExtension + ) + +/*++ + +Routine Description: + + To detect whether there is a card in the socket. + +Arguments: + + SdhcExtension - Host controller specific driver context. + +Return value: + + BOOLEAN value to indicate whether there is a card in the socket. + +--*/ + +{ + + ULONG PresentState; + + PresentState = SdhcReadRegisterUlong(SdhcExtension, SDHC_PRESENT_STATE); + return (BOOLEAN) ((PresentState & SDHC_PS_CARD_INSERTED) != 0); +} + +BOOLEAN +SdhcIsWriteProtected( + _In_ PSDHC_EXTENSION SdhcExtension + ) + +/*++ + +Routine Description: + + To detect whether the card is write protected. + +Arguments: + + SdhcExtension - Host controller specific driver context. + +Return value: + + BOOLEAN value to indicate whether the card is write protected. + +--*/ + +{ + + ULONG PresentState; + BOOLEAN WriteProtected; + + // + // Write protect is active low. + // + + PresentState = SdhcReadRegisterUlong(SdhcExtension, SDHC_PRESENT_STATE); + WriteProtected = (BOOLEAN) ((PresentState & SDHC_PS_WRITE_PROTECT) == 0); + return WriteProtected; +} + +NTSTATUS +SdhcSendCommand( + _In_ PSDHC_EXTENSION SdhcExtension, + _In_ PSDPORT_REQUEST Request + ) + +/*++ + +Routine Description: + + This routine takes the SD command package and writes it to the appropriate + registers on the host controller. It also computes the proper flag + settings. + +Arguments: + + SdhcExtension - Host controller specific driver context. + + Request - Supplies the descriptor for this SD command + +Return value: + + STATUS_SUCCESS - Command successfully sent. + + STATUS_INVALID_PARAMETER - Invalid command response type specified. + +--*/ + +{ + + PSDPORT_COMMAND Command; + USHORT CommandType; + USHORT CommandReg; + NTSTATUS Status; + USHORT TransferMode; + + // + // Initialize transfer parameters if this command is a data command. + // + + Command = &Request->Command; + if ((Command->TransferType != SdTransferTypeNone) && + (Command->TransferType != SdTransferTypeUndefined)) { + + Status = SdhcBuildTransfer(SdhcExtension, Request); + if (!NT_SUCCESS(Status)) { + return Status; + } + } + + // + // Set the response parameters based off the given response type. + // + + SdhcWriteRegisterUlong(SdhcExtension, SDHC_ARGUMENT, Command->Argument); + + CommandReg = Command->Index << 8; + switch (Command->ResponseType) { + case SdResponseTypeNone: + break; + + case SdResponseTypeR1: + case SdResponseTypeR5: + case SdResponseTypeR6: + CommandReg |= SDHC_CMD_RESPONSE_48BIT_NOBUSY | + SDHC_CMD_CRC_CHECK_ENABLE | + SDHC_CMD_INDEX_CHECK_ENABLE; + break; + + case SdResponseTypeR1B: + case SdResponseTypeR5B: + CommandReg |= SDHC_CMD_RESPONSE_48BIT_WBUSY | + SDHC_CMD_CRC_CHECK_ENABLE | + SDHC_CMD_INDEX_CHECK_ENABLE; + break; + + case SdResponseTypeR2: + CommandReg |= SDHC_CMD_RESPONSE_136BIT | + SDHC_CMD_CRC_CHECK_ENABLE; + break; + + case SdResponseTypeR3: + case SdResponseTypeR4: + CommandReg |= SDHC_CMD_RESPONSE_48BIT_NOBUSY; + break; + + default: + + NT_ASSERTMSG("SDHC - Invalid response type", FALSE); + + return STATUS_INVALID_PARAMETER; + } + + if (Request->Command.TransferType != SdTransferTypeNone) { + TransferMode = 0; + CommandReg |= SDHC_CMD_DATA_PRESENT; + + } else { + TransferMode = + SdhcReadRegisterUshort(SdhcExtension, SDHC_TRANSFER_MODE); + + TransferMode &= ~SDHC_TM_DMA_ENABLE; + TransferMode &= ~SDHC_TM_AUTO_CMD12_ENABLE; + TransferMode &= ~SDHC_TM_AUTO_CMD23_ENABLE; + SdhcWriteRegisterUshort(SdhcExtension, + SDHC_TRANSFER_MODE, + TransferMode); + } + + switch (Command->Type) { + case SdCommandTypeSuspend: + CommandType = SDHC_CMD_TYPE_SUSPEND; + break; + + case SdCommandTypeResume: + CommandType = SDHC_CMD_TYPE_RESUME; + break; + + case SdCommandTypeAbort: + CommandType = SDHC_CMD_TYPE_ABORT; + break; + + default: + CommandType = 0; + break; + } + + // + // Set the bitmask for the required events that will fire after + // writing to the command register. Depending on the response + // type or whether the command involves data transfer, we will need + // to wait on a number of different events. + // + + Request->RequiredEvents = SDHC_IS_CMD_COMPLETE; + if ((Command->ResponseType == SdResponseTypeR1B) || + (Command->ResponseType == SdResponseTypeR5B)) { + + Request->RequiredEvents |= SDHC_IS_TRANSFER_COMPLETE; + } + + if (Request->Command.TransferMethod == SdTransferMethodSgDma) { + Request->RequiredEvents |= SDHC_IS_TRANSFER_COMPLETE; + + } else if (Request->Command.TransferMethod == SdTransferMethodPio) { + if (Request->Command.TransferDirection == SdTransferDirectionRead) { + Request->RequiredEvents |= SDHC_IS_BUFFER_READ_READY; + + } else { + Request->RequiredEvents |= SDHC_IS_BUFFER_WRITE_READY; + } + } + + // + // Issue the actual command. + // + + CommandReg |= CommandType; + SdhcWriteRegisterUshort(SdhcExtension, SDHC_COMMAND, CommandReg); + + // + // We must wait until the request completes. + // + + return STATUS_PENDING; +} + +NTSTATUS +SdhcGetResponse( + _In_ PSDHC_EXTENSION SdhcExtension, + _In_ PSDPORT_COMMAND Command, + _Out_ PVOID ResponseBuffer + ) + +/*++ + +Routine Description: + + This routine reads the response of the SD card which is sent over + the command line, and stores it in the specified buffer + +Arguments: + + SdhcExtension - Host controller specific driver context. + + Request - Supplies the descriptor for this SD command. + +Return value: + + STATUS_SUCCESS - Response successfully returned. + + STATUS_INVALID_PARAMETER - Invalid response length. + +--*/ + +{ + + UCHAR Index; + PUCHAR Response; + UCHAR ResponseLength; + + ResponseLength = SdhcGetResponseLength(Command); + if (ResponseLength > 16) { + return STATUS_INVALID_PARAMETER; + } + + Response = (PUCHAR) ResponseBuffer; + for (Index = 0; Index < ResponseLength; Index += 1) { + +#pragma prefast(suppress: 22103, "Response length is guaranteed to be <= ResponseLength.") + + Response[Index] = + SdhcReadRegisterUchar(SdhcExtension, SDHC_RESPONSE + Index); + } + + return STATUS_SUCCESS; +} + +NTSTATUS +SdhcSetTransferMode( + _In_ PSDHC_EXTENSION SdhcExtension, + _In_ PSDPORT_REQUEST Request + ) + +/*++ + +Routine Description: + + This routine sets up the host for a data transfer. + +Arguments: + + SdhcExtension - Host controller specific driver context. + + Command - Supplies the descriptor for this SD command. + +Return value: + + STATUS_SUCCESS - Transfer mode successfully set. + + STATUS_INVALID_PARAMETER - Invalid command transfer parameters. + +--*/ + +{ + + USHORT BlockCount; + USHORT BlockSize; + USHORT TransferMode; + + NT_ASSERT(Request->Command.TransferMethod != SdTransferMethodUndefined); + + BlockCount = Request->Command.BlockCount; + if (Request->Command.BlockSize > 2048) { + + NT_ASSERTMSG("SDHC - Invalid block size for command", FALSE); + + return STATUS_INVALID_PARAMETER; + } + + if ((Request->Command.TransferDirection != SdTransferDirectionRead) && + (Request->Command.TransferDirection != SdTransferDirectionWrite)) { + + return STATUS_INVALID_PARAMETER; + } + + TransferMode &= ~(SDHC_TM_AUTO_CMD12_ENABLE | + SDHC_TM_AUTO_CMD23_ENABLE | + SDHC_TM_DMA_ENABLE | + SDHC_TM_BLKCNT_ENABLE | + SDHC_TM_MULTIBLOCK); + + // if (Command->TransferType = TransferTypeMultiBlockNoStop) { + + //} + + if (BlockCount > 1) { + TransferMode |= SDHC_TM_MULTIBLOCK; + TransferMode |= SDHC_TM_BLKCNT_ENABLE; + TransferMode |= SDHC_TM_AUTO_CMD12_ENABLE; + } + + if (Request->Command.TransferMethod == SdTransferMethodSgDma) { + TransferMode |= SDHC_TM_DMA_ENABLE; + + } else { + + NT_ASSERT(Request->Command.TransferMethod == SdTransferMethodPio); + + } + + BlockSize = Request->Command.BlockSize; + TransferMode &= ~SDHC_TM_TRANSFER_READ; + if (Request->Command.TransferDirection == SdTransferDirectionRead) { + TransferMode |= SDHC_TM_TRANSFER_READ; + } + + SdhcWriteRegisterUlong(SdhcExtension, SDHC_SYSADDR, BlockCount); + SdhcWriteRegisterUshort(SdhcExtension, SDHC_BLOCK_SIZE, BlockSize); + SdhcWriteRegisterUshort(SdhcExtension, SDHC_BLOCK_COUNT, BlockCount); + SdhcWriteRegisterUshort(SdhcExtension, SDHC_TRANSFER_MODE, TransferMode); + return STATUS_SUCCESS; +} + +VOID +SdhcReadDataPort( + _In_ PSDHC_EXTENSION SdhcExtension, + _Out_writes_all_(Length) PUCHAR Buffer, + _In_ SIZE_T Length + ) + +/*++ + +Routine Description: + + The data port must be accessed maintaining DWORD alignment. So for example: + + IN DWORD 130 + IN DWORD 130 + + is the same as + + IN USHORT 130 + IN USHORT 132 + IN UCHAR 130 + IN UCHAR 131 + IN UCHAR 132 + IN UCHAR 133 + +Arguments: + + SdhcExtension - Host controller specific driver context. + + Buffer - Data buffer to read. + + Length - Length of the data buffer in bytes. + +Return value: + + None. + +--*/ + +{ + + PUCHAR Port; + + Port = (PUCHAR) SdhcExtension->BaseAddress + SDHC_DATA_PORT; + while (Length >= sizeof(ULONG)) { + SdhcReadRegisterBufferUlong(SdhcExtension, + SDHC_DATA_PORT, + (PULONG) Buffer, + 1); + + Buffer += sizeof(ULONG); + Length -= sizeof(ULONG); + } + + if (Length >= sizeof(USHORT)) { + SdhcReadRegisterBufferUshort(SdhcExtension, + SDHC_DATA_PORT, + (PUSHORT) Buffer, + 1); + + Buffer += sizeof(USHORT); + Length -= sizeof(USHORT); + } + + if (Length >= sizeof(UCHAR)) { + SdhcReadRegisterBufferUchar(SdhcExtension, + SDHC_DATA_PORT + sizeof(USHORT), + Buffer, + 1); + } +} + +VOID +SdhcWriteDataPort( + _In_ PSDHC_EXTENSION SdhcExtension, + _In_reads_(Length) PUCHAR Buffer, + _In_ ULONG Length + ) + +/*++ + +Routine Description: + + The data port must be accessed maintaining DWORD alignment. So for example: + + IN DWORD 130 + IN DWORD 130 + + is the same as + + IN USHORT 130 + IN USHORT 132 + IN UCHAR 130 + IN UCHAR 131 + IN UCHAR 132 + IN UCHAR 133 + +Arguments: + + SdhcExtension - Host controller specific driver context. + + Buffer - Data buffer to write. + + Length - Length of the data buffer in bytes. + +Return value: + + None. + +--*/ + +{ + + while (Length >= sizeof(ULONG)) { + SdhcWriteRegisterBufferUlong(SdhcExtension, + SDHC_DATA_PORT, + (PULONG) Buffer, + 1); + + Buffer += sizeof(ULONG); + Length -= sizeof(ULONG); + } + + if (Length >= sizeof(USHORT)) { + SdhcWriteRegisterBufferUshort(SdhcExtension, + SDHC_DATA_PORT, + (PUSHORT) Buffer, + 1); + + Buffer += sizeof(USHORT); + Length -= sizeof(USHORT); + } + + if (Length >= sizeof(UCHAR)) { + SdhcWriteRegisterBufferUchar(SdhcExtension, + SDHC_DATA_PORT + sizeof(USHORT), + Buffer, + 1); + } + + NT_ASSERT((SdhcReadRegisterUshort(SdhcExtension, SDHC_ERROR_STATUS) & + SDHC_ES_BAD_DATA_SPACE_ACCESS) == 0); +} + +NTSTATUS +SdhcBuildTransfer( + _In_ PSDHC_EXTENSION SdhcExtension, + _In_ PSDPORT_REQUEST Request + ) + +/*++ + +Routine Description: + + Prepare the transfer request. + +Arguments: + + SdhcExtension - Host controller specific driver context. + + Command - The command for which we're building the transfer request. + +Return value: + + NTSTATUS + +--*/ + +{ + + NTSTATUS Status; + + NT_ASSERT(Request->Command.TransferType != SdTransferTypeNone); + + NT_ASSERT(Request->Command.TransferMethod != SdTransferMethodUndefined); + + switch (Request->Command.TransferMethod) { + case SdTransferMethodPio: + Status = SdhcBuildPioTransfer(SdhcExtension, Request); + break; + + case SdTransferMethodSgDma: + Status = SdhcBuildAdmaTransfer(SdhcExtension, Request); + break; + + default: + Status = STATUS_NOT_SUPPORTED; + break; + } + + return Status; +} + +NTSTATUS +SdhcStartTransfer( + _In_ PSDHC_EXTENSION SdhcExtension, + _In_ PSDPORT_REQUEST Request + ) + +/*++ + +Routine Description: + + Execute the transfer request. + +Arguments: + + SdhcExtension - Host controller specific driver context. + + Request - The command for which we're building the transfer request. + +Return value: + + NTSTATUS + +--*/ + +{ + + NTSTATUS Status; + + NT_ASSERT(Request->Command.TransferType != SdTransferTypeNone); + + switch (Request->Command.TransferMethod) { + case SdTransferMethodPio: + Status = SdhcStartPioTransfer(SdhcExtension, Request); + break; + + case SdTransferMethodSgDma: + Status = SdhcStartAdmaTransfer(SdhcExtension, Request); + break; + + default: + Status = STATUS_NOT_SUPPORTED; + break; + } + + return Status; +} + +NTSTATUS +SdhcBuildPioTransfer( + _In_ PSDHC_EXTENSION SdhcExtension, + _In_ PSDPORT_REQUEST Request + ) + +/*++ + +Routine Description: + + Prepare the PIO transfer request. + +Arguments: + + SdhcExtension - Host controller specific driver context. + + Request - The command for which we're building the transfer. + +Return value: + + NTSTATUS + +--*/ + +{ + + return SdhcSetTransferMode(SdhcExtension, Request); +} + + +NTSTATUS +SdhcBuildAdmaTransfer( + _In_ PSDHC_EXTENSION SdhcExtension, + _In_ PSDPORT_REQUEST Request + ) + +/*++ + +Routine Description: + + Prepare the ADMA2 transfer request. + +Arguments: + + SdhcExtension - Host controller specific driver context. + + Request - The command for which we're building the transfer. + +Return value: + + NTSTATUS + +--*/ + +{ + + NTSTATUS Status; + ULONG TransferLength; + + Status = SdhcSetTransferMode(SdhcExtension, Request); + if (!NT_SUCCESS(Status)) { + return Status; + } + + NT_ASSERT(Request->Command.ScatterGatherList != NULL); + + // + // Create the ADMA2 descriptor table in the host's DMA buffer. + // + + Status = + SdhcCreateAdmaDescriptorTable( + Request, + (BOOLEAN) SdhcExtension->Capabilities.Supported.Address64Bit, + &TransferLength); + + if (!NT_SUCCESS(Status)) { + return Status; + } + + SdhcWriteRegisterUlong(SdhcExtension, + SDHC_ADMA_SYSADDR_LOW, + Request->Command.DmaPhysicalAddress.LowPart); + + if (SdhcExtension->Capabilities.Supported.Address64Bit) { + SdhcWriteRegisterUlong(SdhcExtension, + SDHC_ADMA_SYSADDR_HIGH, + Request->Command.DmaPhysicalAddress.HighPart); + } else { + + NT_ASSERT(Request->Command.DmaPhysicalAddress.HighPart == 0); + + } + + return STATUS_SUCCESS; +} + +NTSTATUS +SdhcStartPioTransfer( + _In_ PSDHC_EXTENSION SdhcExtension, + _In_ PSDPORT_REQUEST Request + ) + +/*++ + +Routine Description: + + Execute the PIO transfer request. + +Arguments: + + SdhcExtension - Host controller specific driver context. + + Request - The command for which we're building the transfer. + +Return value: + + NTSTATUS + +--*/ + +{ + + NT_ASSERT((Request->Command.TransferDirection == SdTransferDirectionRead) || + (Request->Command.TransferDirection == SdTransferDirectionWrite)); + + if (Request->Command.TransferDirection == SdTransferDirectionRead) { + SdhcReadDataPort(SdhcExtension, + Request->Command.DataBuffer, + Request->Command.BlockSize); + + } else { + SdhcWriteDataPort(SdhcExtension, + Request->Command.DataBuffer, + Request->Command.BlockSize); + } + + Request->Command.BlockCount -= 1; + if (Request->Command.BlockCount >= 1) { + Request->Command.DataBuffer += Request->Command.BlockSize; + if (Request->Command.TransferDirection == SdTransferDirectionRead) { + Request->RequiredEvents |= SDHC_IS_BUFFER_READ_READY; + + } else { + Request->RequiredEvents |= SDHC_IS_BUFFER_WRITE_READY; + } + + Request->Status = STATUS_MORE_PROCESSING_REQUIRED; + + } else { + + NT_ASSERT(Request->Command.BlockCount == 0); + + Request->RequiredEvents |= SDHC_IS_TRANSFER_COMPLETE; + Request->Status = STATUS_SUCCESS; + } + + return STATUS_PENDING; +} + +NTSTATUS +SdhcStartAdmaTransfer( + _In_ PSDHC_EXTENSION SdhcExtension, + _In_ PSDPORT_REQUEST Request + ) + +/*++ + +Routine Description: + + Execute the ADMA2 transfer request. + +Arguments: + + SdhcExtension - Host controller specific driver context. + + Request - The command for which we're building the transfer. + +Return value: + + NTSTATUS + +--*/ + +{ + + UNREFERENCED_PARAMETER(SdhcExtension); + + Request->Status = STATUS_SUCCESS; + SdPortCompleteRequest(Request, Request->Status); + return STATUS_SUCCESS; +} + +USHORT +SdhcCalcClockFrequency( + _In_ PSDHC_EXTENSION SdhcExtension, + _In_ ULONG TargetFrequency, + _Out_opt_ PULONG ActualFrequency + ) + +/*++ + +Routine Description: + + Execute the ADMA2 transfer request. + +Arguments: + + SdhcExtension - Host controller specific driver context. + + TargetFrequency - The frequency in kHz to which we want to set the bus. + + ActualFrequency - The actual frequency to which the bus is set. + +Return value: + + ClockControl - The value of the Clock Control register to be written. + +--*/ + +{ + + ULONG BaseFrequency; + USHORT ClockControl; + ULONG Divisor; + USHORT SpecVersion; + + *ActualFrequency = 0; + BaseFrequency = SdhcExtension->Capabilities.BaseClockFrequencyKhz; + Divisor = MAX(BaseFrequency / TargetFrequency, 1); + + NT_ASSERT(Divisor > 0); + + SpecVersion = SdhcReadRegisterUshort(SdhcExtension, SDHC_VERSION) & 0xFF; + if (SpecVersion > SDHC_SPEC_VERSION_3) { + + // + // Calculate the fastest available clock frequency which is <= + // tthe requested frequency. + // + + Divisor = 1; + while (((BaseFrequency / Divisor) > TargetFrequency) && + (Divisor < SDHC_MAX_CLOCK_DIVISOR)) { + + Divisor <<= 1; + } + + *ActualFrequency = BaseFrequency / Divisor; + Divisor >>= 1; + ClockControl = ((USHORT) Divisor << 8); + + } else { + + // + // Host controller version 3.0 supports the 10-bit divided clock mode. + // + + Divisor = BaseFrequency / TargetFrequency; + Divisor >>= 1; + if ((TargetFrequency < BaseFrequency) && + (TargetFrequency * 2 * Divisor != BaseFrequency)) { + + Divisor += 1; + } + + if (Divisor > SDHC_MAX_CLOCK_DIVISOR_SPEC_3 / 2) { + Divisor = SDHC_MAX_CLOCK_DIVISOR_SPEC_3 / 2; + } + + if (Divisor == 0) { + *ActualFrequency = BaseFrequency; + + } else { + *ActualFrequency = BaseFrequency / Divisor; + *ActualFrequency >>= 1; + } + + ClockControl = ((USHORT) Divisor & 0xFF) << 8; + Divisor >>= 8; + ClockControl |= ((USHORT) Divisor & 0x03) << 6; + } + + NT_ASSERT((BaseFrequency <= TargetFrequency) ? (Divisor == 0) : TRUE); + + return ClockControl; +} + +NTSTATUS +SdhcCreateAdmaDescriptorTable( + _In_ PSDPORT_REQUEST Request, + _In_ BOOLEAN Use64BitDescriptor, + _Out_ PULONG TotalTransferLength + ) + +/*++ + +Routine Description: + + This routine creates a ADMA descriptor table based on scattor gatther list + given by Sglist. + +Arguments: + + Socket - Supplies the pointer to the socket + + Request - Data transfer request for which to build the descriptor table. + + TotalTransferLength - Supplies the pointer to return the total transfer + length of the descriptor table + +Return value: + + Whether the table was successfully created. + +--*/ + +{ + + PUCHAR Buffer; + PSDHC_ADMA2_DESCRIPTOR_TABLE_ENTRY Descriptor; + ULONG NumberOfElements; + PHYSICAL_ADDRESS NextAddress; + ULONG NextLength; + ULONG RemainingLength; + PSCATTER_GATHER_ELEMENT SglistElement; + + Buffer = Request->Command.DmaVirtualAddress; + Descriptor = NULL; + NumberOfElements = Request->Command.ScatterGatherList->NumberOfElements; + SglistElement = &Request->Command.ScatterGatherList->Elements[0]; + *TotalTransferLength = 0; + + NT_ASSERT(NumberOfElements > 0); + + // + // Iterate through each element in the SG list and convert it into the + // descriptor table required by the controller. + // + + while (NumberOfElements > 0) { + RemainingLength = SglistElement->Length; + NextAddress.QuadPart = SglistElement->Address.QuadPart; + + NT_ASSERT(RemainingLength > 0); + + while (RemainingLength > 0) { + Descriptor = (PSDHC_ADMA2_DESCRIPTOR_TABLE_ENTRY) Buffer; + Buffer += sizeof(SDHC_ADMA2_DESCRIPTOR_TABLE_ENTRY); + + NT_ASSERT((ULONG_PTR) Buffer < + (ULONG_PTR) Request->Command.DmaVirtualAddress + + Request->Command.Length); + + NextLength = MIN(SDHC_ADMA2_MAX_LENGTH_PER_ENTRY, RemainingLength); + RemainingLength -= NextLength; + + // + // Set the entry attributes and length. + // + + Descriptor->AsUlong = 0; + Descriptor->Action = SDHC_ADMA2_ACTION_TRAN; + Descriptor->Attribute = SDHC_ADMA2_ATTRIBUTE_VALID; + Descriptor->Length = NextLength; + *TotalTransferLength += NextLength; + + // + // Set the address field. + // + + if (Use64BitDescriptor) { + *((PULONGLONG) Buffer) = NextAddress.QuadPart; + Buffer += sizeof(LONGLONG); + + } else { + + // + // The HighPart should not be a non-zero value, since in the + // DMA adapter object, we declared that this device only + // supports 32-bit addressing. + // + + NT_ASSERT(NextAddress.HighPart == 0); + + *((PULONG) Buffer) = NextAddress.LowPart; + Buffer += sizeof(ULONG); + } + + NextAddress.QuadPart += NextLength; + } + + SglistElement += 1; + NumberOfElements -= 1; + + // + // Set the END bit if we're at the last element. + // + + if (NumberOfElements == 0) { + Descriptor->Attribute |= SDHC_ADMA2_ATTRIBUTE_END; + } + } + + return STATUS_SUCCESS; +} + +VOID +SdhcInitializePciConfigSpace( + _In_ PSD_MINIPORT Miniport + ) + +/*++ + +Routine Description: + + This routine updates the PCI configuration space. + +Arguments: + + Argument - Pointer to the functional device object extension for the SD host controller + +Return value: + + None. + +--*/ + +{ + + + + + + + + + if (Miniport->ConfigurationInfo.BusType != SdBusTypePci) { + return; + } + + // + // Some PCI based controllers require access to PCI configuration + // space to enable certain features. In order to do this, sdport + // provides two APIs, SdPortGetPciConfigSpace and + // SdPortSetPciConfigSpace to access various PCI configuration + // registers. For example, to access offset 0xA0 and unset bit + // 31 (hypothetically to turn on or off a feature): + // + // ULONG PciConfig; + // + // PciConfig = 0; + // SdPortGetPciConfigSpace(Miniport, + // 0xA0, + // (PUCHAR)&PciConfig, + // sizeof(PciConfig)); + // + // PciConfig &= ~(1 << 31); + // SdPortSetPciConfigSpace(Miniport, + // 0xA0, + // (PUCHAR)&PciConfig, + // sizeof(PciConfig)); + // + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +} diff --git a/sd/miniport/sdhc/sdhc.h b/sd/miniport/sdhc/sdhc.h new file mode 100644 index 00000000..e16044b7 --- /dev/null +++ b/sd/miniport/sdhc/sdhc.h @@ -0,0 +1,2091 @@ +/*++ + +Copyright (c) 2014 Microsoft Corporation + +Module Name: + + sdhc.h + +Abstract: + + Header for default standard host controller implementation. + +Author: + + Greg Garbern (greggar) 01-May-2014 + +Environment: + + Kernel mode only. + +Revision History: + + Greg Garbern (greggar) 12-June-2014 + +--*/ + +#if defined (_MSC_VER) && (_MSC_VER > 1000) +#pragma once +#endif + +#pragma warning(disable:4214) // bit field types other than int +#pragma warning(disable:4201) // nameless struct/union +#pragma warning(disable:4115) // named type definition in parentheses + + + + + + + + + + + + + + + + + + + + +// +// Memory registers +// + +#define SDHC_SYSADDR 0x00 +#define SDHC_BLOCK_SIZE 0x04 +#define SDHC_BLOCK_COUNT 0x06 +#define SDHC_ARGUMENT 0x08 +#define SDHC_TRANSFER_MODE 0x0c +#define SDHC_COMMAND 0x0e +#define SDHC_RESPONSE 0x10 +#define SDHC_DATA_PORT 0x20 +#define SDHC_PRESENT_STATE 0x24 +#define SDHC_HOST_CONTROL 0x28 +#define SDHC_POWER_CONTROL 0x29 +#define SDHC_BLOCKGAP_CONTROL 0x2a +#define SDHC_WAKEUP_CONTROL 0x2b +#define SDHC_CLOCK_CONTROL 0x2c +#define SDHC_TIMEOUT_CONTROL 0x2e +#define SDHC_RESET 0x2f +#define SDHC_INTERRUPT_STATUS 0x30 +#define SDHC_ERROR_STATUS 0x32 +#define SDHC_INTERRUPT_STATUS_ENABLE 0x34 +#define SDHC_ERROR_STATUS_ENABLE 0x36 +#define SDHC_INTERRUPT_SIGNAL_ENABLE 0x38 +#define SDHC_ERROR_SIGNAL_ENABLE 0x3a +#define SDHC_AUTO_CMD12_ERROR_STATUS 0x3c +#define SDHC_HOST_CONTROL2 0x3e +#define SDHC_CAPABILITIES 0x40 +#define SDHC_CAPABILITIES2 0x44 +#define SDHC_MAXIMUM_CURRENT 0x48 +#define SDHC_ADMA_ERROR_STATUS 0x54 +#define SDHC_ADMA_SYSADDR_LOW 0x58 +#define SDHC_ADMA_SYSADDR_HIGH 0x5c + + +#define SDHC_SLOT_INFORMATION 0xfc +#define SDHC_VERSION 0xfe + +// +// Bits defined in SDHC_TRANSFER_MODE +// + +#define SDHC_TM_DMA_ENABLE 0x0001 +#define SDHC_TM_BLKCNT_ENABLE 0x0002 +#define SDHC_TM_AUTO_CMD12_ENABLE 0x0004 +#define SDHC_TM_AUTO_CMD23_ENABLE 0x0008 +#define SDHC_TM_TRANSFER_READ 0x0010 +#define SDHC_TM_MULTIBLOCK 0x0020 + +// +// Bits defined in SDHC_COMMAND +// + +#define SDHC_CMD_RESPONSE_136BIT 0x0001 +#define SDHC_CMD_RESPONSE_48BIT_NOBUSY 0x0002 +#define SDHC_CMD_RESPONSE_48BIT_WBUSY 0x0003 + +#define SDHC_CMD_CRC_CHECK_ENABLE 0x0008 +#define SDHC_CMD_INDEX_CHECK_ENABLE 0x0010 +#define SDHC_CMD_DATA_PRESENT 0x0020 + +#define SDHC_CMD_TYPE_SUSPEND 0x0040 +#define SDHC_CMD_TYPE_RESUME 0x0080 +#define SDHC_CMD_TYPE_ABORT 0x0060 + +// +// Bits defined in SDHC_PRESENT_STATE +// + +#define SDHC_PS_CMD_INHIBIT 0x00000001 +#define SDHC_PS_DAT_INHIBIT 0x00000002 +#define SDHC_PS_DAT_ACTIVE 0x00000004 +#define SDHC_PS_RETUNING_REQUEST 0x00000008 +#define SDHC_PS_WRITE_TRANSFER_ACTIVE 0x00000100 +#define SDHC_PS_READ_TRANSFER_ACTIVE 0x00000200 +#define SDHC_PS_BUFFER_WRITE_ENABLE 0x00000400 +#define SDHC_PS_BUFFER_READ_ENABLE 0x00000800 + +#define SDHC_PS_CARD_INSERTED 0x00010000 +#define SDHC_PS_CARD_STATE_STABLE 0x00020000 +#define SDHC_PS_CARD_DETECT 0x00040000 +#define SDHC_PS_WRITE_PROTECT 0x00080000 + +#define SDHC_PS_DAT0_SIGNAL 0x00100000 +#define SDHC_PS_DAT1_SIGNAL 0x00200000 +#define SDHC_PS_DAT2_SIGNAL 0x00400000 +#define SDHC_PS_DAT3_SIGNAL 0x00800000 + +#define SDHC_PS_DAT_3_0 (SDHC_PS_DAT0_SIGNAL | \ + SDHC_PS_DAT1_SIGNAL | \ + SDHC_PS_DAT2_SIGNAL | \ + SDHC_PS_DAT3_SIGNAL) + +#define SDHC_PS_CMD_SIGNAL 0x01000000 + +// +// Bits defined in SDHC_HOST_CONTROL +// + +#define SDHC_HC_LED_POWER 0x01 +#define SDHC_HC_DATA_WIDTH_4BIT 0x02 +#define SDHC_HC_ENABLE_HIGH_SPEED 0x04 +#define SDHC_HC_DATA_WIDTH_8BIT 0x20 + +#define SDHC_HC_DMA_SELECT_MASK 0x18 +#define SDHC_HC_DMA_SELECT_SDMA 0x00 +#define SDHC_HC_DMA_SELECT_ADMA32 0x10 +#define SDHC_HC_DMA_SELECT_ADMA64 0x18 + +// +// Bits defined in SDHC_HOST_CONTROL2 +// + +#define SDHC_HC2_SDR12 0x0000 +#define SDHC_HC2_SDR25 0x0001 +#define SDHC_HC2_SDR50 0x0002 +#define SDHC_HC2_SDR104 0x0003 +#define SDHC_HC2_DDR50 0x0004 +#define SDHC_HC2_HS200 0x0005 + +#define SDHC_HC2_UHS_MODES (SDHC_HC2_SDR12 | \ + SDHC_HC2_SDR25 | \ + SDHC_HC2_SDR50 | \ + SDHC_HC2_SDR104| \ + SDHC_HC2_DDR50 | \ + SDHC_HC2_HS200) + +#define SDHC_HC2_1_8V_SIGNALING 0x0008 + +#define SDHC_HC2_SELECT_TYPE_B 0x0000 +#define SDHC_HC2_SELECT_TYPE_A 0x0010 +#define SDHC_HC2_SELECT_TYPE_C 0x0020 +#define SDHC_HC2_SELECT_TYPE_D 0x0030 + +#define SDHC_HC2_EXECUTE_TUNING 0x0040 +#define SDHC_HC2_SELECT_SAMPLING_CLOCK 0x0080 +#define SDHC_HC2_ENABLE_ASYNC_INTERRUPT 0x4000 +#define SDHC_HC2_ENABLE_PRESET_VALUE 0x8000 + +// +// Bits defined in SDHC_POWER_CONTROL +// + +#define SDHC_PC_BUS_POWER 0x01 +#define SDHC_PC_1_8V 0x0a +#define SDHC_PC_3_0V 0x0c +#define SDHC_PC_3_3V 0x0e + +#define SDHC_PC_VOLTAGE_MASK 0x0e + +// +// Bits defined in SDHC_BLOCKGAP_CONTROL +// + +#define SDHC_BGC_STOP_NEXT_GAP 0x01 +#define SDHC_BGC_CONTINUE 0x02 +#define SDHC_BGC_READ_WAIT_ENABLE 0x04 +#define SDHC_BGC_INTERRUPT_ENABLE 0x08 + +// +// Bits defined in SDHC_WAKEUP_CONTROL +// + +#define SDHC_WC_CARD_INT_ENABLE 0x01 +#define SDHC_WC_CARD_INSERTION_ENABLE 0x02 +#define SDHC_WC_CARD_REMOVAL_ENABLE 0x04 +#define SDHC_WC_CARD_SUPPORTS_WAKEUP 0x80 + + +// +// Bits defined in SDHC_CLOCK_CONTROL +// + +#define SDHC_CC_INTERNAL_CLOCK_ENABLE 0x0001 +#define SDHC_CC_CLOCK_STABLE 0x0002 +#define SDHC_CC_CLOCK_ENABLE 0x0004 +#define SDHC_CC_CLOCK_DIVISOR_2 0x0100 +#define SDHC_CC_CLOCK_DIVISOR_4 0x0200 +#define SDHC_CC_CLOCK_DIVISOR_8 0x0400 +#define SDHC_CC_CLOCK_DIVISOR_16 0x0800 +#define SDHC_CC_CLOCK_DIVISOR_32 0x1000 +#define SDHC_CC_CLOCK_DIVISOR_64 0x2000 +#define SDHC_CC_CLOCK_DIVISOR_128 0x4000 +#define SDHC_CC_CLOCK_DIVISOR_256 0x8000 + + +// +// Bits defined in SDHC_TIMEOUT_CONTROL +// + +#define SDHC_TC_COUNTER_MASK 0x0f +#define SDHC_TC_MAX_DATA_TIMEOUT 0x0e + +// +// Bits defined in SDHC_RESET +// + +#define SDHC_RESET_ALL 0x01 +#define SDHC_RESET_CMD 0x02 +#define SDHC_RESET_DAT 0x04 + +// +// Bits defined in SDHC_INTERRUPT_STATUS +// SDHC_INTERRUPT_STATUS_ENABLE +// SDHC_INTERRUPT_SIGNAL_ENABLE +// + +#define SDHC_IS_CMD_COMPLETE 0x0001 +#define SDHC_IS_TRANSFER_COMPLETE 0x0002 +#define SDHC_IS_BLOCKGAP_EVENT 0x0004 +#define SDHC_IS_DMA_EVENT 0x0008 +#define SDHC_IS_BUFFER_WRITE_READY 0x0010 +#define SDHC_IS_BUFFER_READ_READY 0x0020 +#define SDHC_IS_CARD_INSERTION 0x0040 +#define SDHC_IS_CARD_REMOVAL 0x0080 +#define SDHC_IS_CARD_INTERRUPT 0x0100 +#define SDHC_IS_TUNING_INTERRUPT 0x1000 + +#define SDHC_IS_ERROR_INTERRUPT 0x8000 + +#define SDHC_IS_CARD_DETECT (SDHC_IS_CARD_INSERTION | SDHC_IS_CARD_REMOVAL) + +// +// Bits defined in SDHC_ERROR_STATUS +// Bits defined in SDHC_ERROR_STATUS_ENABLE +// Bits defined in SDHC_ERROR_SIGNAL_ENABLE +// +// PLEASE NOTE: these values need to match exactly the +// "generic" values in sdbus.h +// + +#define SDHC_ES_CMD_TIMEOUT 0x0001 +#define SDHC_ES_CMD_CRC_ERROR 0x0002 +#define SDHC_ES_CMD_END_BIT_ERROR 0x0004 +#define SDHC_ES_CMD_INDEX_ERROR 0x0008 +#define SDHC_ES_DATA_TIMEOUT 0x0010 +#define SDHC_ES_DATA_CRC_ERROR 0x0020 +#define SDHC_ES_DATA_END_BIT_ERROR 0x0040 +#define SDHC_ES_BUS_POWER_ERROR 0x0080 +#define SDHC_ES_AUTO_CMD12_ERROR 0x0100 +#define SDHC_ES_ADMA_ERROR 0x0200 +#define SDHC_ES_BAD_DATA_SPACE_ACCESS 0x2000 + +// +// Bits defined in SDHC_AUTO_CMD12_ERROR_STATUS +// + +#define SDHC_ACMD12_NOT_EXECUTED 0x0001 +#define SDHC_ACMD12_RESPONSE_TIMEOUT 0x0002 +#define SDHC_ACMD12_RESPONSE_CRC_ERROR 0x0004 +#define SDHC_ACMD12_END_BIT_ERROR 0x0008 +#define SDHC_ACMD12_INDEX_ERROR 0x0010 +#define SDHC_ACMD12_CWODAT_NOT_EXECUTED 0x0080 + + +#define SDHC_MAX_CLOCK_DIVISOR 256 +#define SDHC_MAX_CLOCK_DIVISOR_SPEC_3 2046 + + +// +// determines the poll interval for host reset and clock setting (10ms) +// + +#define SDHC_DEFAULT_POLL_INTERVAL 10000 + +// +// determines the poll count (10 ms * 100 tries = 1 second) +// + +#define SDHC_DEFAULT_POLL_COUNT 100 + +#define SDHC_MAX_SET_POWER_RETRIES 5 + +#define SDHC_ALIGNMENT_SDMA 1 +#define SDHC_ALIGNMENT_ADMA2 3 +#define SDHC_ALIGNMENT_ADMA2_64 7 + +#define SDHC_SPEC_VERSION_1 0 +#define SDHC_SPEC_VERSION_2 1 +#define SDHC_SPEC_VERSION_3 2 + +//---------------------------------------------------------------------------- +// Host register layout +//---------------------------------------------------------------------------- + +// --------------------------------------------------------------------------- +// +// SD card information +// +// --------------------------------------------------------------------------- + +#pragma pack(push) +#pragma pack(1) + +// +// The entire layout of an SD host controller in memory for debug purposes. +// + +typedef struct _SD_HOST_CONTROLLER_REGISTERS { + + union { + struct { + USHORT Low; + USHORT High; + } Argument2; + struct { + USHORT Low; + USHORT High; + } SDMAAddress; + } Argument2; + + USHORT BlockSize; // 04h + + USHORT BlockCount; // 06h + + union { + struct { + USHORT Low; // 08h + USHORT High; // 0Ah + } Argument1; + ULONG Ulong; + } Argument1; + + union { + struct { + USHORT DMAEnable : 1; + USHORT BlockCountEnable : 1; + USHORT AutoCommandEnable : 2; + USHORT DataTransferDirectionSelect : 1; + USHORT MultiBlockSelect : 1; + USHORT Reserved0 : 10; + } Flags; + USHORT Value; // 0Ch + } TransferMode; + + union { + struct { + USHORT ResponseTypeSelect : 2; + USHORT Reserved0 : 1; + USHORT CommandCRCCheckEnable : 1; + USHORT CommandIndexCheckEnable : 1; + USHORT DataPresentSelect : 1; + USHORT CommandType : 2; + USHORT CommandIndex : 6; + USHORT Reserved1 : 2; + } Flags; + USHORT Value; // 0Eh + } Command; + + union { + + struct { + union { + struct { + ULONG ReservedManufacturerTest0 : 1; + ULONG ReservedManufacturerTest1 : 1; + ULONG ReservedAppspecific : 1; + ULONG AKE_SEQ_ERROR : 1; + ULONG ReservedSDIO : 1; + ULONG APP_CMD : 1; + ULONG Reserved0 : 2; + ULONG READY_FOR_DATA : 1; + ULONG CURRENT_STATE : 4; + ULONG ERASE_RESSET : 1; + ULONG CARD_ECC_DISABLE : 1; + ULONG WP_ERASE_SKIP : 1; + ULONG CSD_OVERWRITE : 1; + ULONG RESERVED_DEFERRED_RESPONSE : 1; + ULONG RESERVED : 1; + ULONG ERROR : 1; + ULONG CC_ERROR : 1; + ULONG CARD_ECC_FAILED : 1; + ULONG ILLEGAL_COMMAND : 1; + ULONG COM_CRC_ERROR : 1; + ULONG LOCK_UNLOCK_FAILED : 1; + ULONG CARD_IS_LOCKED : 1; + ULONG WP_VIOLATION : 1; + ULONG ERASE_PARAM : 1; + ULONG ERASE_SEQ_ERROR : 1; + ULONG BLOCK_LEN_ERROR : 1; + ULONG ADDRESS_ERROR : 1; + ULONG OUT_OF_RANGE : 1; + } Flags; + ULONG Ulong; + } CardStatus; + } R1; + + struct { + ULONG Reserved0[3]; + ULONG CardStatus; + } R1b; + + struct { + union { + + struct { + USHORT ManufacturingData : 12; + USHORT Reserved0 : 4; + ULONG SerialNumber; + UCHAR Revision; + UCHAR ProductName[5]; + USHORT ApplicationID; + UCHAR ManufactureID; + } CID; + + struct { + UCHAR Reserved0 : 2; + UCHAR FILE_FORMAT : 2; + UCHAR TMP_WRITE_PROTECT : 1; + UCHAR PERM_WRITE_PROTECT : 1; + UCHAR COPY : 1; + UCHAR FILE_FORMAT_GRP : 1; + + USHORT Reserved1 : 5; + USHORT WRITE_BL_PARTIAL : 1; + USHORT WRITE_BL_LEN : 4; + USHORT R2W_FACTOR : 3; + USHORT Reserved2 : 2; + USHORT WP_GRP_ENABLE : 1; + + ULONG WP_GRP_SIZE : 7; + ULONG SECTOR_SIZE : 7; + ULONG ERASE_BLK_EN : 1; + ULONG C_SIZE_MULT : 3; + ULONG VDD_W_CURR_MAX : 3; + ULONG VDD_W_CURR_MIN : 3; + ULONG VDD_R_CURR_MAX : 3; + ULONG VDD_R_CURR_MIN : 3; + ULONG C_SIZE_LOW : 2; + + ULONG C_SIZE_HIGH : 10; + ULONG Reserved3 : 2; + ULONG DSR_IMP : 1; + ULONG READ_BLK_MISALIGN : 1; + ULONG WRITE_BLK_MISALIGN : 1; + ULONG READ_BL_PARTIAL : 1; + ULONG READ_BL_LEN : 4; + ULONG CCC : 12; + + UCHAR TRAN_SPEED; + UCHAR NSAC; + UCHAR TAAC; + + UCHAR Reserved4 : 6; + UCHAR CSD_STRUCTURE : 2; + } CSDv1; + + struct { + UCHAR Reserved0 : 2; + UCHAR FILE_FORMAT : 2; + UCHAR TMP_WRITE_PROTECT : 1; + UCHAR PERM_WRITE_PROTECT : 1; + UCHAR COPY : 1; + UCHAR FILE_FORMAT_GRP : 1; + + USHORT Reserved1 : 5; + USHORT WRITE_BL_PARTIAL : 1; + USHORT WRITE_BL_LEN : 4; + USHORT R2W_FACTOR : 3; + USHORT Reserved2 : 2; + USHORT WP_GRP_ENABLE : 1; + + ULONG WP_GRP_SIZE : 7; + ULONG SECTOR_SIZE : 7; + ULONG ERASE_BLK_EN : 1; + ULONG Reserved3 : 1; + ULONG DeviceSizeLow : 16; + + ULONG DeviceSizeHigh : 6; + ULONG Reserved4 : 6; + ULONG DSR_IMP : 1; + ULONG READ_BLK_MISALIGN : 1; + ULONG WRITE_BLK_MISALIGN : 1; + ULONG READ_BL_PARTIAL : 1; + ULONG READ_BL_LEN : 4; + ULONG CCC : 12; + + UCHAR TRAN_SPEED : 8; + UCHAR NSAC : 8; + UCHAR TAAC : 8; + UCHAR Reserved5 : 6; + UCHAR CSD_STRUCTURE : 2; + } CSDv2; + } Register; + } R2; + + struct { + union { + struct { + ULONG Reserved0 : 7; + ULONG ReservedLowVoltageRange : 1; + ULONG Reserved1 : 7; + ULONG Voltage27V_28V : 1; + ULONG Voltage28V_29V : 1; + ULONG Voltage29V_30V : 1; + ULONG Voltage30V_31V : 1; + ULONG Voltage31V_32V : 1; + ULONG Voltage32V_33V : 1; + ULONG Voltage33V_34V : 1; + ULONG Voltage34V_35V : 1; + ULONG Voltage35V_36V : 1; + ULONG SwitchingTo18VAccepted : 1; + ULONG Reserved2 : 5; + ULONG CardCapacityStatus : 1; + ULONG CardPowerUpStatus : 1; + } Flags; + ULONG ULong; + } Ocr; + } R3; + + struct { + UCHAR Buffer[16]; + } R4; + + struct { + UCHAR Buffer[16]; + } R5; + + struct { + union { + struct { + USHORT ReservedManufacturerTest0 : 1; + USHORT ReservedManufacturerTest1 : 1; + USHORT ReservedAppspecific : 1; + USHORT AKE_SEQ_ERROR : 1; + USHORT ReservedSDIO : 1; + USHORT APP_CMDEnable : 1; + USHORT Reserved0 : 2; + USHORT READY_FOR_DATA : 1; + USHORT CurrentState : 4; + + USHORT ERROR : 1; + USHORT ILLEGAL_COMMAND : 1; + USHORT COM_CRC_ERROR : 1; + } Flags; + USHORT Register; + } CardStatusBits; + + USHORT NewRCA : 16; + } R6; + + struct { + ULONG CheckPattern : 8; + ULONG VoltageAccepted : 4; + ULONG Reserved : 20; + } R7; + + struct { + USHORT Response0; // 10h + USHORT Response1; // 12h + USHORT Response2; // 14h + USHORT Response3; // 16h + USHORT Response4; // 18h + USHORT Response5; // 1Ah + USHORT Response6; // 1Ch + USHORT Response7; // 1Eh + } Words; + UCHAR Buffer[16]; + } Response; + + union { + struct { + USHORT BufferDataPort0; // 20h + USHORT BufferDataPort1; // 22h + } Words; + ULONG Port; + } BufferDataPort; + + union { + struct { + USHORT PresentState0; // 24h + USHORT PresentState1; // 26h + } Words; + struct { + ULONG CommandInhibitCMD : 1; + ULONG CommandInhibitDAT : 1; + ULONG DATLineActive : 1; + ULONG ReTuningRequest : 1; + ULONG Reserved0 : 4; + ULONG WriteTransferActive : 1; + ULONG ReadTransferActive : 1; + ULONG BufferWriteEnable : 1; + ULONG BufferReadEnable : 1; + ULONG Reserved1 : 4; + ULONG CardInserted : 1; + ULONG CardStateStable : 1; + ULONG CardDetectPinLevel : 1; + ULONG WriteProtectSwitchPinLevel : 1; + ULONG DATLineSignalLevel : 4; + ULONG CMDLineSignalLevel : 1; + ULONG Reserved2 : 7; + } Flags; + } PresentState; + + union { + struct { + UCHAR LEDControlOn : 1; + UCHAR DataTransferWidth4Bit : 1; + UCHAR HighSpeedEnable : 1; + UCHAR DMASelect : 2; + UCHAR ExtendedDataTransferWidth8Bit : 1; + UCHAR CardDetectTestLevelCardInserted : 1; + UCHAR CardDetectSignalSelectionEnable : 1; + } Flags; + UCHAR Byte; // 28h + } HostControl1; + + union { + struct { + UCHAR SDBusPowerOn : 1; + UCHAR SDBUSVoltageSelect : 3; + UCHAR Reserved0 : 4; + } Flags; + UCHAR Byte; // 29h + } PowerControl; + + union { + struct { + UCHAR StopAtBlockGapRequest : 1; + UCHAR ContinueRequest : 1; + UCHAR ReadWaitControlEnable : 1; + UCHAR InterruptAtBlockGapEnable : 1; + UCHAR Reserved0 : 4; + } Flags; + UCHAR Byte; // 2Ah + } BlockGapControl; + + union { + struct { + UCHAR WakeupEventEnableOnSDCardInterrupt : 1; + UCHAR WakeupEventEnableOnSDCardInsertion : 1; + UCHAR WakeupEventEnableOnSDCardRemoval : 1; + UCHAR Reserved0 : 5; + } Flags; + UCHAR Byte; // 2Bh + } WakeupControl; + + union { + struct { + USHORT InternalClockEnable : 1; + USHORT InternalClockStable : 1; + USHORT SDClockEnable : 1; + USHORT Reserved0 : 2; + USHORT ClockGeneratorSelectProgrammable : 1; + USHORT FrequencySelectUpperBits : 2; + USHORT FrequencySelectLowerBits : 8; + } Flags; + USHORT Word; // 2Ch + } ClockControl; + + union { + struct { + UCHAR DataTimeoutCounterValue : 4; + UCHAR Reserved0 : 4; + } Flags; + UCHAR Byte; // 2Eh + } TimeoutControl; + + union { + struct { + UCHAR SoftwareResetForAll : 1; + UCHAR SoftwareResetForCMDLine : 1; + UCHAR SoftwareResetForDATLine : 1; + UCHAR Reserved0 : 5; + } Flags; + UCHAR Byte; // 2Fh + } SoftwareReset; + + union { + struct { + USHORT CommandComplete : 1; + USHORT TransferComplete : 1; + USHORT BlockGapEvent : 1; + USHORT DMAInterrupt : 1; + USHORT BufferWriteReady : 1; + USHORT BufferReadReady : 1; + USHORT CardInsertion : 1; + USHORT CardRemoval : 1; + USHORT CardInterrupt : 1; + USHORT INT_A : 1; + USHORT INT_B : 1; + USHORT INT_C : 1; + USHORT RetuningEvent : 1; + USHORT Reserved0 : 2; + USHORT ErrorInterrupt : 1; + } Flags; + USHORT Word; + } NormalInterruptStatus; + + union { + struct { + USHORT CommandTimeoutError : 1; + USHORT CommandCRCError : 1; + USHORT CommandEndBitError : 1; + USHORT CommandIndexError : 1; + USHORT DataTimeoutError : 1; + USHORT DataCRCError : 1; + USHORT DataEndBitError : 1; + USHORT CurrentLimitError : 1; + USHORT AutoCMD12Error : 1; + USHORT ADMAError : 1; + USHORT TuningError : 1; + USHORT Reserved0 : 1; + USHORT VendorSpecific : 4; + } Flags; + USHORT Word; + } ErrorInterruptStatus; + + union { + struct { + USHORT CommandCompleteStatusEnable : 1; + USHORT TransferCompleteStatusEnable : 1; + USHORT BlockGapEventStatusEnable : 1; + USHORT DMAInterruptStatusEnable : 1; + USHORT BufferWriteReadyStatusEnable : 1; + USHORT BufferReadReadyStatusEnable : 1; + USHORT CardInsertionStatusEnable : 1; + USHORT CardRemovalStatusEnable : 1; + USHORT CardInterruptStatusEnable : 1; + USHORT INT_AStatusEnable : 1; + USHORT INT_BStatusEnable : 1; + USHORT INT_CStatusEnable : 1; + USHORT RetuningEventStatusEnable : 1; + USHORT Reserved0 : 2; + USHORT FixedToZero : 1; + } Flags; + USHORT Word; // 34h + } NormalInterruptStatusEnable; + + union { + struct { + USHORT CommandTimeoutErrorStatusEnable : 1; + USHORT CommandCRCErrorStatusEnable : 1; + USHORT CommandEndBitErrorStatusEnable : 1; + USHORT CommandIndexErrorStatusEnable : 1; + USHORT DataTimeoutErrorStatusEnable : 1; + USHORT DataCRCErrorStatusEnable : 1; + USHORT DataEndBitErrorStatusEnable : 1; + USHORT CurrentLimitErrorStatusEnable : 1; + USHORT AutoCMD12ErrorStatusEnable : 1; + USHORT ADMAErrorStatusEnable : 1; + USHORT TuningErrorStatusEnable : 1; + USHORT Reserved0 : 1; + USHORT VendorSpecificStatusEnable : 4; + } Flags; + USHORT Word; + } ErrorInterruptStatusEnable; // 36h + + union { + struct { + USHORT CommandCompleteSignalEnable : 1; + USHORT TransferCompleteSignalEnable : 1; + USHORT BlockGapEventSignalEnable : 1; + USHORT DMAInterruptSignalEnable : 1; + USHORT BufferWriteReadySignalEnable : 1; + USHORT BufferReadReadySignalEnable : 1; + USHORT CardInsertionSignalEnable : 1; + USHORT CardRemovalSignalEnable : 1; + USHORT CardInterruptSignalEnable : 1; + USHORT INT_ASignalEnable : 1; + USHORT INT_BSignalEnable : 1; + USHORT INT_CSignalEnable : 1; + USHORT RetuningEventSignalEnable : 1; + USHORT Reserved0 : 2; + USHORT FixedToZero : 1; + } Flags; + USHORT Word; + } NormalInterruptSignalEnable; // 38h + + union { + struct { + USHORT CommandTimeoutErrorSignalEnable : 1; + USHORT CommandCRCErrorSignalEnable : 1; + USHORT CommandEndBitErrorSignalEnable : 1; + USHORT CommandIndexErrorSignalEnable : 1; + USHORT DataTimeoutErrorSignalEnable : 1; + USHORT DataCRCErrorSignalEnable : 1; + USHORT DataEndBitErrorSignalEnable : 1; + USHORT CurrentLimitErrorSignalEnable : 1; + USHORT AutoCMD12ErrorSignalEnable : 1; + USHORT ADMAErrorSignalEnable : 1; + USHORT TuningErrorSignalEnable : 1; + USHORT Reserved0 : 1; + USHORT VendorSpecificSignalEnable : 4; + } Flags; + USHORT Word; + } ErrorInterruptSignalEnable; // 3Ah + + union { + struct { + USHORT AutoCMD12NotExecuted : 1; + USHORT AutoCMD12TimeoutError : 1; + USHORT AutoCMD12CRCError : 1; + USHORT AutoCMD12EndBitError : 1; + USHORT AutoCMDIndexError : 1; + USHORT Reserved0 : 2; + USHORT CommandNotIssuedByAutoCMD12Error : 1; + USHORT Reserved1 : 8; + } Flags; + USHORT Word; + } AutoCMDErrorStatus; // 3Ch + + union { + struct { + USHORT UHSModeSelect : 3; + USHORT Signalling18V : 1; + USHORT DriverStrengthSelect : 2; + USHORT ExecuteTuning : 1; + USHORT SamplingClockSelect : 1; + USHORT Reserved : 6; + USHORT AsynchronousInterruptEnable : 1; + USHORT PresetValueEnable : 1; + } Flags; + USHORT Word; + } HostControl2; // 3Eh + + union { + struct { + ULONGLONG TimeoutClockFrequency : 6; + ULONGLONG Reserved0 : 1; + ULONGLONG TimeoutClockUnit : 1; + ULONGLONG BaseClockFrequencyForSDClock : 8; + ULONGLONG MaxBlockLength : 2; + ULONGLONG EmbeddedDrive8Bit : 1; + ULONGLONG ADMA2SUpport : 1; + ULONGLONG Reserved1 : 1; + ULONGLONG HighSpeedSupport : 1; + ULONGLONG SDMASupport : 1; + ULONGLONG SuspendResumeSupport : 1; + ULONGLONG VoltageSupport33 : 1; + ULONGLONG VoltageSupport30 : 1; + ULONGLONG VoltageSupport18 : 1; + ULONGLONG Reserved2 : 1; + ULONGLONG SystemBus64bitSupport : 1; + ULONGLONG AsynchronousInterruptSupport : 1; + ULONGLONG SlotType : 2; + ULONGLONG SDR50Support : 1; + ULONGLONG SDR104Support : 1; + ULONGLONG DDR50Support : 1; + ULONGLONG Reserved3 : 1; + ULONGLONG DriverTypeASupport : 1; + ULONGLONG DriverTypeCSupport : 1; + ULONGLONG DriverTypeDSupport : 1; + ULONGLONG Reserved4 : 1; + ULONGLONG TimerCountForRetuning : 4; + ULONGLONG Reserved5 : 1; + ULONGLONG UseTuningForSDR50 : 1; + ULONGLONG RetuningModes : 2; + ULONGLONG ClockMultiplier : 8; + ULONGLONG Reserved6 : 8; + } Flags; + struct { + USHORT Capabilities0; // 40h + USHORT Capabilities1; // 42h + USHORT Capabilities2; // 44h + USHORT Capabilities3; // 46h + } Words; + ULONGLONG ULongLong; + } Capabilities; + + union { + struct { + ULONGLONG MaxCurrent33V : 8; + ULONGLONG MaxCurrent30V : 8; + ULONGLONG MaxCurrent18V : 8; + ULONGLONG Reserved0 : 40; + } Flags; + struct { + USHORT MaxCurrentCaps0; // 48h + USHORT MaxCurrentCaps1; // 4Ah + USHORT MaxCurrentCaps2; // 4Ch + USHORT MaxCurrentCaps3; // 4Eh + } Words; + ULONGLONG ULongLong; + } MaxCurrentCaps; + + union { + struct { + USHORT ForceEventForAutoCMD12NotExecuted : 1; + USHORT ForceEventForAutoCMD12TimeoutError : 1; + USHORT ForceEventForAutoCMD12CRCError : 1; + USHORT ForceEventForAutoCMD12EndBitError : 1; + USHORT ForceEventForAutoCMD12IndexError : 1; + USHORT Reserved0 : 2; + USHORT ForceEventForCommandNotIssuedByAutoCMD12Error : 1; + USHORT Reserved1 : 8; + } Flags; + USHORT Word; // 50h + } ForceEventAutoCMDError; + + union { + struct { + USHORT ForceCommandTimeoutError : 1; + USHORT ForceCommandCRCError : 1; + USHORT ForceCommandEndBitError : 1; + USHORT ForceCommandIndexError : 1; + USHORT ForceDataTimeoutError : 1; + USHORT ForceDataCRCError : 1; + USHORT ForceDataEndBitError : 1; + USHORT ForceCurrentLimitError : 1; + USHORT ForceAutoCMD12Error : 1; + USHORT ForceADMAError : 1; + USHORT Reserved0 : 2; + USHORT VendorSpecific : 4; + } Flags; + USHORT Word; // 52h + } ForceEventInterruptError; + + union { + struct { + UCHAR ADMAErrorStates : 2; + UCHAR ADMALengthMismatchError : 1; + UCHAR Reserved0 : 5; + } Flags; + UCHAR Byte; + } ADMAErrorStatus; + + UCHAR Reserved0; // 55h + USHORT Reserved1; // 56h + + union { + struct { + USHORT ADMASystemAddress0; // 58h + USHORT ADMASystemAddress1; // 5Ah + USHORT ADMASystemAddress2; // 5Ch + USHORT ADMASystemAddress3; // 5Eh + } Words; + ULONGLONG ULongLong; + } ADMASystemAddress; + + union { + struct { + USHORT SDCLKFrequencySelectValue : 10; + USHORT ClockGeneratorSelectValue : 1; + USHORT Reserved0 : 3; + USHORT DriverStrengthSelectValue : 2; + } Flags; + USHORT Word; + } PresetValueInit; // 60h + + union { + struct { + USHORT SDCLKFrequencySelectValue : 10; + USHORT ClockGeneratorSelectValue : 1; + USHORT Reserved0 : 3; + USHORT DriverStrengthSelectValue : 2; + } Flags; + USHORT Word; + } PresetValueDefaultSpeed; // 62h + + union { + struct { + USHORT SDCLKFrequencySelectValue : 10; + USHORT ClockGeneratorSelectValue : 1; + USHORT Reserved0 : 3; + USHORT DriverStrengthSelectValue : 2; + } Flags; + USHORT Word; + } PresetValueHighSpeed; // 64h + + union { + struct { + USHORT SDCLKFrequencySelectValue : 10; + USHORT ClockGeneratorSelectValue : 1; + USHORT Reserved0 : 3; + USHORT DriverStrengthSelectValue : 2; + } Flags; + USHORT Word; + } PresetValueSDR12; // 66h + + union { + struct { + USHORT SDCLKFrequencySelectValue : 10; + USHORT ClockGeneratorSelectValue : 1; + USHORT Reserved0 : 3; + USHORT DriverStrengthSelectValue : 2; + } Flags; + USHORT Word; + } PresetValueSDR25; // 68h + + union { + struct { + USHORT SDCLKFrequencySelectValue : 10; + USHORT ClockGeneratorSelectValue : 1; + USHORT Reserved0 : 3; + USHORT DriverStrengthSelectValue : 2; + } Flags; + USHORT Word; + } PresetValueSDR50; // 6Ah + + union { + struct { + USHORT SDCLKFrequencySelectValue : 10; + USHORT ClockGeneratorSelectValue : 1; + USHORT Reserved0 : 3; + USHORT DriverStrengthSelectValue : 2; + } Flags; + USHORT Word; + } PresetValueSDR104; // 6Ch + + union { + struct { + USHORT SDCLKFrequencySelectValue : 10; + USHORT ClockGeneratorSelectValue : 1; + USHORT Reserved0 : 3; + USHORT DriverStrengthSelectValue : 2; + } Flags; + USHORT Word; + } PresetValueDDR50; // 6Eh + + UCHAR Reserved2[112]; // 70h - DFh + + union { + struct { + ULONG NumberOfClockPins : 3; + ULONG Reserved0 : 1; + ULONG NumberOfInterruptInputPins : 2; + ULONG Reserved1 : 2; + ULONG BusWidthPreset : 7; + ULONG Reserved2 : 1; + ULONG ClockPinSelect : 3; + ULONG Reserved3 : 1; + ULONG InterruptPinSelect : 3; + ULONG Reserved4 : 1; + ULONG BackEndPowerControl : 7; + ULONG Reserved5 : 1; + } Flags; + struct { + USHORT Low; // E0h + USHORT High; // E2h + } Words; + ULONG Ulong; + } SharedBusControl; + + UCHAR Reserved3[12]; // E4h - EFh + UCHAR Reserved4[12]; // F0h - FBh + + union { + struct { + USHORT Slot1 : 1; + USHORT Slot2 : 1; + USHORT Slot3 : 1; + USHORT Slot4 : 1; + USHORT Slot5 : 1; + USHORT Slot6 : 1; + USHORT Slot7 : 1; + USHORT Slot8 : 1; + USHORT Reserved0 : 8; + } Flags; + USHORT Word; // FCh + } SlotInterruptStatus; + + union { + struct { + USHORT SpecificationVersionNumber : 8; + USHORT VendorVersionNumber : 8; + } Flags; + USHORT Word; // FEh + } HostControllerVersion; + +} SD_HOST_CONTROLLER_REGISTERS, *PSD_HOST_CONTROLLER_REGISTERS; + +// the size of the SD_CONTROLLER_REGISTER structure must always be 256 bytes +C_ASSERT(sizeof(SD_HOST_CONTROLLER_REGISTERS) == 256); + +#pragma pack(pop) + +// --------------------------------------------------------------------------- +// +// Register layout definitions +// +// --------------------------------------------------------------------------- + +#pragma pack(1) + +// +// Host control register +// + +typedef union _SDHC_HOST_CONTROL_REGISTER { + struct { + UCHAR LedControl:1; + UCHAR DataTransferWidth:1; + UCHAR HgihSpeedEnable:1; + UCHAR DmaSelect:2; + UCHAR Reserved1:1; + UCHAR CardDetectTestLevel:1; + UCHAR CardDetectSignalSlection:1; + }; + UCHAR AsUchar; +} SDHC_HOST_CONTROL_REGISTER, *PSDHC_HOST_CONTROL_REGISTER; + +typedef union _SDHC_HOST_CONTROL2_REGISTER { + struct { + USHORT UhsModeSelect:3; + USHORT SignalingEnable1_8V:1; + USHORT DriverStrengthSelect:2; + USHORT ExecuteTuning:1; + USHORT SamplingClockSelect:1; + USHORT Reserved:6; + USHORT AsyncInterruptEnable:1; + USHORT PresetValueEnable:1; + }; + USHORT AsUshort; +} SDHC_HOST_CONTROL2_REGISTER, *PSDHC_HOST_CONTROL2_REGISTER; + + +// +// Power control register +// + +typedef union _SDHC_POWER_CONTROL_REGISTER { + struct { + UCHAR SdBusPower:1; + UCHAR SdBusPowerSelect:3; + UCHAR Reserved1:4; + }; + UCHAR AsUchar; +} SDHC_POWER_CONTROL_REGISTER, *PSDHC_POWER_CONTROL_REGISTER; + + +// +// Clock control register +// + +typedef union _SDHC_CLOCK_CONTROL_REGISTER { + struct { + USHORT InternalClockEnable:1; + USHORT InternalClockStable:1; + USHORT SdClockEnable:1; + USHORT Reserved1:4; + USHORT SdclkFrequencySelect:8; + }; + UCHAR AsUshort; +} SDHC_CLOCK_CONTROL_REGISTER, *PSDHC_CLOCK_CONTROL_REGISTER; + + +// +// Transfer mode register +// + +typedef union _SDHC_TRANSFER_MODE_REGISTER { + struct { + USHORT DmaEnable:1; + USHORT BlockCountEnable:1; + USHORT AutoCmd12Enable:1; + USHORT AutoCmd23Enable:1; + USHORT DataTranferDirectionSelect:1; + USHORT BlockModeSelect:1; + USHORT Reserved2:10; + }; + USHORT AsUshort; +} SDHC_TRANSFER_MODE_REGISTER, *PSDHC_TRANSFER_MODE_REGISTER; + + +// +// Capabilities register +// + +typedef union _SDHC_CAPABILITIES_REGISTER { + struct { + ULONG TimeoutClockFrequency:6; + ULONG Reserved1:1; + ULONG TimeoutClockUnit:1; + ULONG BaseClockFrequency:8; + ULONG MaxBlockLength:2; + ULONG Support8BitBus:1; + ULONG Adma2Support:1; + ULONG Reserved2:1; + ULONG HighSpeedSupport:1; + ULONG DmaSupport:1; + ULONG SuspendResumeSupport:1; + ULONG Voltage33:1; + ULONG Voltage30:1; + ULONG Voltage18:1; + ULONG Reserved3:1; + ULONG SystemBus64Support:1; + ULONG AsynchronousInterruptSupport:1; + ULONG SlotType:2; + }; + ULONG AsUlong; +} SDHC_CAPABILITIES_REGISTER, *PSDHC_CAPABILITIES_REGISTER; + +typedef union _SDHC_CAPABILITIES2_REGISTER { + struct { + ULONG SDR50Support:1; + ULONG SDR104Support:1; + ULONG DDR50Support:1; + ULONG Reserved1:1; + ULONG DriverTypeA:1; + ULONG DriverTypeC:1; + ULONG DriverTypeD:1; + ULONG Reserved2:1; + ULONG RetuningTimerCount:4; + ULONG Reserved3:1; + ULONG UseTuningForSDR50:1; + ULONG RetuningModes:2; + ULONG ClockMultiplier:8; + ULONG Reserved4:8; + }; + ULONG AsUlong; +} SDHC_CAPABILITIES2_REGISTER, *PSDHC_CAPABILITIES2_REGISTER; + +// --------------------------------------------------------------------------- +// +// ADMA2 descriptor table definitions +// +// --------------------------------------------------------------------------- + +// +// Bits defined in descriptor->attribute +// + +#define SDHC_ADMA2_ATTRIBUTE_VALID 0x00000001 +#define SDHC_ADMA2_ATTRIBUTE_END 0x00000002 +#define SDHC_ADMA2_ATTRIBUTE_INT 0x00000004 + +// +// Bits defined in descriptor->Action +// + +#define SDHC_ADMA2_ACTION_NOP 0x00000000 +#define SDHC_ADMA2_ACTION_TRAN 0x00000002 +#define SDHC_ADMA2_ACTION_LINK 0x00000003 + +// +// Max transfer length per descriptor entry +// +// SD Host Controller Spec 1.13.4 +// Length field is 16 bit field so we can go up to 64K (0xFFFF). +// However, we need to limit max length to 0xF000 because using 0xFFFF +// can cause un-aligned, In addition, some HC require the length to be +// multiple of 0x1000 (except 1st and last descriptor) +// +#define SDHC_ADMA2_MAX_LENGTH_PER_ENTRY 0x0000F000 + +// +// Layout of a descriptor (excluding the Address field) +// + +typedef union _SDHC_ADMA2_DESCRIPTOR_TABLE_ENTRY { + struct { + ULONG Attribute:3; + ULONG Reserved1:1; + ULONG Action:2; + ULONG Reserved2:10; + ULONG Length:16; + }; + ULONG AsUlong; +} SDHC_ADMA2_DESCRIPTOR_TABLE_ENTRY, *PSDHC_ADMA2_DESCRIPTOR_TABLE_ENTRY; + +#pragma pack() + +// +// Voltage profile +// + +typedef union _SDHC_VOLTAGE_PROFILE { + struct { + ULONG Reserved1 : 7; + ULONG VoltageLow : 1; + ULONG Voltage20 : 1; + ULONG Voltage21 : 1; + ULONG Voltage22 : 1; + ULONG Voltage23 : 1; + ULONG Voltage24 : 1; + ULONG Voltage25 : 1; + ULONG Voltage26 : 1; + ULONG Voltage27 : 1; + ULONG Voltage28 : 1; + ULONG Voltage29 : 1; + ULONG Voltage30 : 1; + ULONG Voltage31 : 1; + ULONG Voltage32 : 1; + ULONG Voltage33 : 1; + ULONG Voltage34 : 1; + ULONG Voltage35 : 1; + }; + ULONG AsUlong; +} SDHC_VOLTAGE_PROFILE, *PSDHC_VOLTAGE_PROFILE; + +typedef enum _SDHC_SPEED_MODE { + SdhcSpeedModeNormal = 0, + SdhcSpeedModeHigh, + SdhcSpeedModeSDR50, + SdhcSpeedModeDDR50, + SdhcSpeedModeSDR104, + SdhcSpeedModeHS200, + SdhcSpeedModeHS400 +} SDHC_SPEED_MODE; + +#define SDHC_MAX_OUTSTANDING_REQUESTS 1 + +typedef struct _SDHC_EXTENSION { + + BOOLEAN Removable; + + // + // Host register space. + // + + PHYSICAL_ADDRESS PhysicalBaseAddress; + PVOID BaseAddress; + SIZE_T BaseAddressSpaceSize; + PSD_HOST_CONTROLLER_REGISTERS BaseAddressDebug; + + // + // Capabilities. + // + + SDPORT_CAPABILITIES Capabilities; + SDHC_SPEED_MODE SpeedMode; + UCHAR SpecVersion; + + // + // Requests to handle. + // + + PSDPORT_REQUEST OutstandingRequests[SDHC_MAX_OUTSTANDING_REQUESTS]; + USHORT UnhandledEvents; + +} SDHC_EXTENSION, *PSDHC_EXTENSION; + +// --------------------------------------------------------------------------- +// PCI Config definitions +// --------------------------------------------------------------------------- + +#define SDHC_PCICFG_SLOT_INFORMATION 0x40 + +NTSTATUS +DriverEntry( + _In_ PVOID DriverObject, + _In_ PVOID RegistryPath + ); + +//----------------------------------------------------------------------------- +// SlotExtension callbacks. +//----------------------------------------------------------------------------- + +SDPORT_GET_SLOT_COUNT SdhcGetSlotCount; +/* +NTSTATUS +SdhcGetSlotCount( + _In_ PVOID Argument, + _In_ SDPORT_BUS_TYPE BusType + ); +*/ + +SDPORT_GET_SLOT_CAPABILITIES SdhcGetSlotCapabilities; +/* +VOID +SdhcGetSlotCapabilities( + _In_ PSDPORT_SLOT_EXTENSION SlotExtension, + _Inout_ PSDPORT_CAPABILITIES Capabilities + ); +*/ + +SDPORT_INITIALIZE SdhcSlotInitialize; +/* +NTSTATUS +SdhcSlotInitialize( + _Inout_ PSDPORT_SLOT_EXTENSION SlotExtension + ); +*/ + +SDPORT_ISSUE_BUS_OPERATION SdhcSlotIssueBusOperation; +/* +NTSTATUS +SdhcSlotIssueBusOperation( + _In_ PSDPORT_SLOT_EXTENSION SlotExtension, + _In_ PSDPORT_REQUEST Request + ); +*/ + +SDPORT_GET_CARD_DETECT_STATE SdhcSlotGetCardDetectState; +/* +BOOLEAN +SdhcSlotGetCardDetectState( + _In_ PSDPORT_SLOT_EXTENSION SlotExtension + ); +*/ + +SDPORT_GET_WRITE_PROTECT_STATE SdhcSlotGetWriteProtectState; +/* +BOOLEAN +SdhcSlotGetWriteProtectState( + _In_ PSDPORT_SLOT_EXTENSION SlotExtension + ); +*/ + +SDPORT_INTERRUPT SdhcSlotInterrupt; +/* +BOOLEAN +SdhcSlotInterrupt( + _In_ PSDPORT_SLOT_EXTENSION SlotExtension, + _Out_ PULONG Events, + _Out_ PULONG Errors, + _Out_ PBOOLEAN NotifyCardChange, + _Out_ PBOOLEAN NotifySdioInterrupt, + _Out_ PBOOLEAN NotifyTuning + ); +*/ + +SDPORT_ISSUE_REQUEST SdhcSlotIssueRequest; +/* +NTSTATUS +SdhcSlotIssueRequest( + _In_ PSDPORT_SLOT_EXTENSION SlotExtension, + _In_ PSDPORT_REQUEST Request + ); +*/ + +SDPORT_GET_RESPONSE SdhcSlotGetResponse; +/* +VOID +SdhcSlotGetResponse( + _In_ PVOID PrivateExtension, + _In_ PSDPORT_COMMAND Command, + _Out_ PVOID ResponseBuffer + ); +*/ + +SDPORT_TOGGLE_EVENTS SdhcSlotToggleEvents; +/* +VOID +SdhcSlotToggleEevnts( + _In_ PSDPORT_SLOT_EXTENSION SlotExtension, + _In_ ULONG EventMask, + _In_ BOOLEAN Enable + ); +*/ + +SDPORT_CLEAR_EVENTS SdhcSlotClearEvents; +/* +VOID +SdhcSlotClearEvents( + _In_ PSDPORT_SLOT_EXTENSION SlotExtension, + _In_ ULONG EventMask + ); +*/ + +SDPORT_REQUEST_DPC SdhcRequestDpc; +/* +VOID +SdhcRequestDpc( + _In_ PVOID PrivateExtension, + _Inout_ PSDPORT_REQUEST Request, + _In_ ULONG Events, + _In_ ULONG Errors + ); +*/ + +SDPORT_SAVE_CONTEXT SdhcSaveContext; +/* +VOID +SdhcSaveContext( + _In_ PSDPORT_SLOT_EXTENSION SlotExtension + ); +*/ + +SDPORT_RESTORE_CONTEXT SdhcRestoreContext; +/* +VOID +SdhcRestoreContext( + _In_ PSDPORT_SLOT_EXTENSION SlotExtension + ); +*/ + +//----------------------------------------------------------------------------- +// Hardware access routines. +//----------------------------------------------------------------------------- + +NTSTATUS +SdhcResetHost( + _In_ PSDHC_EXTENSION SdhcExtension, + _In_ UCHAR ResetType + ); + +NTSTATUS +SdhcSetVoltage( + _In_ PSDHC_EXTENSION SdhcExtension, + _In_ SDPORT_BUS_VOLTAGE VoltageProfile + ); + +NTSTATUS +SdhcSetClock( + _In_ PSDHC_EXTENSION SdhcExtension, + _In_ ULONG Frequency + ); + +NTSTATUS +SdhcSetBusWidth( + _In_ PSDHC_EXTENSION SdhcExtension, + _In_ UCHAR BusWidth + ); + +NTSTATUS +SdhcSetSpeed( + _In_ PSDHC_EXTENSION SdhcExtension, + _In_ SDPORT_BUS_SPEED Speed + ); + +NTSTATUS +SdhcSetHighSpeed( + _In_ PSDHC_EXTENSION SdhcExtension, + _In_ BOOLEAN Enable + ); + +NTSTATUS +SdhcSetUhsMode( + _In_ PSDHC_EXTENSION SdhcExtension, + _In_ USHORT Mode + ); + +NTSTATUS +SdhcSetSignaling( + _In_ PSDHC_EXTENSION SdhcExtension, + _In_ BOOLEAN Enable + ); + +NTSTATUS +SdhcExecuteTuning( + _In_ PSDHC_EXTENSION SdhcExtension + ); + +VOID +SdhcSetLed( + _In_ PSDHC_EXTENSION SdhcExtension, + _In_ BOOLEAN Enable + ); + +NTSTATUS +SdhcSetPresetValue( + _In_ PSDHC_EXTENSION SdhcExtension, + _In_ BOOLEAN Enable + ); + +VOID +SdhcSetBlockGapControl( + _In_ PSDHC_EXTENSION SdhcExtension, + _In_ BOOLEAN Continue, + _In_ BOOLEAN RequestStop + ); + +VOID +SdhcSetBlockGapControl( + _In_ PSDHC_EXTENSION SdhcExtension, + _In_ BOOLEAN Continue, + _In_ BOOLEAN RequestStop + ); + +VOID +SdhcEnableInterrupt( + _In_ PSDHC_EXTENSION SdhcExtension, + _In_ ULONG NormalMask + ); + +VOID +SdhcDisableInterrupt( + _In_ PSDHC_EXTENSION SdhcExtension, + _In_ ULONG NormalMask + ); + +USHORT +SdhcGetInterruptStatus( + _In_ PSDHC_EXTENSION SdhcExtension + ); + +USHORT +SdhcGetErrorStatus( + _In_ PSDHC_EXTENSION SdhcExtension + ); + +USHORT +SdhcGetAutoCmd12ErrorStatus( + _In_ PSDHC_EXTENSION SdhcExtension + ); + +USHORT +SdhcGetAdmaErrorStatus( + _In_ PSDHC_EXTENSION SdhcExtension + ); + +VOID +SdhcAcknowledgeInterrupts( + _In_ PSDHC_EXTENSION SdhcExtension, + _In_ USHORT Interrupts + ); + +BOOLEAN +SdhcIsCardInserted( + _In_ PSDHC_EXTENSION SdhcExtension + ); + +BOOLEAN +SdhcIsWriteProtected( + _In_ PSDHC_EXTENSION SdhcExtension + ); + +NTSTATUS +SdhcSendCommand( + _In_ PSDHC_EXTENSION SdhcExtension, + _In_ PSDPORT_REQUEST Request + ); + +NTSTATUS +SdhcGetResponse( + _In_ PSDHC_EXTENSION SdhcExtension, + _In_ PSDPORT_COMMAND Command, + _Out_ PVOID ResponseBuffer + ); + +NTSTATUS +SdhcSetTransferMode( + _In_ PSDHC_EXTENSION SdhcExtension, + _In_ PSDPORT_REQUEST Request + ); + +VOID +SdhcReadDataPort( + _In_ PSDHC_EXTENSION SdhcExtension, + _Out_writes_all_(Length) PUCHAR Buffer, + _In_ SIZE_T Length + ); + +VOID +SdhcWriteDataPort( + _In_ PSDHC_EXTENSION SdhcExtension, + _In_reads_(Length) PUCHAR Buffer, + _In_ ULONG Length + ); + +NTSTATUS +SdhcBuildTransfer( + _In_ PSDHC_EXTENSION SdhcExtension, + _In_ PSDPORT_REQUEST Request + ); + +NTSTATUS +SdhcStartTransfer( + _In_ PSDHC_EXTENSION SdhcExtension, + _In_ PSDPORT_REQUEST Request + ); + +NTSTATUS +SdhcBuildPioTransfer( + _In_ PSDHC_EXTENSION SdhcExtension, + _In_ PSDPORT_REQUEST Request + ); + +NTSTATUS +SdhcBuildAdmaTransfer( + _In_ PSDHC_EXTENSION SdhcExtension, + _In_ PSDPORT_REQUEST Request + ); + +NTSTATUS +SdhcStartPioTransfer( + _In_ PSDHC_EXTENSION SdhcExtension, + _In_ PSDPORT_REQUEST Request + ); + +NTSTATUS +SdhcStartAdmaTransfer( + _In_ PSDHC_EXTENSION SdhcExtension, + _In_ PSDPORT_REQUEST Request + ); + +//----------------------------------------------------------------------------- +// General utility functions. +//----------------------------------------------------------------------------- + +USHORT +SdhcCalcClockFrequency( + _In_ PSDHC_EXTENSION SdhcExtension, + _In_ ULONG TargetFrequency, + _Out_opt_ PULONG ActualFrequency + ); + +USHORT +SdhcConvertEventsToHwMask( + _In_ ULONG Events + ); + +NTSTATUS +SdhcConvertErrorToStatus( + _In_ USHORT Error + ); + +NTSTATUS +SdhcCreateAdmaDescriptorTable( + _In_ PSDPORT_REQUEST Request, + _In_ BOOLEAN Use64BitDescriptor, + _Out_ PULONG TotalTransferLength + ); + +VOID +SdhcInitializePciConfigSpace( + _In_ PSD_MINIPORT Miniport + ); + +__forceinline +USHORT +SdhcGetHwUhsMode( + _In_ SDPORT_BUS_SPEED BusSpeed + ) + +{ + + NT_ASSERT(BusSpeed != SdBusSpeedNormal); + + NT_ASSERT(BusSpeed != SdBusSpeedHigh); + + switch (BusSpeed) { + case SdBusSpeedSDR12: + return SDHC_HC2_SDR12; + + case SdBusSpeedSDR25: + return SDHC_HC2_SDR25; + + case SdBusSpeedSDR50: + return SDHC_HC2_SDR50; + + case SdBusSpeedDDR50: + return SDHC_HC2_SDR50; + + case SdBusSpeedSDR104: + return SDHC_HC2_SDR50; + + // + // PCI controllers don't support the higher speed eMMC modes. + // + + case SdBusSpeedHS200: + case SdBusSpeedHS400: + default: + break; + } + + NT_ASSERTMSG("SDHC - Invalid bus speed selected", FALSE); + + return 0; +} + +__forceinline +USHORT +SdhcConvertEventsToHwMask( + _In_ ULONG EventMask + ) + +{ + + return EventMask & 0xFFFF; +} + +__forceinline +USHORT +SdhcConvertErrorsToHwMask( + _In_ ULONG ErrorMask + ) + +{ + + return ErrorMask & 0xFFFF; +} + +__forceinline +NTSTATUS +SdhcConvertErrorToStatus( + _In_ USHORT Error + ) + +{ + + if (Error == 0) { + return STATUS_SUCCESS; + } + + if (Error & (SDHC_ES_CMD_TIMEOUT | SDHC_ES_DATA_TIMEOUT)) { + return STATUS_IO_TIMEOUT; + } + + if (Error & (SDHC_ES_CMD_CRC_ERROR | SDHC_ES_DATA_CRC_ERROR)) { + return STATUS_CRC_ERROR; + } + + if (Error & (SDHC_ES_CMD_END_BIT_ERROR | SDHC_ES_DATA_END_BIT_ERROR)) { + return STATUS_DEVICE_DATA_ERROR; + } + + if (Error & SDHC_ES_CMD_INDEX_ERROR) { + return STATUS_DEVICE_PROTOCOL_ERROR; + } + + if (Error & SDHC_ES_BUS_POWER_ERROR) { + return STATUS_DEVICE_POWER_FAILURE; + } + + return STATUS_IO_DEVICE_ERROR; +} + + +//----------------------------------------------------------------------------- +// Register access macros. +//----------------------------------------------------------------------------- + +__forceinline +VOID +SdhcWriteRegisterUlong( + _In_ PSDHC_EXTENSION SdhcExtension, + _In_ ULONG Register, + _In_ ULONG Data + ) + +{ + + SdPortWriteRegisterUlong(SdhcExtension->BaseAddress, Register, Data); + return; +} + +__forceinline +VOID +SdhcWriteRegisterUshort( + _In_ PSDHC_EXTENSION SdhcExtension, + _In_ ULONG Register, + _In_ USHORT Data + ) + +{ + + SdPortWriteRegisterUshort(SdhcExtension->BaseAddress, Register, Data); + return; +} + +__forceinline +VOID +SdhcWriteRegisterUchar( + _In_ PSDHC_EXTENSION SdhcExtension, + _In_ ULONG Register, + _In_ UCHAR Data + ) + +{ + + SdPortWriteRegisterUchar(SdhcExtension->BaseAddress, Register, Data); + return; +} + +__forceinline +ULONG +SdhcReadRegisterUlong( + _In_ PSDHC_EXTENSION SdhcExtension, + _In_ ULONG Register + ) + +{ + return SdPortReadRegisterUlong(SdhcExtension->BaseAddress, Register); +} + +__forceinline +USHORT +SdhcReadRegisterUshort( + _In_ PSDHC_EXTENSION SdhcExtension, + _In_ ULONG Register + ) + +{ + return SdPortReadRegisterUshort(SdhcExtension->BaseAddress, Register); +} + +__forceinline +UCHAR +SdhcReadRegisterUchar( + _In_ PSDHC_EXTENSION SdhcExtension, + _In_ ULONG Register + ) + +{ + return SdPortReadRegisterUchar(SdhcExtension->BaseAddress, Register); +} + +__forceinline +VOID +SdhcReadRegisterBufferUlong( + _In_ PSDHC_EXTENSION SdhcExtension, + _In_ ULONG Register, + _Out_writes_all_(Length) PULONG Buffer, + _In_ ULONG Length) + +{ + SdPortReadRegisterBufferUlong(SdhcExtension->BaseAddress, + Register, + Buffer, + Length); +} + +__forceinline +VOID +SdhcReadRegisterBufferUshort( + _In_ PSDHC_EXTENSION SdhcExtension, + _In_ ULONG Register, + _Out_writes_all_(Length) PUSHORT Buffer, + _In_ ULONG Length) + +{ + SdPortReadRegisterBufferUshort(SdhcExtension->BaseAddress, + Register, + Buffer, + Length); +} + +__forceinline +VOID +SdhcReadRegisterBufferUchar( + _In_ PSDHC_EXTENSION SdhcExtension, + _In_ ULONG Register, + _Out_writes_all_(Length) PUCHAR Buffer, + _In_ ULONG Length) + +{ + SdPortReadRegisterBufferUchar(SdhcExtension->BaseAddress, + Register, + Buffer, + Length); +} + +__forceinline +VOID +SdhcWriteRegisterBufferUlong( + _In_ PSDHC_EXTENSION SdhcExtension, + _In_ ULONG Register, + _In_reads_(Length) PULONG Buffer, + _In_ ULONG Length + ) + +{ + + SdPortWriteRegisterBufferUlong(SdhcExtension->BaseAddress, + Register, + Buffer, + Length); +} + +__forceinline +VOID +SdhcWriteRegisterBufferUshort( + _In_ PSDHC_EXTENSION SdhcExtension, + _In_ ULONG Register, + _In_reads_(Length) PUSHORT Buffer, + _In_ ULONG Length + ) + +{ + + SdPortWriteRegisterBufferUshort(SdhcExtension->BaseAddress, + Register, + Buffer, + Length); +} + +__forceinline +VOID +SdhcWriteRegisterBufferUchar( + _In_ PSDHC_EXTENSION SdhcExtension, + _In_ ULONG Register, + _In_reads_(Length) PUCHAR Buffer, + _In_ ULONG Length + ) + +{ + + SdPortWriteRegisterBufferUchar(SdhcExtension->BaseAddress, + Register, + Buffer, + Length); + +} + +__forceinline +UCHAR +SdhcGetResponseLength( + _In_ PSDPORT_COMMAND Command + ) + +/*++ + +Routine Description: + + Return the number of bytes associated with a given response type. + +Arguments: + + ResponseType + +Return value: + + Length of response. + +--*/ + +{ + + UCHAR Length; + + switch (Command->ResponseType) { + case SdResponseTypeR1: + case SdResponseTypeR3: + case SdResponseTypeR4: + case SdResponseTypeR5: + case SdResponseTypeR6: + case SdResponseTypeR1B: + case SdResponseTypeR5B: + Length = 4; + break; + + case SdResponseTypeR2: + Length = 16; + break; + + case SdResponseTypeNone: + Length = 0; + break; + + default: + + NT_ASSERTMSG("Invalid response type", FALSE); + + Length = 0; + break; + } + + return Length; +} + +#define MIN(x,y) ((x) > (y) ? (y) : (x)) // return minimum among x & y +#define MAX(x,y) ((x) > (y) ? (x) : (y)) // return maximum among x & y +#define DIV_CEIL(x, y) (((x) + (y) - 1) / (y)) diff --git a/sd/miniport/sdhc/sdhc.inx b/sd/miniport/sdhc/sdhc.inx new file mode 100644 index 00000000..7e7f7abb Binary files /dev/null and b/sd/miniport/sdhc/sdhc.inx differ diff --git a/sd/miniport/sdhc/sdhc.rc b/sd/miniport/sdhc/sdhc.rc new file mode 100644 index 00000000..87580888 --- /dev/null +++ b/sd/miniport/sdhc/sdhc.rc @@ -0,0 +1,15 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// +#include + +#include + +#define VER_FILETYPE VFT_DRV +#define VER_FILESUBTYPE VFT2_DRV_SYSTEM +#define VER_FILEDESCRIPTION_STR "SD Host Controller Standard Driver" +#define VER_INTERNALNAME_STR "sdhc.sys" +#define VER_ORIGINALFILENAME_STR "sdhc.sys" + +#include "common.ver" + diff --git a/sd/miniport/sdhc/sdhc.sln b/sd/miniport/sdhc/sdhc.sln new file mode 100644 index 00000000..9e343b4a --- /dev/null +++ b/sd/miniport/sdhc/sdhc.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0 +MinimumVisualStudioVersion = 12.0 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sdhc", "inbox\sdhc.vcxproj", "{696C1C9C-405C-4675-B344-B5FF53BAB93A}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {696C1C9C-405C-4675-B344-B5FF53BAB93A}.Debug|Win32.ActiveCfg = Debug|Win32 + {696C1C9C-405C-4675-B344-B5FF53BAB93A}.Debug|Win32.Build.0 = Debug|Win32 + {696C1C9C-405C-4675-B344-B5FF53BAB93A}.Release|Win32.ActiveCfg = Release|Win32 + {696C1C9C-405C-4675-B344-B5FF53BAB93A}.Release|Win32.Build.0 = Release|Win32 + {696C1C9C-405C-4675-B344-B5FF53BAB93A}.Debug|x64.ActiveCfg = Debug|x64 + {696C1C9C-405C-4675-B344-B5FF53BAB93A}.Debug|x64.Build.0 = Debug|x64 + {696C1C9C-405C-4675-B344-B5FF53BAB93A}.Release|x64.ActiveCfg = Release|x64 + {696C1C9C-405C-4675-B344-B5FF53BAB93A}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/sd/sdiomars/mars.vcxproj b/sd/sdiomars/mars.vcxproj index 6bebd02e..37b47d09 100644 --- a/sd/sdiomars/mars.vcxproj +++ b/sd/sdiomars/mars.vcxproj @@ -19,12 +19,12 @@ - {18D5F2EE-E11C-44E7-BCB6-E4C39F679B9D} + {DF923AC2-B46E-4D14-9B5D-C55006B8AECE} $(MSBuildProjectName) 1 Debug Win32 - {83B758B0-F972-48D1-823B-3B817E5497AD} + {42F7E138-B841-4F20-B19B-9AAB78D9B502} diff --git a/sd/sdiomars/mars.vcxproj.Filters b/sd/sdiomars/mars.vcxproj.Filters index f3dd1af1..d691397d 100644 --- a/sd/sdiomars/mars.vcxproj.Filters +++ b/sd/sdiomars/mars.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {149057E1-1BB6-43A6-8760-824CA3861F1D} + {E3DC03C6-1CAC-44C6-9FC4-0EE64DBBAD0A} h;hpp;hxx;hm;inl;inc;xsd - {A9A3E7C6-26AD-4B64-B75B-B1BCF262750C} + {F0C0BF8A-3AA1-4D6F-858E-25C590B9BF47} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {39C916B8-B030-41D4-A3C1-4EFD5E0D83F7} + {27E4CB77-8F83-4C7D-90AA-87026013ACDA} inf;inv;inx;mof;mc; - {297888D3-E8F6-4472-8CCA-71D8D1E66B79} + {43996541-713E-472F-87E9-8B79F7EC2A98} diff --git a/sd/sdiomars/sdiomars.sln b/sd/sdiomars/sdiomars.sln index 23cfa5ea..2a6d1cdb 100644 --- a/sd/sdiomars/sdiomars.sln +++ b/sd/sdiomars/sdiomars.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mars", "mars.vcxproj", "{18D5F2EE-E11C-44E7-BCB6-E4C39F679B9D}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mars", "mars.vcxproj", "{DF923AC2-B46E-4D14-9B5D-C55006B8AECE}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +13,14 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {18D5F2EE-E11C-44E7-BCB6-E4C39F679B9D}.Debug|Win32.ActiveCfg = Debug|Win32 - {18D5F2EE-E11C-44E7-BCB6-E4C39F679B9D}.Debug|Win32.Build.0 = Debug|Win32 - {18D5F2EE-E11C-44E7-BCB6-E4C39F679B9D}.Release|Win32.ActiveCfg = Release|Win32 - {18D5F2EE-E11C-44E7-BCB6-E4C39F679B9D}.Release|Win32.Build.0 = Release|Win32 - {18D5F2EE-E11C-44E7-BCB6-E4C39F679B9D}.Debug|x64.ActiveCfg = Debug|x64 - {18D5F2EE-E11C-44E7-BCB6-E4C39F679B9D}.Debug|x64.Build.0 = Debug|x64 - {18D5F2EE-E11C-44E7-BCB6-E4C39F679B9D}.Release|x64.ActiveCfg = Release|x64 - {18D5F2EE-E11C-44E7-BCB6-E4C39F679B9D}.Release|x64.Build.0 = Release|x64 + {DF923AC2-B46E-4D14-9B5D-C55006B8AECE}.Debug|Win32.ActiveCfg = Debug|Win32 + {DF923AC2-B46E-4D14-9B5D-C55006B8AECE}.Debug|Win32.Build.0 = Debug|Win32 + {DF923AC2-B46E-4D14-9B5D-C55006B8AECE}.Release|Win32.ActiveCfg = Release|Win32 + {DF923AC2-B46E-4D14-9B5D-C55006B8AECE}.Release|Win32.Build.0 = Release|Win32 + {DF923AC2-B46E-4D14-9B5D-C55006B8AECE}.Debug|x64.ActiveCfg = Debug|x64 + {DF923AC2-B46E-4D14-9B5D-C55006B8AECE}.Debug|x64.Build.0 = Debug|x64 + {DF923AC2-B46E-4D14-9B5D-C55006B8AECE}.Release|x64.ActiveCfg = Release|x64 + {DF923AC2-B46E-4D14-9B5D-C55006B8AECE}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/sd/sdiomars/sdiosample.htm b/sd/sdiomars/sdiosample.htm new file mode 100644 index 00000000..e2e24da9 --- /dev/null +++ b/sd/sdiomars/sdiosample.htm @@ -0,0 +1,356 @@ + + + + + + + + +SDIO Sample Driver + + + + + + + + + +
+ +

Driver Framework SDIO Sample Driver

+ +

Description

+ +

This is a sample for a functional Secure Digital (SD) IO driver. The driver is written using the Kernel Mode Driver Framework. It is a driver for a generic mars development board that implements the SDIO protocol without additional functionality.

+ +

Theory of Operation

+

The mars board driver exemplifies several different functions that are essential for writing an SDIO driver that leverages KDMF and the SDBUS API. It will show how to: +
- Install and start an SDIO device. +
- Release an SDIO device. +
- Perform data transfers. +
- Alter the settings that the SDIO device uses to communicate with the SD Host Controller. +

+ +

The driver building and +installation instructions given here apply only to Windows® XP and later operating systems.

+ +

Note: This sample provides an example +of a minimal driver. Neither the driver nor the sample programs are intended +for use in a production environment. Rather, they are intended for educational +purposes and as a skeleton driver.

+ +

Building +the Sample

+ +

Click the Free Build +Environment or Checked Build Environment icon under your Development Kits program +group to set basic environment variables needed by the build utility.

+ +

Change to the directory +containing the device source code, such as src\sd\sdiomars

+ +

Run build -ceZ, or +use the macro BLD. This behavior invokes the Microsoft make routines +that produce log files called Buildxxx.log, and also Buildxxx.wrn and +Buildxxx.err if there are any warnings or errors. Where xxx stands for fre +or chk depending on the environment chosen. If the build succeeds, the +driver mars.sys and the generated inf file mars.inf will be placed in a platform specific subdirectory of your %TargetPath% +directory specified in the Sources file.

+ +

Installing +the Sample

+ +

To install the bus driver on Windows XP and later operating systems:

+ +
    +
  1. Copy mars.sys, mars.inf, kmdfsamples.cat & WDF Coinstaller (wdfcoinstallerMMmmm.dll) to a disk.
  2. +
  3. Double-click the ‘Add Hardware’ wizard in + Control Panel.
  4. +
  5. At the 'Welcome to the Add Hardware Wizard', + click ‘Next’.
  6. +
  7. Select 'Yes, I have already connected the + hardware', then click Next.
  8. +
  9. Select ‘Add a new hardware device’ from the + list, then click Next.
  10. +
  11. Select ‘Install the hardware that I manually + select from a list(Advanced),' and then click next.
  12. +
  13. Select ‘Show All Devices’, then click Next.
  14. +
  15. Click 'Have Disk', make sure that 'A:\' is in + the "Copy manufacturer's files from:" box, and click OK.
  16. +
  17. Click on the desired entry, and then click + Next.
  18. +
  19. At 'The wizard is ready to install your + hardware', click Next.
  20. +
  21. Click Finish at 'Completing the Add/Remove + Hardware Wizard.'
  22. +
+
+

Alternatively, you can +use the DEVCON.EXE from the DDK to install the driver programmatically.

+ +

c:\>DEVCON.EXE +INSTALL mars.inf "SD\vid_0388&pid_0000"

+ +

The system copies the +mars.sys file to %systemroot%\system32\drivers directory and loads the +driver.

+ +

CODE +TOUR

+ +

File Manifest

+ +
File              Description
 
+
ntddmars.h           Header containing global definitions
+
mars.inx             Device Installation File
+
mars.h               Header containing driver specific definitions
+
mars.c               Source code for driver functions
+
Sources              Generic file for building the code sample.
+
makefile             The file merely indirects to the real makefile that is shared by all the driver components of the windows Driver Kit.
+
makefile.inc         The file stamps the inx file with kmdf version and generates the inf file.
+
sdiosample.htm       Sample Tour documentation for this sample (this file).
+ +

 

+ +

 

+ +
+ + + + diff --git a/security/elam/elam.sln b/security/elam/elam.sln index 7e7fff34..53aa1f57 100644 --- a/security/elam/elam.sln +++ b/security/elam/elam.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "elamsample", "elamsample.vcxproj", "{C71588A8-91B3-4830-A8BC-EE0CADD1F74F}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "elamsample", "elamsample.vcxproj", "{691F9AAE-40A3-4950-8529-1C817ED43A61}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +13,14 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {C71588A8-91B3-4830-A8BC-EE0CADD1F74F}.Debug|Win32.ActiveCfg = Debug|Win32 - {C71588A8-91B3-4830-A8BC-EE0CADD1F74F}.Debug|Win32.Build.0 = Debug|Win32 - {C71588A8-91B3-4830-A8BC-EE0CADD1F74F}.Release|Win32.ActiveCfg = Release|Win32 - {C71588A8-91B3-4830-A8BC-EE0CADD1F74F}.Release|Win32.Build.0 = Release|Win32 - {C71588A8-91B3-4830-A8BC-EE0CADD1F74F}.Debug|x64.ActiveCfg = Debug|x64 - {C71588A8-91B3-4830-A8BC-EE0CADD1F74F}.Debug|x64.Build.0 = Debug|x64 - {C71588A8-91B3-4830-A8BC-EE0CADD1F74F}.Release|x64.ActiveCfg = Release|x64 - {C71588A8-91B3-4830-A8BC-EE0CADD1F74F}.Release|x64.Build.0 = Release|x64 + {691F9AAE-40A3-4950-8529-1C817ED43A61}.Debug|Win32.ActiveCfg = Debug|Win32 + {691F9AAE-40A3-4950-8529-1C817ED43A61}.Debug|Win32.Build.0 = Debug|Win32 + {691F9AAE-40A3-4950-8529-1C817ED43A61}.Release|Win32.ActiveCfg = Release|Win32 + {691F9AAE-40A3-4950-8529-1C817ED43A61}.Release|Win32.Build.0 = Release|Win32 + {691F9AAE-40A3-4950-8529-1C817ED43A61}.Debug|x64.ActiveCfg = Debug|x64 + {691F9AAE-40A3-4950-8529-1C817ED43A61}.Debug|x64.Build.0 = Debug|x64 + {691F9AAE-40A3-4950-8529-1C817ED43A61}.Release|x64.ActiveCfg = Release|x64 + {691F9AAE-40A3-4950-8529-1C817ED43A61}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/security/elam/elamsample.htm b/security/elam/elamsample.htm new file mode 100644 index 00000000..2c93d624 --- /dev/null +++ b/security/elam/elamsample.htm @@ -0,0 +1,1110 @@ + + + + + + + + + + + + + + + + + + + + +
+ +

ELAMSAMPLE

+ +

SUMMARY

+ +

This +sample demonstrates how to use the APIs IoRegisterBootDriverCallback +and IoUnRegisterBootDriverCallback from an Early +Launch Anti-Malware driver, to receive notifications about the initialization +of regular boot start drivers

+ +

The +building and installation instructions given here apply to Windows® 8 and later +operating systems.

+ +

This +sample driver is a minimal driver meant to demonstrate the usage of the APIs +mentioned above. It is not intended for use in a production environment.

+ +

BUILDING THE SAMPLE

+ +

Click the +Free Build Environment or Checked Build Environment icon under Development Kits +program group to set basic environment variables.

+ +

Change to +the directory containing the device source code, such as “src\security\elam”.

+ +

Run build +-ceZ, or use the macro BLD. This command +invokes the Microsoft make routines to build the components. If the build succeeds, you will +find the driver, elamsample.sys, in the binary output directory specified for +the build environment. You can get the output path from the buildxxx.log file. +If it fails you can find errors and warnings in the buildxxx.err +and buildxxx.wrn respectively.

+ +

SIGNING THE SAMPLE

+ +

Early Launch +drivers are required to be signed with a code-signing certificate that also +contains the Early Launch EKU "1.3.6.1.4.1.311.61.4.1". +In a production environment, Early Launch drivers are signed by Microsoft for +qualifying Anti-Malware vendors with a WHQL certificate that contains this EKU. +The makecert.exe tool can be used to generate a self-signed test certificate +that contains both the Early Launch EKU and the “1.3.6.1.5.5.7.3.3” Code +Signing EKU. Once a certificate of this form has been created, signtool.exe can +be used to sign elamsample.sys.

+ +

INSTALLATION

+ +

1.    +Copy +the signed elamsample.sys file to the %WINDIR%\System32\Drivers directory on +your test machine.

+ +

2.    +Use +the sc.exe tool present in Windows to install the driver:

+ +
sc create ElamSample binpath=%windir%\system32\drivers\elamsample.sys type=kernel start=boot error=critical group=Early-Launch
 
+ +

3.    +Enable +test signing:

+ +

 

+ +

bcdedit /set testsigning +on

+ +

CODE +TOUR

+ +

DriverEntry - Creates a framework driver object and +calls IoRegisterBootDriverCallback to register to +boot driver status callbacks.

+ +

ElamSampleEvtDriverUnload: Calls IoUnregisterBootDriverCallback +to unregister for callbacks when elamsample.sys is about to be unloaded.

+ +

ElamSampleBootDriverCallback: Dispatches to other +functions to process the specific callback types.

+ +

ElamSampleProcessStatusUpdate: Displays callback BdCbStatusUpdate information, such as when dependencies and +drivers are about to be initialized, or when the ELAM driver is about to be +unload.

+ +

ElamSampleProcessInitializeImage: Displays callback BdCbInitializeImage information, such as the driver image +name and the name of the entity that signed the driver.

+ +

ElamSamplePrintHex: A utility function to display a +buffer in hexadecimal form.

+ +

TESTING

+ +

After installing the driver, attach the Kernel +Debugger and reboot your test machine. If ELAMSAMPLE_TRACE_LEVEL is set to DPFLTR_ERROR_LEVEL, +traces will be output to the debugger automatically. For example:

+ +

ElamSample is being initialized.

+ +

ElamSample reports the following dependency is about to be initialized:

+ +

ElamSample:    Image name "\FileSystem\RAW"

+ +

ElamSample:    Not signed.

+ +

 

+ +

ElamSample reports that Boot Start driver dependencies are being initialized.

+ +

 

+ +

ElamSample reports the following dependency is about to be initialized:

+ +

ElamSample:    Image name "\SystemRoot\system32\PSHED.dll"

+ +

ElamSample:    Image hash algorithm = +0x0000800c.

+ +

ElamSample:    Image hash:

+ +

ElamSample:    21 29 88 ca 88 ab dc 0f c3 f1 c0 74 df e0 29 58

+ +

ElamSample:    2e cd 41 5e 56 bd 77 53 39 9b d9 d7 f4 47 65 d8

+ +

ElamSample:    Image is signed by +"Microsoft Windows".

+ +

ElamSample:    Certificate issued by +"MSIT Test CodeSign CA 3".

+ +

ElamSample:    Certificate thumb print +algorithm = 0x0000800c.

+ +

ElamSample:    Certificate thumb print:

+ +

ElamSample:    93 29 d5 f2 e2 7a c9 79 41 +b2 6d c0 78 35 2a d3

+ +

ElamSample:    da 2d 7e 72 f0 05 5f 8b 63 +8c 7b a2 6b 37 5c 4f

+ +

 

+ +

ElamSample reports that Boot Start drivers are about to be initialized.

+ +

 

+ +

ElamSample reports the following Boot Start driver is about to be initialized:

+ +

ElamSample:    Image name "\SystemRoot\System32\drivers\rdyboost.sys"

+ +

ElamSample:    Registry path +"\Registry\Machine\System\CurrentControlSet\Services\rdyboost"

+ +

ElamSample:    Image hash algorithm = +0x0000800c.

+ +

ElamSample:    Image hash:

+ +

ElamSample:    9e 91 b2 e1 29 97 af e9 ac 6c 48 24 01 43 c8 b4

+ +

ElamSample:    f6 81 bf 57 df 80 0b 05 4d 58 bb e6 d9 83 a9 +08

+ +

ElamSample:    Image is signed by +"Microsoft Windows".

+ +

ElamSample:    Certificate issued by +"MSIT Test CodeSign CA 3".

+ +

ElamSample:    Certificate thumb print +algorithm = 0x0000800c.

+ +

ElamSample:    Certificate thumb print:

+ +

ElamSample:    93 29 d5 f2 e2 7a c9 79 41 +b2 6d c0 78 35 2a d3

+ +

ElamSample:    da 2d 7e 72 f0 05 5f 8b 63 +8c 7b a2 6b 37 5c 4f

+ +

 

+ +

ElamSample reports that all Boot Start drivers have been initialized and that ElamSample is about to be unloaded

+ +

ElamSample is being unloaded.

+ +

File Manifest

+ +
File                           Description
 
ElamSample.htm                 Documentation for this sample (this file).
 
ElamSample.c                   DriverEntry and Callback processing.
ElamSample.h                   Header file with definitions and prototypes.
ElamSample.rc                  Resource file for the sample.
Sources                        Generic file that lists source files and all the build options.
+ +

Top +of page +

+ + + + + +
+

 

+
+ +

© 2011 Microsoft Corporation

+ +
+ + + + diff --git a/security/elam/elamsample.vcxproj b/security/elam/elamsample.vcxproj index e490e121..fd4a3004 100644 --- a/security/elam/elamsample.vcxproj +++ b/security/elam/elamsample.vcxproj @@ -19,12 +19,12 @@
- {C71588A8-91B3-4830-A8BC-EE0CADD1F74F} + {691F9AAE-40A3-4950-8529-1C817ED43A61} $(MSBuildProjectName) 1 Debug Win32 - {E8CB1907-B783-4529-86E1-12F5415AB9D2} + {06CC2AEF-6CBC-49CE-B869-459F80D28EC0} diff --git a/security/elam/elamsample.vcxproj.Filters b/security/elam/elamsample.vcxproj.Filters index 3683aaec..6e8c26bb 100644 --- a/security/elam/elamsample.vcxproj.Filters +++ b/security/elam/elamsample.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {3A878DCA-5746-41B2-9BE4-9535E3608E01} + {D19514A8-1E7E-43BE-80B3-850E5BFCD858} h;hpp;hxx;hm;inl;inc;xsd - {531B9233-20AD-48D5-9E0F-A34ECBD0BBCF} + {379127B6-7854-4E76-996A-4C2A635EE774} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {A70EFA76-F255-4C79-A344-617EEEFE6F2A} + {EF2BCD73-C364-4E77-BB95-15C633EAB208} inf;inv;inx;mof;mc; - {8CE83F1F-76AF-4984-A91B-7054E133CD6C} + {A4C7ECB5-5FA4-4E9E-BF1C-5DF0BAF5BFE9} diff --git a/sensors/ADXL345Acc/ADXL345Acc.sln b/sensors/ADXL345Acc/ADXL345Acc.sln index 64590d56..c34fd00c 100644 --- a/sensors/ADXL345Acc/ADXL345Acc.sln +++ b/sensors/ADXL345Acc/ADXL345Acc.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ADXL345Acc", "ADXL345Acc.vcxproj", "{2D16915F-5347-4001-93F9-CFD137515B67}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ADXL345Acc", "ADXL345Acc.vcxproj", "{AA39917C-9A08-46B6-9825-BBADE84E1AA4}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +13,14 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {2D16915F-5347-4001-93F9-CFD137515B67}.Debug|Win32.ActiveCfg = Debug|Win32 - {2D16915F-5347-4001-93F9-CFD137515B67}.Debug|Win32.Build.0 = Debug|Win32 - {2D16915F-5347-4001-93F9-CFD137515B67}.Release|Win32.ActiveCfg = Release|Win32 - {2D16915F-5347-4001-93F9-CFD137515B67}.Release|Win32.Build.0 = Release|Win32 - {2D16915F-5347-4001-93F9-CFD137515B67}.Debug|x64.ActiveCfg = Debug|x64 - {2D16915F-5347-4001-93F9-CFD137515B67}.Debug|x64.Build.0 = Debug|x64 - {2D16915F-5347-4001-93F9-CFD137515B67}.Release|x64.ActiveCfg = Release|x64 - {2D16915F-5347-4001-93F9-CFD137515B67}.Release|x64.Build.0 = Release|x64 + {AA39917C-9A08-46B6-9825-BBADE84E1AA4}.Debug|Win32.ActiveCfg = Debug|Win32 + {AA39917C-9A08-46B6-9825-BBADE84E1AA4}.Debug|Win32.Build.0 = Debug|Win32 + {AA39917C-9A08-46B6-9825-BBADE84E1AA4}.Release|Win32.ActiveCfg = Release|Win32 + {AA39917C-9A08-46B6-9825-BBADE84E1AA4}.Release|Win32.Build.0 = Release|Win32 + {AA39917C-9A08-46B6-9825-BBADE84E1AA4}.Debug|x64.ActiveCfg = Debug|x64 + {AA39917C-9A08-46B6-9825-BBADE84E1AA4}.Debug|x64.Build.0 = Debug|x64 + {AA39917C-9A08-46B6-9825-BBADE84E1AA4}.Release|x64.ActiveCfg = Release|x64 + {AA39917C-9A08-46B6-9825-BBADE84E1AA4}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/sensors/ADXL345Acc/ADXL345Acc.vcxproj b/sensors/ADXL345Acc/ADXL345Acc.vcxproj index 39eaea9d..d6a262fa 100644 --- a/sensors/ADXL345Acc/ADXL345Acc.vcxproj +++ b/sensors/ADXL345Acc/ADXL345Acc.vcxproj @@ -19,12 +19,12 @@ - {2D16915F-5347-4001-93F9-CFD137515B67} + {AA39917C-9A08-46B6-9825-BBADE84E1AA4} $(MSBuildProjectName) 2 Debug Win32 - {2A86D395-8598-4F82-B608-73644859A00A} + {59D15CA4-F585-4DF1-BC42-AAE6E12222A8} diff --git a/sensors/ADXL345Acc/ADXL345Acc.vcxproj.Filters b/sensors/ADXL345Acc/ADXL345Acc.vcxproj.Filters index e38a355d..4140ca88 100644 --- a/sensors/ADXL345Acc/ADXL345Acc.vcxproj.Filters +++ b/sensors/ADXL345Acc/ADXL345Acc.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {C4BC0C7C-94E5-49B8-88C7-B45EEE7AB91C} + {C20A2709-5B6F-46F4-8717-93474B5C7924} h;hpp;hxx;hm;inl;inc;xsd - {F1C52F29-9855-4A7F-BBC5-928F9DFDD3A6} + {B1F5FC9F-2060-43A9-8D30-62E524609F21} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {375CB752-508A-4609-8FDC-EFAA81E7E70E} + {D04E0A09-D852-49DD-899C-68ABED2092F1} inf;inv;inx;mof;mc; - {C269088F-3471-440D-8D9E-B0186F25B79C} + {5933B2A7-3E1B-4302-BB84-18D793739C74} diff --git a/sensors/Activity/Activity.sln b/sensors/Activity/Activity.sln index 5596cc29..f1fb8677 100644 --- a/sensors/Activity/Activity.sln +++ b/sensors/Activity/Activity.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Activity", "Activity.vcxproj", "{512537DA-35C8-462A-8019-40A25BA53B9A}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Activity", "Activity.vcxproj", "{92029423-4EFC-49A3-BE21-B69213B42AD6}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +13,14 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {512537DA-35C8-462A-8019-40A25BA53B9A}.Debug|Win32.ActiveCfg = Debug|Win32 - {512537DA-35C8-462A-8019-40A25BA53B9A}.Debug|Win32.Build.0 = Debug|Win32 - {512537DA-35C8-462A-8019-40A25BA53B9A}.Release|Win32.ActiveCfg = Release|Win32 - {512537DA-35C8-462A-8019-40A25BA53B9A}.Release|Win32.Build.0 = Release|Win32 - {512537DA-35C8-462A-8019-40A25BA53B9A}.Debug|x64.ActiveCfg = Debug|x64 - {512537DA-35C8-462A-8019-40A25BA53B9A}.Debug|x64.Build.0 = Debug|x64 - {512537DA-35C8-462A-8019-40A25BA53B9A}.Release|x64.ActiveCfg = Release|x64 - {512537DA-35C8-462A-8019-40A25BA53B9A}.Release|x64.Build.0 = Release|x64 + {92029423-4EFC-49A3-BE21-B69213B42AD6}.Debug|Win32.ActiveCfg = Debug|Win32 + {92029423-4EFC-49A3-BE21-B69213B42AD6}.Debug|Win32.Build.0 = Debug|Win32 + {92029423-4EFC-49A3-BE21-B69213B42AD6}.Release|Win32.ActiveCfg = Release|Win32 + {92029423-4EFC-49A3-BE21-B69213B42AD6}.Release|Win32.Build.0 = Release|Win32 + {92029423-4EFC-49A3-BE21-B69213B42AD6}.Debug|x64.ActiveCfg = Debug|x64 + {92029423-4EFC-49A3-BE21-B69213B42AD6}.Debug|x64.Build.0 = Debug|x64 + {92029423-4EFC-49A3-BE21-B69213B42AD6}.Release|x64.ActiveCfg = Release|x64 + {92029423-4EFC-49A3-BE21-B69213B42AD6}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/sensors/Activity/Activity.vcxproj b/sensors/Activity/Activity.vcxproj index f12f95a5..7414cdf1 100644 --- a/sensors/Activity/Activity.vcxproj +++ b/sensors/Activity/Activity.vcxproj @@ -19,12 +19,12 @@ - {512537DA-35C8-462A-8019-40A25BA53B9A} + {92029423-4EFC-49A3-BE21-B69213B42AD6} $(MSBuildProjectName) 2 Debug Win32 - {C50CD6B5-8376-4CA3-9FA4-BD7714277D9F} + {74D183AB-2BAC-41B6-8969-14F6FCEF6376} diff --git a/sensors/Activity/Activity.vcxproj.Filters b/sensors/Activity/Activity.vcxproj.Filters index 042472b5..b9782669 100644 --- a/sensors/Activity/Activity.vcxproj.Filters +++ b/sensors/Activity/Activity.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {850998C4-064A-4E35-8847-8CDAA33EA2F6} + {2CABA5C9-80C7-4E60-BEA7-32D9A2EAA7BB} h;hpp;hxx;hm;inl;inc;xsd - {9BB46857-98A8-4F92-9710-98255DB22181} + {A2ACE853-D985-44E1-B2A8-A7A4DAB1AAB2} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {2F2E5D53-FAB3-4416-9DE4-D645E908662E} + {F30F39F6-AB44-41F0-9B71-C4C30F923ED3} inf;inv;inx;mof;mc; - {0AFC4E0D-7BBE-444E-9B9E-BC7942F6DB8A} + {CE567ED5-70CD-43EE-AEC5-2831011DF02E} diff --git a/sensors/CustomSensors/CustomSensors.sln b/sensors/CustomSensors/CustomSensors.sln index f1c0e6a0..f6177827 100644 --- a/sensors/CustomSensors/CustomSensors.sln +++ b/sensors/CustomSensors/CustomSensors.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CustomSensors", "CustomSensors.vcxproj", "{E5E68D5F-7226-4F7E-885D-386B1FE421E2}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CustomSensors", "CustomSensors.vcxproj", "{581FD075-974D-4650-8524-C17DA15E744B}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +13,14 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {E5E68D5F-7226-4F7E-885D-386B1FE421E2}.Debug|Win32.ActiveCfg = Debug|Win32 - {E5E68D5F-7226-4F7E-885D-386B1FE421E2}.Debug|Win32.Build.0 = Debug|Win32 - {E5E68D5F-7226-4F7E-885D-386B1FE421E2}.Release|Win32.ActiveCfg = Release|Win32 - {E5E68D5F-7226-4F7E-885D-386B1FE421E2}.Release|Win32.Build.0 = Release|Win32 - {E5E68D5F-7226-4F7E-885D-386B1FE421E2}.Debug|x64.ActiveCfg = Debug|x64 - {E5E68D5F-7226-4F7E-885D-386B1FE421E2}.Debug|x64.Build.0 = Debug|x64 - {E5E68D5F-7226-4F7E-885D-386B1FE421E2}.Release|x64.ActiveCfg = Release|x64 - {E5E68D5F-7226-4F7E-885D-386B1FE421E2}.Release|x64.Build.0 = Release|x64 + {581FD075-974D-4650-8524-C17DA15E744B}.Debug|Win32.ActiveCfg = Debug|Win32 + {581FD075-974D-4650-8524-C17DA15E744B}.Debug|Win32.Build.0 = Debug|Win32 + {581FD075-974D-4650-8524-C17DA15E744B}.Release|Win32.ActiveCfg = Release|Win32 + {581FD075-974D-4650-8524-C17DA15E744B}.Release|Win32.Build.0 = Release|Win32 + {581FD075-974D-4650-8524-C17DA15E744B}.Debug|x64.ActiveCfg = Debug|x64 + {581FD075-974D-4650-8524-C17DA15E744B}.Debug|x64.Build.0 = Debug|x64 + {581FD075-974D-4650-8524-C17DA15E744B}.Release|x64.ActiveCfg = Release|x64 + {581FD075-974D-4650-8524-C17DA15E744B}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/sensors/CustomSensors/CustomSensors.vcxproj b/sensors/CustomSensors/CustomSensors.vcxproj index 39cb0813..d8e0699f 100644 --- a/sensors/CustomSensors/CustomSensors.vcxproj +++ b/sensors/CustomSensors/CustomSensors.vcxproj @@ -19,12 +19,12 @@ - {E5E68D5F-7226-4F7E-885D-386B1FE421E2} + {581FD075-974D-4650-8524-C17DA15E744B} $(MSBuildProjectName) 2 Debug Win32 - {9B76DB90-A9D2-4AA1-A187-2C70A92A9AE9} + {26FA62DC-6E68-426D-9DDE-1D66E2CDEA41} diff --git a/sensors/CustomSensors/CustomSensors.vcxproj.Filters b/sensors/CustomSensors/CustomSensors.vcxproj.Filters index 8bdd8bfc..275aed16 100644 --- a/sensors/CustomSensors/CustomSensors.vcxproj.Filters +++ b/sensors/CustomSensors/CustomSensors.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {D028F6CF-8FB8-4F57-AE58-E70A29431AB6} + {4737C037-E6F5-419C-AC9F-B88532462988} h;hpp;hxx;hm;inl;inc;xsd - {D93A37EB-7DE4-47AC-BE20-6EEE2AA1665A} + {C6BF209A-BDDA-4488-883C-E4C3BDD7AB16} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {447FEA91-FC9B-461E-B410-6AB0BE58A8A1} + {EB50A155-6055-4736-A912-5B2970F2EFBE} inf;inv;inx;mof;mc; - {0E1976EB-F0B4-4EF6-B1BD-DA8610D793C0} + {3B9BA3C9-953B-49F5-8F39-A7FE1522F2A5} diff --git a/sensors/Pedometer/Pedometer.sln b/sensors/Pedometer/Pedometer.sln index 2dd26c5d..1411fcd2 100644 --- a/sensors/Pedometer/Pedometer.sln +++ b/sensors/Pedometer/Pedometer.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Pedometer", "Pedometer.vcxproj", "{F82B1ED1-FCD9-4DE5-8B5E-B9054AE4A9AC}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Pedometer", "Pedometer.vcxproj", "{E4AB8CAA-0898-4F87-B6DB-273E1D661550}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +13,14 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {F82B1ED1-FCD9-4DE5-8B5E-B9054AE4A9AC}.Debug|Win32.ActiveCfg = Debug|Win32 - {F82B1ED1-FCD9-4DE5-8B5E-B9054AE4A9AC}.Debug|Win32.Build.0 = Debug|Win32 - {F82B1ED1-FCD9-4DE5-8B5E-B9054AE4A9AC}.Release|Win32.ActiveCfg = Release|Win32 - {F82B1ED1-FCD9-4DE5-8B5E-B9054AE4A9AC}.Release|Win32.Build.0 = Release|Win32 - {F82B1ED1-FCD9-4DE5-8B5E-B9054AE4A9AC}.Debug|x64.ActiveCfg = Debug|x64 - {F82B1ED1-FCD9-4DE5-8B5E-B9054AE4A9AC}.Debug|x64.Build.0 = Debug|x64 - {F82B1ED1-FCD9-4DE5-8B5E-B9054AE4A9AC}.Release|x64.ActiveCfg = Release|x64 - {F82B1ED1-FCD9-4DE5-8B5E-B9054AE4A9AC}.Release|x64.Build.0 = Release|x64 + {E4AB8CAA-0898-4F87-B6DB-273E1D661550}.Debug|Win32.ActiveCfg = Debug|Win32 + {E4AB8CAA-0898-4F87-B6DB-273E1D661550}.Debug|Win32.Build.0 = Debug|Win32 + {E4AB8CAA-0898-4F87-B6DB-273E1D661550}.Release|Win32.ActiveCfg = Release|Win32 + {E4AB8CAA-0898-4F87-B6DB-273E1D661550}.Release|Win32.Build.0 = Release|Win32 + {E4AB8CAA-0898-4F87-B6DB-273E1D661550}.Debug|x64.ActiveCfg = Debug|x64 + {E4AB8CAA-0898-4F87-B6DB-273E1D661550}.Debug|x64.Build.0 = Debug|x64 + {E4AB8CAA-0898-4F87-B6DB-273E1D661550}.Release|x64.ActiveCfg = Release|x64 + {E4AB8CAA-0898-4F87-B6DB-273E1D661550}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/sensors/Pedometer/Pedometer.vcxproj b/sensors/Pedometer/Pedometer.vcxproj index 50315746..8b6b3122 100644 --- a/sensors/Pedometer/Pedometer.vcxproj +++ b/sensors/Pedometer/Pedometer.vcxproj @@ -19,12 +19,12 @@ - {F82B1ED1-FCD9-4DE5-8B5E-B9054AE4A9AC} + {E4AB8CAA-0898-4F87-B6DB-273E1D661550} $(MSBuildProjectName) 2 Debug Win32 - {4F24B4B2-7CA4-4BE0-BB9D-B4CC91C80B55} + {1DF52CE2-1A85-4EAE-A0B3-FC48C81A3E3D} diff --git a/sensors/Pedometer/Pedometer.vcxproj.Filters b/sensors/Pedometer/Pedometer.vcxproj.Filters index b45b352a..687bc30e 100644 --- a/sensors/Pedometer/Pedometer.vcxproj.Filters +++ b/sensors/Pedometer/Pedometer.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {F3D96445-84BA-479E-83E8-22EC66AD5C7C} + {4069EBC4-432A-48E0-AD1E-9EDEAB260F0E} h;hpp;hxx;hm;inl;inc;xsd - {FDF8BD7D-FF71-4B97-AF7B-53FC2AC03D64} + {6DA94DA3-51F2-4464-BDF8-6F25FA6ABEC6} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {568E7CBB-7EE9-4E95-96A3-2BD5EEAC74B7} + {440472A3-6A34-466D-AEF0-81507558AE46} inf;inv;inx;mof;mc; - {C8552346-5082-4BEA-9395-FD366C835F18} + {DB1109AA-F1A5-43B8-B112-1CA70243A5AB} diff --git a/sensors/Pedometer/device.cpp b/sensors/Pedometer/device.cpp index 8a3c003f..a3d3ba30 100644 --- a/sensors/Pedometer/device.cpp +++ b/sensors/Pedometer/device.cpp @@ -248,7 +248,7 @@ PedometerDevice::Initialize( m_pEnumerationProperties->List[SENSOR_SUPPORTED_STEPTYPES].Key = PKEY_SensorData_SupportedStepTypes; InitPropVariantFromUInt32(PedometerStepType_Unknown | PedometerStepType_Walking | PedometerStepType_Running, - &(m_pEnumerationProperties->List[SENSOR_PROPERTY_SUPPORTED_STEPTYPES].Value)); + &(m_pEnumerationProperties->List[SENSOR_SUPPORTED_STEPTYPES].Value)); // Sensor Properties m_Interval = Pedometer_Default_MinDataInterval_Ms; diff --git a/sensors/SimpleDeviceOrientationSensor/SimpleDeviceOrientationSensor.sln b/sensors/SimpleDeviceOrientationSensor/SimpleDeviceOrientationSensor.sln index 81db1b4a..db9504a3 100644 --- a/sensors/SimpleDeviceOrientationSensor/SimpleDeviceOrientationSensor.sln +++ b/sensors/SimpleDeviceOrientationSensor/SimpleDeviceOrientationSensor.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SimpleDeviceOrientationSensor", "SimpleDeviceOrientationSensor.vcxproj", "{38463481-89DC-440D-9172-2F42FFA39D56}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SimpleDeviceOrientationSensor", "SimpleDeviceOrientationSensor.vcxproj", "{BD66C84A-75D9-48E7-848C-E3E8BCF303F9}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +13,14 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {38463481-89DC-440D-9172-2F42FFA39D56}.Debug|Win32.ActiveCfg = Debug|Win32 - {38463481-89DC-440D-9172-2F42FFA39D56}.Debug|Win32.Build.0 = Debug|Win32 - {38463481-89DC-440D-9172-2F42FFA39D56}.Release|Win32.ActiveCfg = Release|Win32 - {38463481-89DC-440D-9172-2F42FFA39D56}.Release|Win32.Build.0 = Release|Win32 - {38463481-89DC-440D-9172-2F42FFA39D56}.Debug|x64.ActiveCfg = Debug|x64 - {38463481-89DC-440D-9172-2F42FFA39D56}.Debug|x64.Build.0 = Debug|x64 - {38463481-89DC-440D-9172-2F42FFA39D56}.Release|x64.ActiveCfg = Release|x64 - {38463481-89DC-440D-9172-2F42FFA39D56}.Release|x64.Build.0 = Release|x64 + {BD66C84A-75D9-48E7-848C-E3E8BCF303F9}.Debug|Win32.ActiveCfg = Debug|Win32 + {BD66C84A-75D9-48E7-848C-E3E8BCF303F9}.Debug|Win32.Build.0 = Debug|Win32 + {BD66C84A-75D9-48E7-848C-E3E8BCF303F9}.Release|Win32.ActiveCfg = Release|Win32 + {BD66C84A-75D9-48E7-848C-E3E8BCF303F9}.Release|Win32.Build.0 = Release|Win32 + {BD66C84A-75D9-48E7-848C-E3E8BCF303F9}.Debug|x64.ActiveCfg = Debug|x64 + {BD66C84A-75D9-48E7-848C-E3E8BCF303F9}.Debug|x64.Build.0 = Debug|x64 + {BD66C84A-75D9-48E7-848C-E3E8BCF303F9}.Release|x64.ActiveCfg = Release|x64 + {BD66C84A-75D9-48E7-848C-E3E8BCF303F9}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/sensors/SimpleDeviceOrientationSensor/SimpleDeviceOrientationSensor.vcxproj b/sensors/SimpleDeviceOrientationSensor/SimpleDeviceOrientationSensor.vcxproj index 2ba0bfba..85ce76fc 100644 --- a/sensors/SimpleDeviceOrientationSensor/SimpleDeviceOrientationSensor.vcxproj +++ b/sensors/SimpleDeviceOrientationSensor/SimpleDeviceOrientationSensor.vcxproj @@ -19,12 +19,12 @@ - {38463481-89DC-440D-9172-2F42FFA39D56} + {BD66C84A-75D9-48E7-848C-E3E8BCF303F9} $(MSBuildProjectName) 2 Debug Win32 - {D490E038-D377-4D07-A673-6033B0C4F352} + {835CB733-E6FD-434E-8E5D-6A44D0666B3D} diff --git a/sensors/SimpleDeviceOrientationSensor/SimpleDeviceOrientationSensor.vcxproj.Filters b/sensors/SimpleDeviceOrientationSensor/SimpleDeviceOrientationSensor.vcxproj.Filters index 8647029d..964e0d85 100644 --- a/sensors/SimpleDeviceOrientationSensor/SimpleDeviceOrientationSensor.vcxproj.Filters +++ b/sensors/SimpleDeviceOrientationSensor/SimpleDeviceOrientationSensor.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {9A4063EE-9E56-4BA5-9114-90BA4CFF25FD} + {8FE1EA5F-0794-452D-8ADA-B87816A19EB9} h;hpp;hxx;hm;inl;inc;xsd - {460836F1-204C-4153-8166-BB2EDD6702CF} + {8137339A-0DE2-48F6-B4B6-29FF3DBF10FA} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {EE7FF0E6-BBFB-452E-AAE7-13D24CB3AB32} + {A44CA721-816C-481C-AFB4-FD9F44215A4B} inf;inv;inx;mof;mc; - {9639AD67-32DC-4CD6-82C4-AC08C60DA7BE} + {B68042DD-8FCE-4A4B-82E3-3F536F3C45DE} diff --git a/serial/VirtualSerial/ComPort/virtualserial.vcxproj b/serial/VirtualSerial/ComPort/virtualserial.vcxproj index 66943fc2..6aeff0e9 100644 --- a/serial/VirtualSerial/ComPort/virtualserial.vcxproj +++ b/serial/VirtualSerial/ComPort/virtualserial.vcxproj @@ -19,12 +19,12 @@ - {EFB282A8-A881-44E7-964D-F068A4FD19C9} + {24460F70-3AE4-4587-A9C7-095934572855} $(MSBuildProjectName) 1 Debug Win32 - {BA45F248-4EC7-4AF6-A0B1-438FABDF4722} + {334C2162-D8A0-4318-9A7B-B53226899B27} diff --git a/serial/VirtualSerial/ComPort/virtualserial.vcxproj.Filters b/serial/VirtualSerial/ComPort/virtualserial.vcxproj.Filters index 43e9f856..fb625164 100644 --- a/serial/VirtualSerial/ComPort/virtualserial.vcxproj.Filters +++ b/serial/VirtualSerial/ComPort/virtualserial.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {2B1C4ECC-41B3-4BE4-B6AB-A37A6988B553} + {F92B6BB2-9116-46B1-9D16-A4B81E90515F} h;hpp;hxx;hm;inl;inc;xsd - {FD1A6174-0DDB-456B-B047-A0BE30AC7612} + {EC2A81F6-5F0F-4504-86F7-2F303B06F301} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {75CE36CB-D686-4BF7-8BD9-F7275C1AC174} + {FDACC4A4-3E06-4908-BAF1-FE77087CCD0A} inf;inv;inx;mof;mc; - {05B7B9F6-1D0D-4F2D-BAA2-C6E6B1E74EE1} + {9CA0A168-1E88-40BA-9F0E-D3F60623D475} diff --git a/serial/VirtualSerial/FakeModem/fakemodem.vcxproj b/serial/VirtualSerial/FakeModem/fakemodem.vcxproj index 0eb999de..c03701e1 100644 --- a/serial/VirtualSerial/FakeModem/fakemodem.vcxproj +++ b/serial/VirtualSerial/FakeModem/fakemodem.vcxproj @@ -19,12 +19,12 @@ - {8C65DE8E-4978-4EC0-8C6B-3C8BEF8FE281} + {BCF39170-D785-4372-A97E-AAE0915630BE} $(MSBuildProjectName) 1 Debug Win32 - {BDA85DC8-F904-4FBD-B19D-160DD1CF4C3F} + {BB77384F-D084-459A-A05F-FDF65FF05318} diff --git a/serial/VirtualSerial/FakeModem/fakemodem.vcxproj.Filters b/serial/VirtualSerial/FakeModem/fakemodem.vcxproj.Filters index 1471427c..d3b31071 100644 --- a/serial/VirtualSerial/FakeModem/fakemodem.vcxproj.Filters +++ b/serial/VirtualSerial/FakeModem/fakemodem.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {171E6CE6-A3BC-4E0C-A70B-3D3A14E3013E} + {47091361-E39C-4D26-B87F-90F3718A64D7} h;hpp;hxx;hm;inl;inc;xsd - {7D188E14-FC54-4649-BF86-227A339DF62D} + {C1AA6012-3D25-4230-B45A-9C8B8A699985} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {376804A3-5F06-4C4D-8E78-89D50B462EA5} + {EDF4A55C-BC2C-477F-9B14-1D736F901B53} inf;inv;inx;mof;mc; - {CD2DEFBB-4830-410C-8909-649347BC8898} + {23FBCF57-F7A0-4114-AE58-3674DB595114} diff --git a/serial/VirtualSerial/VirtualSerial.sln b/serial/VirtualSerial/VirtualSerial.sln index e682dae3..b904e486 100644 --- a/serial/VirtualSerial/VirtualSerial.sln +++ b/serial/VirtualSerial/VirtualSerial.sln @@ -3,13 +3,13 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ComPort", "ComPort", "{6C0EE406-586D-4B80-BB5D-DAF3113ECF24}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ComPort", "ComPort", "{76B0904E-842B-44FB-B2E0-8BC932912E20}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "FakeModem", "FakeModem", "{E25B6521-5167-4BB2-B779-8C56A9B9B980}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "FakeModem", "FakeModem", "{388FA684-8FCF-417F-AB70-1E417037B715}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "virtualserial", "ComPort\virtualserial.vcxproj", "{EFB282A8-A881-44E7-964D-F068A4FD19C9}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "virtualserial", "ComPort\virtualserial.vcxproj", "{24460F70-3AE4-4587-A9C7-095934572855}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fakemodem", "FakeModem\fakemodem.vcxproj", "{8C65DE8E-4978-4EC0-8C6B-3C8BEF8FE281}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fakemodem", "FakeModem\fakemodem.vcxproj", "{BCF39170-D785-4372-A97E-AAE0915630BE}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -19,28 +19,28 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {EFB282A8-A881-44E7-964D-F068A4FD19C9}.Debug|Win32.ActiveCfg = Debug|Win32 - {EFB282A8-A881-44E7-964D-F068A4FD19C9}.Debug|Win32.Build.0 = Debug|Win32 - {EFB282A8-A881-44E7-964D-F068A4FD19C9}.Release|Win32.ActiveCfg = Release|Win32 - {EFB282A8-A881-44E7-964D-F068A4FD19C9}.Release|Win32.Build.0 = Release|Win32 - {EFB282A8-A881-44E7-964D-F068A4FD19C9}.Debug|x64.ActiveCfg = Debug|x64 - {EFB282A8-A881-44E7-964D-F068A4FD19C9}.Debug|x64.Build.0 = Debug|x64 - {EFB282A8-A881-44E7-964D-F068A4FD19C9}.Release|x64.ActiveCfg = Release|x64 - {EFB282A8-A881-44E7-964D-F068A4FD19C9}.Release|x64.Build.0 = Release|x64 - {8C65DE8E-4978-4EC0-8C6B-3C8BEF8FE281}.Debug|Win32.ActiveCfg = Debug|Win32 - {8C65DE8E-4978-4EC0-8C6B-3C8BEF8FE281}.Debug|Win32.Build.0 = Debug|Win32 - {8C65DE8E-4978-4EC0-8C6B-3C8BEF8FE281}.Release|Win32.ActiveCfg = Release|Win32 - {8C65DE8E-4978-4EC0-8C6B-3C8BEF8FE281}.Release|Win32.Build.0 = Release|Win32 - {8C65DE8E-4978-4EC0-8C6B-3C8BEF8FE281}.Debug|x64.ActiveCfg = Debug|x64 - {8C65DE8E-4978-4EC0-8C6B-3C8BEF8FE281}.Debug|x64.Build.0 = Debug|x64 - {8C65DE8E-4978-4EC0-8C6B-3C8BEF8FE281}.Release|x64.ActiveCfg = Release|x64 - {8C65DE8E-4978-4EC0-8C6B-3C8BEF8FE281}.Release|x64.Build.0 = Release|x64 + {24460F70-3AE4-4587-A9C7-095934572855}.Debug|Win32.ActiveCfg = Debug|Win32 + {24460F70-3AE4-4587-A9C7-095934572855}.Debug|Win32.Build.0 = Debug|Win32 + {24460F70-3AE4-4587-A9C7-095934572855}.Release|Win32.ActiveCfg = Release|Win32 + {24460F70-3AE4-4587-A9C7-095934572855}.Release|Win32.Build.0 = Release|Win32 + {24460F70-3AE4-4587-A9C7-095934572855}.Debug|x64.ActiveCfg = Debug|x64 + {24460F70-3AE4-4587-A9C7-095934572855}.Debug|x64.Build.0 = Debug|x64 + {24460F70-3AE4-4587-A9C7-095934572855}.Release|x64.ActiveCfg = Release|x64 + {24460F70-3AE4-4587-A9C7-095934572855}.Release|x64.Build.0 = Release|x64 + {BCF39170-D785-4372-A97E-AAE0915630BE}.Debug|Win32.ActiveCfg = Debug|Win32 + {BCF39170-D785-4372-A97E-AAE0915630BE}.Debug|Win32.Build.0 = Debug|Win32 + {BCF39170-D785-4372-A97E-AAE0915630BE}.Release|Win32.ActiveCfg = Release|Win32 + {BCF39170-D785-4372-A97E-AAE0915630BE}.Release|Win32.Build.0 = Release|Win32 + {BCF39170-D785-4372-A97E-AAE0915630BE}.Debug|x64.ActiveCfg = Debug|x64 + {BCF39170-D785-4372-A97E-AAE0915630BE}.Debug|x64.Build.0 = Debug|x64 + {BCF39170-D785-4372-A97E-AAE0915630BE}.Release|x64.ActiveCfg = Release|x64 + {BCF39170-D785-4372-A97E-AAE0915630BE}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {EFB282A8-A881-44E7-964D-F068A4FD19C9} = {6C0EE406-586D-4B80-BB5D-DAF3113ECF24} - {8C65DE8E-4978-4EC0-8C6B-3C8BEF8FE281} = {E25B6521-5167-4BB2-B779-8C56A9B9B980} + {24460F70-3AE4-4587-A9C7-095934572855} = {76B0904E-842B-44FB-B2E0-8BC932912E20} + {BCF39170-D785-4372-A97E-AAE0915630BE} = {388FA684-8FCF-417F-AB70-1E417037B715} EndGlobalSection EndGlobal diff --git a/serial/VirtualSerial2/ComPort/VirtualSerial2um.vcxproj b/serial/VirtualSerial2/ComPort/VirtualSerial2um.vcxproj new file mode 100644 index 00000000..3b3a3606 --- /dev/null +++ b/serial/VirtualSerial2/ComPort/VirtualSerial2um.vcxproj @@ -0,0 +1,194 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {9C376D98-E44B-44C6-BA97-C41F501548E6} + $(MSBuildProjectName) + 2 + Debug + Win32 + {C1C1FD00-5B5C-4F07-AB92-50461FEE885F} + + + + Windows10 + False + Universal + UMDF + WindowsUserModeDriver10.0 + DynamicLibrary + + + Windows10 + True + Universal + UMDF + WindowsUserModeDriver10.0 + DynamicLibrary + + + Windows10 + False + Universal + UMDF + WindowsUserModeDriver10.0 + DynamicLibrary + + + Windows10 + True + Universal + UMDF + WindowsUserModeDriver10.0 + DynamicLibrary + + + + $(IntDir) + + + + + + + + + + + + + + + + $(InfArch) + true + .\$(IntDir)\VirtualSerial2um.inf + + + + VirtualSerial2um + + + VirtualSerial2um + + + VirtualSerial2um + + + VirtualSerial2um + + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + %(AdditionalIncludeDirectories);$(DDK_INC_PATH)\wdm;..\..\inc + + + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + %(AdditionalIncludeDirectories);$(DDK_INC_PATH)\wdm;..\..\inc + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + %(AdditionalIncludeDirectories);$(DDK_INC_PATH)\wdm;..\..\inc + + + %(AdditionalDependencies);$(SDK_LIB_PATH)\mincore.lib + + + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + %(AdditionalIncludeDirectories);$(DDK_INC_PATH)\wdm;..\..\inc + + + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + %(AdditionalIncludeDirectories);$(DDK_INC_PATH)\wdm;..\..\inc + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + %(AdditionalIncludeDirectories);$(DDK_INC_PATH)\wdm;..\..\inc + + + %(AdditionalDependencies);$(SDK_LIB_PATH)\mincore.lib + + + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + %(AdditionalIncludeDirectories);$(DDK_INC_PATH)\wdm;..\..\inc + + + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + %(AdditionalIncludeDirectories);$(DDK_INC_PATH)\wdm;..\..\inc + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + %(AdditionalIncludeDirectories);$(DDK_INC_PATH)\wdm;..\..\inc + + + %(AdditionalDependencies);$(SDK_LIB_PATH)\mincore.lib + + + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + %(AdditionalIncludeDirectories);$(DDK_INC_PATH)\wdm;..\..\inc + + + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + %(AdditionalIncludeDirectories);$(DDK_INC_PATH)\wdm;..\..\inc + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + %(AdditionalIncludeDirectories);$(DDK_INC_PATH)\wdm;..\..\inc + + + %(AdditionalDependencies);$(SDK_LIB_PATH)\mincore.lib + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/serial/VirtualSerial2/ComPort/VirtualSerial2um.vcxproj.Filters b/serial/VirtualSerial2/ComPort/VirtualSerial2um.vcxproj.Filters new file mode 100644 index 00000000..de01b778 --- /dev/null +++ b/serial/VirtualSerial2/ComPort/VirtualSerial2um.vcxproj.Filters @@ -0,0 +1,48 @@ + + + + + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* + {74E463E8-2208-4136-9C1D-4160F1D7A44A} + + + h;hpp;hxx;hm;inl;inc;xsd + {86516042-B85B-4491-8ACF-5B7E87D1FB11} + + + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml + {1B09240F-68FE-4973-8631-0BFDDF0CEAB9} + + + inf;inv;inx;mof;mc; + {85FCBC36-920C-4155-96D9-7C492514995E} + + + + + Driver Files + + + Driver Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Resource Files + + + \ No newline at end of file diff --git a/serial/VirtualSerial2/ComPort/virtualserial2um.inx b/serial/VirtualSerial2/ComPort/virtualserial2um.inx new file mode 100644 index 00000000..312c950c --- /dev/null +++ b/serial/VirtualSerial2/ComPort/virtualserial2um.inx @@ -0,0 +1,73 @@ +; +; Copyright (C) Microsoft Corporation, All Rights Reserved. +; +; VirtualSerial.inf +; +;Installation Notes: +; Type "devcon install VirtualSerial2um.inf UMDF\VirtualSerial2um" to install + +[Version] +Signature="$Windows NT$" +Class=Ports +ClassGuid={4D36E978-E325-11CE-BFC1-08002BE10318} +Provider=%MSFTUMDF% +CatalogFile=WUDF.cat +DriverVer=03/25/2005,0.0.0.1 + +[Manufacturer] +%MSFTUMDF%=Microsoft,NT$ARCH$ + +[Microsoft.NT$ARCH$] +%VirtualSerialDeviceName%=VirtualSerial_Install,UMDF\VirtualSerial2um + +[SourceDisksFiles] +Virtualserial2um.dll=1 + +[SourceDisksNames] +1 = %MediaDescription% + +; =================== UMDF VirtualSerial Device ================================== + +[VirtualSerial_Install.NT] +CopyFiles=UMDriverCopy + +[VirtualSerial_Install.NT.hw] +AddReg=SetDeviceType_AddReg + +[VirtualSerial_Install.NT.Services] +AddService=WUDFRd,0x000001fa,WUDFRD_ServiceInstall + +[VirtualSerial_Install.NT.Wdf] +UmdfService = VirtualSerial, VirtualSerial_Install +UmdfServiceOrder = VirtualSerial +UmdfKernelModeClientPolicy = AllowKernelModeClients +UmdfFileObjectPolicy = AllowNullAndUnknownFileObjects +UmdfFsContextUsePolicy = CannotUseFsContexts + +[VirtualSerial_Install] +UmdfLibraryVersion=$UMDFVERSION$ +ServiceBinary=%12%\UMDF\Virtualserial2um.dll + +[WUDFRD_ServiceInstall] +DisplayName = %WudfRdDisplayName% +ServiceType = 1 +StartType = 3 +ErrorControl = 1 +ServiceBinary = %12%\WUDFRd.sys + +[SetDeviceType_AddReg] +HKR,,DeviceType,0x10001,0x0000001b ; 0x1b = FILE_DEVICE_SERIAL_PORT + +[DestinationDirs] +UMDriverCopy=12,UMDF ; copy to drivers\UMDF + +[UMDriverCopy] +Virtualserial2um.dll + +; =================== Generic ================================== + +[Strings] +MSFTUMDF="Microsoft" +MediaDescription="Microsoft Sample Driver Installation Media" +WudfRdDisplayName="Windows Driver Foundation - User-mode Driver Framework Reflector" +VirtualSerialDeviceName="Microsoft VirtualSerial Sample (UMDF 2)" diff --git a/serial/VirtualSerial2/ComPort/virtualserial2um.rc b/serial/VirtualSerial2/ComPort/virtualserial2um.rc new file mode 100644 index 00000000..f9f0a8d0 --- /dev/null +++ b/serial/VirtualSerial2/ComPort/virtualserial2um.rc @@ -0,0 +1,17 @@ +//--------------------------------------------------------------------------- +// Virtualserial.rc +// +// Copyright (c) Microsoft Corporation, All Rights Reserved +//--------------------------------------------------------------------------- + + +#include +#include + +#define VER_FILETYPE VFT_DLL +#define VER_FILESUBTYPE VFT_UNKNOWN +#define VER_FILEDESCRIPTION_STR "WDF:UMDF VirtualSerial User-Mode v2 Driver Sample" +#define VER_INTERNALNAME_STR "VirtualSerial2um" +#define VER_ORIGINALFILENAME_STR "Virtualserial2um.dll" + +#include "common.ver" diff --git a/serial/VirtualSerial2/FakeModem/fakemodem2um.inx b/serial/VirtualSerial2/FakeModem/fakemodem2um.inx new file mode 100644 index 00000000..31fe730d --- /dev/null +++ b/serial/VirtualSerial2/FakeModem/fakemodem2um.inx @@ -0,0 +1,193 @@ +; +; Copyright (C) Microsoft Corporation, All Rights Reserved. +; +; FakeModem.inf +; "Fakemodem" Controllerless driver illustrative example +; +; Installation Notes: +; Use toaster dynambus.sys and notify.exe to plug in a fake modem device + +[Version] +Signature="$Windows NT$" +Class=Modem +ClassGuid={4D36E96D-E325-11CE-BFC1-08002BE10318} +Provider=%MSFTUMDF% +CatalogFile=WUDF.cat +DriverVer=12/30/2010,0.0.0.1 + +[Manufacturer] +%MSFTUMDF%=Microsoft,NT$ARCH$ + +[Microsoft.NT$ARCH$] +%FakeModemDeviceName%=FakeModem_Install,{b85b7c50-6a01-11d2-b841-00c04fad5171}\fakemodem + +[SourceDisksFiles] +FakeModem2um.dll=1 + +[SourceDisksNames] +1 = %MediaDescription% + +; =================== UMDF FakeModem Device ================================== + +; The AddReg line below instructs the installer to add the registry +; entries listed in the following sections of this INF file: +; [All], [MfgAddReg], [ExtraCRLFResponses], [ModemX.AddReg], [INTERNAL] + +[FakeModem_Install.NT] +CopyFiles=UMDriverCopy +AddReg = All, MfgAddReg, ExtraCRLFResponses, ModemX.AddReg, INTERNAL + +[FakeModem_Install.NT.hw] +AddReg = LowerFilterAddReg + +[LowerFilterAddReg] +HKR,,"LowerFilters",0x00010000,WUDFRd + +[FakeModem_Install.NT.Services] +AddService=WUDFRd,0x00000000,WUDFRD_ServiceInstall + +[WUDFRD_ServiceInstall] +DisplayName = %WudfRdDisplayName% +ServiceType = 1 +StartType = 3 +ErrorControl = 1 +ServiceBinary = %12%\WUDFRd.sys + +[FakeModem_Install.NT.Wdf] +UmdfService = FakeModem, FakeModem_Install +UmdfServiceOrder = FakeModem +UmdfKernelModeClientPolicy = AllowKernelModeClients +UmdfFsContextUsePolicy = CannotUseFsContexts + +[FakeModem_Install] +UmdfLibraryVersion=$UMDFVERSION$ +ServiceBinary=%12%\UMDF\FakeModem2um.dll + +[DestinationDirs] +UMDriverCopy=12,UMDF ; copy to drivers\UMDF + +[UMDriverCopy] +FakeModem2um.dll + +;------------------------------------------------------------------------------------------------------- +; DDK procalc tool can be used to check properties settings which describes modem' properties. +; Generally, customization entries are added here which override commands from the All section + +[ModemX.AddReg] +HKR,,Properties, 1, 80,01,00,00, ff,00,00,00, ff,00,00,00, 07,00,00,00, 0f,00,00,00, f7,03,00,00, 00,c2,01,00, 40,38,00,00 +HKR,,InactivityScale, 1, 0a,00,00,00 +HKR, Settings, InactivityTimeout,, "S30=<#>" +HKR, Settings, ErrorControl_On,, "\N3" +HKR, Settings, ErrorControl_Forced,, "\N2" +HKR, Settings, Compression_On,, "%%C3" +HKR, Settings, SpeedNegotiation_Off,, "N0" +HKR, Settings, SpeedNegotiation_On,, "N1" + +;-------------------------------------------------------------------------------------------------------------------------- +;This section will define the type of modem and thus present the appropriate icon in the Device manager + +[INTERNAL] +HKR,, DeviceType, 1, 02 + +;------------------------------------------------------------------------------------------------------------------------- +; Responses section contains all of the appropriate and required responses in order for the O/S to understand the +; Modem responses to system queries. + +[All] +HKR,,ConfigDialog,,modemui.dll +HKR,,EnumPropPages,,"modemui.dll,EnumPropPages" +HKR,,PortSubClass,1,02 +HKR,Init,1,,"AT" +HKR,Init, 2,, "AT &F E0 V1 &D2 &C1 S0=0 W2 S95=47" + +[MfgAddReg] +HKR,, InactivityScale, 1, 01,00,00,00 +HKR, Monitor, 1,, "ATS0=0" +HKR, Monitor, 2,, "None" +HKR, Hangup, 1,, "ATH" +HKR, Answer, 1,, "ATA" +HKR,, Reset,, "ATZ" +HKR, Settings, Prefix,, "AT" +HKR, Settings, Terminator,, "" +HKR, Settings, DialPrefix,, "D" +HKR, Settings, DialSuffix,, ";" +HKR, Settings, SpeakerVolume_Low,, "L1" +HKR, Settings, SpeakerVolume_Med,, "L2" +HKR, Settings, SpeakerVolume_High,, "L3" +HKR, Settings, SpeakerMode_Off,, "M0" +HKR, Settings, SpeakerMode_Dial,, "M1" +HKR, Settings, SpeakerMode_On,, "M2" +HKR, Settings, SpeakerMode_Setup,, "M3" +HKR, Settings, FlowControl_Off,, "&K0" +HKR, Settings, FlowControl_Hard,, "&K3" +HKR, Settings, FlowControl_Soft,, "&K4" +HKR, Settings, ErrorControl_On,, "\N5" +HKR, Settings, ErrorControl_Off,, "\N0" +HKR, Settings, ErrorControl_Forced,, "\N4" +HKR, Settings, Compression_On,, "%%C1" +HKR, Settings, Compression_Off,, "%%C0" +HKR, Settings, Modulation_CCITT,, "B0 " +HKR, Settings, Modulation_Bell,, "B1 " +HKR, Settings, SpeedNegotiation_Off,, "*S0" +HKR, Settings, SpeedNegotiation_On,, "*S1" +HKR, Settings, Pulse,, "P" +HKR, Settings, Tone,, "T" +HKR, Settings, Blind_Off,, "X4" +HKR, Settings, Blind_On,, "X3" +HKR, Settings, CallSetupFailTimer,, "S7=<#>" + +HKR, Responses, "+FCERROR", 1, 03, 00, 00,00,00,00, 00,00,00,00 +HKR, Responses, "BLACKLISTED", 1, 03, 00, 00,00,00,00, 00,00,00,00 +HKR, Responses, "BUSY", 1, 06, 00, 00,00,00,00, 00,00,00,00 + +HKR, Responses, "CONNECT", 1, 02, 00, 00,00,00,00, 00,00,00,00 +HKR, Responses, "DATA", 1, 03, 00, 00,00,00,00, 00,00,00,00 +HKR, Responses, "DELAYED", 1, 03, 00, 00,00,00,00, 00,00,00,00 +HKR, Responses, "ERROR", 1, 03, 00, 00,00,00,00, 00,00,00,00 + +HKR, Responses, "FAX", 1, 03, 00, 00,00,00,00, 00,00,00,00 +HKR, Responses, "NO ANSWER", 1, 07, 00, 00,00,00,00, 00,00,00,00 +HKR, Responses, "NO CARRIER", 1, 04, 00, 00,00,00,00, 00,00,00,00 +HKR, Responses, "NO DIALTONE", 1, 05, 00, 00,00,00,00, 00,00,00,00 +HKR, Responses, "NOTUSED", 1, 00, 00, 00,00,00,00, 00,00,00,00 +HKR, Responses, "OK", 1, 00, 00, 00,00,00,00, 00,00,00,00 +HKR, Responses, "RING", 1, 08, 00, 00,00,00,00, 00,00,00,00 +HKR, Responses, "RINGING", 1, 01, 00, 00,00,00,00, 00,00,00,00 +HKR, Responses, "0", 1, 00, 00, 00,00,00,00, 00,00,00,00 ; OK +HKR, Responses, "1", 1, 02, 00, 00,00,00,00, 00,00,00,00 +HKR, Responses, "10", 1, 02, 00, 60,09,00,00, 00,00,00,00 +HKR, Responses, "11", 1, 02, 00, c0,12,00,00, 00,00,00,00 +HKR, Responses, "12", 1, 02, 00, 80,25,00,00, 00,00,00,00 +HKR, Responses, "13", 1, 02, 00, 20,1c,00,00, 00,00,00,00 +HKR, Responses, "14", 1, 02, 00, e0,2e,00,00, 00,00,00,00 +HKR, Responses, "15", 1, 02, 00, 40,38,00,00, 00,00,00,00 ; connect at 14400 +HKR, Responses, "2", 1, 08, 00, 00,00,00,00, 00,00,00,00 ; RING +HKR, Responses, "3", 1, 04, 00, 00,00,00,00, 00,00,00,00 ; NO CARRIER +HKR, Responses, "4", 1, 03, 00, 00,00,00,00, 00,00,00,00 ; ERROR +HKR, Responses, "5", 1, 02, 00, b0,04,00,00, 00,00,00,00 +HKR, Responses, "6", 1, 05, 00, 00,00,00,00, 00,00,00,00 ; NO DIALTONE +HKR, Responses, "69", 1, 01, 03, 00,00,00,00, 00,00,00,00 +HKR, Responses, "7", 1, 06, 00, 00,00,00,00, 00,00,00,00 ; BUSY +HKR, Responses, "70", 1, 01, 01, 00,00,00,00, 00,00,00,00 ; Protocol:None +HKR, Responses, "77", 1, 01, 02, 00,00,00,00, 00,00,00,00 ; Protocol:LAPM +HKR, Responses, "78", 1, 01, 03, 00,00,00,00, 00,00,00,00 ; Connect V42BIS +HKR, Responses, "8", 1, 07, 00, 00,00,00,00, 00,00,00,00 ; NO ANSWER +HKR, Responses, "80", 1, 01, 02, 00,00,00,00, 00,00,00,00 ; Protocol:ALT +HKR, Responses, "81", 1, 01, 02, 00,00,00,00, 00,00,00,00 + +[ExtraCRLFResponses] +HKR, Responses, "OK", 1, 00, 00, 00,00,00,00, 00,00,00,00 +HKR, Responses, "ERROR", 1, 03, 00, 00,00,00,00, 00,00,00,00 +HKR, Responses, "BUSY", 1, 06, 00, 00,00,00,00, 00,00,00,00 +HKR, Responses, "NO ANSWER", 1, 07, 00, 00,00,00,00, 00,00,00,00 +HKR, Responses, "NO CARRIER", 1, 04, 00, 00,00,00,00, 00,00,00,00 +HKR, Responses, "NO DIALTONE", 1, 05, 00, 00,00,00,00, 00,00,00,00 + + +; =================== Generic ================================== + +[Strings] +MSFTUMDF="Microsoft" +MediaDescription="Microsoft Sample Driver Installation Media" +WudfRdDisplayName="Windows Driver Foundation - User-mode Driver Framework Reflector" +FakeModemDeviceName="Microsoft Fake Modem User-Mode Device Sample" diff --git a/serial/VirtualSerial2/FakeModem/fakemodem2um.rc b/serial/VirtualSerial2/FakeModem/fakemodem2um.rc new file mode 100644 index 00000000..7d916be2 --- /dev/null +++ b/serial/VirtualSerial2/FakeModem/fakemodem2um.rc @@ -0,0 +1,17 @@ +//--------------------------------------------------------------------------- +// FakeModem.rc +// +// Copyright (c) Microsoft Corporation, All Rights Reserved +//--------------------------------------------------------------------------- + + +#include +#include + +#define VER_FILETYPE VFT_DLL +#define VER_FILESUBTYPE VFT_UNKNOWN +#define VER_FILEDESCRIPTION_STR "WDF:UMDF Fake Modem User-Mode Driver Sample" +#define VER_INTERNALNAME_STR "FakeModem2um" +#define VER_ORIGINALFILENAME_STR "FakeModem2um.dll" + +#include "common.ver" diff --git a/serial/VirtualSerial2/FakeModem/fakemodem2um.vcxproj b/serial/VirtualSerial2/FakeModem/fakemodem2um.vcxproj new file mode 100644 index 00000000..584aa824 --- /dev/null +++ b/serial/VirtualSerial2/FakeModem/fakemodem2um.vcxproj @@ -0,0 +1,194 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {6F515009-0F48-480C-8EDC-4423269D1076} + $(MSBuildProjectName) + 2 + Debug + Win32 + {69E9B9C0-51CD-40CF-BFBA-291563913487} + + + + Windows10 + False + Universal + UMDF + WindowsUserModeDriver10.0 + DynamicLibrary + + + Windows10 + True + Universal + UMDF + WindowsUserModeDriver10.0 + DynamicLibrary + + + Windows10 + False + Universal + UMDF + WindowsUserModeDriver10.0 + DynamicLibrary + + + Windows10 + True + Universal + UMDF + WindowsUserModeDriver10.0 + DynamicLibrary + + + + $(IntDir) + + + + + + + + + + + + + + + + $(InfArch) + true + .\$(IntDir)\fakemodem2um.inf + + + + fakemodem2um + + + fakemodem2um + + + fakemodem2um + + + fakemodem2um + + + + %(PreprocessorDefinitions);_UNICODE;UNICODE;_FAKE_MODEM=1 + %(AdditionalIncludeDirectories);$(DDK_INC_PATH)\wdm;..\..\inc + + + + + %(PreprocessorDefinitions);_UNICODE;UNICODE;_FAKE_MODEM=1 + %(AdditionalIncludeDirectories);$(DDK_INC_PATH)\wdm;..\..\inc + + + %(PreprocessorDefinitions);_UNICODE;UNICODE;_FAKE_MODEM=1 + %(AdditionalIncludeDirectories);$(DDK_INC_PATH)\wdm;..\..\inc + + + %(AdditionalDependencies);$(SDK_LIB_PATH)\mincore.lib + + + + + %(PreprocessorDefinitions);_UNICODE;UNICODE;_FAKE_MODEM=1 + %(AdditionalIncludeDirectories);$(DDK_INC_PATH)\wdm;..\..\inc + + + + + %(PreprocessorDefinitions);_UNICODE;UNICODE;_FAKE_MODEM=1 + %(AdditionalIncludeDirectories);$(DDK_INC_PATH)\wdm;..\..\inc + + + %(PreprocessorDefinitions);_UNICODE;UNICODE;_FAKE_MODEM=1 + %(AdditionalIncludeDirectories);$(DDK_INC_PATH)\wdm;..\..\inc + + + %(AdditionalDependencies);$(SDK_LIB_PATH)\mincore.lib + + + + + %(PreprocessorDefinitions);_UNICODE;UNICODE;_FAKE_MODEM=1 + %(AdditionalIncludeDirectories);$(DDK_INC_PATH)\wdm;..\..\inc + + + + + %(PreprocessorDefinitions);_UNICODE;UNICODE;_FAKE_MODEM=1 + %(AdditionalIncludeDirectories);$(DDK_INC_PATH)\wdm;..\..\inc + + + %(PreprocessorDefinitions);_UNICODE;UNICODE;_FAKE_MODEM=1 + %(AdditionalIncludeDirectories);$(DDK_INC_PATH)\wdm;..\..\inc + + + %(AdditionalDependencies);$(SDK_LIB_PATH)\mincore.lib + + + + + %(PreprocessorDefinitions);_UNICODE;UNICODE;_FAKE_MODEM=1 + %(AdditionalIncludeDirectories);$(DDK_INC_PATH)\wdm;..\..\inc + + + + + %(PreprocessorDefinitions);_UNICODE;UNICODE;_FAKE_MODEM=1 + %(AdditionalIncludeDirectories);$(DDK_INC_PATH)\wdm;..\..\inc + + + %(PreprocessorDefinitions);_UNICODE;UNICODE;_FAKE_MODEM=1 + %(AdditionalIncludeDirectories);$(DDK_INC_PATH)\wdm;..\..\inc + + + %(AdditionalDependencies);$(SDK_LIB_PATH)\mincore.lib + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/serial/VirtualSerial2/FakeModem/fakemodem2um.vcxproj.Filters b/serial/VirtualSerial2/FakeModem/fakemodem2um.vcxproj.Filters new file mode 100644 index 00000000..5067a79b --- /dev/null +++ b/serial/VirtualSerial2/FakeModem/fakemodem2um.vcxproj.Filters @@ -0,0 +1,48 @@ + + + + + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* + {6E68FD79-4D9F-4503-A0B5-3EFA5BC16118} + + + h;hpp;hxx;hm;inl;inc;xsd + {009A35E7-F389-45E7-87EF-C71F6ED40D4A} + + + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml + {6351F996-859F-4432-9FE1-82A5C2B6D89B} + + + inf;inv;inx;mof;mc; + {42391772-ED65-4368-9478-D821892B39BA} + + + + + Driver Files + + + Driver Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Resource Files + + + \ No newline at end of file diff --git a/serial/VirtualSerial2/ReadMe.md b/serial/VirtualSerial2/ReadMe.md new file mode 100644 index 00000000..2b1bc513 --- /dev/null +++ b/serial/VirtualSerial2/ReadMe.md @@ -0,0 +1,59 @@ +Virtual serial driver sample +============================ + +This sample demonstrates these two serial drivers: + +- A simple virtual serial driver (ComPort) +- A controller-less modem driver (FakeModem).This driver supports sending and receiving AT commands using the ReadFile and WriteFile calls or via a TAPI interface using an application such as, HyperTerminal. + +This sample driver is a minimal driver meant to demonstrate the usage of the User-Mode Driver Framework. It is not intended for use in a production environment. + +For more information, see [Serial Controller and Device Drivers](http://msdn.microsoft.com/en-us/library/windows/hardware/ff546939) in the WDK documentation. + +Code tour +--------- + +File manifest + +Description + +comsup.cpp & comsup.h + +COM Support code - specifically base classes which provide implementations for the standard COM interfaces **IUnknown** and **IClassFactory** which are used throughout the sample. + +The implementation of **IClassFactory** is designed to create instances of the CMyDriver class. If you should change the name of your base driver class, you would also need to modify this file. + +dllsup.cpp + +DLL Support code - provides the DLL's entry point as well as the single required export (**DllGetClassObject**). + +These depend on comsup.cpp to perform the necessary class creation. + +exports.def + +This file lists the functions that the driver DLL exports. + +internal.h + +This is the main header file for the sample driver. + +driver.cpp & driver.h + +Definition and implementation of the driver callback class (CMyDriver) for the sample. This includes **DriverEntry** and events on the framework driver object. + +device.cpp & driver.h + +Definition and implementation of the device callback class (CMyDriver) for the sample. This includes events on the framework device object. + +queue.cpp & queue.h + +Definition and implementation of the base queue callback class (CMyQueue). This includes events on the framework I/O queue object. + +VirtualSerial.rc /FakeModem.rc + +This file defines resource information for the sample driver. + +VirtualSerial.inf / FakeModem.inf + +INF file that contains installation information for this driver. + diff --git a/serial/VirtualSerial2/VirtualSerial.sln b/serial/VirtualSerial2/VirtualSerial.sln new file mode 100644 index 00000000..79e3f2b0 --- /dev/null +++ b/serial/VirtualSerial2/VirtualSerial.sln @@ -0,0 +1,46 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0 +MinimumVisualStudioVersion = 12.0 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ComPort", "ComPort", "{69B24279-DAE7-4F6B-AB01-D5399C616D6F}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "FakeModem", "FakeModem", "{231410A2-76BA-4213-95C7-523B902B21E1}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "VirtualSerial2um", "ComPort\VirtualSerial2um.vcxproj", "{9C376D98-E44B-44C6-BA97-C41F501548E6}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fakemodem2um", "FakeModem\fakemodem2um.vcxproj", "{6F515009-0F48-480C-8EDC-4423269D1076}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {9C376D98-E44B-44C6-BA97-C41F501548E6}.Debug|Win32.ActiveCfg = Debug|Win32 + {9C376D98-E44B-44C6-BA97-C41F501548E6}.Debug|Win32.Build.0 = Debug|Win32 + {9C376D98-E44B-44C6-BA97-C41F501548E6}.Release|Win32.ActiveCfg = Release|Win32 + {9C376D98-E44B-44C6-BA97-C41F501548E6}.Release|Win32.Build.0 = Release|Win32 + {9C376D98-E44B-44C6-BA97-C41F501548E6}.Debug|x64.ActiveCfg = Debug|x64 + {9C376D98-E44B-44C6-BA97-C41F501548E6}.Debug|x64.Build.0 = Debug|x64 + {9C376D98-E44B-44C6-BA97-C41F501548E6}.Release|x64.ActiveCfg = Release|x64 + {9C376D98-E44B-44C6-BA97-C41F501548E6}.Release|x64.Build.0 = Release|x64 + {6F515009-0F48-480C-8EDC-4423269D1076}.Debug|Win32.ActiveCfg = Debug|Win32 + {6F515009-0F48-480C-8EDC-4423269D1076}.Debug|Win32.Build.0 = Debug|Win32 + {6F515009-0F48-480C-8EDC-4423269D1076}.Release|Win32.ActiveCfg = Release|Win32 + {6F515009-0F48-480C-8EDC-4423269D1076}.Release|Win32.Build.0 = Release|Win32 + {6F515009-0F48-480C-8EDC-4423269D1076}.Debug|x64.ActiveCfg = Debug|x64 + {6F515009-0F48-480C-8EDC-4423269D1076}.Debug|x64.Build.0 = Debug|x64 + {6F515009-0F48-480C-8EDC-4423269D1076}.Release|x64.ActiveCfg = Release|x64 + {6F515009-0F48-480C-8EDC-4423269D1076}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {9C376D98-E44B-44C6-BA97-C41F501548E6} = {69B24279-DAE7-4F6B-AB01-D5399C616D6F} + {6F515009-0F48-480C-8EDC-4423269D1076} = {231410A2-76BA-4213-95C7-523B902B21E1} + EndGlobalSection +EndGlobal diff --git a/serial/VirtualSerial2/device.c b/serial/VirtualSerial2/device.c new file mode 100644 index 00000000..78bd463b --- /dev/null +++ b/serial/VirtualSerial2/device.c @@ -0,0 +1,449 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved. + +Module Name: + + Device.c + +Abstract: + + This module contains the implementation of the VirtualSerial sample + driver's device callback object. + + The VirtualSerial sample device does very little. It does not implement + either of the PNP interfaces so once the device is setup, it won't ever get + any callbacks until the device is removed. + +Environment: + + Windows Driver Framework + +--*/ + +#include "internal.h" + +NTSTATUS +DeviceCreate( + _In_ WDFDRIVER Driver, + _In_ PWDFDEVICE_INIT DeviceInit, + _Out_ PDEVICE_CONTEXT *DeviceContext + ) +/*++ + + Routine Description: + + This method creates and initializs an instance of the VirtualSerial driver's + device callback object. + + Arguments: + + FxDeviceInit - the settings for the device. + + Device - a location to store the referenced pointer to the device object. + + Return Value: + + Status + +--*/ +{ + NTSTATUS status; + WDF_OBJECT_ATTRIBUTES deviceAttributes; + WDFDEVICE device; + PDEVICE_CONTEXT deviceContext; + UNREFERENCED_PARAMETER (Driver); + + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE( + &deviceAttributes, + DEVICE_CONTEXT); + + deviceAttributes.SynchronizationScope = WdfSynchronizationScopeDevice; + deviceAttributes.EvtCleanupCallback = EvtDeviceCleanup; + + status = WdfDeviceCreate(&DeviceInit, + &deviceAttributes, + &device); + if (!NT_SUCCESS(status)) { + Trace(TRACE_LEVEL_ERROR, + "Error: WdfDeviceCreate failed 0x%x", status); + return status; + } + + deviceContext = GetDeviceContext(device); + deviceContext->Device = device; + + *DeviceContext = deviceContext; + + return status; +} + + +NTSTATUS +DeviceConfigure( + _In_ PDEVICE_CONTEXT DeviceContext + ) +/*++ + + Routine Description: + + This method is called after the device callback object has been initialized + and returned to the driver. It would setup the device's queues and their + corresponding callback objects. + + Arguments: + + FxDevice - the framework device object for which we're handling events. + + Return Value: + + status + +--*/ +{ + NTSTATUS status; + WDFDEVICE device = DeviceContext->Device; + WDFKEY key; + LPGUID guid; + errno_t errorNo; + + DECLARE_CONST_UNICODE_STRING(portName, REG_VALUENAME_PORTNAME); + DECLARE_UNICODE_STRING_SIZE (comPort, 10); + DECLARE_UNICODE_STRING_SIZE (symbolicLinkName, SYMBOLIC_LINK_NAME_LENGTH); + +#ifdef _FAKE_MODEM + // + // Compiled as fake modem + // + guid = (LPGUID) &GUID_DEVINTERFACE_MODEM; +#else + // + // Compiled as virtual serial port + // + guid = (LPGUID) &GUID_DEVINTERFACE_COMPORT; +#endif + + // + // Create device interface + // + status = WdfDeviceCreateDeviceInterface( + device, + guid, + NULL); + if (!NT_SUCCESS(status)) { + Trace(TRACE_LEVEL_ERROR, + "Error: Cannot create device interface"); + goto Exit; + } + + // + // Read the COM port number from the registry, which has been automatically + // created by "MsPorts!PortsClassInstaller" if INF file says "Class=Ports" + // + status = WdfDeviceOpenRegistryKey( + device, + PLUGPLAY_REGKEY_DEVICE, + KEY_QUERY_VALUE, + WDF_NO_OBJECT_ATTRIBUTES, + &key); + if (!NT_SUCCESS(status)) { + Trace(TRACE_LEVEL_ERROR, + "Error: Failed to retrieve device hardware key root"); + goto Exit; + } + + status = WdfRegistryQueryUnicodeString( + key, + &portName, + NULL, + &comPort); + if (!NT_SUCCESS(status)) { + Trace(TRACE_LEVEL_ERROR, + "Error: Failed to read PortName"); + goto Exit; + } + + // + // Manually create the symbolic link name. Length is the length in + // bytes not including the NULL terminator. + // + // 6054 and 26035 are code analysis warnings that comPort.Buffer might + // not be NULL terminated, while we know that they are. + // + #pragma warning(suppress: 6054 26035) + symbolicLinkName.Length = (USHORT)((wcslen(comPort.Buffer) * sizeof(wchar_t)) + + sizeof(SYMBOLIC_LINK_NAME_PREFIX) - sizeof(UNICODE_NULL)); + + if (symbolicLinkName.Length >= symbolicLinkName.MaximumLength) { + + Trace(TRACE_LEVEL_ERROR, "Error: Buffer overflow when creating COM port name. Size" + " is %d, buffer length is %d", symbolicLinkName.Length, symbolicLinkName.MaximumLength); + status = STATUS_BUFFER_OVERFLOW; + goto Exit; + } + + errorNo = wcscpy_s(symbolicLinkName.Buffer, + SYMBOLIC_LINK_NAME_LENGTH, + SYMBOLIC_LINK_NAME_PREFIX); + + if (errorNo != 0) { + Trace(TRACE_LEVEL_ERROR, + "Failed to copy %ws to buffer with error %d", + SYMBOLIC_LINK_NAME_PREFIX, errorNo); + status = STATUS_INVALID_PARAMETER; + goto Exit; + } + + errorNo = wcscat_s(symbolicLinkName.Buffer, + SYMBOLIC_LINK_NAME_LENGTH, + comPort.Buffer); + + if (errorNo != 0) { + Trace(TRACE_LEVEL_ERROR, + "Failed to copy %ws to buffer with error %d", + comPort.Buffer, errorNo); + status = STATUS_INVALID_PARAMETER; + goto Exit; + } + + // + // Create symbolic link + // + status = WdfDeviceCreateSymbolicLink( + device, + &symbolicLinkName); + if (!NT_SUCCESS(status)) { + Trace(TRACE_LEVEL_ERROR, + "Error: Cannot create symbolic link %ws", symbolicLinkName.Buffer); + goto Exit; + } + + status = DeviceGetPdoName(DeviceContext); + if (!NT_SUCCESS(status)) { + goto Exit; + } + + status = DeviceWriteLegacyHardwareKey( + DeviceContext->PdoName, + comPort.Buffer, + DeviceContext->Device); + if (NT_SUCCESS(status)) { + DeviceContext->CreatedLegacyHardwareKey = TRUE; + } + + status = QueueCreate(DeviceContext); + if (!NT_SUCCESS(status)) { + goto Exit; + } + +Exit: + return status; +} + + +NTSTATUS +DeviceGetPdoName( + _In_ PDEVICE_CONTEXT DeviceContext + ) +{ + NTSTATUS status; + WDFDEVICE device = DeviceContext->Device; + WDF_OBJECT_ATTRIBUTES attributes; + WDFMEMORY memory; + + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + attributes.ParentObject = device; + + status = WdfDeviceAllocAndQueryProperty( + device, + DevicePropertyPhysicalDeviceObjectName, + NonPagedPool, + &attributes, + &memory); + if (!NT_SUCCESS(status)) { + Trace(TRACE_LEVEL_ERROR, + "Error: Failed to query PDO name"); + goto Exit; + } + + DeviceContext->PdoName = (PWCHAR) WdfMemoryGetBuffer(memory, NULL); + Trace(TRACE_LEVEL_ERROR, + "PDO Name is %ws", DeviceContext->PdoName); + +Exit: + return status; +} + + +NTSTATUS +DeviceWriteLegacyHardwareKey( + _In_ PWSTR PdoName, + _In_ PWSTR ComPort, + _In_ WDFDEVICE Device + ) +{ + WDFKEY key = NULL; + NTSTATUS status; + UNICODE_STRING pdoString = {0}; + UNICODE_STRING comPort = {0}; + + DECLARE_CONST_UNICODE_STRING(deviceSubkey, SERIAL_DEVICE_MAP); + + RtlInitUnicodeString(&pdoString, PdoName); + RtlInitUnicodeString(&comPort, ComPort); + + status = WdfDeviceOpenDevicemapKey(Device, + &deviceSubkey, + KEY_SET_VALUE, + WDF_NO_OBJECT_ATTRIBUTES, + &key); + if (!NT_SUCCESS(status)) { + Trace(TRACE_LEVEL_ERROR, + "Error: Failed to open DEVICEMAP\\SERIALCOMM key 0x%x", status); + goto exit; + } + + status = WdfRegistryAssignUnicodeString(key, + &pdoString, + &comPort); + + if (!NT_SUCCESS(status)) { + Trace(TRACE_LEVEL_ERROR, + "Error: Failed to write to DEVICEMAP\\SERIALCOMM key 0x%x", status); + goto exit; + } + +exit: + + if (key != NULL) { + WdfRegistryClose(key); + key = NULL; + } + + return status; +} + + +VOID +EvtDeviceCleanup( + _In_ WDFOBJECT Object + ) +{ + WDFDEVICE device = (WDFDEVICE) Object; + PDEVICE_CONTEXT deviceContext = GetDeviceContext(device); + NTSTATUS status; + WDFKEY key = NULL; + UNICODE_STRING pdoString = {0}; + + DECLARE_CONST_UNICODE_STRING(deviceSubkey, SERIAL_DEVICE_MAP); + + if (deviceContext->CreatedLegacyHardwareKey == TRUE) { + + RtlInitUnicodeString(&pdoString, deviceContext->PdoName); + + status = WdfDeviceOpenDevicemapKey(device, + &deviceSubkey, + KEY_SET_VALUE, + WDF_NO_OBJECT_ATTRIBUTES, + &key); + + if (!NT_SUCCESS(status)) { + Trace(TRACE_LEVEL_ERROR, + "Error: Failed to open DEVICEMAP\\SERIALCOMM key 0x%x", status); + goto exit; + } + + status = WdfRegistryRemoveValue(key, + &pdoString); + if (!NT_SUCCESS(status)) { + Trace(TRACE_LEVEL_ERROR, + "Error: Failed to delete %S key, 0x%x", pdoString.Buffer, status); + goto exit; + } + + status = WdfRegistryRemoveKey(key); + if (!NT_SUCCESS(status)) { + Trace(TRACE_LEVEL_ERROR, + "Error: Failed to delete %S, 0x%x", SERIAL_DEVICE_MAP, status); + goto exit; + } + } + +exit: + + if (key != NULL) { + WdfRegistryClose(key); + key = NULL; + } + + return; +} + + +ULONG +GetBaudRate( + _In_ PDEVICE_CONTEXT DeviceContext + ) +{ + return DeviceContext->BaudRate; +} + +VOID +SetBaudRate( + _In_ PDEVICE_CONTEXT DeviceContext, + _In_ ULONG BaudRate + ) +{ + DeviceContext->BaudRate = BaudRate; +} + +ULONG * +GetModemControlRegisterPtr( + _In_ PDEVICE_CONTEXT DeviceContext + ) +{ + return &DeviceContext->ModemControlRegister; +} + +ULONG * +GetFifoControlRegisterPtr( + _In_ PDEVICE_CONTEXT DeviceContext + ) +{ + return &DeviceContext->FifoControlRegister; +} + +ULONG * +GetLineControlRegisterPtr( + _In_ PDEVICE_CONTEXT DeviceContext + ) +{ + return &DeviceContext->LineControlRegister; +} + +VOID +SetValidDataMask( + _In_ PDEVICE_CONTEXT DeviceContext, + _In_ UCHAR Mask + ) +{ + DeviceContext->ValidDataMask = Mask; +} + +VOID +SetTimeouts( + _In_ PDEVICE_CONTEXT DeviceContext, + _In_ SERIAL_TIMEOUTS Timeouts + ) +{ + DeviceContext->Timeouts = Timeouts; +} + +VOID +GetTimeouts( + _In_ PDEVICE_CONTEXT DeviceContext, + _Out_ SERIAL_TIMEOUTS *Timeouts + ) +{ + *Timeouts = DeviceContext->Timeouts; +} diff --git a/serial/VirtualSerial2/device.h b/serial/VirtualSerial2/device.h new file mode 100644 index 00000000..e2718841 --- /dev/null +++ b/serial/VirtualSerial2/device.h @@ -0,0 +1,122 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved + +Module Name: + + Device.h + +Abstract: + + This module contains the type definitions for the VirtualSerial sample + driver's device callback class. + +Environment: + + Windows Driver Framework + +--*/ + +#pragma once + +#define SYMBOLIC_LINK_NAME_LENGTH 32 +#define SYMBOLIC_LINK_NAME_PREFIX L"\\DosDevices\\Global\\" +#define REG_PATH_DEVICEMAP L"HARDWARE\\DEVICEMAP" +#define SERIAL_DEVICE_MAP L"SERIALCOMM" +#define REG_VALUENAME_PORTNAME L"PortName" +#define REG_PATH_SERIALCOMM REG_PATH_DEVICEMAP L"\\" SERIAL_DEVICE_MAP + +typedef struct _DEVICE_CONTEXT +{ + WDFDEVICE Device; + + ULONG BaudRate; + + ULONG ModemControlRegister; + + ULONG FifoControlRegister; + + ULONG LineControlRegister; + + UCHAR ValidDataMask; + + SERIAL_TIMEOUTS Timeouts; + + BOOLEAN CreatedLegacyHardwareKey; + + PWSTR PdoName; + +} DEVICE_CONTEXT, *PDEVICE_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(DEVICE_CONTEXT, GetDeviceContext); + + +NTSTATUS +DeviceCreate( + _In_ WDFDRIVER Driver, + _In_ PWDFDEVICE_INIT DeviceInit, + _Out_ PDEVICE_CONTEXT *DeviceContext + ); + +NTSTATUS +DeviceConfigure( + _In_ PDEVICE_CONTEXT DeviceContext + ); + +NTSTATUS +DeviceGetPdoName( + _In_ PDEVICE_CONTEXT DeviceContext + ); + +NTSTATUS +DeviceWriteLegacyHardwareKey( + _In_ PWSTR PdoName, + _In_ PWSTR ComPort, + _In_ WDFDEVICE Device + ); + +EVT_WDF_DEVICE_CONTEXT_CLEANUP EvtDeviceCleanup; + +ULONG +GetBaudRate( + _In_ PDEVICE_CONTEXT DeviceContext + ); + +VOID +SetBaudRate( + _In_ PDEVICE_CONTEXT DeviceContext, + _In_ ULONG BaudRate + ); + +ULONG * +GetModemControlRegisterPtr( + _In_ PDEVICE_CONTEXT DeviceContext + ); + +ULONG * +GetFifoControlRegisterPtr( + _In_ PDEVICE_CONTEXT DeviceContext + ); + +ULONG * +GetLineControlRegisterPtr( + _In_ PDEVICE_CONTEXT DeviceContext + ); + +VOID +SetValidDataMask( + _In_ PDEVICE_CONTEXT DeviceContext, + _In_ UCHAR Mask + ); + +VOID +SetTimeouts( + _In_ PDEVICE_CONTEXT DeviceContext, + _In_ SERIAL_TIMEOUTS Timeouts + ); + +VOID +GetTimeouts( + _In_ PDEVICE_CONTEXT DeviceContext, + _Out_ SERIAL_TIMEOUTS *Timeouts + ); \ No newline at end of file diff --git a/serial/VirtualSerial2/driver.c b/serial/VirtualSerial2/driver.c new file mode 100644 index 00000000..bb7f4c73 --- /dev/null +++ b/serial/VirtualSerial2/driver.c @@ -0,0 +1,72 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved. + +Module Name: + + Driver.c + +Abstract: + + This module contains the implementation of the VirtualSerial Sample's + core driver callback object. + +Environment: + + Windows Driver Framework + +--*/ + +#include +#include "internal.h" + +NTSTATUS +DriverEntry( + _In_ PDRIVER_OBJECT DriverObject, + _In_ PUNICODE_STRING RegistryPath + ) +{ + NTSTATUS status; + WDF_DRIVER_CONFIG driverConfig; + + WDF_DRIVER_CONFIG_INIT(&driverConfig, + EvtDeviceAdd); + + status = WdfDriverCreate(DriverObject, + RegistryPath, + WDF_NO_OBJECT_ATTRIBUTES, + &driverConfig, + WDF_NO_HANDLE); + if (!NT_SUCCESS(status)) { + Trace(TRACE_LEVEL_ERROR, + "Error: WdfDriverCreate failed 0x%x", status); + return status; + } + + return status; +} + +NTSTATUS +EvtDeviceAdd( + _In_ WDFDRIVER Driver, + _Inout_ PWDFDEVICE_INIT DeviceInit + ) +{ + NTSTATUS status; + PDEVICE_CONTEXT deviceContext; + + status = DeviceCreate(Driver, + DeviceInit, + &deviceContext); + if (!NT_SUCCESS(status)) { + return status; + } + + status = DeviceConfigure(deviceContext); + if (!NT_SUCCESS(status)) { + return status; + } + + return status; +} + diff --git a/serial/VirtualSerial2/driver.h b/serial/VirtualSerial2/driver.h new file mode 100644 index 00000000..787cef02 --- /dev/null +++ b/serial/VirtualSerial2/driver.h @@ -0,0 +1,30 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved + +Module Name: + + Driver.h + +Abstract: + + This module contains the type definitions for the VirtualSerial sample's + driver callback class. + +Environment: + + Windows Driver Framework + +--*/ + +#pragma once + +// +// This class handles driver events for the VirtualSerial sample. In particular +// it supports the OnDeviceAdd event, which occurs when the driver is called +// to setup per-device handlers for a new device stack. +// + +DRIVER_INITIALIZE DriverEntry; + +EVT_WDF_DRIVER_DEVICE_ADD EvtDeviceAdd; diff --git a/serial/VirtualSerial2/internal.h b/serial/VirtualSerial2/internal.h new file mode 100644 index 00000000..82c149e3 --- /dev/null +++ b/serial/VirtualSerial2/internal.h @@ -0,0 +1,58 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved + +Module Name: + + Internal.h + +Abstract: + + This module contains the local type definitions for the VirtualSerial + driver sample. + +Environment: + + Windows Driver Framework + +--*/ + +#pragma once + +#ifdef _KERNEL_MODE +#include +#else +#include +#endif + +#include + +#define _NTDEF_ + +// +// Include the type specific headers. +// +#include "serial.h" +#include "driver.h" +#include "device.h" +#include "ringbuffer.h" +#include "queue.h" + +// +// Tracing and Assert +// + +#define Trace(level, _fmt_, ...) \ + DbgPrintEx(DPFLTR_DEFAULT_ID, level, \ + _fmt_ "\n", __VA_ARGS__) + +#define TRACE_LEVEL_ERROR DPFLTR_ERROR_LEVEL +#define TRACE_LEVEL_INFO DPFLTR_INFO_LEVEL + +#ifndef ASSERT +#define ASSERT(exp) { \ + if (!(exp)) { \ + RtlAssert(#exp, __FILE__, __LINE__, NULL); \ + } \ +} +#endif \ No newline at end of file diff --git a/serial/VirtualSerial2/queue.c b/serial/VirtualSerial2/queue.c new file mode 100644 index 00000000..80571b42 --- /dev/null +++ b/serial/VirtualSerial2/queue.c @@ -0,0 +1,963 @@ +/*++ + +Copyright (c) Microsoft Corporation, All Rights Reserved + +Module Name: + + Queue.c + +Abstract: + + This file implements the I/O queue interface and performs + the read/write/ioctl operations. + +Environment: + + Windows Driver Framework + +--*/ + + +#include "internal.h" + +NTSTATUS +QueueCreate( + _In_ PDEVICE_CONTEXT DeviceContext + ) +{ + NTSTATUS status; + WDFDEVICE device = DeviceContext->Device; + WDF_IO_QUEUE_CONFIG queueConfig; + WDF_OBJECT_ATTRIBUTES queueAttributes; + WDFQUEUE queue; + PQUEUE_CONTEXT queueContext; + + // + // Create the default queue + // + + WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE( + &queueConfig, + WdfIoQueueDispatchParallel); + + queueConfig.EvtIoRead = EvtIoRead; + queueConfig.EvtIoWrite = EvtIoWrite; + queueConfig.EvtIoDeviceControl = EvtIoDeviceControl; + + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE( + &queueAttributes, + QUEUE_CONTEXT); + + status = WdfIoQueueCreate( + device, + &queueConfig, + &queueAttributes, + &queue); + + if( !NT_SUCCESS(status) ) { + Trace(TRACE_LEVEL_ERROR, + "Error: WdfIoQueueCreate failed 0x%x", status); + return status; + } + + queueContext = GetQueueContext(queue); + queueContext->Queue = queue; + queueContext->DeviceContext = DeviceContext; + + // + // Create a manual queue to hold pending read requests. By keeping + // them in the queue, framework takes care of cancelling them if the app + // exits + // + + WDF_IO_QUEUE_CONFIG_INIT( + &queueConfig, + WdfIoQueueDispatchManual); + + status = WdfIoQueueCreate( + device, + &queueConfig, + WDF_NO_OBJECT_ATTRIBUTES, + &queue); + + if( !NT_SUCCESS(status) ) { + Trace(TRACE_LEVEL_ERROR, + "Error: WdfIoQueueCreate manual queue failed 0x%x", status); + return status; + } + + queueContext->ReadQueue = queue; + + // + // Create another manual queue to hold pending IOCTL_SERIAL_WAIT_ON_MASK + // + + WDF_IO_QUEUE_CONFIG_INIT( + &queueConfig, + WdfIoQueueDispatchManual); + + status = WdfIoQueueCreate( + device, + &queueConfig, + WDF_NO_OBJECT_ATTRIBUTES, + &queue); + + if( !NT_SUCCESS(status) ) { + Trace(TRACE_LEVEL_ERROR, + "Error: WdfIoQueueCreate manual queue failed 0x%x", status); + return status; + } + + queueContext->WaitMaskQueue = queue; + + RingBufferInitialize(&queueContext->RingBuffer, + queueContext->Buffer, + sizeof(queueContext->Buffer)); + + return status; +} + + +NTSTATUS +RequestCopyFromBuffer( + _In_ WDFREQUEST Request, + _In_ PVOID SourceBuffer, + _In_ size_t NumBytesToCopyFrom + ) +{ + NTSTATUS status; + WDFMEMORY memory; + + status = WdfRequestRetrieveOutputMemory(Request, &memory); + if( !NT_SUCCESS(status) ) { + Trace(TRACE_LEVEL_ERROR, + "Error: WdfRequestRetrieveOutputMemory failed 0x%x", status); + return status; + } + + status = WdfMemoryCopyFromBuffer(memory, 0, + SourceBuffer, NumBytesToCopyFrom); + if( !NT_SUCCESS(status) ) { + Trace(TRACE_LEVEL_ERROR, + "Error: WdfMemoryCopyFromBuffer failed 0x%x", status); + return status; + } + + WdfRequestSetInformation(Request, NumBytesToCopyFrom); + return status; +} + + +NTSTATUS +RequestCopyToBuffer( + _In_ WDFREQUEST Request, + _In_ PVOID DestinationBuffer, + _In_ size_t NumBytesToCopyTo + ) +{ + NTSTATUS status; + WDFMEMORY memory; + + status = WdfRequestRetrieveInputMemory(Request, &memory); + if( !NT_SUCCESS(status) ) { + Trace(TRACE_LEVEL_ERROR, + "Error: WdfRequestRetrieveInputMemory failed 0x%x", status); + return status; + } + + status = WdfMemoryCopyToBuffer(memory, 0, + DestinationBuffer, NumBytesToCopyTo); + if( !NT_SUCCESS(status) ) { + Trace(TRACE_LEVEL_ERROR, + "Error: WdfMemoryCopyToBuffer failed 0x%x", status); + return status; + } + + WdfRequestSetInformation(Request, NumBytesToCopyTo); + return status; +} + + +VOID +EvtIoDeviceControl( + _In_ WDFQUEUE Queue, + _In_ WDFREQUEST Request, + _In_ size_t OutputBufferLength, + _In_ size_t InputBufferLength, + _In_ ULONG IoControlCode + ) +{ + NTSTATUS status; + PQUEUE_CONTEXT queueContext = GetQueueContext(Queue); + PDEVICE_CONTEXT deviceContext = queueContext->DeviceContext; + UNREFERENCED_PARAMETER (OutputBufferLength); + UNREFERENCED_PARAMETER (InputBufferLength); + + Trace(TRACE_LEVEL_INFO, + "EvtIoDeviceControl 0x%x", IoControlCode); + + switch (IoControlCode) + { + + case IOCTL_SERIAL_SET_BAUD_RATE: + { + // + // This is a driver for a virtual serial port. Since there is no + // actual hardware, we just store the baud rate and don't do + // anything with it. + // + SERIAL_BAUD_RATE baudRateBuffer = {0}; + + status = RequestCopyToBuffer(Request, + &baudRateBuffer, + sizeof(baudRateBuffer)); + + if( NT_SUCCESS(status) ) { + SetBaudRate(deviceContext, baudRateBuffer.BaudRate); + }; + break; + } + + case IOCTL_SERIAL_GET_BAUD_RATE: + { + SERIAL_BAUD_RATE baudRateBuffer = {0}; + + baudRateBuffer.BaudRate = GetBaudRate(deviceContext); + + status = RequestCopyFromBuffer(Request, + &baudRateBuffer, + sizeof(baudRateBuffer)); + break; + } + + case IOCTL_SERIAL_SET_MODEM_CONTROL: + { + // + // This is a driver for a virtual serial port. Since there is no + // actual hardware, we just store the modem control register + // configuration and don't do anything with it. + // + ULONG *modemControlRegister = GetModemControlRegisterPtr(deviceContext); + + ASSERT(modemControlRegister); + + status = RequestCopyToBuffer(Request, + modemControlRegister, + sizeof(ULONG)); + break; + } + + case IOCTL_SERIAL_GET_MODEM_CONTROL: + { + ULONG *modemControlRegister = GetModemControlRegisterPtr(deviceContext); + + ASSERT(modemControlRegister); + + status = RequestCopyFromBuffer(Request, + modemControlRegister, + sizeof(ULONG)); + break; + } + + case IOCTL_SERIAL_SET_FIFO_CONTROL: + { + // + // This is a driver for a virtual serial port. Since there is no + // actual hardware, we just store the FIFO control register + // configuration and don't do anything with it. + // + ULONG *fifoControlRegister = GetFifoControlRegisterPtr(deviceContext); + + ASSERT(fifoControlRegister); + + status = RequestCopyToBuffer(Request, + fifoControlRegister, + sizeof(ULONG)); + break; + } + + case IOCTL_SERIAL_GET_LINE_CONTROL: + { + status = QueueProcessGetLineControl( + queueContext, + Request); + break; + } + + + case IOCTL_SERIAL_SET_LINE_CONTROL: + { + status = QueueProcessSetLineControl( + queueContext, + Request); + break; + } + + case IOCTL_SERIAL_GET_TIMEOUTS: + { + SERIAL_TIMEOUTS timeoutValues = {0}; + + status = RequestCopyFromBuffer(Request, + (void*) &timeoutValues, + sizeof(timeoutValues)); + break; + } + + case IOCTL_SERIAL_SET_TIMEOUTS: + { + SERIAL_TIMEOUTS timeoutValues = {0}; + + status = RequestCopyToBuffer(Request, + (void*) &timeoutValues, + sizeof(timeoutValues)); + + if( NT_SUCCESS(status) ) + { + if ((timeoutValues.ReadIntervalTimeout == MAXULONG) && + (timeoutValues.ReadTotalTimeoutMultiplier == MAXULONG) && + (timeoutValues.ReadTotalTimeoutConstant == MAXULONG)) + { + status = STATUS_INVALID_PARAMETER; + } + } + + if( NT_SUCCESS(status) ) { + SetTimeouts(deviceContext, timeoutValues); + } + + break; + } + + case IOCTL_SERIAL_WAIT_ON_MASK: + { + // + // NOTE: A wait-on-mask request should not be completed until either: + // 1) A wait event occurs; or + // 2) A set-wait-mask request is received + // + // This is a driver for a virtual serial port. Since there is no + // actual hardware, we complete the request with some failure code. + // + WDFREQUEST savedRequest; + + status = WdfIoQueueRetrieveNextRequest( + queueContext->WaitMaskQueue, + &savedRequest); + + if (NT_SUCCESS(status)) { + WdfRequestComplete(savedRequest, + STATUS_UNSUCCESSFUL); + } + + // + // Keep the request in a manual queue and the framework will take + // care of cancelling them when the app exits + // + status = WdfRequestForwardToIoQueue( + Request, + queueContext->WaitMaskQueue); + + if( !NT_SUCCESS(status) ) { + Trace(TRACE_LEVEL_ERROR, + "Error: WdfRequestForwardToIoQueue failed 0x%x", status); + WdfRequestComplete(Request, status); + } + + // + // Instead of "break", use "return" to prevent the current request + // from being completed. + // + return; + } + + case IOCTL_SERIAL_SET_WAIT_MASK: + { + // + // NOTE: If a wait-on-mask request is already pending when set-wait-mask + // request is processed, the pending wait-on-event request is completed + // with STATUS_SUCCESS and the output wait event mask is set to zero. + // + WDFREQUEST savedRequest; + + status = WdfIoQueueRetrieveNextRequest( + queueContext->WaitMaskQueue, + &savedRequest); + + if (NT_SUCCESS(status)) { + + ULONG eventMask = 0; + status = RequestCopyFromBuffer( + savedRequest, + &eventMask, + sizeof(eventMask)); + + WdfRequestComplete(savedRequest, status); + } + + // + // NOTE: The application expects STATUS_SUCCESS for these IOCTLs. + // + status = STATUS_SUCCESS; + break; + } + + case IOCTL_SERIAL_SET_QUEUE_SIZE: + case IOCTL_SERIAL_SET_DTR: + case IOCTL_SERIAL_SET_RTS: + case IOCTL_SERIAL_CLR_RTS: + case IOCTL_SERIAL_SET_XON: + case IOCTL_SERIAL_SET_XOFF: + case IOCTL_SERIAL_SET_CHARS: + case IOCTL_SERIAL_GET_CHARS: + case IOCTL_SERIAL_GET_HANDFLOW: + case IOCTL_SERIAL_SET_HANDFLOW: + case IOCTL_SERIAL_RESET_DEVICE: + // + // NOTE: The application expects STATUS_SUCCESS for these IOCTLs. + // + status = STATUS_SUCCESS; + break; + + default: + status = STATUS_INVALID_PARAMETER; + break; + } + + // + // complete the request + // + WdfRequestComplete(Request, status); +} + + +VOID +EvtIoWrite( + _In_ WDFQUEUE Queue, + _In_ WDFREQUEST Request, + _In_ size_t Length + ) +{ + NTSTATUS status; + PQUEUE_CONTEXT queueContext = GetQueueContext(Queue); + WDFMEMORY memory; + WDFREQUEST savedRequest; + size_t availableData = 0; + + Trace(TRACE_LEVEL_INFO, + "EvtIoWrite 0x%p", Request); + + status = WdfRequestRetrieveInputMemory(Request, &memory); + if( !NT_SUCCESS(status) ) { + Trace(TRACE_LEVEL_ERROR, + "Error: WdfRequestRetrieveInputMemory failed 0x%x", status); + return; + } + + // + // Process input + // + status = QueueProcessWriteBytes( + queueContext, + (PUCHAR)WdfMemoryGetBuffer(memory, NULL), + Length); + if( !NT_SUCCESS(status) ) { + return; + } + + WdfRequestCompleteWithInformation(Request, status, Length); + + // + // Get the amount of data available in the ring buffer + // + RingBufferGetAvailableData( + &queueContext->RingBuffer, + &availableData); + + if (availableData == 0) { + return; + } + + // + // Continue with the next request, if there is one pending + // + for ( ; ; ) { + + status = WdfIoQueueRetrieveNextRequest( + queueContext->ReadQueue, + &savedRequest); + + if (!NT_SUCCESS(status)) { + break; + } + + status = WdfRequestForwardToIoQueue( + savedRequest, + Queue); + + if( !NT_SUCCESS(status) ) { + Trace(TRACE_LEVEL_ERROR, + "Error: WdfRequestForwardToIoQueue failed 0x%x", status); + WdfRequestComplete(savedRequest, status); + } + } +} + + +VOID +EvtIoRead( + _In_ WDFQUEUE Queue, + _In_ WDFREQUEST Request, + _In_ size_t Length + ) +{ + NTSTATUS status; + PQUEUE_CONTEXT queueContext = GetQueueContext(Queue); + WDFMEMORY memory; + size_t bytesCopied = 0; + + Trace(TRACE_LEVEL_INFO, + "EvtIoRead 0x%p", Request); + + status = WdfRequestRetrieveOutputMemory(Request, &memory); + if( !NT_SUCCESS(status) ) { + Trace(TRACE_LEVEL_ERROR, + "Error: WdfRequestRetrieveOutputMemory failed 0x%x", status); + WdfRequestComplete(Request, status); + return; + } + + status = RingBufferRead(&queueContext->RingBuffer, + (BYTE*)WdfMemoryGetBuffer(memory, NULL), + Length, + &bytesCopied); + if( !NT_SUCCESS(status) ) { + WdfRequestComplete(Request, status); + return; + } + + if (bytesCopied > 0) { + // + // Data was read from buffer succesfully + // + WdfRequestCompleteWithInformation(Request, status, bytesCopied); + return; + } + else { + // + // No data to read. Queue the request for later processing. + // + status = WdfRequestForwardToIoQueue(Request, + queueContext->ReadQueue); + if( !NT_SUCCESS(status) ) { + Trace(TRACE_LEVEL_ERROR, + "Error: WdfRequestForwardToIoQueue failed 0x%x", status); + WdfRequestComplete(Request, status); + } + } +} + + +NTSTATUS +QueueProcessWriteBytes( + _In_ PQUEUE_CONTEXT QueueContext, + _In_reads_bytes_(Length) + PUCHAR Characters, + _In_ size_t Length + ) +/*++ +Routine Description: + + This function is called when the framework receives IRP_MJ_WRITE + requests from the system. The write event handler(FmEvtIoWrite) calls ProcessWriteBytes. + It parses the Characters passed in and looks for the for sequences "AT" -ok , + "ATA" --CONNECT, ATD -- CONNECT and sets the state of the device appropriately. + These bytes are placed in the read Buffer to be processed later since this device + works in a loopback fashion. + +Arguments: + + Characters - Pointer to the write IRP's system buffer. + + Length - Length of the IO operation + The default property of the queue is to not dispatch + zero lenght read & write requests to the driver and + complete is with status success. So we will never get + a zero length request. +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + UCHAR currentCharacter; + UCHAR connectString[] = "\r\nCONNECT\r\n"; + UCHAR connectStringCch = ARRAY_SIZE(connectString) - 1; + UCHAR okString[] = "\r\nOK\r\n"; + UCHAR okStringCch = ARRAY_SIZE(okString) - 1; + + while (Length != 0) { + + currentCharacter = *(Characters++); + Length--; + + if(currentCharacter == '\0') { + continue; + } + + status = RingBufferWrite(&QueueContext->RingBuffer, + ¤tCharacter, + sizeof(currentCharacter)); + if( !NT_SUCCESS(status) ) { + return status; + } + + switch (QueueContext->CommandMatchState) { + + case COMMAND_MATCH_STATE_IDLE: + + if ((currentCharacter == 'a') || (currentCharacter == 'A')) { + // + // got an A + // + QueueContext->CommandMatchState = COMMAND_MATCH_STATE_GOT_A; + QueueContext->ConnectCommand = FALSE; + QueueContext->IgnoreNextChar = FALSE; + } + break; + + case COMMAND_MATCH_STATE_GOT_A: + + if ((currentCharacter == 't') || (currentCharacter == 'T')) { + // + // got a T + // + QueueContext->CommandMatchState = COMMAND_MATCH_STATE_GOT_T; + } + else { + QueueContext->CommandMatchState = COMMAND_MATCH_STATE_IDLE; + } + + break; + + case COMMAND_MATCH_STATE_GOT_T: + + if (! QueueContext->IgnoreNextChar) { + // + // the last char was not a special char + // check for CONNECT command + // + if ((currentCharacter == 'A') || (currentCharacter == 'a')) { + QueueContext->ConnectCommand = TRUE; + } + + if ((currentCharacter == 'D') || (currentCharacter == 'd')) { + QueueContext->ConnectCommand = TRUE; + } + } + + QueueContext->IgnoreNextChar = TRUE; + + if (currentCharacter == '\r') { + // + // got a CR, send a response to the command + // + QueueContext->CommandMatchState = COMMAND_MATCH_STATE_IDLE; + + if (QueueContext->ConnectCommand) { + // + // place CONNECT in the buffer + // + status = RingBufferWrite(&QueueContext->RingBuffer, + connectString, + connectStringCch); + if( !NT_SUCCESS(status) ) { + return status; + } + // + // connected now raise CD + // + QueueContext->CurrentlyConnected = TRUE; + QueueContext->ConnectionStateChanged = TRUE; + } + else { + // + // place OK in the buffer + // + status = RingBufferWrite(&QueueContext->RingBuffer, + okString, + okStringCch); + if( !NT_SUCCESS(status) ) { + return status; + } + } + } + break; + + default: + break; + } + } + return status; +} + + +NTSTATUS +QueueProcessGetLineControl( + _In_ PQUEUE_CONTEXT QueueContext, + _In_ WDFREQUEST Request + ) +{ + NTSTATUS status; + PDEVICE_CONTEXT deviceContext; + SERIAL_LINE_CONTROL lineControl = {0}; + ULONG lineControlSnapshot; + ULONG *lineControlRegister; + + deviceContext = QueueContext->DeviceContext; + lineControlRegister = GetLineControlRegisterPtr(deviceContext); + + ASSERT(lineControlRegister); + + // + // Take a snapshot of the line control register variable + // + lineControlSnapshot = *lineControlRegister; + + // + // Decode the word length + // + if ((lineControlSnapshot & SERIAL_DATA_MASK) == SERIAL_5_DATA) + { + lineControl.WordLength = 5; + } + else if ((lineControlSnapshot & SERIAL_DATA_MASK) == SERIAL_6_DATA) + { + lineControl.WordLength = 6; + } + else if ((lineControlSnapshot & SERIAL_DATA_MASK) == SERIAL_7_DATA) + { + lineControl.WordLength = 7; + } + else if ((lineControlSnapshot & SERIAL_DATA_MASK) == SERIAL_8_DATA) + { + lineControl.WordLength = 8; + } + + // + // Decode the parity + // + if ((lineControlSnapshot & SERIAL_PARITY_MASK) == SERIAL_NONE_PARITY) + { + lineControl.Parity = NO_PARITY; + } + else if ((lineControlSnapshot & SERIAL_PARITY_MASK) == SERIAL_ODD_PARITY) + { + lineControl.Parity = ODD_PARITY; + } + else if ((lineControlSnapshot & SERIAL_PARITY_MASK) == SERIAL_EVEN_PARITY) + { + lineControl.Parity = EVEN_PARITY; + } + else if ((lineControlSnapshot & SERIAL_PARITY_MASK) == SERIAL_MARK_PARITY) + { + lineControl.Parity = MARK_PARITY; + } + else if ((lineControlSnapshot & SERIAL_PARITY_MASK) == SERIAL_SPACE_PARITY) + { + lineControl.Parity = SPACE_PARITY; + } + + // + // Decode the length of the stop bit + // + if (lineControlSnapshot & SERIAL_2_STOP) + { + if (lineControl.WordLength == 5) + { + lineControl.StopBits = STOP_BITS_1_5; + } + else + { + lineControl.StopBits = STOP_BITS_2; + } + } + else + { + lineControl.StopBits = STOP_BIT_1; + } + + // + // Copy the information that was decoded to the caller's buffer + // + status = RequestCopyFromBuffer(Request, + (void*) &lineControl, + sizeof(lineControl)); + return status; +} + + +NTSTATUS +QueueProcessSetLineControl( + _In_ PQUEUE_CONTEXT QueueContext, + _In_ WDFREQUEST Request + ) +{ + NTSTATUS status; + PDEVICE_CONTEXT deviceContext; + SERIAL_LINE_CONTROL lineControl = {0}; + ULONG *lineControlRegister; + UCHAR lineControlData = 0; + UCHAR lineControlStop = 0; + UCHAR lineControlParity = 0; + ULONG lineControlSnapshot; + ULONG lineControlNew; + ULONG lineControlPrevious; + ULONG i; + + deviceContext = QueueContext->DeviceContext; + lineControlRegister = GetLineControlRegisterPtr(deviceContext); + + ASSERT(lineControlRegister); + + // + // This is a driver for a virtual serial port. Since there is no + // actual hardware, we just store the line control register + // configuration and don't do anything with it. + // + status = RequestCopyToBuffer(Request, + (void*) &lineControl, + sizeof(lineControl)); + + // + // Bits 0 and 1 of the line control register + // + if( NT_SUCCESS(status) ) + { + switch (lineControl.WordLength) + { + case 5: + lineControlData = SERIAL_5_DATA; + SetValidDataMask(deviceContext, 0x1f); + break; + + case 6: + lineControlData = SERIAL_6_DATA; + SetValidDataMask(deviceContext, 0x3f); + break; + + case 7: + lineControlData = SERIAL_7_DATA; + SetValidDataMask(deviceContext, 0x7f); + break; + + case 8: + lineControlData = SERIAL_8_DATA; + SetValidDataMask(deviceContext, 0xff); + break; + + default: + status = STATUS_INVALID_PARAMETER; + break; + } + } + + // + // Bit 2 of the line control register + // + if( NT_SUCCESS(status) ) + { + switch (lineControl.StopBits) + { + case STOP_BIT_1: + lineControlStop = SERIAL_1_STOP; + break; + + case STOP_BITS_1_5: + if (lineControlData != SERIAL_5_DATA) + { + status = STATUS_INVALID_PARAMETER; + break; + } + lineControlStop = SERIAL_1_5_STOP; + break; + + case STOP_BITS_2: + if (lineControlData == SERIAL_5_DATA) + { + status = STATUS_INVALID_PARAMETER; + break; + } + lineControlStop = SERIAL_2_STOP; + break; + + default: + status = STATUS_INVALID_PARAMETER; + break; + } + } + + // + // Bits 3, 4 and 5 of the line control register + // + if( NT_SUCCESS(status) ) + { + switch (lineControl.Parity) + { + case NO_PARITY: + lineControlParity = SERIAL_NONE_PARITY; + break; + + case EVEN_PARITY: + lineControlParity = SERIAL_EVEN_PARITY; + break; + + case ODD_PARITY: + lineControlParity = SERIAL_ODD_PARITY; + break; + + case SPACE_PARITY: + lineControlParity = SERIAL_SPACE_PARITY; + break; + + case MARK_PARITY: + lineControlParity = SERIAL_MARK_PARITY; + break; + + default: + status = STATUS_INVALID_PARAMETER; + break; + } + } + + // + // Update our line control register variable atomically + // + i=0; + do { + i++; + if ((i & 0xf) == 0) { + // + // We've been spinning in a loop for a while trying to + // update the line control register variable atomically. + // Yield the CPU for other threads for a while. + // +#ifdef _KERNEL_MODE + LARGE_INTEGER interval; + interval.QuadPart = 0; + KeDelayExecutionThread(UserMode, FALSE, &interval); +#else + SwitchToThread(); +#endif + } + + lineControlSnapshot = *lineControlRegister; + + lineControlNew = (lineControlSnapshot & SERIAL_LCR_BREAK) | + (lineControlData | lineControlParity | lineControlStop); + + lineControlPrevious = InterlockedCompareExchange( + (LONG *) lineControlRegister, + lineControlNew, + lineControlSnapshot); + + } while (lineControlPrevious != lineControlSnapshot); + + return status; +} diff --git a/serial/VirtualSerial2/queue.h b/serial/VirtualSerial2/queue.h new file mode 100644 index 00000000..909d699b --- /dev/null +++ b/serial/VirtualSerial2/queue.h @@ -0,0 +1,113 @@ +/*++ + +Copyright (c) Microsoft Corporation, All Rights Reserved + +Module Name: + + queue.h + +Abstract: + + This file defines the queue callback interface. + +Environment: + + Windows Driver Framework + +--*/ + +#pragma once + +#include "internal.h" + +// Set ring buffer size +#define DATA_BUFFER_SIZE 1024 + +// +// Device states +// +#define COMMAND_MATCH_STATE_IDLE 0 +#define COMMAND_MATCH_STATE_GOT_A 1 +#define COMMAND_MATCH_STATE_GOT_T 2 + +// +// Define useful macros +// + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) +#endif + +#define MAXULONG 0xffffffff + +typedef struct _QUEUE_CONTEXT +{ + UCHAR CommandMatchState; + + BOOLEAN ConnectCommand; + + BOOLEAN IgnoreNextChar; + + BOOLEAN ConnectionStateChanged; + + BOOLEAN CurrentlyConnected; + + RING_BUFFER RingBuffer; // Ring buffer for pending data + + BYTE Buffer[DATA_BUFFER_SIZE]; + + WDFQUEUE Queue; // Default parallel queue + + WDFQUEUE ReadQueue; // Manual queue for pending reads + + WDFQUEUE WaitMaskQueue; // Manual queue for pending ioctl wait-on-mask + + PDEVICE_CONTEXT DeviceContext; + +} QUEUE_CONTEXT, *PQUEUE_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(QUEUE_CONTEXT, GetQueueContext); + +EVT_WDF_IO_QUEUE_IO_READ EvtIoRead; +EVT_WDF_IO_QUEUE_IO_WRITE EvtIoWrite; +EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL EvtIoDeviceControl; + +NTSTATUS +QueueCreate( + _In_ PDEVICE_CONTEXT DeviceContext + ); + +NTSTATUS +QueueProcessWriteBytes( + _In_ PQUEUE_CONTEXT QueueContext, + _In_reads_bytes_(Length) + PUCHAR Characters, + _In_ size_t Length + ); + +NTSTATUS +QueueProcessGetLineControl( + _In_ PQUEUE_CONTEXT QueueContext, + _In_ WDFREQUEST Request + ); + +NTSTATUS +QueueProcessSetLineControl( + _In_ PQUEUE_CONTEXT QueueContext, + _In_ WDFREQUEST Request + ); + +NTSTATUS +RequestCopyFromBuffer( + _In_ WDFREQUEST Request, + _In_ PVOID SourceBuffer, + _In_ size_t NumBytesToCopyFrom + ); + +NTSTATUS +RequestCopyToBuffer( + _In_ WDFREQUEST Request, + _In_ PVOID DestinationBuffer, + _In_ size_t NumBytesToCopyTo + ); + diff --git a/serial/VirtualSerial2/ringbuffer.c b/serial/VirtualSerial2/ringbuffer.c new file mode 100644 index 00000000..0efbe821 --- /dev/null +++ b/serial/VirtualSerial2/ringbuffer.c @@ -0,0 +1,338 @@ +/*++ + +Copyright (c) Microsoft Corporation, All Rights Reserved + +Module Name: + + RingBuffer.c + +Abstract: + + This file implements the Ring Buffer + +Environment: + +--*/ + +#include "internal.h" + +VOID +RingBufferInitialize( + _In_ PRING_BUFFER Self, + _In_reads_bytes_(BufferSize) + BYTE* Buffer, + _In_ size_t BufferSize + ) +{ + Self->Size = BufferSize; + Self->Base = Buffer; + Self->End = Buffer + BufferSize; + Self->Head = Buffer; + Self->Tail = Buffer; +} + + +VOID +RingBufferGetAvailableSpace( + _In_ PRING_BUFFER Self, + _Out_ size_t *AvailableSpace + ) +{ + BYTE* headSnapshot = NULL; + BYTE* tailSnapshot = NULL; + BYTE* tailPlusOne = NULL; + + ASSERT(AvailableSpace); + + // + // Take a snapshot of the head and tail pointers. We will compute the + // available space based on this snapshot. This is safe to do in a + // single-producer, single-consumer model, because - + // * A producer will call GetAvailableSpace() to determine whether + // there is enough space to write the data it is trying to write. + // The only other thread that could modify the amount of space + // available is the consumer thread, which can only increase the + // amount of space available. Hence it is safe for the producer + // to write based on this snapshot. + // * A consumer thread will call GetAvailableSpace() to determine + // whether there is enough data in the buffer for it to read. + // (Available data = Buffer size - Available space). The only + // other thread that could modify the amount of space available + // is the producer thread, which can only decrease the amount of + // space available (thereby increasing the amount of data + // available. Hence it is safe for the consumer to read based on + // this snapshot. + // + headSnapshot = Self->Head; + tailSnapshot = Self->Tail; + + // + // In order to distinguish between a full buffer and an empty buffer, + // we always leave the last byte of the buffer unused. So, an empty + // buffer is denoted by - + // tail == head + // ... and a full buffer is denoted by - + // (tail+1) == head + // + tailPlusOne = ((tailSnapshot+1) == Self->End) ? Self->Base : (tailSnapshot+1); + + if (tailPlusOne == headSnapshot) + { + // + // Buffer full + // + *AvailableSpace = 0; + } + else if (tailSnapshot == headSnapshot) + { + // + // Buffer empty + // The -1 in the computation below is to account for the fact that + // we always leave the last byte of the ring buffer unused in order + // to distinguish between an empty buffer and a full buffer. + // + *AvailableSpace = Self->Size - 1; + } + else + { + if (tailSnapshot > headSnapshot) + { + // + // Data has not wrapped around the end of the buffer + // The -1 in the computation below is to account for the fact + // that we always leave the last byte of the ring buffer unused + // in order to distinguish between an empty buffer and a full + // buffer. + // + *AvailableSpace = Self->Size - (tailSnapshot - headSnapshot) - 1; + } + else + { + // + // Data has wrapped around the end of the buffer + // The -1 in the computation below is to account for the fact + // that we always leave the last byte of the ring buffer unused + // in order to distinguish between an empty buffer and a full + // buffer. + // + *AvailableSpace = (headSnapshot - tailSnapshot) - 1; + } + } +} + + +VOID +RingBufferGetAvailableData( + _In_ PRING_BUFFER Self, + _Out_ size_t *AvailableData + ) +{ + size_t availableSpace; + + ASSERT(AvailableData); + + RingBufferGetAvailableSpace(Self, &availableSpace); + + // + // The -1 in the arithmetic below accounts for the fact that we always + // keep 1 byte of the ring buffer unused in order to distinguish + // between a full buffer and an empty buffer. + // + *AvailableData = Self->Size - availableSpace - 1; +} + + +NTSTATUS +RingBufferWrite( + _In_ PRING_BUFFER Self, + _In_reads_bytes_(DataSize) + BYTE* Data, + _In_ size_t DataSize + ) +{ + size_t availableSpace; + size_t bytesToCopy; + size_t spaceFromCurrToEnd; + + ASSERT(Data && (0 != DataSize)); + + if (Self->Tail >= Self->End) + { + return STATUS_INTERNAL_ERROR; + } + + // + // Get the amount of space available in the buffer + // + RingBufferGetAvailableSpace(Self, &availableSpace); + + // + // If there is not enough space to fit in all the data passed in by the + // caller then copy as much as possible and throw away the rest + // + if (availableSpace < DataSize) + { + bytesToCopy = availableSpace; + } + else + { + bytesToCopy = DataSize; + } + + if (bytesToCopy) + { + // + // The buffer has some space at least + // + if ((Self->Tail + bytesToCopy) > Self->End) + { + // + // The data being written will wrap around the end of the buffer. + // So the copy has to be done in two steps - + // * X bytes from current position to end of the buffer + // * the remaining (bytesToCopy - X) from the start of the buffer + // + + // + // The first step of the copy ... + // + spaceFromCurrToEnd = Self->End - Self->Tail; + + RtlCopyMemory(Self->Tail, Data, spaceFromCurrToEnd); + + Data += spaceFromCurrToEnd; + + bytesToCopy -= spaceFromCurrToEnd; + + // + // The second step of the copy ... + // + RtlCopyMemory(Self->Base, Data, bytesToCopy); + + // + // Advance the tail pointer + // + Self->Tail = Self->Base + bytesToCopy; + } + else + { + // + // Data does NOT wrap around the end of the buffer. Just copy it + // over in a single step + // + RtlCopyMemory(Self->Tail, Data, bytesToCopy); + + // + // Advance the tail pointer + // + Self->Tail += bytesToCopy; + if (Self->Tail == Self->End) + { + // + // We have exactly reached the end of the buffer. The next + // write should wrap around and start from the beginning. + // + Self->Tail = Self->Base; + } + } + + ASSERT(Self->Tail < Self->End); + } + + return STATUS_SUCCESS; +} + + +NTSTATUS +RingBufferRead( + _In_ PRING_BUFFER Self, + _Out_writes_bytes_to_(DataSize, *BytesCopied) + BYTE* Data, + _In_ size_t DataSize, + _Out_ size_t *BytesCopied + ) +{ + size_t availableData; + size_t dataFromCurrToEnd; + + ASSERT(Data && (DataSize != 0)); + + if (Self->Head >= Self->End) + { + return STATUS_INTERNAL_ERROR; + } + + // + // Get the amount of data available in the buffer + // + RingBufferGetAvailableData(Self, &availableData); + + if (availableData == 0) + { + *BytesCopied = 0; + return STATUS_SUCCESS; + } + + if (DataSize > availableData) + { + DataSize = availableData; + } + + *BytesCopied = DataSize; + + if ((Self->Head + DataSize) > Self->End) + { + // + // The data requested by the caller is wrapped around the end of the + // buffer. So we'll do the copy in two steps - + // * Copy X bytes from the current position to the end buffer into + // the caller's buffer + // * Copy (DataSize - X) bytes from the beginning to the buffer into + // the caller's buffer + // + + // + // The first step of the copy ... + // + dataFromCurrToEnd = Self->End - Self->Head; + RtlCopyMemory(Data, Self->Head, dataFromCurrToEnd); + Data += dataFromCurrToEnd; + DataSize -= dataFromCurrToEnd; + + // + // The second step of the copy ... + // + RtlCopyMemory(Data, Self->Base, DataSize); + + // + // Advance the head pointer + // + Self->Head = Self->Base + DataSize; + } + else + { + // + // The data in the buffer is NOT wrapped around the end of the buffer. + // Simply copy the data over to the caller's buffer in a single step. + // + RtlCopyMemory(Data, Self->Head, DataSize); + + // + // Advance the head pointer + // + Self->Head += DataSize; + if (Self->Head == Self->End) + { + // + // We have exactly reached the end of the buffer. The next + // read should wrap around and start from the beginning. + // + Self->Head = Self->Base; + } + } + + ASSERT(Self->Head < Self->End); + + return STATUS_SUCCESS; +} + diff --git a/serial/VirtualSerial2/ringbuffer.h b/serial/VirtualSerial2/ringbuffer.h new file mode 100644 index 00000000..8c5e3e39 --- /dev/null +++ b/serial/VirtualSerial2/ringbuffer.h @@ -0,0 +1,117 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved + +Module Name: + + Ringbuffer.h + +--*/ + +#pragma once + +typedef struct _RING_BUFFER +{ + // + // The size in bytes of the ring buffer. + // + size_t Size; + + // + // A pointer to the base of the ring buffer. + // + BYTE* Base; + + // + // A pointer to the byte beyond the end of the ring buffer. Used for + // quick comparisons when determining if we need to wrap. + // + BYTE* End; + + // + // A pointer to the current read point in the ring buffer. + // + // Updates to this are not protected by any lock. This is different from + // the write pointer, which is protected by the "pending read pointer" + // lock. The reason for this difference is that in this driver, we do not + // keep write requests pending. If there is not enough space to write all + // the data that was requested, we write as much as we can and drop the + // rest (lossy data transfer). + // + // If we had multiple threads modifying this pointer, then that would + // provide yet another reason for protecting updates to the pointer using a + // lock. However, in this driver, at any given time we have only one thread + // that modifies this pointer (the thread that runs the read callback). + // This is true because we use a sequential queue for read requests. If we + // were to change our read queue to be a parallel queue, this would no + // longer be true. + // + // + BYTE* Head; + + // + // A pointer to the current write point in the ring buffer. + // + // Updates to this pointer are protected by the "pending read pointer + // lock", because we do not want a consumer thread to mark a read request + // as pending while we are in the process of writing data to the buffer. + // The reason is that the write that we are currently performing might + // actually supply enough data to satisfy the read request, in which case + // it should not be marked pending at all. + // If the read request were to be marked pending in the situation described + // above, then we would need some trigger to later retrieve the request and + // complete it. In our driver, arrival of data is the only event that can + // trigger this. So if no more data arrives, the request will remain + // pending forever, even though there is enough data in the buffer to + // complete it. Hence we do not keep a read request pending in situations + // where the read buffer contains enough data to satisfy it. + // + // If we had multiple threads modifying this pointer, then that would + // provide yet another reason for protecting updates to the pointer using a + // lock. However, in this driver, at any given time we have only one thread + // that modifies this pointer (the thread that runs the write callback). + // This is true because we use a sequential queue for write requests. If we + // were to change our write queue to be a parallel queue, this would no + // longer be true. + // + BYTE* Tail; + +} RING_BUFFER, *PRING_BUFFER; + + +VOID +RingBufferInitialize( + _In_ PRING_BUFFER Self, + _In_reads_bytes_(BufferSize) + BYTE* Buffer, + _In_ size_t BufferSize + ); + +NTSTATUS +RingBufferWrite( + _In_ PRING_BUFFER Self, + _In_reads_bytes_(DataSize) + BYTE* Data, + _In_ size_t DataSize + ); + +NTSTATUS +RingBufferRead( + _In_ PRING_BUFFER Self, + _Out_writes_bytes_to_(DataSize, *BytesCopied) + BYTE* Data, + _In_ size_t DataSize, + _Out_ size_t *BytesCopied + ); + +VOID +RingBufferGetAvailableSpace( + _In_ PRING_BUFFER Self, + _Out_ size_t *AvailableSpace + ); + +VOID +RingBufferGetAvailableData( + _In_ PRING_BUFFER Self, + _Out_ size_t *AvailableData + ); diff --git a/serial/VirtualSerial2/serial.h b/serial/VirtualSerial2/serial.h new file mode 100644 index 00000000..223c1ceb --- /dev/null +++ b/serial/VirtualSerial2/serial.h @@ -0,0 +1,128 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved + +Module Name: + + Serial.h + +Abstract: + + Type definitions and data for the serial port driver + +--*/ + +#pragma once + +// +// This defines the bit used to control whether the device is sending +// a break. When this bit is set the device is sending a space (logic 0). +// +// Most protocols will assume that this is a hangup. +// +#define SERIAL_LCR_BREAK 0x40 + +// +// These defines are used to set the line control register. +// +#define SERIAL_5_DATA ((UCHAR)0x00) +#define SERIAL_6_DATA ((UCHAR)0x01) +#define SERIAL_7_DATA ((UCHAR)0x02) +#define SERIAL_8_DATA ((UCHAR)0x03) +#define SERIAL_DATA_MASK ((UCHAR)0x03) + +#define SERIAL_1_STOP ((UCHAR)0x00) +#define SERIAL_1_5_STOP ((UCHAR)0x04) // Only valid for 5 data bits +#define SERIAL_2_STOP ((UCHAR)0x04) // Not valid for 5 data bits +#define SERIAL_STOP_MASK ((UCHAR)0x04) + +#define SERIAL_NONE_PARITY ((UCHAR)0x00) +#define SERIAL_ODD_PARITY ((UCHAR)0x08) +#define SERIAL_EVEN_PARITY ((UCHAR)0x18) +#define SERIAL_MARK_PARITY ((UCHAR)0x28) +#define SERIAL_SPACE_PARITY ((UCHAR)0x38) +#define SERIAL_PARITY_MASK ((UCHAR)0x38) + +#ifdef _KERNEL_MODE + +#include + +#else + +//////////////////////////////////////////////////////////////////////////////// +// +// Instead of #include , the following are copied from that header, +// as ntddser.h is conflicted with winioctl.h which is included from wdf.h +// +//////////////////////////////////////////////////////////////////////////////// + +#define IOCTL_SERIAL_SET_BAUD_RATE CTL_CODE(FILE_DEVICE_SERIAL_PORT, 1,METHOD_BUFFERED,FILE_ANY_ACCESS) +#define IOCTL_SERIAL_SET_QUEUE_SIZE CTL_CODE(FILE_DEVICE_SERIAL_PORT, 2,METHOD_BUFFERED,FILE_ANY_ACCESS) +#define IOCTL_SERIAL_SET_LINE_CONTROL CTL_CODE(FILE_DEVICE_SERIAL_PORT, 3,METHOD_BUFFERED,FILE_ANY_ACCESS) +#define IOCTL_SERIAL_SET_BREAK_ON CTL_CODE(FILE_DEVICE_SERIAL_PORT, 4,METHOD_BUFFERED,FILE_ANY_ACCESS) +#define IOCTL_SERIAL_SET_BREAK_OFF CTL_CODE(FILE_DEVICE_SERIAL_PORT, 5,METHOD_BUFFERED,FILE_ANY_ACCESS) +#define IOCTL_SERIAL_IMMEDIATE_CHAR CTL_CODE(FILE_DEVICE_SERIAL_PORT, 6,METHOD_BUFFERED,FILE_ANY_ACCESS) +#define IOCTL_SERIAL_SET_TIMEOUTS CTL_CODE(FILE_DEVICE_SERIAL_PORT, 7,METHOD_BUFFERED,FILE_ANY_ACCESS) +#define IOCTL_SERIAL_GET_TIMEOUTS CTL_CODE(FILE_DEVICE_SERIAL_PORT, 8,METHOD_BUFFERED,FILE_ANY_ACCESS) +#define IOCTL_SERIAL_SET_DTR CTL_CODE(FILE_DEVICE_SERIAL_PORT, 9,METHOD_BUFFERED,FILE_ANY_ACCESS) +#define IOCTL_SERIAL_CLR_DTR CTL_CODE(FILE_DEVICE_SERIAL_PORT,10,METHOD_BUFFERED,FILE_ANY_ACCESS) +#define IOCTL_SERIAL_RESET_DEVICE CTL_CODE(FILE_DEVICE_SERIAL_PORT,11,METHOD_BUFFERED,FILE_ANY_ACCESS) +#define IOCTL_SERIAL_SET_RTS CTL_CODE(FILE_DEVICE_SERIAL_PORT,12,METHOD_BUFFERED,FILE_ANY_ACCESS) +#define IOCTL_SERIAL_CLR_RTS CTL_CODE(FILE_DEVICE_SERIAL_PORT,13,METHOD_BUFFERED,FILE_ANY_ACCESS) +#define IOCTL_SERIAL_SET_XOFF CTL_CODE(FILE_DEVICE_SERIAL_PORT,14,METHOD_BUFFERED,FILE_ANY_ACCESS) +#define IOCTL_SERIAL_SET_XON CTL_CODE(FILE_DEVICE_SERIAL_PORT,15,METHOD_BUFFERED,FILE_ANY_ACCESS) +#define IOCTL_SERIAL_GET_WAIT_MASK CTL_CODE(FILE_DEVICE_SERIAL_PORT,16,METHOD_BUFFERED,FILE_ANY_ACCESS) +#define IOCTL_SERIAL_SET_WAIT_MASK CTL_CODE(FILE_DEVICE_SERIAL_PORT,17,METHOD_BUFFERED,FILE_ANY_ACCESS) +#define IOCTL_SERIAL_WAIT_ON_MASK CTL_CODE(FILE_DEVICE_SERIAL_PORT,18,METHOD_BUFFERED,FILE_ANY_ACCESS) +#define IOCTL_SERIAL_PURGE CTL_CODE(FILE_DEVICE_SERIAL_PORT,19,METHOD_BUFFERED,FILE_ANY_ACCESS) +#define IOCTL_SERIAL_GET_BAUD_RATE CTL_CODE(FILE_DEVICE_SERIAL_PORT,20,METHOD_BUFFERED,FILE_ANY_ACCESS) +#define IOCTL_SERIAL_GET_LINE_CONTROL CTL_CODE(FILE_DEVICE_SERIAL_PORT,21,METHOD_BUFFERED,FILE_ANY_ACCESS) +#define IOCTL_SERIAL_GET_CHARS CTL_CODE(FILE_DEVICE_SERIAL_PORT,22,METHOD_BUFFERED,FILE_ANY_ACCESS) +#define IOCTL_SERIAL_SET_CHARS CTL_CODE(FILE_DEVICE_SERIAL_PORT,23,METHOD_BUFFERED,FILE_ANY_ACCESS) +#define IOCTL_SERIAL_GET_HANDFLOW CTL_CODE(FILE_DEVICE_SERIAL_PORT,24,METHOD_BUFFERED,FILE_ANY_ACCESS) +#define IOCTL_SERIAL_SET_HANDFLOW CTL_CODE(FILE_DEVICE_SERIAL_PORT,25,METHOD_BUFFERED,FILE_ANY_ACCESS) +#define IOCTL_SERIAL_GET_MODEMSTATUS CTL_CODE(FILE_DEVICE_SERIAL_PORT,26,METHOD_BUFFERED,FILE_ANY_ACCESS) +#define IOCTL_SERIAL_GET_COMMSTATUS CTL_CODE(FILE_DEVICE_SERIAL_PORT,27,METHOD_BUFFERED,FILE_ANY_ACCESS) +#define IOCTL_SERIAL_XOFF_COUNTER CTL_CODE(FILE_DEVICE_SERIAL_PORT,28,METHOD_BUFFERED,FILE_ANY_ACCESS) +#define IOCTL_SERIAL_GET_PROPERTIES CTL_CODE(FILE_DEVICE_SERIAL_PORT,29,METHOD_BUFFERED,FILE_ANY_ACCESS) +#define IOCTL_SERIAL_GET_DTRRTS CTL_CODE(FILE_DEVICE_SERIAL_PORT,30,METHOD_BUFFERED,FILE_ANY_ACCESS) + +#define IOCTL_SERIAL_GET_MODEM_CONTROL CTL_CODE(FILE_DEVICE_SERIAL_PORT,37,METHOD_BUFFERED,FILE_ANY_ACCESS) +#define IOCTL_SERIAL_SET_MODEM_CONTROL CTL_CODE(FILE_DEVICE_SERIAL_PORT,38,METHOD_BUFFERED,FILE_ANY_ACCESS) +#define IOCTL_SERIAL_SET_FIFO_CONTROL CTL_CODE(FILE_DEVICE_SERIAL_PORT,39,METHOD_BUFFERED,FILE_ANY_ACCESS) + + +typedef struct _SERIAL_BAUD_RATE { + ULONG BaudRate; + } SERIAL_BAUD_RATE,*PSERIAL_BAUD_RATE; + +typedef struct _SERIAL_LINE_CONTROL { + UCHAR StopBits; + UCHAR Parity; + UCHAR WordLength; + } SERIAL_LINE_CONTROL,*PSERIAL_LINE_CONTROL; + +typedef struct _SERIAL_TIMEOUTS { + ULONG ReadIntervalTimeout; + ULONG ReadTotalTimeoutMultiplier; + ULONG ReadTotalTimeoutConstant; + ULONG WriteTotalTimeoutMultiplier; + ULONG WriteTotalTimeoutConstant; + } SERIAL_TIMEOUTS,*PSERIAL_TIMEOUTS; + +#define STOP_BIT_1 0 +#define STOP_BITS_1_5 1 +#define STOP_BITS_2 2 + +#define NO_PARITY 0 +#define ODD_PARITY 1 +#define EVEN_PARITY 2 +#define MARK_PARITY 3 +#define SPACE_PARITY 4 + +#endif // #ifdef _KERNEL_MODE, #include + +// +// DEFINE_GUID(GUID_DEVINTERFACE_MODEM, 0x2c7089aa, 0x2e0e, 0x11d1, 0xb1, 0x14, 0x00, 0xc0, 0x4f, 0xc2, 0xaa, 0xe4); +// +#include diff --git a/serial/serenum/SerEnum_sample.vcxproj b/serial/serenum/SerEnum_sample.vcxproj index dfb24ba2..c7d3b6ed 100644 --- a/serial/serenum/SerEnum_sample.vcxproj +++ b/serial/serenum/SerEnum_sample.vcxproj @@ -19,11 +19,11 @@ - {E52D8BEE-C6BE-4357-902C-C6DB9C0EF34F} + {85657CCC-F271-4F62-B992-708E9B68D043} $(MSBuildProjectName) Debug Win32 - {CA7D7702-DAFD-4229-BF86-20E446AECF97} + {CD6B9A4D-86E9-453F-A2B1-B73D11DDB875} diff --git a/serial/serenum/SerEnum_sample.vcxproj.Filters b/serial/serenum/SerEnum_sample.vcxproj.Filters index acc1f18d..77002c01 100644 --- a/serial/serenum/SerEnum_sample.vcxproj.Filters +++ b/serial/serenum/SerEnum_sample.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {5046CCD8-3045-41D7-BCAE-587CADA81725} + {D57D43F2-64D0-43E4-B935-81E0A951D524} h;hpp;hxx;hm;inl;inc;xsd - {976EA0BF-ABEF-4B5E-9C22-13AEAACBE66B} + {CA2B31D9-E351-4F8B-AA0B-DCC95839874B} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {D81BDD2E-183B-4A6D-B1A6-A6D4DE701F20} + {511C0F53-35B0-40BA-8992-FE665F0F6C69} inf;inv;inx;mof;mc; - {35AA0A20-80E1-4672-B792-9FEECE8B736E} + {96BE96BE-26EF-481B-B9F1-FF8D065F76E3} diff --git a/serial/serenum/serenum.htm b/serial/serenum/serenum.htm new file mode 100644 index 00000000..79387f4e --- /dev/null +++ b/serial/serenum/serenum.htm @@ -0,0 +1,203 @@ + + + + + + + + +Serenum + + + + + + + + + +
+ +

Serenum

+ +

SUMMARY

+ +

Serenum enumerates Plug-n-Play RS-232 +devices that are compliant with the current revision of Plug and Play External +COM Device.

+ +

It loads as an upper +filter driver to many different RS-232 device drivers that are compliant with +its requirements and performs this service for them.

+ +

BUILDING THE SAMPLE

+ +

To build the sample, run +the build command. Once built, the sample produces one binary: Serenum.sys. The sample is 64-bit compliant, works on both +x86 and Alpha platforms, and supports both Plug and Play and Power Management. +There is no one Inf for serenum because it is loaded as a filter driver in +different driver stacks. An example of this can be found in %WINDIR%\inf\msports.inf.

+ +

CODE TOUR

+ +

File Manifest

+ +
File           Description
 
Enum.c          Functions that enumerate external serial devices—the main purpose of this driver
Makefile        Makefile for building this driver
Pnp.c           Plug and Play support code
Power.c         Power support code
Serenum.c       Basic driver functionality
Serenum.h       Local header with defines, prototypes, etc
Serenum.rc      Resource script
Sources         Data file for build.exe
String.c        String handling support; mainly ASCII to UNICODE functionality
 
 
+ +

Top of page +

+ +
 
+ + + + + +
+

 

+
+ +
 
 
+ +

© +2004 Microsoft Corporation

+ +
+ + + + diff --git a/serial/serenum/serenum.sln b/serial/serenum/serenum.sln index 3e0480c9..4eed4e90 100644 --- a/serial/serenum/serenum.sln +++ b/serial/serenum/serenum.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SerEnum_sample", "SerEnum_sample.vcxproj", "{E52D8BEE-C6BE-4357-902C-C6DB9C0EF34F}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SerEnum_sample", "SerEnum_sample.vcxproj", "{85657CCC-F271-4F62-B992-708E9B68D043}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +13,14 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {E52D8BEE-C6BE-4357-902C-C6DB9C0EF34F}.Debug|Win32.ActiveCfg = Debug|Win32 - {E52D8BEE-C6BE-4357-902C-C6DB9C0EF34F}.Debug|Win32.Build.0 = Debug|Win32 - {E52D8BEE-C6BE-4357-902C-C6DB9C0EF34F}.Release|Win32.ActiveCfg = Release|Win32 - {E52D8BEE-C6BE-4357-902C-C6DB9C0EF34F}.Release|Win32.Build.0 = Release|Win32 - {E52D8BEE-C6BE-4357-902C-C6DB9C0EF34F}.Debug|x64.ActiveCfg = Debug|x64 - {E52D8BEE-C6BE-4357-902C-C6DB9C0EF34F}.Debug|x64.Build.0 = Debug|x64 - {E52D8BEE-C6BE-4357-902C-C6DB9C0EF34F}.Release|x64.ActiveCfg = Release|x64 - {E52D8BEE-C6BE-4357-902C-C6DB9C0EF34F}.Release|x64.Build.0 = Release|x64 + {85657CCC-F271-4F62-B992-708E9B68D043}.Debug|Win32.ActiveCfg = Debug|Win32 + {85657CCC-F271-4F62-B992-708E9B68D043}.Debug|Win32.Build.0 = Debug|Win32 + {85657CCC-F271-4F62-B992-708E9B68D043}.Release|Win32.ActiveCfg = Release|Win32 + {85657CCC-F271-4F62-B992-708E9B68D043}.Release|Win32.Build.0 = Release|Win32 + {85657CCC-F271-4F62-B992-708E9B68D043}.Debug|x64.ActiveCfg = Debug|x64 + {85657CCC-F271-4F62-B992-708E9B68D043}.Debug|x64.Build.0 = Debug|x64 + {85657CCC-F271-4F62-B992-708E9B68D043}.Release|x64.ActiveCfg = Release|x64 + {85657CCC-F271-4F62-B992-708E9B68D043}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/serial/serial/ioctl.c b/serial/serial/ioctl.c index 3fd2d8f6..ceef711e 100644 --- a/serial/serial/ioctl.c +++ b/serial/serial/ioctl.c @@ -1296,24 +1296,16 @@ Return Value: } - try { - - reqContext->Type3InputBuffer = + reqContext->Type3InputBuffer = ExAllocatePoolWithQuotaTag( - NonPagedPool, + NonPagedPool | POOL_QUOTA_FAIL_INSTEAD_OF_RAISE, Rs->InSize, POOL_TAG ); - } except (EXCEPTION_EXECUTE_HANDLER) { - - reqContext->Type3InputBuffer = NULL; - Status = GetExceptionCode(); - - } - if (!reqContext->Type3InputBuffer) { + Status = STATUS_INSUFFICIENT_RESOURCES; break; } diff --git a/serial/serial/pnp.c b/serial/serial/pnp.c index 1feb5958..d20e47dd 100644 --- a/serial/serial/pnp.c +++ b/serial/serial/pnp.c @@ -147,7 +147,7 @@ Return Value: SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_PNP, "-->SerialEvtDeviceAdd\n"); - status = RtlUnicodeStringPrintf(&deviceName, L"%ws%d", + status = RtlUnicodeStringPrintf(&deviceName, L"%ws%u", L"\\Device\\Serial", currentInstance++); @@ -1454,20 +1454,18 @@ Return Value: // so that it will show up if the user boots to dos. // -#pragma prefast(suppress: __WARNING_IRQ_SET_TOO_HIGH, "This warning is because we are calling interrupt synchronize routine directly. Suppress it because interrupt is not connected yet.") -#pragma prefast(suppress:6387, "Interrupt is UNREFERENCED_PARAMETER, so it can be NULL") + // __WARNING_IRQ_SET_TOO_HIGH: we are calling interrupt synchronize routine directly. Suppress it because interrupt is not connected yet. + // __WARNING_INVALID_PARAM_VALUE_1: Interrupt is UNREFERENCED_PARAMETER, so it can be NULL +#pragma warning(suppress: __WARNING_IRQ_SET_TOO_HIGH; suppress: __WARNING_INVALID_PARAM_VALUE_1) SerialReset(NULL, pDevExt); -#pragma prefast(suppress: __WARNING_IRQ_SET_TOO_HIGH, "This warning is because we are calling interrupt synchronize routine directly. Suppress it because interrupt is not connected yet.") -#pragma prefast(suppress:6387, "Interrupt is UNREFERENCED_PARAMETER, so it can be NULL") +#pragma warning(suppress: __WARNING_IRQ_SET_TOO_HIGH; suppress: __WARNING_INVALID_PARAM_VALUE_1) SerialMarkClose(NULL, pDevExt); -#pragma prefast(suppress: __WARNING_IRQ_SET_TOO_HIGH, "This warning is because we are calling interrupt synchronize routine directly. Suppress it because interrupt is not connected yet.") -#pragma prefast(suppress:6387, "Interrupt is UNREFERENCED_PARAMETER, so it can be NULL") +#pragma warning(suppress: __WARNING_IRQ_SET_TOO_HIGH; suppress: __WARNING_INVALID_PARAM_VALUE_1) SerialClrRTS(NULL, pDevExt); -#pragma prefast(suppress: __WARNING_IRQ_SET_TOO_HIGH, "This warning is because we are calling interrupt synchronize routine directly. Suppress it because interrupt is not connected yet.") -#pragma prefast(suppress:6387, "Interrupt is UNREFERENCED_PARAMETER, so it can be NULL") +#pragma warning(suppress: __WARNING_IRQ_SET_TOO_HIGH; suppress: __WARNING_INVALID_PARAM_VALUE_1) SerialClrDTR(NULL, pDevExt); // diff --git a/serial/serial/serial.sln b/serial/serial/serial.sln index b5cea148..01eed1bf 100644 --- a/serial/serial/serial.sln +++ b/serial/serial/serial.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wdfserial", "wdfserial.vcxproj", "{B4050279-1352-4D9E-9CF6-6409E8330DF1}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wdfserial", "wdfserial.vcxproj", "{787157F2-E2F3-4ACB-A858-7DBA4400ED38}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +13,14 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {B4050279-1352-4D9E-9CF6-6409E8330DF1}.Debug|Win32.ActiveCfg = Debug|Win32 - {B4050279-1352-4D9E-9CF6-6409E8330DF1}.Debug|Win32.Build.0 = Debug|Win32 - {B4050279-1352-4D9E-9CF6-6409E8330DF1}.Release|Win32.ActiveCfg = Release|Win32 - {B4050279-1352-4D9E-9CF6-6409E8330DF1}.Release|Win32.Build.0 = Release|Win32 - {B4050279-1352-4D9E-9CF6-6409E8330DF1}.Debug|x64.ActiveCfg = Debug|x64 - {B4050279-1352-4D9E-9CF6-6409E8330DF1}.Debug|x64.Build.0 = Debug|x64 - {B4050279-1352-4D9E-9CF6-6409E8330DF1}.Release|x64.ActiveCfg = Release|x64 - {B4050279-1352-4D9E-9CF6-6409E8330DF1}.Release|x64.Build.0 = Release|x64 + {787157F2-E2F3-4ACB-A858-7DBA4400ED38}.Debug|Win32.ActiveCfg = Debug|Win32 + {787157F2-E2F3-4ACB-A858-7DBA4400ED38}.Debug|Win32.Build.0 = Debug|Win32 + {787157F2-E2F3-4ACB-A858-7DBA4400ED38}.Release|Win32.ActiveCfg = Release|Win32 + {787157F2-E2F3-4ACB-A858-7DBA4400ED38}.Release|Win32.Build.0 = Release|Win32 + {787157F2-E2F3-4ACB-A858-7DBA4400ED38}.Debug|x64.ActiveCfg = Debug|x64 + {787157F2-E2F3-4ACB-A858-7DBA4400ED38}.Debug|x64.Build.0 = Debug|x64 + {787157F2-E2F3-4ACB-A858-7DBA4400ED38}.Release|x64.ActiveCfg = Release|x64 + {787157F2-E2F3-4ACB-A858-7DBA4400ED38}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/serial/serial/wdfserial.vcxproj b/serial/serial/wdfserial.vcxproj index 866f8317..2c25e2e1 100644 --- a/serial/serial/wdfserial.vcxproj +++ b/serial/serial/wdfserial.vcxproj @@ -19,12 +19,12 @@
- {B4050279-1352-4D9E-9CF6-6409E8330DF1} + {787157F2-E2F3-4ACB-A858-7DBA4400ED38} $(MSBuildProjectName) 1 Debug Win32 - {CCF3EBBE-8B29-4E2E-8FDF-363939305496} + {368172FD-353B-4B6F-983C-DB2CB6D3E37C} diff --git a/serial/serial/wdfserial.vcxproj.Filters b/serial/serial/wdfserial.vcxproj.Filters index bdaa0854..d46307e6 100644 --- a/serial/serial/wdfserial.vcxproj.Filters +++ b/serial/serial/wdfserial.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {F3AB51FC-17F5-4450-9B7D-97EBDEB45FFE} + {F6210FA1-03EF-44C9-A049-317C86CB6108} h;hpp;hxx;hm;inl;inc;xsd - {C94DF774-16E6-4184-8B88-1823A5717BCF} + {D2D50F99-E5BE-444B-A65B-9E509A935F45} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {1B2DDEE2-3883-4D83-BF10-01F31CB52591} + {10B8A7EE-C817-424C-A850-E21F7DE8C8B5} inf;inv;inx;mof;mc; - {BAE6B924-5A31-4C39-BFA5-E5266CF030D1} + {1FDF6179-3D32-4F47-BF5F-D497E58451C2} diff --git a/setup/DIFxAPI/AppDrv/AppDrv.vcxproj b/setup/DIFxAPI/AppDrv/AppDrv.vcxproj index c82e3348..b9c158a5 100644 --- a/setup/DIFxAPI/AppDrv/AppDrv.vcxproj +++ b/setup/DIFxAPI/AppDrv/AppDrv.vcxproj @@ -19,11 +19,11 @@ - {51E48BC7-B82C-4F02-8C66-9A94C32E8DE4} + {CF7081EA-BC95-4C48-8829-39228285EB60} $(MSBuildProjectName) Debug Win32 - {2431EBAC-383A-407F-B131-FDA52CCA3DFF} + {8A763ADF-480B-4CEB-9240-3C962CEC774B} diff --git a/setup/DIFxAPI/AppDrv/AppDrv.vcxproj.Filters b/setup/DIFxAPI/AppDrv/AppDrv.vcxproj.Filters index 7c8e3101..061dfdbd 100644 --- a/setup/DIFxAPI/AppDrv/AppDrv.vcxproj.Filters +++ b/setup/DIFxAPI/AppDrv/AppDrv.vcxproj.Filters @@ -3,15 +3,15 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {9481CE08-D6B5-4535-BEB1-2150D2E62176} + {C20EAAB1-6327-43E1-91D3-E9A0114A2F12} h;hpp;hxx;hm;inl;inc;xsd - {FCEAD7F6-88BE-4D1B-B2DB-3C93C6E8D318} + {62C6EDFE-CF17-4164-A7B5-ECD8A4BD7FD9} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {78BA1C9C-DC6C-4ED4-8B64-78677A62B0A0} + {2B8AA188-7F46-4526-ABB6-BC3389BC9506} diff --git a/setup/DIFxAPI/DIFxAPI.sln b/setup/DIFxAPI/DIFxAPI.sln index c7fc6244..32c2afcf 100644 --- a/setup/DIFxAPI/DIFxAPI.sln +++ b/setup/DIFxAPI/DIFxAPI.sln @@ -3,13 +3,13 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "AppDrv", "AppDrv", "{B11F7E40-EE73-4682-AB3B-064469A819E1}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "AppDrv", "AppDrv", "{934A7B3A-B938-4EDA-9E5F-E7F433FA087F}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "DIFxCmd", "DIFxCmd", "{2B03F68A-553F-4311-89F2-C8FFC7525379}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "DIFxCmd", "DIFxCmd", "{C23C988D-F193-4B5F-8AEC-BBB7DFA9563A}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AppDrv", "AppDrv\AppDrv.vcxproj", "{51E48BC7-B82C-4F02-8C66-9A94C32E8DE4}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AppDrv", "AppDrv\AppDrv.vcxproj", "{CF7081EA-BC95-4C48-8829-39228285EB60}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DIFxCmd", "DIFxCmd\DIFxCmd.vcxproj", "{C368C716-AC0A-4165-861B-42D55AD9FB99}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DIFxCmd", "DIFxCmd\DIFxCmd.vcxproj", "{C849846A-EA1D-491D-BB56-139869BE3B21}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -19,28 +19,28 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {51E48BC7-B82C-4F02-8C66-9A94C32E8DE4}.Debug|Win32.ActiveCfg = Debug|Win32 - {51E48BC7-B82C-4F02-8C66-9A94C32E8DE4}.Debug|Win32.Build.0 = Debug|Win32 - {51E48BC7-B82C-4F02-8C66-9A94C32E8DE4}.Release|Win32.ActiveCfg = Release|Win32 - {51E48BC7-B82C-4F02-8C66-9A94C32E8DE4}.Release|Win32.Build.0 = Release|Win32 - {51E48BC7-B82C-4F02-8C66-9A94C32E8DE4}.Debug|x64.ActiveCfg = Debug|x64 - {51E48BC7-B82C-4F02-8C66-9A94C32E8DE4}.Debug|x64.Build.0 = Debug|x64 - {51E48BC7-B82C-4F02-8C66-9A94C32E8DE4}.Release|x64.ActiveCfg = Release|x64 - {51E48BC7-B82C-4F02-8C66-9A94C32E8DE4}.Release|x64.Build.0 = Release|x64 - {C368C716-AC0A-4165-861B-42D55AD9FB99}.Debug|Win32.ActiveCfg = Debug|Win32 - {C368C716-AC0A-4165-861B-42D55AD9FB99}.Debug|Win32.Build.0 = Debug|Win32 - {C368C716-AC0A-4165-861B-42D55AD9FB99}.Release|Win32.ActiveCfg = Release|Win32 - {C368C716-AC0A-4165-861B-42D55AD9FB99}.Release|Win32.Build.0 = Release|Win32 - {C368C716-AC0A-4165-861B-42D55AD9FB99}.Debug|x64.ActiveCfg = Debug|x64 - {C368C716-AC0A-4165-861B-42D55AD9FB99}.Debug|x64.Build.0 = Debug|x64 - {C368C716-AC0A-4165-861B-42D55AD9FB99}.Release|x64.ActiveCfg = Release|x64 - {C368C716-AC0A-4165-861B-42D55AD9FB99}.Release|x64.Build.0 = Release|x64 + {CF7081EA-BC95-4C48-8829-39228285EB60}.Debug|Win32.ActiveCfg = Debug|Win32 + {CF7081EA-BC95-4C48-8829-39228285EB60}.Debug|Win32.Build.0 = Debug|Win32 + {CF7081EA-BC95-4C48-8829-39228285EB60}.Release|Win32.ActiveCfg = Release|Win32 + {CF7081EA-BC95-4C48-8829-39228285EB60}.Release|Win32.Build.0 = Release|Win32 + {CF7081EA-BC95-4C48-8829-39228285EB60}.Debug|x64.ActiveCfg = Debug|x64 + {CF7081EA-BC95-4C48-8829-39228285EB60}.Debug|x64.Build.0 = Debug|x64 + {CF7081EA-BC95-4C48-8829-39228285EB60}.Release|x64.ActiveCfg = Release|x64 + {CF7081EA-BC95-4C48-8829-39228285EB60}.Release|x64.Build.0 = Release|x64 + {C849846A-EA1D-491D-BB56-139869BE3B21}.Debug|Win32.ActiveCfg = Debug|Win32 + {C849846A-EA1D-491D-BB56-139869BE3B21}.Debug|Win32.Build.0 = Debug|Win32 + {C849846A-EA1D-491D-BB56-139869BE3B21}.Release|Win32.ActiveCfg = Release|Win32 + {C849846A-EA1D-491D-BB56-139869BE3B21}.Release|Win32.Build.0 = Release|Win32 + {C849846A-EA1D-491D-BB56-139869BE3B21}.Debug|x64.ActiveCfg = Debug|x64 + {C849846A-EA1D-491D-BB56-139869BE3B21}.Debug|x64.Build.0 = Debug|x64 + {C849846A-EA1D-491D-BB56-139869BE3B21}.Release|x64.ActiveCfg = Release|x64 + {C849846A-EA1D-491D-BB56-139869BE3B21}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {51E48BC7-B82C-4F02-8C66-9A94C32E8DE4} = {B11F7E40-EE73-4682-AB3B-064469A819E1} - {C368C716-AC0A-4165-861B-42D55AD9FB99} = {2B03F68A-553F-4311-89F2-C8FFC7525379} + {CF7081EA-BC95-4C48-8829-39228285EB60} = {934A7B3A-B938-4EDA-9E5F-E7F433FA087F} + {C849846A-EA1D-491D-BB56-139869BE3B21} = {C23C988D-F193-4B5F-8AEC-BBB7DFA9563A} EndGlobalSection EndGlobal diff --git a/setup/DIFxAPI/DIFxCmd/DIFxCmd.vcxproj b/setup/DIFxAPI/DIFxCmd/DIFxCmd.vcxproj index 65d9c57b..20d87ab4 100644 --- a/setup/DIFxAPI/DIFxCmd/DIFxCmd.vcxproj +++ b/setup/DIFxAPI/DIFxCmd/DIFxCmd.vcxproj @@ -19,11 +19,11 @@ - {C368C716-AC0A-4165-861B-42D55AD9FB99} + {C849846A-EA1D-491D-BB56-139869BE3B21} $(MSBuildProjectName) Debug Win32 - {EB4A0E3E-31D0-4D1E-9415-453DC8D122F6} + {67461C3B-65C3-4497-9785-A7B43A0D539C} diff --git a/setup/DIFxAPI/DIFxCmd/DIFxCmd.vcxproj.Filters b/setup/DIFxAPI/DIFxCmd/DIFxCmd.vcxproj.Filters index 6657863f..f817f427 100644 --- a/setup/DIFxAPI/DIFxCmd/DIFxCmd.vcxproj.Filters +++ b/setup/DIFxAPI/DIFxCmd/DIFxCmd.vcxproj.Filters @@ -3,15 +3,15 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {EB72BAFA-7E87-4214-8F90-7AB380D50C9E} + {C0AD9456-1A17-4002-A2F1-D7267C7E5A03} h;hpp;hxx;hm;inl;inc;xsd - {E9A405A6-0CA8-4171-A852-CA5C44A9B6BA} + {7C1C7A58-A86E-40FC-B36C-AC97607BAA7A} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {784DA48C-700C-4454-974B-0DA8644295CB} + {52B4B894-1310-435B-B6D1-9A452A91D303} diff --git a/setup/devcon/devcon.htm b/setup/devcon/devcon.htm new file mode 100644 index 00000000..200ecf21 --- /dev/null +++ b/setup/devcon/devcon.htm @@ -0,0 +1,680 @@ + + + + + + + + +DevCon Sample + + + + + + + +
+ +

DevCon Sample

+ +

DEVCON

+ +

DevCon is a command-line tool that +displays detailed information about devices, and lets you search for and +manipulate devices from the command line. DevCon +enables, disables, installs, configures, and removes devices on the local +computer and displays detailed information about devices on local and remote +computers. DevCon is included in the Windows DDK.

+ +

ABOUT THIS DOCUMENT

+ +

This document describes +the DevCon source code, which is included in the +Windows DDK in the /src/setup/devcon directory. It +explains the DevCon design, and describes how to use +the SetupAPI and device installation functions to +enumerate devices and perform device operations in a console application.

+ +

For a complete +description of DevCon features and instructions for +using them, see the DevCon help file in the DDK +documentation in Driver Development Tools/Tools for Testing Drivers/DevCon.

+ +

SCOPE

+ +

These instructions +pertain to Windows XP and Windows Server 2003. DevCon +was designed for use on Windows 2000, Windows XP, and Windows Server 2003. It +will not work on Windows 95, Windows 98, or Windows ME.

+ +

HOW IT WORKS

+ +

Running "devcon help" will provide a list of commands along +with short descriptions of what each command does. "devcon help <command>" will give more +detailed help on that command. The interpretation of each command is done via a +dispatch table "DispatchTable" that is at +the bottom of "cmds.cpp". Some of the +commands make use of a generic device enumerator "EnumerateDevices". +A few of these commands will work when given a remote target computer, and will +also work if using the 32-bit devcon on Wow64.  +A description of some of the more interesting functions and the APIs they use +follows:

+ +

cmdClasses

+ +

This command demonstrates +the use of SetupDiBuildClassInfoListEx to enumerate +all device class GUID's. The function SetupDiClassNameFromGuidEx and SetupDiGetClassDescriptionEx +are used to obtain more information about each device class.

+ +

cmdListClass

+ +

This command demonstrates +the use of SetupDiClassGuidsFromNameEx to enumerate +one or more class GUID's that match the class name. +This command also demonstrates the use of SetupDiGetClassDevsEx +to list all the devices for each class GUID.

+ +

cmdFind cmdFindAll cmdStatus

+ +

A simple use of EnumerateDevices (explained below) to list devices and +display different levels of information about each device. Note that all but cmdFindAll use DIGCF_PRESENT to only list information about +devices that are currently present. The main functionality for these and +related devices is done inside FindCallback.

+ +

cmdEnable cmdDisable cmdRestart

+ +

These commands show +how to issue DIF_PROPERTYCHANGE to enable a device, disable a device, or +restart a device. The main functionality for each of these commands is done +inside ControlCallback.

+ +

These operations cannot +be done on a remote machine or in the context of Wow64. CFGMGR32 API's should +not be used as they skip class and co-installers.

+ +

cmdUpdate

+ +

This command shows how to +use UpdateDriverForPlugAndPlayDevices to update the +driver for all devices to a specific driver. Normally INSTALLFLAG_FORCE would +not be specified allowing UpdateDriverForPlugAndPlayDevices +to determine if there is a better match already known. It's specified in DevCon to allow DevCon to be used +more effectively as a debugging/testing tool. This cannot be done on a remote +machine or in the context of Wow64.

+ +

cmdInstall

+ +

A variation of cmdUpdate to install a driver when there is no associated +hardware. It creates a new root-enumerated device instance and associates it +with a made up hardware ID specified on the command line (which should +correspond to a hardware ID in the INF). This cannot be done on a remote +machine or in the context of Wow64.

+ +

cmdRemove

+ +

A +command to remove devices. Plug & Play devices that are removed will reappear in +response to cmdRescan. The main functionality of this +command is in RemoveCallback that demonstrates the +use of DIF_REMOVE. This cannot be done on a remote machine or in the context of +Wow64. CFGMGR32 API's should not be used as they skip class and co-installers.

+ +

cmdRescan

+ +

This command shows the +correct way to rescan for all Plug & Play devices that may have previously +been removed, or that otherwise require a rescan to detect them.

+ +

cmdDPAdd

+ +

This +command allows you to add a Driver Package to the machine.  The main functionality of this command +demonstrates the use of SetupCopyOEMInf. Adding a Driver +Package to the machine doesn’t mean the drivers are installed on devices, it +simply means the drivers are available automatically when a new device is +plugged in or a existing device is updated.

+ +

cmdDPDelete

+ +

This +command allows you to uninstall a Driver Package from the machine.  The main functionality of this command +demonstrates the use of SetupUninstallOEMInf. +Removing a Driver Package from the machine does not uninstall the drivers +associated with a device. If you want to accomplish both then use cmdRemove on all the devices using a given Driver Package +and then cmdDPDelete to remove the Driver Package +itself from the machine. This functionality is not available in Windows 2000 or +earlier.

+ +

cmdDPEnum

+ +

This +command allows you to enumerate all of the 3rd party Driver Packages +currently installed on the machine and also shows you how to get some common +properties from a Driver Package (Provider, Class description, DriverVer date and version).

+ +

cmdDPEnumLegacy

+ +

This +command shows you how to enumerate 3rd party Driver Packages on +Windows Server 2003 and earlier operating systems.

+ +

Reboot

+ +

This function shows how +to correctly reboot the machine from a hardware install program. In particular +it passes flags to ExitWindowsEx that cause the +reboot to be associated with hardware installation. You should never reboot the machine unnecessarily.

+ +

EnumerateDevices

+ +

Demonstrates +the use of SetupDiGetClassDevsEx to enumerate all +devices or all present devices, either globally or limited to a specific setup +class. +Demonstrates the use of SetupDiCreateDeviceInfoListEx +to create a blank list associated with a class or not (for most cases, a blank +list need not be associated with a class). Demonstrates the +use of SetupDiOpenDeviceInfo to add a device instance +into a device info list. These last two API's are ideal to obtain a DeviceInfoData structure from a device instance and machine +name when mixing CFGMGR32 API's with SETUPAPI API's. SetupDiGetDeviceInfoListDetail +is called to obtain a remote machine handle that may be passed into CFGMGR32 +API's. SetupDiEnumDeviceInfo is called to enumerate +each and every device that is in the device info list (either explicitly added, +or determined by the call to SetupDiGetClassDevsEx). +The instance ID is obtained by calling CM_Get_Device_ID_Ex, +using information in devInfo (obtained from SetupDiEnumerateDeviceInfo) and devInfoListDetail +(obtained from SetupDiGetDeviceInfoListDetail). GetHwIds is called to obtain a list of hardware and +compatible ID's (explained below). Once an interesting device has been +determined (typically by checking hardware ID's) then the callback is called to +operate on that individual device.

+ +

GetHwIds

+ +

Shows how to get the +complete list of hardware ID's or compatible ID's for a device using SetupDiGetDeviceRegistryProperty.

+ +

GetDeviceDescription

+ +

Shows +how to obtain descriptive information about a device. The friendly name is used if it exists, otherwise the device description is used.

+ +

DumpDeviceWithInfo

+ +

Shows +how to obtain an instance ID (or use any CFGMGR32 API) given HDEVINFO (device +info list) and PSP_DEVINFO_DATA (device info data).

+ +

DumpDeviceStatus

+ +

Shows +how to interpret the information returned by CM_Get_DevNode_Status_Ex. +Refer to cfg.h for information returned by this API.

+ +

DumpDeviceResources

+ +

Shows +how to obtain information about resources used by a device.

+ +

DumpDeviceDriverFiles

+ +

Provided as a debugging +aid, obtains information about the files apparently being used for a device. It +uses SetupDiBuildDriverInfoList to obtain information +about the driver being used for the specified device. The driver list +associated with a device may be enumerated by calling SetupDiEnumDriverInfo. +In this case, there will be no more than one driver listed. This function +proceeds to obtain a list of files that would normally be copied for this +driver using DIF_INSTALLDEVICEFILES. SetupScanFileQueue +is used to enumerate the file queue to display the list of files that are associated +with the driver.

+ +

DumpDeviceDriverNodes

+ +

Provided as a debugging +aid, this function determines the list of compatible drivers for a device. It +uses SetupDiBuildDriverInfoList to obtain the list of +compatible drivers. In this case, all drivers are enumerated, however typically +DIF_SELECTBESTCOMPATDRV and SetupDiGetSelectedDriver +would be used together to find which driver the OS would consider to be the +best.

+ +

DumpDeviceStack

+ +

This function determines +class and device upper and lower filters.

+ +

BUILDING THE DEVCON SAMPLE

+ +
To build the devcon +sample:
+ +

1.      Click the Build Environment icon +of choice in the Development Kits Build Environments sub-menu. This will set up +the correct build environment to build this sample. Note that this sample will +build in the 64-bit environments as well as the 32-bit environments.

+ +

2.      In a command window, change to the +directory containing the DevCon source code. For +example:

+ +
+ +

cd src\setup\devcon

+ +
+ +

3.      Use the macro BLD or run the +following from the command prompt:

+ +
+ +

build –c

+ +

This invokes the +Microsoft make routines that produce the Build.log, Build.wrn, and Build.err log +files.

+ +

When the build completes, +the executable will be placed in the ObjXXX\I386 subdirectory of the +<TARGETPATH> directory specified in the Sources file (depending on build +environment chosen).

+ +

If the build does not +succeed, check for these errors: 1) the build environment is not set up +properly, or 2) modifications made to the sample source code introduced errors. +

+ +
+ +

USING DEVCON

+ +

DevCon is provided in ready-to-run form +in tools\devcon. For usage, refer to the document +provided with devcon.exe. DevCon is a command line +utility with built-in documentation available by typing "devcon help".

+ +

TESTING

+ +

Type "devcon find *" to list device instances of all present +devices on the local machine.

+ +

Type +"devcon status @root\rdp_mou\0000" to list +status of the terminal server mouse driver.

+ +

Type +"devcon status *PNP05*" to list status of +all COM ports.

+ +

CODE TOUR

+ +

File Manifest

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

File

+
+

Description

+
+

DevCon.htm

+
+

Sample tour documentation for this binary (this file).

+
+

DevCon.cpp

+
+

Source file for tmain entry + point and utility functions.

+
+

Cmds.cpp

+
+

Source file for supported commands.

+
+

Dump.cpp

+
+

Source file for functions that output information about + devices.

+
+

DevCon.h

+
+

Header file for sample.

+
+

DevCon.rc

+
+

Resource file containing some + strings and version information.

+
+

rc_ids.h

+
+

Header file for resources.

+
+

Msg.mc

+
+

Message file that is used to build msg.rc + and msg.h used for help texts and other messages.

+
+

Sources

+
+

Generic file that lists source files and all the build + options.

+
+

Makefile

+
+

File that redirects to the real make file that is shared + by all the driver components of the Windows DDK.

+
+ +

FEEDBACK

+ +

We welcome your comments, problem reports +and wish-list requests. Please submit them by pointing your Internet browser to +http://www.microsoft.com/ddk.

+ +

Top of page

+ + + + + +
+

 

+
+ +

© 2004 Microsoft Corporation

+ +
+ + + + diff --git a/setup/devcon/devcon.sln b/setup/devcon/devcon.sln index cc5b6752..68b6a2f9 100644 --- a/setup/devcon/devcon.sln +++ b/setup/devcon/devcon.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "devcon", "devcon.vcxproj", "{E3D0CF6A-32E9-4970-8BED-43CC8DF57A5D}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "devcon", "devcon.vcxproj", "{B3ABCC72-91F9-40CB-A8F4-CB9C1400C5FC}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +13,14 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {E3D0CF6A-32E9-4970-8BED-43CC8DF57A5D}.Debug|Win32.ActiveCfg = Debug|Win32 - {E3D0CF6A-32E9-4970-8BED-43CC8DF57A5D}.Debug|Win32.Build.0 = Debug|Win32 - {E3D0CF6A-32E9-4970-8BED-43CC8DF57A5D}.Release|Win32.ActiveCfg = Release|Win32 - {E3D0CF6A-32E9-4970-8BED-43CC8DF57A5D}.Release|Win32.Build.0 = Release|Win32 - {E3D0CF6A-32E9-4970-8BED-43CC8DF57A5D}.Debug|x64.ActiveCfg = Debug|x64 - {E3D0CF6A-32E9-4970-8BED-43CC8DF57A5D}.Debug|x64.Build.0 = Debug|x64 - {E3D0CF6A-32E9-4970-8BED-43CC8DF57A5D}.Release|x64.ActiveCfg = Release|x64 - {E3D0CF6A-32E9-4970-8BED-43CC8DF57A5D}.Release|x64.Build.0 = Release|x64 + {B3ABCC72-91F9-40CB-A8F4-CB9C1400C5FC}.Debug|Win32.ActiveCfg = Debug|Win32 + {B3ABCC72-91F9-40CB-A8F4-CB9C1400C5FC}.Debug|Win32.Build.0 = Debug|Win32 + {B3ABCC72-91F9-40CB-A8F4-CB9C1400C5FC}.Release|Win32.ActiveCfg = Release|Win32 + {B3ABCC72-91F9-40CB-A8F4-CB9C1400C5FC}.Release|Win32.Build.0 = Release|Win32 + {B3ABCC72-91F9-40CB-A8F4-CB9C1400C5FC}.Debug|x64.ActiveCfg = Debug|x64 + {B3ABCC72-91F9-40CB-A8F4-CB9C1400C5FC}.Debug|x64.Build.0 = Debug|x64 + {B3ABCC72-91F9-40CB-A8F4-CB9C1400C5FC}.Release|x64.ActiveCfg = Release|x64 + {B3ABCC72-91F9-40CB-A8F4-CB9C1400C5FC}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/setup/devcon/devcon.vcxproj b/setup/devcon/devcon.vcxproj index c674ef8a..096388e6 100644 --- a/setup/devcon/devcon.vcxproj +++ b/setup/devcon/devcon.vcxproj @@ -19,11 +19,11 @@
- {E3D0CF6A-32E9-4970-8BED-43CC8DF57A5D} + {B3ABCC72-91F9-40CB-A8F4-CB9C1400C5FC} $(MSBuildProjectName) Debug Win32 - {406B583C-3ECF-4696-B3DD-6F2E8B3C1ED5} + {6B50AB2B-3ADE-4D0B-A859-3E6EB578AB42} diff --git a/setup/devcon/devcon.vcxproj.Filters b/setup/devcon/devcon.vcxproj.Filters index 803e16d8..38a699dc 100644 --- a/setup/devcon/devcon.vcxproj.Filters +++ b/setup/devcon/devcon.vcxproj.Filters @@ -3,15 +3,15 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {C14D27DB-E3A6-4543-A3C4-7EF046CD3D67} + {5372BDCC-9AF5-4735-84C0-9AB168DD5DF1} h;hpp;hxx;hm;inl;inc;xsd - {8837D39E-7F9A-4CCB-B352-F512532281A3} + {108192B6-9F15-48AA-A1E2-5C076B2ACFFB} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {CCD87CAF-050E-44E6-B5BE-C919F85E854D} + {FBAAD2FE-6B28-4F66-90D0-2B6662CA1195} diff --git a/smartcrd/ReadMe.md b/smartcrd/ReadMe.md new file mode 100644 index 00000000..d3d0f600 --- /dev/null +++ b/smartcrd/ReadMe.md @@ -0,0 +1,41 @@ +PCMCIA Smart Card Driver +======================== + +The PCMCIA Smart Card Driver is used for the SCM PCMCIA smart card reader. This driver is written using Kernel-Mode Driver Framework. + +This driver in its original form was written in WDM. It was converted to KMDF to take advantage of all the benefits provided by KMDF in terms of reducing complexity and making it robust. Since this driver still needs to work with the existing smartcard library to handle smartcard specific processing, the driver is not restricted to using only KMDF interfaces. Escaping out of KMDF is necessary for processing I/O requests to get the underlying IRPs and provide that to the smartcard library. The driver also uses advanced IRP handling techniques to work around the limitations imposed by the smartcard library. Except for this quirk, the driver is a fully functional KMDF driver. As a sample, it also makes it easier to adapt this driver for USB devices since KMDF has good support for interfacing with USB devices. + +Power Management is described in detail in the WDK documentation. There is, however, one situation that is specific to smart card readers: how to deal with smart card insertions and removals while the system is in standby or hibernation mode. + +A card reader will not see any card insertion or removal events in these modes, because the bus might not even have power. The card state must be saved before the reader goes into standby or hibernation mode. After the system returns from these modes, it is necessary to determine what the state of the card is. Card tracking calls must complete whenever there was a card in the reader before standby or hibernation mode or whenever there is a card in the reader after these modes. This step is necessary because the user could have changed the card while the system was in a low-power mode. + + +Build the sample +---------------- + +For information on how to build a driver solution using Microsoft Visual Studio, see [Building a Driver](http://msdn.microsoft.com/en-us/library/windows/hardware/ff554644). + +**Note**  Starting in Windows 8, the WDK no longer contains the co-installers by default. You can obtain the co-installers by downloading the *wdfcoinstaller.msi* package from [WDK 8 Redistributable Components](http://go.microsoft.com/fwlink/p/?LinkID=226396). + +Run the sample +-------------- + +Installation +------------ + +The PSCR.SYS driver is included in-box in Windows or, starting with Windows 8.1, available from Windows Update. Therefore, when the SCM 488 PCMCIA reader is inserted, the system will automatically install the driver. However, if you want to customize the source code of this driver and replace the in-box driver or the driver from Windows Update with your driver, use the supplied INF file. + +Tools +----- + +Microsoft offers a test tool (Ifdtest.exe) that allows you to use a smart card reader directly from the command line. Normally, the smart card resource manager is connected to a reader. To use Ifdtest.exe, you must stop the smart card resource manager (Scardsvr.exe) by typing net stop scardsvr at the command line. Ifdtest.exe is also used for the smart card reader logo test. + +The driver will not unload as long as you have Ifdtest.exe running and connected to the driver. + +Resources +--------- + +ISO 7816 Part 3 describes smart cards and smart card protocols in detail. Refer to the PC99 Handbook for smart card reader requirements. + +For more information about Windows smart card reader drivers, see [Smart Card Reader Devices Design Guide](http://msdn.microsoft.com/en-us/library/windows/hardware/). + diff --git a/smartcrd/pscr/Pscr.vcxproj b/smartcrd/pscr/Pscr.vcxproj new file mode 100644 index 00000000..88bc7891 --- /dev/null +++ b/smartcrd/pscr/Pscr.vcxproj @@ -0,0 +1,183 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {E963C756-D675-4202-A229-6B3ADB94B252} + $(MSBuildProjectName) + 1 + Debug + Win32 + {1C4F5FFD-0F09-4478-A3F7-DEF422837617} + + + + Windows10 + False + Desktop + KMDF + WindowsKernelModeDriver10.0 + Driver + + + Windows10 + True + Desktop + KMDF + WindowsKernelModeDriver10.0 + Driver + + + Windows10 + False + Desktop + KMDF + WindowsKernelModeDriver10.0 + Driver + + + Windows10 + True + Desktop + KMDF + WindowsKernelModeDriver10.0 + Driver + + + + $(IntDir) + + + + + + + + + + + + + + + + $(InfArch) + true + .\$(IntDir)\pscr.inf + + + + Pscr + + + Pscr + + + Pscr + + + Pscr + + + + %(AdditionalDependencies);$(DDK_LIB_PATH)\smclib.lib;$(DDK_LIB_PATH)\ntoskrnl.lib + + + %(AdditionalIncludeDirectories);..\inc + + + %(AdditionalIncludeDirectories);..\inc + + + + + %(AdditionalIncludeDirectories);..\inc + + + + + %(AdditionalDependencies);$(DDK_LIB_PATH)\smclib.lib;$(DDK_LIB_PATH)\ntoskrnl.lib + + + %(AdditionalIncludeDirectories);..\inc + + + %(AdditionalIncludeDirectories);..\inc + + + + + %(AdditionalIncludeDirectories);..\inc + + + + + %(AdditionalDependencies);$(DDK_LIB_PATH)\smclib.lib;$(DDK_LIB_PATH)\ntoskrnl.lib + + + %(AdditionalIncludeDirectories);..\inc + + + %(AdditionalIncludeDirectories);..\inc + + + + + %(AdditionalIncludeDirectories);..\inc + + + + + %(AdditionalDependencies);$(DDK_LIB_PATH)\smclib.lib;$(DDK_LIB_PATH)\ntoskrnl.lib + + + %(AdditionalIncludeDirectories);..\inc + + + %(AdditionalIncludeDirectories);..\inc + + + + + %(AdditionalIncludeDirectories);..\inc + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/smartcrd/pscr/Pscr.vcxproj.Filters b/smartcrd/pscr/Pscr.vcxproj.Filters new file mode 100644 index 00000000..55f941f4 --- /dev/null +++ b/smartcrd/pscr/Pscr.vcxproj.Filters @@ -0,0 +1,51 @@ + + + + + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* + {7EB6DC3A-11A4-48F2-9730-419C9A104242} + + + h;hpp;hxx;hm;inl;inc;xsd + {2AAA41D4-E19E-409F-87C1-EA4C640F0BAA} + + + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml + {9FEF86B3-6289-44F6-B036-2C15E61CDDDE} + + + inf;inv;inx;mof;mc; + {A832F7F9-C73F-4032-83DF-1CA14DE6C0FF} + + + + + Driver Files + + + Driver Files + + + Driver Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Resource Files + + + \ No newline at end of file diff --git a/smartcrd/pscr/pscr.htm b/smartcrd/pscr/pscr.htm new file mode 100644 index 00000000..934a4c0e --- /dev/null +++ b/smartcrd/pscr/pscr.htm @@ -0,0 +1,867 @@ + + + + + + + + +PSCR.SYS—PCMCIA Smart Card Driver + + + + + + + + + + +
+ +

PSCR.SYS—PCMCIA +Smart Card Driver

+ +

SUMMARY

+ +

The PCMCIA +Smart Card Driver is used for the SCM PCMCIA smart card reader. This +driver is written using Kernel-Mode Driver Framework.

+ +

This +driver implements Plug and Play and Power Management and is compliant with +64-bit versions of Microsoft® Windows®.

+ +

BUILDING PSCR.SYS

+ +

To build +the Pscr.sys driver, select either the checked or free DDK environment, +navigate to the Bulltlp3 directory, and type build. This driver +uses services provided by the smart card driver library (Smclib.sys), which are +explained in detail in the accompanying documentation.

+ +

INSTALLING PSCR.SYS

+ +

The +PSCR.SYS driver is included in-box in the Windows Operating Systems. Therefore, +when the SCM 488 PCMCIA reader is inserted, the system will automatically +install the in-box driver. However, if you want to customize the source code of +this driver and would like to replace the in-box driver with your driver, you +can follow the instructions below.

+ +

To install +your driver, you will need to provide the INF file (on a disk), WDF coinstaller from the %BASEDIR%\redist\wdf\ directory and the driver file, which will be copied to +your System32\Drivers directory. The INF file makes a reference to the WDF coinstaller.

+ +

1.    Launch “Device +Manager” by clicking the “Windows” button and type “devmgmt.msc” in the “Search +programs and files” box.

+ +

2.    Locate the SCM 488 +Smartcard reader device from the “Smart cards readers” category.

+ +

3.    Right click on the +reader device and select “Update Driver Software…”.

+ +

4.    Select “Browse my +computer for driver software”.

+ +

5.    Select “Let me pick +from a list of device drivers on my computer”.

+ +

6.    Click the “Have +Disk…” button and point it to the folder that contains your driver, INF and +coinstaller.

+ +

7.    Follow the +instructions of the device installation wizard to finish the installation.

+ +

TOOLS

+ +

Microsoft +offers a test tool (Ifdtest.exe) that allows you to use a smart card reader +directly from the command line. Normally, the smart card resource manager is +connected to a reader. To use Ifdtest.exe, you must stop the smart card +resource manager (Scardsvr.exe) by typing net stop scardsvr +at the command line. Ifdtest.exe is also used for the smart card reader logo +test.

+ +

The driver +will not unload as long as you have Ifdtest.exe running and connected to the +driver.

+ +

You can +download Ifdtest.exe from http://www.microsoft.com/whdc/whql/default.mspx by following the +links for smart cards. You need to order special test smart cards to have your +smart card reader qualify for the "Designed for Windows" logo. You +can find ordering information at http://www.microsoft.com/whdc/whql/default.mspx.  

+ +

RESOURCES

+ +

ISO 7816 +Part 3 describes smart cards and smart card protocols in detail. Refer to the +PC99 Handbook for smart card reader requirements.

+ +

CODE TOUR

+ +

File Manifest

+ +
Files         Description
PSCR.HTM      The documentation for this sample (this file).
PSCR.RC       Resource definition file for driver.
SOURCES       The generic file for building the code sample.
MAKEFILE      Makefile required to build the driver.
PSCR.INF      The INF file for installing the code sample.
PSCRCB.C      Source file that contains the callback functions for the smart card library.
PSCRCB.H      Function prototypes for the previous file.
PSCRCMD.C     Implements the reader commands.
PSCRCMD.H     Function prototypes for the previous file.
PSCRLOG.MC    Error messages for this driver.
PSCRNT.C      The main source file (load, unload, Plug and Play, Power Management).
PSCRNT.H      Data definitions and prototypes for the previous file.
PSCRRDWR.C    Implements read/write operations.
PSCRRDWR.H    Data definitions and constant definitions for this reader.
PSCRVERS.H    Driver-specific version information.
 
+ +

Programming +Tour

+ +

Driver Design

+ +

This driver in its +original form was written in WDM. It was converted to KMDF to avail all the +benefits provided by KMDF in terms of reducing complexity and making it robust. +Since this driver still had to work with the existing smartcard library to +handle smartcard specific processing, I couldn’t restrict the driver to using +only KMDF interfaces. I have to escape out of KMDF for processing I/O requests +to get the underlying IRPs and provide that to smartcard library, and use +advanced IRP handling techniques to work around the limitations imposed by +smartcard library. Except for this quirk, the driver as a whole is fully +functional KMDF driver. As a sample, it also makes it easier for somebody to +adapt this driver for USB devices because KMDF has good support for interfacing +with USB devices.

+ +

Power Management

+ + + +

Power Management is +described in detail in the DDK documentation. There is, however, one situation +that is specific to smart card readers: how to deal with smart card insertions +and removals while the system is in standby or hibernation mode.

+ +

Your reader will +not see any card insertion or removal events in these modes, because the bus +might not even have power. You must save the card state before your reader goes +into standby or hibernation mode. After the system returns from these modes, +you need to determine what the state of the card is. You must complete card +tracking calls whenever there was a card in the reader before standby or +hibernation mode or whenever there is a card in the reader after these +modes. This step is necessary because the user could have changed the card +while the system was in a low-power mode.

+ +

 

+ +

Top +of page +

+ + + + + +
+

 

+
+ +

© 2004 Microsoft +Corporation +

+ +
+ + + + + diff --git a/smartcrd/pscr/pscr.inx b/smartcrd/pscr/pscr.inx new file mode 100644 index 00000000..28e93816 Binary files /dev/null and b/smartcrd/pscr/pscr.inx differ diff --git a/smartcrd/pscr/pscr.rc b/smartcrd/pscr/pscr.rc new file mode 100644 index 00000000..4bf91809 --- /dev/null +++ b/smartcrd/pscr/pscr.rc @@ -0,0 +1,48 @@ +//+------------------------------------------------------------------------- +// +// Microsoft Windows +// +// Copyright (C) SCM Microsystems, 1998 - 1999 +// +// File: pscr.rc +// +// Notes: +// +// The file pscr.rc was reviewed by LCA in June 2011 and per license is +// acceptable for Microsoft use under Dealpoint ID 178449. +// +//-------------------------------------------------------------------------- + +#include +#include + +/* These need to be defined before including common.ver: */ +/*-----------------------------------------------------------------*/ +/* String Equate Default Value (if not defined) */ +/* ------------------------ -------------------------------- */ +/* VER_LEGALCOPYRIGHT_STR VER_LEGALCOPYRIGHT_YEARS */ +/* VER_FILETYPE */ +/* VER_FILESUBTYPE */ +/* VER_FILEDESCRIPTION_STR */ +/* VER_INTERNALNAME_STR */ +/* VER_FILEVERSION VER_PRODUCTVERSION */ +/* VER_FILEVERSION_STR VER_PRODUCTVERSION_STR */ +/* VER_ORIGINALFILENAME_STR VER_INTERNALNAME_STR */ +/*-----------------------------------------------------------------*/ + + +#define VER_LEGALCOPYRIGHT_YEARS "1997-1999" +#define VER_LEGALCOPYRIGHT_STR "Copyright (C) SCM Microsystems, Inc. " VER_LEGALCOPYRIGHT_YEARS + +#define VER_FILETYPE VFT_DRV +#define VER_FILESUBTYPE VFT2_DRV_SYSTEM +#define VER_FILEDESCRIPTION_STR "SCM PCMCIA Smart Card Reader" +#define VER_INTERNALNAME_STR "pscr.sys" +#define VER_ORIGINALFILENAME_STR "pscr.sys" + +#undef VER_COMPANYNAME_STR +#define VER_COMPANYNAME_STR "SCM Microsystems, Inc." + +#include "common.ver" +#include "pscrlog.rc" + diff --git a/smartcrd/pscr/pscrcb.c b/smartcrd/pscr/pscrcb.c new file mode 100644 index 00000000..4b89680c --- /dev/null +++ b/smartcrd/pscr/pscrcb.c @@ -0,0 +1,1008 @@ +/*++ + +Copyright (c) 1997 - 1999 SCM Microsystems, Inc. + +Module Name: + + PscrCB.c + +Abstract: + + callback handler for PSCR.xxx driver + +Author: + + Andreas Straub + +Environment: + + Win 95 Sys... calls are resolved by Pscr95Wrap.asm functions and + Pscr95Wrap.h macros, resp. + + NT 4.0 Sys... functions resolved by PscrNTWrap.c functions and + PscrNTWrap.h macros, resp. + +Notes: + + The file pscrcb.c was reviewed by LCA in June 2011 and per license is + acceptable for Microsoft use under Dealpoint ID 178449. + +Revision History: + + Andreas Straub 8/18/1997 1.00 Initial Version + Andreas Straub 9/24/1997 1.02 Flush Interface if card tracking + requested + +--*/ + +#include +#include +#include +#include + + +NTSTATUS +CBCardPower( + PSMARTCARD_EXTENSION SmartcardExtension + ) +/*++ + +CBCardPower: + callback handler for SMCLIB RDF_CARD_POWER + +Arguments: + SmartcardExtension context of call + +Return Value: + STATUS_SUCCESS + STATUS_NO_MEDIA + STATUS_TIMEOUT + STATUS_BUFFER_TOO_SMALL + +--*/ +{ + NTSTATUS NTStatus = STATUS_SUCCESS; + UCHAR ATRBuffer[ ATR_SIZE ], TLVList[16]; + ULONG Command, + ATRLength = 0; + PREADER_EXTENSION ReaderExtension; + BYTE CardState; + KIRQL irql; +#if DBG || DEBUG + static PCHAR request[] = { "PowerDown", "ColdReset", "WarmReset"}; +#endif + + SmartcardDebug( + DEBUG_TRACE, + ( "PSCR!CBCardPower: Enter, Request = %s\n", + request[SmartcardExtension->MinorIoControlCode]) + ); + + ReaderExtension = SmartcardExtension->ReaderExtension; + + // + // update actual power state + // + Command = SmartcardExtension->MinorIoControlCode; + + switch ( Command ) { + case SCARD_WARM_RESET: + + // if the card was not powerd, fall thru to cold reset + KeAcquireSpinLock(&SmartcardExtension->OsData->SpinLock, + &irql); + + if ( SmartcardExtension->ReaderCapabilities.CurrentState > + SCARD_SWALLOWED ) { + KeReleaseSpinLock(&SmartcardExtension->OsData->SpinLock, + irql); + + // reset the card + ATRLength = ATR_SIZE; + NTStatus = CmdReset( + ReaderExtension, + ReaderExtension->Device, + TRUE, // warm reset + ATRBuffer, + &ATRLength + ); + + break; + } else { + KeReleaseSpinLock(&SmartcardExtension->OsData->SpinLock, + irql); + + } + + // warm reset not possible because card was not powerd + case SCARD_COLD_RESET: + + // reset the card + ATRLength = ATR_SIZE; + NTStatus = CmdReset( + ReaderExtension, + ReaderExtension->Device, + FALSE, // cold reset + ATRBuffer, + &ATRLength + ); + break; + + case SCARD_POWER_DOWN: + ATRLength = 0; + NTStatus = CmdDeactivate( + ReaderExtension, + ReaderExtension->Device + ); + + // discard old card status + CardState = CBGetCardState(SmartcardExtension); + CBUpdateCardState(SmartcardExtension, CardState, FALSE); + break; + } + + if (NT_SUCCESS(NTStatus)) { + + // + // Set the 'restart of work waiting time' counter for T=0 + // This will send a WTX request for n NULL bytes received + // + TLVList[0] = TAG_SET_NULL_BYTES; + TLVList[1] = 1; + TLVList[2] = 0x05; + + NTStatus = CmdSetInterfaceParameter( + ReaderExtension, + DEVICE_READER, + TLVList, + 3 + ); + } + + // Removing this assert as this causes unnecessary confusion. The driver + // passes ifdtest even with an error here. + // NT_ASSERT(NT_SUCCESS(NTStatus)); + + // finish the request + if ( NT_SUCCESS( NTStatus )) { + // update all neccessary data if an ATR was received + if ( ATRLength > 2 ) { + // + // the lib expects only the ATR, so we skip the + // 900x from the reader + // + ATRLength -= 2; + + // copy ATR to user buffer buffer + if ( ATRLength <= SmartcardExtension->IoRequest.ReplyBufferLength ) { + SysCopyMemory( + SmartcardExtension->IoRequest.ReplyBuffer, + ATRBuffer, + ATRLength + ); + *SmartcardExtension->IoRequest.Information = ATRLength; + } + + // copy ATR to card capability buffer + if ( ATRLength <= MAXIMUM_ATR_LENGTH ) { + SysCopyMemory( + SmartcardExtension->CardCapabilities.ATR.Buffer, + ATRBuffer, + ATRLength + ); + + SmartcardExtension->CardCapabilities.ATR.Length = + ( UCHAR )ATRLength; + + // let the lib update the card capabilities + NTStatus = SmartcardUpdateCardCapabilities( + SmartcardExtension + ); + } else { + NTStatus = STATUS_BUFFER_TOO_SMALL; + } + } + } + + if ( !NT_SUCCESS( NTStatus )) { + switch ( NTStatus ) { + case STATUS_NO_MEDIA: + case STATUS_BUFFER_TOO_SMALL: + break; + + case STATUS_TIMEOUT: + NTStatus = STATUS_IO_TIMEOUT; + break; + + default: + NTStatus = STATUS_UNRECOGNIZED_MEDIA; + break; + } + if( NTStatus != STATUS_SUCCESS ) + { + + // notify resman if card was removed + CBUpdateCardState( + SmartcardExtension, + CBGetCardState( SmartcardExtension ), + FALSE + ); + + // resman requires status ok to translate ntstatus to scard... error. + if( SmartcardExtension->ReaderCapabilities.CurrentState <= SCARD_ABSENT ) + { + SmartcardUpdateCardCapabilities( SmartcardExtension ); + NTStatus = STATUS_SUCCESS; + } + } + } + + // start freeze routine, if an interrupt was sent, but no freeze data was read + if( SmartcardExtension->ReaderExtension->RequestInterrupt ) + PscrFreeze( SmartcardExtension ); + + // Clearing the buffers + RtlZeroMemory (ATRBuffer, ATR_SIZE); + RtlZeroMemory (TLVList, 16); + + SmartcardDebug( + DEBUG_TRACE, + ( "PSCR!CBCardPower: Exit (%lx)\n", NTStatus ) + ); + + return( NTStatus ); +} + +NTSTATUS +CBSetProtocol( + PSMARTCARD_EXTENSION SmartcardExtension + ) + +/*++ + +CBSetProtocol: + callback handler for SMCLIB RDF_SET_PROTOCOL + +Arguments: + SmartcardExtension context of call + +Return Value: + STATUS_SUCCESS + STATUS_NO_MEDIA + STATUS_TIMEOUT + STATUS_BUFFER_TOO_SMALL + STATUS_INVALID_DEVICE_STATE + STATUS_INVALID_DEVICE_REQUEST + +--*/ +{ + NTSTATUS NTStatus = STATUS_PENDING; + USHORT SCLibProtocol; + UCHAR TLVList[ TLV_BUFFER_SIZE ]; + PREADER_EXTENSION ReaderExtension = SmartcardExtension->ReaderExtension; + KIRQL irql; + + KeAcquireSpinLock(&SmartcardExtension->OsData->SpinLock, + &irql); + + if (SmartcardExtension->ReaderCapabilities.CurrentState == SCARD_SPECIFIC) { + KeReleaseSpinLock(&SmartcardExtension->OsData->SpinLock, + irql); + + + return STATUS_SUCCESS; + } else { + KeReleaseSpinLock(&SmartcardExtension->OsData->SpinLock, + irql); + + } + + SmartcardDebug( + DEBUG_TRACE, + ( "PSCR!CBSetProtocol: Enter\n" ) + ); + + SCLibProtocol = ( USHORT )( SmartcardExtension->MinorIoControlCode ); + + if (SCLibProtocol & (SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1)) { + // + // setup the TLV list for the Set Interface Parameter List + // + TLVList[ 0 ] = TAG_ICC_PROTOCOLS; + TLVList[ 1 ] = 0x01; + TLVList[ 2 ] = + (SCLibProtocol & SCARD_PROTOCOL_T1 ? PSCR_PROTOCOL_T1 : PSCR_PROTOCOL_T0); + + // do the PTS + NTStatus = CmdSetInterfaceParameter( + ReaderExtension, + ReaderExtension->Device, + TLVList, + 3 // size of list + ); + + } else { + + // we don't support other modi + NTStatus = STATUS_INVALID_DEVICE_REQUEST; + } + + // if protocol selection failed, prevent from calling invalid protocols + if ( NT_SUCCESS( NTStatus )) { + + KeAcquireSpinLock(&SmartcardExtension->OsData->SpinLock, + &irql); + SmartcardExtension->ReaderCapabilities.CurrentState = SCARD_SPECIFIC; + SCLibProtocol = (SCLibProtocol & SCARD_PROTOCOL_T1 & + SmartcardExtension->CardCapabilities.Protocol.Supported) ? + SCARD_PROTOCOL_T1 : + SCARD_PROTOCOL_T0; + + KeReleaseSpinLock(&SmartcardExtension->OsData->SpinLock, + irql); + } else { + SCLibProtocol = SCARD_PROTOCOL_UNDEFINED; + } + + // Return the selected protocol to the caller. + SmartcardExtension->CardCapabilities.Protocol.Selected = SCLibProtocol; + *( PULONG )( SmartcardExtension->IoRequest.ReplyBuffer ) = SCLibProtocol; + *( SmartcardExtension->IoRequest.Information ) = sizeof( ULONG ); + + SmartcardDebug( + DEBUG_TRACE, + ( "PSCR!CBSetProtocol: Exit (%lx)\n", NTStatus ) + ); + + return( NTStatus ); +} + +NTSTATUS +CBTransmit( + PSMARTCARD_EXTENSION SmartcardExtension + ) +/*++ + +CBTransmit: + callback handler for SMCLIB RDF_TRANSMIT + +Arguments: + SmartcardExtension context of call + +Return Value: + STATUS_SUCCESS + STATUS_NO_MEDIA + STATUS_TIMEOUT + STATUS_INVALID_DEVICE_REQUEST + +--*/ +{ + NTSTATUS NTStatus = STATUS_SUCCESS; + + SmartcardDebug( + DEBUG_TRACE, + ( "PSCR!CBTransmit: Enter\n" ) + ); + + // dispatch on the selected protocol + switch ( SmartcardExtension->CardCapabilities.Protocol.Selected ) { + case SCARD_PROTOCOL_T0: + NTStatus = CBT0Transmit( SmartcardExtension ); + break; + + case SCARD_PROTOCOL_T1: + NTStatus = CBT1Transmit( SmartcardExtension ); + break; + + case SCARD_PROTOCOL_RAW: + NTStatus = CBRawTransmit( SmartcardExtension ); + break; + + default: + NTStatus = STATUS_INVALID_DEVICE_REQUEST; + break; + } + + SmartcardDebug( + DEBUG_TRACE, + ( "PSCR!CBTransmit: Exit (%lx)\n", NTStatus ) + ); + + return( NTStatus ); +} + +NTSTATUS +CBRawTransmit( + PSMARTCARD_EXTENSION SmartcardExtension + ) +/*++ + +CBRawTransmit: + finishes the callback RDF_TRANSMIT for the RAW protocol + +Arguments: + SmartcardExtension context of call + +Return Value: + STATUS_SUCCESS + STATUS_NO_MEDIA + STATUS_TIMEOUT + STATUS_INVALID_DEVICE_REQUEST + +--*/ +{ + NTSTATUS NTStatus = STATUS_SUCCESS; + UCHAR TLVList[ TLV_BUFFER_SIZE ], + Val, + Len; + ULONG TLVListLen; + PREADER_EXTENSION ReaderExtension; + + SmartcardDebug( + DEBUG_TRACE, + ( "PSCR!CBRawTransmit: Enter\n" ) + ); + + ReaderExtension = SmartcardExtension->ReaderExtension; + // + // read the status file of ICC1 from the reader + // + TLVListLen = TLV_BUFFER_SIZE; + NTStatus = CmdReadStatusFile( + ReaderExtension, + ReaderExtension->Device, + TLVList, + &TLVListLen + ); + + // + // check the active protocol of the reader + // + if ( NT_SUCCESS( NTStatus )) { + Len = sizeof(Val); + NTStatus = CmdGetTagValue( + TAG_ICC_PROTOCOLS, + TLVList, + TLVListLen, + &Len, + ( PVOID ) &Val + ); + + // execute the active protocol + if ( NT_SUCCESS( NTStatus )) { + + // translate the actual protocol to a value the lib can understand + switch ( Val ) { + case PSCR_PROTOCOL_T0: + NTStatus = CBT0Transmit( SmartcardExtension ); + break; + case PSCR_PROTOCOL_T1: + NTStatus = CBT1Transmit( SmartcardExtension ); + break; + default: + NTStatus = STATUS_UNSUCCESSFUL; + break; + } + } + } + SmartcardDebug( + DEBUG_TRACE, + ( "PSCR!CBRawTransmit: Exit (%lx)\n", NTStatus ) + ); + return( NTStatus ); +} + +NTSTATUS +CBT1Transmit( + PSMARTCARD_EXTENSION SmartcardExtension + ) +/*++ + +CBT1Transmit: + finishes the callback RDF_TRANSMIT for the T1 protocol + +Arguments: + SmartcardExtension context of call + +Return Value: + STATUS_SUCCESS + STATUS_NO_MEDIA + STATUS_TIMEOUT + STATUS_INVALID_DEVICE_REQUEST + +--*/ +{ + NTSTATUS NTStatus = STATUS_SUCCESS; + ULONG IOBytes; + + SmartcardDebug( + DEBUG_TRACE, + ( "PSCR!CBT1Transmit: Enter\n" ) + ); + // + // use the lib support to construct the T=1 packets + // + do { + // + // no header for the T=1 protocol + // + SmartcardExtension->SmartcardRequest.BufferLength = 0; + // + // SCM-TM: Siemens 4440 accepts only NAD=0!!! + // + SmartcardExtension->T1.NAD = 0; + // + // let the lib setup the T=1 APDU & check for errors + // + NTStatus = SmartcardT1Request( SmartcardExtension ); + if ( NT_SUCCESS( NTStatus )) { + + // send command (don't calculate LRC because CRC may be used!) + IOBytes = 0; + NTStatus = PscrWriteDirect( + SmartcardExtension->ReaderExtension, + SmartcardExtension->SmartcardRequest.Buffer, + SmartcardExtension->SmartcardRequest.BufferLength, + &IOBytes + ); + if ( !NT_SUCCESS(NTStatus)) { + SmartcardDebug( + DEBUG_TRACE, + ( "PSCR!CBT1Transmit: PscrWriteDirect error (%lx)\n", NTStatus ) + ); + } + // + // extend the timeout if a Wtx request was sent by the card. if the + // card responds before the waiting time extension expires, the data are + // buffered in the reader. A delay without polling the reader status + // slows down the performance of the driver, but wtx is an exeption, + // not the rule. + // + if (SmartcardExtension->T1.Wtx) { + SysDelay( + (( SmartcardExtension->T1.Wtx * + SmartcardExtension->CardCapabilities.T1.BWT + 999L )/ + 1000L) + ); + + } + + // get response + SmartcardExtension->SmartcardReply.BufferLength = 0; + NTStatus = PscrRead( + SmartcardExtension->ReaderExtension, + SmartcardExtension->SmartcardReply.Buffer, + MAX_T1_BLOCK_SIZE, + &SmartcardExtension->SmartcardReply.BufferLength + ); + + // if PscrRead detects an LRC error, ignore it (maybe CRC used) + if ( NTStatus == STATUS_CRC_ERROR ) { + SmartcardDebug( + DEBUG_TRACE, + ( "PSCR!CBT1Transmit: PscrRead CRC error (%lx)\n", NTStatus ) + ); + } + + // + // We even continue if the prev. read failed. + // We let the smart card library continue, because it might + // send a resynch. request in case of a timeout + // + NTStatus = SmartcardT1Reply( SmartcardExtension ); + } + + // continue if the lib wants to send the next packet + } while ( NTStatus == STATUS_MORE_PROCESSING_REQUIRED ); + + // start freeze routine, if an interrupt was sent, but no freeze data was read + if( SmartcardExtension->ReaderExtension->RequestInterrupt ) + PscrFreeze( SmartcardExtension ); + + SmartcardDebug( + DEBUG_TRACE, + ( "PSCR!CBT1Transmit: Exit (%lx)\n", NTStatus ) + ); + + return( NTStatus ); +} + +NTSTATUS +CBT0Transmit( + PSMARTCARD_EXTENSION SmartcardExtension + ) +/*++ + +CBT0Transmit: + finishes the callback RDF_TRANSMIT for the T0 protocol + +Arguments: + SmartcardExtension context of call + +Return Value: + STATUS_SUCCESS + STATUS_NO_MEDIA + STATUS_TIMEOUT + STATUS_INVALID_DEVICE_REQUEST + +--*/ +{ + NTSTATUS NTStatus = STATUS_SUCCESS; + PUCHAR pRequest,pReply; + ULONG IOBytes, APDULength, RequestLength; + UCHAR IOData[ MAX_T1_BLOCK_SIZE ]; + UCHAR WtxReply[16]; + + SmartcardDebug( + DEBUG_TRACE, + ( "PSCR!CBT0Transmit: Enter\n" ) + ); + + SysFillMemory( SmartcardExtension->SmartcardReply.Buffer, 0xCC, MAX_T1_BLOCK_SIZE ); + + pRequest = SmartcardExtension->SmartcardRequest.Buffer; + pReply = SmartcardExtension->SmartcardReply.Buffer; + + // setup the command header + pRequest[ PSCR_NAD ] = + ( SmartcardExtension->ReaderExtension->Device == DEVICE_ICC1 ) ? + NAD_TO_ICC1 : NAD_TO_ICC1; + + pRequest[ PSCR_PCB ] = PCB_DEFAULT; + // + // get the length of the user data packet & set the appropriate LEN + // information the complete user packet consists of a SCARD_IO_REQUEST + // structure followed by the APDU. the length of SCARD_IO_REQUEST is + // transferred in the member cbPciLength of the structure + // + APDULength = SmartcardExtension->IoRequest.RequestBufferLength; + if ((((PSCARD_IO_REQUEST) SmartcardExtension->IoRequest.RequestBuffer)->cbPciLength) >= APDULength) { + // Prevent integer underflow + return (STATUS_INSUFFICIENT_RESOURCES); + } + APDULength -= ((PSCARD_IO_REQUEST) SmartcardExtension-> + IoRequest.RequestBuffer)->cbPciLength; + // + // a 4 byte APDU will be patched to a 5 byte TPDU by the lib; see + // annex of the ISO + // + if ( APDULength == 4 ) APDULength++; + // + // if the total length of the T1 (reader) packet is larger than 0xFF + // the extended length notation will be used + // + if ( APDULength >= 0xFF ) { + pRequest[ PSCR_LEN ] = 0xFF; + pRequest[ PSCR_LEN+1 ] = HIBYTE( APDULength ); + pRequest[ PSCR_LEN+2 ] = LOBYTE( APDULength ); + SmartcardExtension->SmartcardRequest.BufferLength = + PSCR_EXT_PROLOGUE_LENGTH; + } else { + pRequest[ PSCR_LEN ] = ( UCHAR ) APDULength; + SmartcardExtension->SmartcardRequest.BufferLength = + PSCR_PROLOGUE_LENGTH; + } + + // let the lib setup the T=1 APDU & check for errors + NTStatus = SmartcardT0Request( SmartcardExtension ); + RequestLength = SmartcardExtension->SmartcardRequest.BufferLength; + + while ( NT_SUCCESS( NTStatus )) { + + // check to see if device is busy. + { + PPSCR_REGISTERS IOBase; + UCHAR Status; + + IOBase = SmartcardExtension->ReaderExtension->IOBase; + + Status = READ_PORT_UCHAR( &IOBase->CmdStatusReg ); + + if( 0x03 == Status ) + { + NTStatus = STATUS_DEVICE_BUSY; + break; + } + } + + // send command + IOBytes = 0; + NTStatus = PscrWrite( + SmartcardExtension->ReaderExtension, + pRequest, + RequestLength, + &IOBytes + ); + + // get response + if ( NT_SUCCESS( NTStatus )) { + IOBytes = 0; + NTStatus = PscrRead( + SmartcardExtension->ReaderExtension, + IOData, + MAX_T1_BLOCK_SIZE, + &IOBytes + ); + + // extract APDU from T=1 transport packet + if ( NT_SUCCESS( NTStatus )) { + + if (IOBytes < 4) { + + NTStatus = STATUS_DEVICE_PROTOCOL_ERROR; + break; + + } + if (IOData[ PSCR_PCB ] == WTX_REQUEST) { + + WtxReply[PSCR_NAD] = NAD_TO_PSCR; + WtxReply[PSCR_PCB] = WTX_REPLY; + WtxReply[PSCR_LEN] = 1; + WtxReply[PSCR_INF] = IOData[PSCR_INF]; + + RequestLength = 4; + pRequest = WtxReply; + continue; + } + + if ( IOData[ PSCR_LEN ] == 0xFF ) { + // + // extended length byte used + // + APDULength = IOData[ PSCR_LEN + 1 ] << 8; + APDULength += IOData[ PSCR_LEN + 2 ]; + + SmartcardExtension->SmartcardReply.BufferLength = APDULength ; + if (APDULength >= (sizeof(IOData) - (PSCR_APDU + 2))) { + NTStatus = STATUS_BUFFER_TOO_SMALL; + break; + } + SysCopyMemory( pReply, &IOData[ PSCR_APDU + 2 ], APDULength ); + } else { + + if ((IOData[PSCR_LEN] > SmartcardExtension->SmartcardReply.BufferSize) || + (IOData[PSCR_LEN] > MAX_T1_BLOCK_SIZE + PSCR_APDU)) { + NTStatus = STATUS_DEVICE_PROTOCOL_ERROR; + break; + } + SmartcardExtension->SmartcardReply.BufferLength = + IOData[ PSCR_LEN ]; + + SysCopyMemory( + pReply, + &IOData[ PSCR_APDU ], + IOData[ PSCR_LEN ] + ); + } + + if( SmartcardExtension->ReaderCapabilities.CurrentState <= + SCARD_ABSENT ) + { + NTStatus = STATUS_NO_MEDIA; + } + else + { + // let the lib evaluate the result & tansfer the data + NTStatus = SmartcardT0Reply( SmartcardExtension ); + } + break; + } + } + } + + // start freeze routine, if an interrupt was sent, but no freeze data was read + if( SmartcardExtension->ReaderExtension->RequestInterrupt ) + PscrFreeze( SmartcardExtension ); + + SmartcardDebug( + DEBUG_TRACE, + ( "PSCR!CBT0Transmit: Exit (%lx)\n", NTStatus ) + ); + + return( NTStatus ); +} + +NTSTATUS +CBCardTracking( + PSMARTCARD_EXTENSION SmartcardExtension + ) +/*++ + +CBCardTracking: + callback handler for SMCLIB RDF_CARD_TRACKING. the requested event was + validated by the smclib (i.e. a card removal request will only be passed + if a card is present). + for a win95 build STATUS_PENDING will be returned without any other action. + for NT the cancel routine for the irp will be set to the drivers cancel + routine. + +Arguments: + SmartcardExtension context of call + +Return Value: + STATUS_PENDING + +--*/ +{ + WDFREQUEST request; + PDEVICE_EXTENSION DeviceExtension; + NTSTATUS status; + + SmartcardDebug( + DEBUG_TRACE, + ( "PSCR!CBCardTracking: Enter\n" ) + ); + + request = GET_WDFREQUEST_FROM_IRP(SmartcardExtension->OsData->NotificationIrp); + + DeviceExtension = GetDeviceExtension(WdfIoQueueGetDevice(WdfRequestGetIoQueue(request))); + + IoMarkIrpPending(SmartcardExtension->OsData->NotificationIrp); + + // + // Move the stack pointer back to where it was when the IRP + // was delivered to the driver. This compensates for the + // IoSetNextIrpStackLocation that we did when we presented the IRP + // to the smartcard libarary. + // + IoSkipCurrentIrpStackLocation(SmartcardExtension->OsData->NotificationIrp); + + status = WdfRequestForwardToIoQueue(request, + DeviceExtension->NotificationQueue); + if (!NT_SUCCESS(status)) { + NT_ASSERT(NT_SUCCESS(status)); + InterlockedExchangePointer( + &(SmartcardExtension->OsData->NotificationIrp), + NULL + ); + WdfRequestComplete(request, status); + } + + status = STATUS_PENDING; + + SmartcardDebug( + DEBUG_TRACE, + ( "PSCR!CBCardTracking: Exit \n" ) + ); + + return status; +} + +VOID +CBUpdateCardState( + PSMARTCARD_EXTENSION SmartcardExtension, + UCHAR IccState, + BOOLEAN SystemWakeUp + ) +{ + ULONG oldState; + NTSTATUS status; + KIRQL irql; + WDFREQUEST request; + PDEVICE_EXTENSION DeviceExtension; + + + KeAcquireSpinLock( + &SmartcardExtension->OsData->SpinLock, + &irql + ); + + SmartcardDebug( + DEBUG_TRACE, + ( "PSCR!CBUpdateCardState: Enter \n" ) + ); + + oldState = + (SmartcardExtension->ReaderCapabilities.CurrentState > SCARD_ABSENT ? + SCARD_PRESENT : SCARD_ABSENT); + + SmartcardExtension->ReaderCapabilities.CurrentState = + (IccState == PSCR_ICC_PRESENT ? SCARD_PRESENT : SCARD_ABSENT); + + SmartcardDebug( + DEBUG_DRIVER, + ( "PSCR!CBUpdateCardState: Smart card %s\n", + IccState == PSCR_ICC_PRESENT ? "inserted" : "removed") + ); + + if ( SmartcardExtension->OsData->NotificationIrp != NULL && + (SystemWakeUp && + (oldState == SCARD_PRESENT || + SmartcardExtension->ReaderCapabilities.CurrentState == SCARD_PRESENT) || + SmartcardExtension->ReaderCapabilities.CurrentState != oldState)) { + PIRP notificationIrp ; + + notificationIrp = InterlockedExchangePointer( + &(SmartcardExtension->OsData->NotificationIrp), + NULL + ); + + DeviceExtension = GetDeviceExtension(WdfWdmDeviceGetWdfDeviceHandle(SmartcardExtension->OsData->DeviceObject)); + + KeReleaseSpinLock( + &SmartcardExtension->OsData->SpinLock, + irql + ); + + status = WdfIoQueueRetrieveNextRequest( + DeviceExtension->NotificationQueue, + &request); + if (NT_SUCCESS(status)) { + + SmartcardDebug( + DEBUG_DRIVER, + ( "PSCR!CBUpdateCardState: Completing Irp %p\n", + notificationIrp) + ); + + WdfRequestCompleteWithInformation(request, status, 0); + } + else { + NT_ASSERTMSG("WdfIoQueueRetrieveNextRequest failed", + status == STATUS_NO_MORE_ENTRIES); + } + } else { + KeReleaseSpinLock( + &SmartcardExtension->OsData->SpinLock, + irql + ); + } + + SmartcardDebug( + DEBUG_TRACE, + ( "PSCR!CBUpdateCardState: Exit \n" ) + ); +} + +UCHAR +CBGetCardState( + PSMARTCARD_EXTENSION SmartcardExtension + ) +/*++ + +CBUpdateCardState: + updates the variable CurrentState in SmartcardExtension + +Arguments: + SmartcardExtension context of call + +Return Value: + STATUS_SUCCESS + +--*/ +{ + UCHAR TLVList[ TLV_BUFFER_SIZE ], Val, Len; + ULONG TLVListLen; + PREADER_EXTENSION ReaderExtension = SmartcardExtension->ReaderExtension; + + // read the status file of ICC1 from the reader + TLVListLen = TLV_BUFFER_SIZE; + + if ( NT_SUCCESS( CmdReadStatusFile( + ReaderExtension, + ReaderExtension->Device, + TLVList, + &TLVListLen + ))) { + + // get reader status value + Len = sizeof(Val); + CmdGetTagValue( + TAG_READER_STATUS, + TLVList, + TLVListLen, + &Len, + ( PVOID ) &Val + ); + } else { + // IO-error is interpreted as card absent + Val = PSCR_ICC_ABSENT; + } + + return Val; +} + +// -------------------------------- END OF FILE ------------------------------ + + + diff --git a/smartcrd/pscr/pscrcb.h b/smartcrd/pscr/pscrcb.h new file mode 100644 index 00000000..51a161a8 --- /dev/null +++ b/smartcrd/pscr/pscrcb.h @@ -0,0 +1,84 @@ +/*++ + +Copyright (c) 1997 - 1999 SCM Microsystems, Inc. + +Module Name: + + PscrCB.h + +Abstract: + + prototypes of callback handlers for pscr.xxx + +Author: + + Andreas Straub + +Environment: + + Win 95 + NT 4.0 + +Notes: + + The file pscrcb.h was reviewed by LCA in June 2011 and per license is + acceptable for Microsoft use under Dealpoint ID 178449. + +Revision History: + + Andreas Straub 7/16/1997 Initial Version + +--*/ + +#if !defined( __PSCR_CALLBACK_H__ ) +#define __PSCR_CALLBACK_H__ + +NTSTATUS +CBCardPower( + PSMARTCARD_EXTENSION SmartcardExtension + ); + +NTSTATUS +CBSetProtocol( + PSMARTCARD_EXTENSION SmartcardExtension + ); + +NTSTATUS +CBTransmit( + PSMARTCARD_EXTENSION SmartcardExtension + ); + +NTSTATUS +CBT0Transmit( + PSMARTCARD_EXTENSION SmartcardExtension + ); + +NTSTATUS +CBT1Transmit( + PSMARTCARD_EXTENSION SmartcardExtension + ); + +NTSTATUS +CBRawTransmit( + PSMARTCARD_EXTENSION SmartcardExtension + ); + +NTSTATUS +CBCardTracking( + PSMARTCARD_EXTENSION SmartcardExtension + ); + +VOID +CBUpdateCardState( + PSMARTCARD_EXTENSION SmartcardExtension, + UCHAR CardState, + BOOLEAN SystemWakeUp + ); + +UCHAR +CBGetCardState( + PSMARTCARD_EXTENSION SmartcardExtension + ); +#endif // __PSCR_CALLBACK_H__ + +// ------------------------------- END OF FILE ------------------------------- diff --git a/smartcrd/pscr/pscrcmd.c b/smartcrd/pscr/pscrcmd.c new file mode 100644 index 00000000..ff694089 --- /dev/null +++ b/smartcrd/pscr/pscrcmd.c @@ -0,0 +1,981 @@ +/*++ + +Copyright (c) 1997 - 1999 SCM Microsystems, Inc. + +Module Name: + + PscrCmd.c + +Abstract: + + Basic command functions for SCM PSCR smartcard reader + +Author: + + Andreas Straub + +Environment: + + + Win 95 Sys... calls are resolved by Pscr95Wrap.asm functions and + Pscr95Wrap.h macros, resp. + + NT 4.0 Sys... functions resolved by PscrNTWrap.c functions and + PscrNTWrap.h macros, resp. + +Notes: + + The file pscrcmd.c was reviewed by LCA in June 2011 and per license is + acceptable for Microsoft use under Dealpoint ID 178449. + +Revision History: + + Andreas Straub 8/18/1997 1.00 Initial Version + Andreas Straub 9/24/1997 1.02 delay for read/write removed + +--*/ + +#include +#include +#include + +NTSTATUS +CmdResetInterface( + PREADER_EXTENSION ReaderExtension + ) +/*++ +CmdResetInterface: + + Performs a reset of the reader interface (NOT of the PCMCIA controller) + - flush available data + - set RESET bit + - perform a buffer size exchange between reader & host + - enables interrupts for freeze events + - disables default PTS + +Arguments: + ReaderExtension context of call + +Return Value: + STATUS_SUCCESS + STATUS_IO_DEVICE_ERROR + +--*/ +{ + + NTSTATUS NTStatus = STATUS_SUCCESS; + UCHAR Len, + Tag, + Cnt, + InData[ TLV_BUFFER_SIZE ] = {0}; + PPSCR_REGISTERS IOBase; + UCHAR EnableInterrupts[] = { 0x28, 0x01, 0x01}; + + + IOBase = ReaderExtension->IOBase; + + // discard any data + PscrFlushInterface( ReaderExtension ); + + // reset reader + WRITE_PORT_UCHAR( &IOBase->CmdStatusReg, PSCR_RESET_BIT ); + SysDelay( DELAY_WRITE_PSCR_REG ); + WRITE_PORT_UCHAR( &IOBase->CmdStatusReg, CLEAR_BIT ); + + NTStatus = PscrWait( ReaderExtension, PSCR_DATA_AVAIL_BIT ); + + // read & check vendor string + if ( NT_SUCCESS( NTStatus )) { + + WRITE_PORT_UCHAR( &IOBase->CmdStatusReg, PSCR_HOST_CONTROL_BIT ); + SysDelay( DELAY_WRITE_PSCR_REG ); + // + // get actual len from TLV list + // + READ_PORT_UCHAR( &IOBase->SizeMSReg ); + READ_PORT_UCHAR( &IOBase->SizeLSReg ); + + Tag = READ_PORT_UCHAR( &IOBase->DataReg ); + Len = READ_PORT_UCHAR( &IOBase->DataReg ); + // + // avoid overwrite of buffer + // + if ( Len > TLV_BUFFER_SIZE ) { + Len = TLV_BUFFER_SIZE; + } + for ( Cnt = 0; Cnt < Len; Cnt++ ) { + InData[ Cnt ] = READ_PORT_UCHAR( &IOBase->DataReg ); + } + WRITE_PORT_UCHAR( &IOBase->CmdStatusReg, CLEAR_BIT ); + // + // check vendor string + // + if ( SysCompareMemory( + InData, + PSCR_ID_STRING, + sizeof( PSCR_ID_STRING ) + )) { + NTStatus = STATUS_IO_DEVICE_ERROR; + } else { + // + // vendor string was correct, check buffer size + // + WRITE_PORT_UCHAR( &IOBase->CmdStatusReg, PSCR_SIZE_READ_BIT ); + NTStatus = PscrWait( ReaderExtension, PSCR_DATA_AVAIL_BIT ); + // + // reader ready to transfer interface buffer size + // + if ( NT_SUCCESS( NTStatus )) { + // + // set size read & host control + // + WRITE_PORT_UCHAR( + &IOBase->CmdStatusReg, + PSCR_SIZE_READ_BIT | PSCR_HOST_CONTROL_BIT + ); + + SysDelay( DELAY_WRITE_PSCR_REG ); + // + // read buffer length + // + Len = READ_PORT_UCHAR( &IOBase->SizeMSReg ); + Len = READ_PORT_UCHAR( &IOBase->SizeLSReg ); + // + // avoid overwrite of buffer + // + if ( Len > TLV_BUFFER_SIZE ) { + Len = TLV_BUFFER_SIZE; + } + for ( Cnt = 0; Cnt < Len; Cnt++ ) { + InData[ Cnt ] = READ_PORT_UCHAR( &IOBase->DataReg ); + } + // + // transfer of interface buffer size okay + // + WRITE_PORT_UCHAR( &IOBase->CmdStatusReg, CLEAR_BIT ); + SysDelay( DELAY_WRITE_PSCR_REG ); + // + // notify the reader about the supported buffer size + // + WRITE_PORT_UCHAR( &IOBase->CmdStatusReg, PSCR_HOST_CONTROL_BIT ); + SysDelay( DELAY_WRITE_PSCR_REG ); + + WRITE_PORT_UCHAR( &IOBase->SizeMSReg, 0 ); + WRITE_PORT_UCHAR( &IOBase->SizeLSReg, 2 ); + // + // Write the same data buffer size as the one we just got. + // + if (Len >= 1) { + WRITE_PORT_UCHAR( &IOBase->DataReg, InData[ 0 ] ); + WRITE_PORT_UCHAR( &IOBase->DataReg, InData[ 1 ] ); + } + // + // store the size to report to the lib + // The maximum buffer size of the reader is to betrieved with + // ((ULONG)InData[ 1 ] << 8) | InData[ 0 ] + // + ReaderExtension->MaxIFSD = 254; + + // + // let the reader process the size write command + // + WRITE_PORT_UCHAR( &IOBase->CmdStatusReg, PSCR_SIZE_WRITE_BIT ); + NTStatus = PscrWait( ReaderExtension, PSCR_FREE_BIT ); + } + } + } + // + // clean up any host control settings + // + WRITE_PORT_UCHAR( &IOBase->CmdStatusReg, CLEAR_BIT ); + // + // enable interrupts + // + CmdSetInterfaceParameter( + ReaderExtension, + ReaderExtension->Device, + EnableInterrupts, + sizeof( EnableInterrupts ) + ); + + return( NTStatus ); +} + +NTSTATUS +CmdReset( + PREADER_EXTENSION ReaderExtension, + UCHAR Device, + BOOLEAN WarmReset, + PUCHAR pATR, + PULONG pATRLength + ) +/*++ +CmdReset: + performs a reset of the reader / ICC + +Arguments: + ReaderExtension context of call + Device device requested ( ICC_1, ICC_2, PSCR ) + WarmReset kind of ICC reset + pATR ptr to ATR buffer, NULL if no ATR required + pATRLength size of ATR buffer / length of ATR + +Return Value: + STATUS_SUCCESS + STATUS_NO_MEDIA + STATUS_UNRECOGNIZED_MEDIA + error values from PscrRead / PscrWrite + +--*/ +{ + NTSTATUS NTStatus = STATUS_SUCCESS; + UCHAR IOData[ MAX_T1_BLOCK_SIZE ], + P2; + USHORT ICCStatus; + ULONG IOBytes; + + // ATR from the smartcard requestet? P2 = 1 + P2 = 0; + if (( pATR != NULL ) && ( pATRLength != NULL )) { + if ( *pATRLength > 0 ) + P2 = 0x01; + } + + // build the RESET command. + IOData[ PSCR_NAD ] = NAD_TO_PSCR; + IOData[ PSCR_PCB ] = PCB_DEFAULT; + IOData[ PSCR_LEN ] = 0x05; + + if ( WarmReset == TRUE ) { + IOData[ PSCR_INF+0 ] = CLA_WARM_RESET; + IOData[ PSCR_INF+1 ] = INS_WARM_RESET; + } else { + IOData[ PSCR_INF+0 ] = CLA_RESET; + IOData[ PSCR_INF+1 ] = INS_RESET; + } + IOData[ PSCR_INF+2 ] = Device; + IOData[ PSCR_INF+3 ] = P2; + IOData[ PSCR_INF+4 ] = 0x00; + + // write command + NTStatus = PscrWrite( + ReaderExtension, + IOData, + 8, + &IOBytes + ); + + if ( NT_SUCCESS( NTStatus )) { + // read data + IOBytes = 0; + NTStatus = PscrRead( + ReaderExtension, + IOData, + MAX_T1_BLOCK_SIZE, + &IOBytes + ); + + // error detection + if ( NT_SUCCESS( NTStatus )) { + // + // the location of the error code in the buffer + // is: ( data ) - STATUS_MSB - STATUS_LSB - EPILOGUE + // + ICCStatus = (( USHORT )IOData[ IOBytes-PSCR_EPILOGUE_LENGTH-2 ]) << 8; + ICCStatus |= ( USHORT )IOData[ IOBytes-PSCR_EPILOGUE_LENGTH-1 ]; + + switch ( ICCStatus ) { + case PSCR_SW_SYNC_ATR_SUCCESS: + case PSCR_SW_ASYNC_ATR_SUCCESS: + break; + + case PSCR_SW_NO_ICC: + NTStatus = STATUS_NO_MEDIA; + break; + + case PSCR_SW_NO_PROTOCOL: + case PSCR_SW_NO_ATR: + case PSCR_SW_NO_ATR_OR_PROTOCOL: + case PSCR_SW_NO_ATR_OR_PROTOCOL2: + case PSCR_SW_ICC_NOT_ACTIVE: + case PSCR_SW_NON_SUPPORTED_PROTOCOL: + case PSCR_SW_PROTOCOL_ERROR: + default: + NTStatus = STATUS_UNRECOGNIZED_MEDIA; + } + // + // copy ATR if required + // + if ( NT_SUCCESS( NTStatus )) { + if ( P2 == 0x01 ) { + IOBytes -= PSCR_PROLOGUE_LENGTH + PSCR_EPILOGUE_LENGTH; + if ( IOBytes > *pATRLength ) { + IOBytes = *pATRLength; + } + SysCopyMemory( + pATR, + &IOData[ PSCR_PROLOGUE_LENGTH ], + IOBytes + ); + *pATRLength = IOBytes; + } + } + } + } + return( NTStatus ); +} + + +NTSTATUS +CmdDeactivate( + PREADER_EXTENSION ReaderExtension, + UCHAR Device + ) +/*++ +CmdDeactivate: + Deactivates the requested device + +Arguments: + ReaderExtension context of call + Device requested device + +Return Value: + STATUS_SUCCESS + error values from PscrRead / PscrWrite + +--*/ +{ + NTSTATUS NTStatus = STATUS_SUCCESS; + UCHAR IOData[ MAX_T1_BLOCK_SIZE ]; + ULONG IOBytes; + + // + // build the DEACTIVATE command. + // + IOData[ PSCR_NAD ] = NAD_TO_PSCR; + IOData[ PSCR_PCB ] = PCB_DEFAULT; + IOData[ PSCR_LEN ] = 0x05; + + IOData[ PSCR_INF+0 ] = CLA_DEACTIVATE; + IOData[ PSCR_INF+1 ] = INS_DEACTIVATE; + IOData[ PSCR_INF+2 ] = Device; + IOData[ PSCR_INF+3 ] = 0x00; + IOData[ PSCR_INF+4 ] = 0x00; + // + // write command + // + NTStatus = PscrWrite( + ReaderExtension, + IOData, + 8, + &IOBytes + ); + + if ( NT_SUCCESS( NTStatus )) { + // + // read data to trap communication errors + // + IOBytes = 0; + NTStatus = PscrRead( + ReaderExtension, + IOData, + MAX_T1_BLOCK_SIZE, + &IOBytes + ); + } + return( NTStatus ); +} + +NTSTATUS +CmdReadBinary( + PREADER_EXTENSION ReaderExtension, + USHORT Offset, + PUCHAR pBuffer, + PULONG pBufferLength + ) +/*++ +CmdReadBinary: + read binary data from an PSCR data file + +Arguments: + ReaderExtension context of call + Offset offset in file + pBuffer ptr to data buffer + pBufferLength length of buffer / number of bytes read + +Return Value: + + STATUS_SUCCESS + STATUS_UNSUCCESSFUL + error values from PscrRead / PscrWrite + +--*/ +{ + NTSTATUS NTStatus = STATUS_SUCCESS; + UCHAR IOData[ MAX_T1_BLOCK_SIZE ]; + USHORT ICCStatus; + ULONG IOBytes; + // + // check parameters + // + if (( pBuffer == NULL ) || ( pBufferLength == NULL)) { + NTStatus = STATUS_INVALID_PARAMETER; + } else { + // + // build the READ BINARY command + // + IOData[ PSCR_NAD] = NAD_TO_PSCR; + IOData[ PSCR_PCB] = PCB_DEFAULT; + IOData[ PSCR_LEN] = 0x05; + + IOData[ PSCR_INF+0 ] = CLA_READ_BINARY; + IOData[ PSCR_INF+1 ] = INS_READ_BINARY; + IOData[ PSCR_INF+2 ] = HIBYTE( Offset ); + IOData[ PSCR_INF+3 ] = LOBYTE( Offset ); + IOData[ PSCR_INF+4 ] = 0x00; + // + // write command + // + NTStatus = PscrWrite( + ReaderExtension, + IOData, + 8, + &IOBytes + ); + + if ( NT_SUCCESS( NTStatus )) { + // + // read data + // + IOBytes = 0; + NTStatus = PscrRead( + ReaderExtension, + IOData, + MAX_T1_BLOCK_SIZE, + &IOBytes + ); + + if ( NT_SUCCESS( NTStatus )) { + // + // error check + // + ICCStatus = + ((USHORT)IOData[ IOBytes-2-PSCR_EPILOGUE_LENGTH ]) << 8; + ICCStatus |= + (USHORT)IOData[ IOBytes-1-PSCR_EPILOGUE_LENGTH ]; + + switch ( ICCStatus ) { + case PSCR_SW_FILE_NO_ACCEPPTED_AUTH: + case PSCR_SW_FILE_NO_ACCESS: + case PSCR_SW_FILE_BAD_OFFSET: + case PSCR_SW_END_OF_FILE_READ: + NTStatus = STATUS_UNSUCCESSFUL; + break; + default: + break; + } + // + // copy data + // + if ( NT_SUCCESS( NTStatus )) { + if ( *pBufferLength < + IOBytes-PSCR_PROLOGUE_LENGTH-PSCR_STATUS_LENGTH ) { + NTStatus = STATUS_BUFFER_TOO_SMALL; + } else { + ( *pBufferLength ) = + IOBytes-PSCR_PROLOGUE_LENGTH-PSCR_STATUS_LENGTH; + SysCopyMemory( + pBuffer, + &IOData[ PSCR_PROLOGUE_LENGTH ], + *pBufferLength + ); + } + } + } + } + } + return( NTStatus ); +} + +NTSTATUS +CmdSelectFile( + PREADER_EXTENSION ReaderExtension, + USHORT FileId + ) +/*++ +CmdSelectFile: + selects a file/directoy of the reader + +Arguments: + ReaderExtension context of call + FileId ID of file + +Return Value: + STATUS_SUCCESS + STATUS_UNSUCCESSFUL + error values from PscrRead / PscrWrite +--*/ +{ + NTSTATUS NTStatus = STATUS_SUCCESS; + UCHAR IOData[ MAX_T1_BLOCK_SIZE ]; + USHORT ICCStatus; + ULONG IOBytes; + + // + // build the SELECT FILE command + // + IOData[ PSCR_NAD ] = NAD_TO_PSCR; + IOData[ PSCR_PCB ] = PCB_DEFAULT; + IOData[ PSCR_LEN ] = 0x07; + + IOData[ PSCR_INF+0 ] = CLA_SELECT_FILE; + IOData[ PSCR_INF+1 ] = INS_SELECT_FILE; + IOData[ PSCR_INF+2 ] = 0x00; + IOData[ PSCR_INF+3 ] = 0x00; + IOData[ PSCR_INF+4 ] = 0x02; + IOData[ PSCR_INF+5 ] = HIBYTE( FileId ); + IOData[ PSCR_INF+6 ] = LOBYTE( FileId ); + // + // write command + // + NTStatus = PscrWrite( + ReaderExtension, + IOData, + 10, + &IOBytes + ); + + if ( NT_SUCCESS( NTStatus )) { + // + // get the response of the reader + // + IOBytes = 0; + NTStatus = PscrRead( + ReaderExtension, + IOData, + MAX_T1_BLOCK_SIZE, + &IOBytes + ); + + if ( NT_SUCCESS( NTStatus )) { + // + // check errors + // + ICCStatus = + ((USHORT)IOData[ IOBytes-2-PSCR_EPILOGUE_LENGTH ]) << 8; + ICCStatus |= + (USHORT)IOData[ IOBytes-1-PSCR_EPILOGUE_LENGTH ]; + + if ( ICCStatus == PSCR_SW_FILE_NOT_FOUND ) { + NTStatus = STATUS_UNSUCCESSFUL; + } + } + } + return( NTStatus ); +} + +NTSTATUS +CmdSetInterfaceParameter( + PREADER_EXTENSION ReaderExtension, + UCHAR Device, + PUCHAR pTLVList, + UCHAR TLVListLen + ) +/*++ +CmdSetInterfaceParameter: + Sets the interface pareameter of the ICC interface to the values specified + in the TLV list + +Arguments: + ReaderExtension context of call + Device device + pTLVList ptr to list of tag-len-value's specified by caller + TLVListLen length of list + +Return Value: + STATUS_SUCCESS + STATUS_INVALID_PARAMETER + STATUS_INVALID_DEVICE_STATE + error values from PscrRead / PscrWrite + +--*/ +{ + NTSTATUS NTStatus = STATUS_SUCCESS; + UCHAR IOData[ MAX_T1_BLOCK_SIZE ]; + USHORT ICCStatus; + ULONG IOBytes; + + // + // check parameter + // + if ( pTLVList == NULL ) { + NTStatus = STATUS_INVALID_PARAMETER; + } else { + // + // build the SET INTERFACE PARAMETER command + // + IOData[ PSCR_NAD ] = NAD_TO_PSCR; + IOData[ PSCR_PCB ] = PCB_DEFAULT; + IOData[ PSCR_LEN ] = 0x05 + TLVListLen; + + IOData[ PSCR_INF+0 ] = CLA_SET_INTERFACE_PARAM; + IOData[ PSCR_INF+1 ] = INS_SET_INTERFACE_PARAM; + IOData[ PSCR_INF+2 ] = Device; + IOData[ PSCR_INF+3 ] = 0x00; + IOData[ PSCR_INF+4 ] = TLVListLen; + + SysCopyMemory( &IOData[ PSCR_INF+5 ], pTLVList, TLVListLen ); + // + // write command + // + NTStatus = PscrWrite( + ReaderExtension, + IOData, + 8 + TLVListLen, + &IOBytes + ); + + if ( NT_SUCCESS( NTStatus )) { + + // do an dummy read to catch errors. + IOBytes = 0; + NTStatus = PscrRead( + ReaderExtension, + IOData, + MAX_T1_BLOCK_SIZE, + &IOBytes + ); + + if ( NT_SUCCESS( NTStatus )) { + + // check error + ICCStatus = + ((USHORT)IOData[ IOBytes - 2 - PSCR_EPILOGUE_LENGTH ]) << 8; + ICCStatus |= + (USHORT)IOData[ IOBytes - 1 - PSCR_EPILOGUE_LENGTH ]; + + if ( ICCStatus != 0x9000 ) { + NTStatus = STATUS_INVALID_DEVICE_STATE; + } + } + } + } + return( NTStatus ); +} + + +NTSTATUS +CmdReadStatusFile ( + PREADER_EXTENSION ReaderExtension, + UCHAR Device, + PUCHAR pTLVList, + PULONG pTLVListLen + ) +/*++ +CmdReadStatusFile: + read the status file of the requested device from the reader filesystem + +Arguments: + ReaderExtension context of call + Device requested device + pTLVList ptr to list (i.e. the status file) + pTLVListLen length of buffer / returned list + +Return Value: + STATUS_SUCCESS + STATUS_BUFFER_TOO_SMALL + error values from PscrRead / PscrWrite + +--*/ +{ + NTSTATUS NTStatus = STATUS_UNSUCCESSFUL; + UCHAR IOData[ MAX_T1_BLOCK_SIZE ]; + ULONG IOBytes; + + // select ICC status file if it's not the active file + if ( ReaderExtension->StatusFileSelected == FALSE ) { + + // select master file on reader + NTStatus = CmdSelectFile( ReaderExtension, FILE_MASTER ); + + // select ICC directory + if ( NT_SUCCESS( NTStatus )) { + if ( Device != DEVICE_ICC1 ) { + NTStatus = STATUS_UNSUCCESSFUL; + } else { + NTStatus = CmdSelectFile( + ReaderExtension, + FILE_ICC1_DIR + ); + + // select status file + if ( NT_SUCCESS( NTStatus )) { + NTStatus = CmdSelectFile( + ReaderExtension, + FILE_ICC1_DIR_STATUS + ); + if ( NT_SUCCESS( NTStatus )) { + ReaderExtension->StatusFileSelected = TRUE; + } + } + } + } + } + + // read status file if successful selected + if ( ReaderExtension->StatusFileSelected == TRUE ) { + IOBytes = MAX_T1_BLOCK_SIZE; + NTStatus = CmdReadBinary( + ReaderExtension, + 0, + IOData, + &IOBytes + ); + + // copy data to user buffer + if ( NT_SUCCESS( NTStatus )) { + if (( pTLVList != NULL ) && ( IOBytes < *pTLVListLen )) { + *pTLVListLen = IOBytes; + SysCopyMemory( pTLVList, IOData, IOBytes ); + } else { + NTStatus = STATUS_BUFFER_TOO_SMALL; + } + } + } + return( NTStatus ); +} + + +NTSTATUS +CmdGetFirmwareRevision ( + PREADER_EXTENSION ReaderExtension + ) +/*++ +CmdGetFirmwareRevision: + get the firmware revision of the reader. Ther firmware revision is found + in the PSCR configuration file (ID 0x0020) in the master directory. + The tag of the revision is 0x0F, and the value is coded as an ASCII string, + p.E. "2.20" + +Arguments: + ReaderExtension context of call + +Return Value: + STATUS_SUCCESS + error values from PscrRead / PscrWrite + +--*/ +{ + NTSTATUS NTStatus = STATUS_SUCCESS; + UCHAR TLVList[ MAX_T1_BLOCK_SIZE ], + Len; + char Revision[ 0x10 ], + UpdateKey[ 0x10 ]; + ULONG IOBytes; + // + // select master file on reader + // + NTStatus = CmdSelectFile( ReaderExtension, FILE_MASTER ); + // + // select pscr configuration file + // + if ( NT_SUCCESS( NTStatus )) { + NTStatus = CmdSelectFile( ReaderExtension, FILE_PSCR_CONFIG ); + // + // read confiuration file + // + if ( NT_SUCCESS( NTStatus )) { + IOBytes = MAX_T1_BLOCK_SIZE; + NTStatus = CmdReadBinary( + ReaderExtension, + 0, + TLVList, + &IOBytes + ); + // + // get the value of revison + // + if ( NT_SUCCESS( NTStatus )) { + Len = sizeof(Revision); + CmdGetTagValue( + TAG_SOFTWARE_REV, + TLVList, + IOBytes, + &Len, + Revision + ); + // + // the coding is always X.YY (in ASCII), so we can get the numeric + // values hardcoded by taking the low nibbles of the char's. + // + ReaderExtension->FirmwareMajor = Revision[0] & 0x0F; + ReaderExtension->FirmwareMinor = ( Revision[2] & 0x0F ) << 4; + ReaderExtension->FirmwareMinor |= Revision[3] & 0x0F; + // + // get value of update key + // + Len = sizeof(UpdateKey); + CmdGetTagValue( + TAG_UPDATE_KEY, + TLVList, + IOBytes, + &Len, + UpdateKey + ); + + ReaderExtension->UpdateKey = UpdateKey[0]; + } + } + } + ReaderExtension->StatusFileSelected = FALSE; + return( NTStatus ); +} + +NTSTATUS +CmdPscrCommand ( + PREADER_EXTENSION ReaderExtension, + PUCHAR pInData, + ULONG InDataLen, + PUCHAR pOutData, + ULONG OutDataLen, + PULONG pNBytes + ) +/*++ +CmdPscrCommand: + send a command transparent to the reader + +Arguments: + ReaderExtension context of call + pInData, ptr to input buffer + InDataLen, len of input buffer + pOutData, ptr to output buffer + OutDataLen, len of output buffer + pNBytes number of bytes transferred + +Return Value: + STATUS_SUCCESS + STATUS_INVALID_PARAMETER + error values from PscrRead / PscrWrite + +--*/ +{ + NTSTATUS NTStatus = STATUS_SUCCESS; + UCHAR IOData[ MAX_T1_BLOCK_SIZE ] = { 0}; + ULONG IOBytes; + // + // the function is used for generic ioctl's, so carful ALL + // parametes will be checked! + // + if ( ( pInData == NULL ) || + ( pOutData == NULL ) || + ( pNBytes == NULL ) || + (InDataLen == 0 ) || + (OutDataLen == 0 ) + ) { + NTStatus = STATUS_INVALID_PARAMETER; + } else { + IOBytes = 0; + NTStatus = PscrWriteDirect( + ReaderExtension, + pInData, + InDataLen, + &IOBytes + ); + + if ( NT_SUCCESS( NTStatus )) { + // + // get result. ignore all reader errors + // + IOBytes = 0; + NTStatus = PscrRead( + ReaderExtension, + IOData, + MAX_T1_BLOCK_SIZE, + &IOBytes + ); + // + // tranfer data + // + if ( IOBytes > OutDataLen ) { + NTStatus = STATUS_BUFFER_TOO_SMALL; + } else { + *pNBytes = IOBytes; + SysCopyMemory( pOutData, IOData, IOBytes ); + } + } + } + return( NTStatus ); +} + +NTSTATUS +CmdGetTagValue ( + UCHAR Tag, + PUCHAR pTLVList, + ULONG TLVListLen, + PUCHAR pTagLen, + PVOID pTagVal + ) +/*++ +CmdGetTagValue: + scans a TLV list for the value of a user specified tag + it is assumed, the caller knows the kind of the requested + field, so only the ptr to the buffer will be checked + +Arguments: + Tag requested Tag + pTLVList ptr to list + TLVListLen length of list + pTagLen ptr to length + pTagVal ptr to value + +Return Value: + STATUS_SUCCESS + STATUS_UNSUCCESSFUL + STATUS_INVALID_PARAMETER + +--*/ +{ + NTSTATUS NTStatus = STATUS_SUCCESS; + ULONG Idx; + UCHAR maxLen; + // + // step through the given list + // + if (( pTLVList != NULL ) && ( pTagVal != NULL ) && ( pTagLen != NULL )) { + maxLen = *pTagLen; + // + // look for requested tag + // + Idx = 0; + while ( Idx < TLVListLen ) { + if ( pTLVList[ Idx ] == Tag ) { + // + // ASSUMED THE CALLER KNOWS KIND OF FIELD!!! + // + + if (pTLVList[Idx+1] > maxLen) { + NTStatus = STATUS_UNSUCCESSFUL; + break; + } + *pTagLen = pTLVList[ Idx + 1 ]; + SysCopyMemory( + pTagVal, + &pTLVList[ Idx+2 ], + pTLVList[ Idx+1 ] + ); + + break; + } + Idx += pTLVList[ Idx+1 ] + 2; + } + if ( Idx >= TLVListLen ) { + NTStatus = STATUS_UNSUCCESSFUL; + } + } else { + NTStatus = STATUS_INVALID_PARAMETER; + } + return( NTStatus ); +} + +// ------------------------------- END OF FILE ------------------------------- + diff --git a/smartcrd/pscr/pscrcmd.h b/smartcrd/pscr/pscrcmd.h new file mode 100644 index 00000000..57a4bdea --- /dev/null +++ b/smartcrd/pscr/pscrcmd.h @@ -0,0 +1,107 @@ +/*++ + +Copyright (c) 1997 - 1999 SCM Microsystems, Inc. + +Module Name: + + PscrCmd.h + +Abstract: + + Prototypes of basic command functions for SCM PSCR smartcard reader + +Author: + + Andreas Straub + +Notes: + + The file pscrcmd.h was reviewed by LCA in June 2011 and per license is + acceptable for Microsoft use under Dealpoint ID 178449. + +Revision History: + + Andreas Straub 7/16/1997 Initial Version + +--*/ + +#if !defined( __PSCR_CMD_H__ ) +#define __PSCR_CMD_H__ + +NTSTATUS +CmdResetInterface( + PREADER_EXTENSION ReaderExtension // context of call + ); + +NTSTATUS +CmdReset( + PREADER_EXTENSION ReaderExtension, // context of call + UCHAR Device, // device + BOOLEAN WarmReset, // TRUE: Warm, FALSE: cold Reset + PUCHAR pATR, // ptr to ATR buffer + PULONG ATRLength // len of ATR + ); + +NTSTATUS +CmdDeactivate( + PREADER_EXTENSION ReaderExtension, // context of call + UCHAR Device // device + ); + +NTSTATUS +CmdReadBinary( + PREADER_EXTENSION ReaderExtension, // context of call + USHORT Offset, // offset in file + PUCHAR pData, // data buffer + PULONG pNBytes // length of bytes read + ); + +NTSTATUS +CmdSelectFile( + PREADER_EXTENSION ReaderExtension, // context of call + USHORT FileId // File Id + ); + +NTSTATUS +CmdSetInterfaceParameter( + PREADER_EXTENSION ReaderExtension, // context of call + UCHAR Device, // device + PUCHAR pTLVList, // ptr to TLV list + UCHAR TLVListLen // len of TLV list + ); + +NTSTATUS +CmdReadStatusFile ( + PREADER_EXTENSION ReaderExtension, // context of call + UCHAR Device, // device + PUCHAR pTLVList, // ptr to TLV list + PULONG TLVListLen // len of TLV list + ); + +NTSTATUS +CmdPscrCommand ( + PREADER_EXTENSION ReaderExtension, // context of call + PUCHAR pInData, // ptr to input buffer + ULONG InDataLen, // len of input buffer + PUCHAR pOutData, // ptr to ouput buffer + ULONG OutDataLen, // len of output buffer + PULONG pNBytes // number of bytes transferred + ); + +NTSTATUS +CmdGetFirmwareRevision ( + PREADER_EXTENSION ReaderExtension // context of call + ); + +NTSTATUS +CmdGetTagValue ( + UCHAR Tag, // tag to be searched + PUCHAR pTLVList, // ptr to TLV list + ULONG TLVListLen, // len of TLV list + PUCHAR pTagLen, // tag length + PVOID pTagVal // tag value + ); + +#endif // __PSCR_CMD_H__ + +//------------------------------- END OF FILE -------------------------------*/ diff --git a/smartcrd/pscr/pscrlog.mc b/smartcrd/pscr/pscrlog.mc new file mode 100644 index 00000000..6a608ddd --- /dev/null +++ b/smartcrd/pscr/pscrlog.mc @@ -0,0 +1,103 @@ +;// BUILD Version: 0001 // Increment this if a change has global effects + +;/*++ +; +;Copyright (c) 1997 SCM Microsystems, Inc +; +;Module Name: +; +; PscrLog.mc +; +;Abstract: +; +; Constant definitions for the I/O error code log values. +; +;Notes: +; +; The file pscrlog.mc was reviewed by LCA in June 2011 and per license is +; acceptable for Microsoft use under Dealpoint ID 178449. +; +;Revision History: +; +;--*/ +; +;#ifndef __PSCRLOG_H__ +;#define __PSCRLOG_H__ +; +;// +;// Status values are 32 bit values layed out as follows: +;// +;// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 +;// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 +;// +---+-+-------------------------+-------------------------------+ +;// |Sev|C| Facility | Code | +;// +---+-+-------------------------+-------------------------------+ +;// +;// where +;// +;// Sev - is the severity code +;// +;// 00 - Success +;// 01 - Informational +;// 10 - Warning +;// 11 - Error +;// +;// C - is the Customer code flag +;// +;// Facility - is the facility code +;// +;// Code - is the facility's status code +;// +; +MessageIdTypedef=NTSTATUS + +SeverityNames=(Success=0x0:STATUS_SEVERITY_SUCCESS + Informational=0x1:STATUS_SEVERITY_INFORMATIONAL + Warning=0x2:STATUS_SEVERITY_WARNING + Error=0x3:STATUS_SEVERITY_ERROR + ) + +FacilityNames=(System=0x0 + RpcRuntime=0x2:FACILITY_RPC_RUNTIME + RpcStubs=0x3:FACILITY_RPC_STUBS + Io=0x4:FACILITY_IO_ERROR_CODE + Smartcard=0x10:FACILITY_SCARD + ) + +MessageId=0x0001 Facility=Smartcard Severity=Error SymbolicName=PSCR_NO_DEVICE_FOUND +Language=English +No PSCR Smart Card reader found in the system. +. +MessageId=0x0002 Facility=Smartcard Severity=Error SymbolicName=PSCR_CANT_INITIALIZE_READER +Language=English +The reader inserted is not working properly. +Please try to change the 'Input/Output Range' and/or 'Interrupt Request' +settings in Device Manager. +. +MessageId=0x0003 Facility=Smartcard Severity=Error SymbolicName=PSCR_INSUFFICIENT_RESOURCES +Language=English +Insufficient system resources to start device. +. +MessageId=0x0004 Facility=Smartcard Severity=Error SymbolicName=PSCR_ERROR_INTERRUPT +Language=English +Can't connect to the interrupt provided by the system. +Please try to change the 'Interrupt Request' setting in Device Manager. +. +MessageId=0x0005 Facility=Smartcard Severity=Error SymbolicName=PSCR_ERROR_IO_PORT +Language=English +No I/O port specified or port can not be mapped. +Please try to change the 'Input/Output Range' setting in the Device Manager. +. +MessageId=0x0006 Facility=Smartcard Severity=Error SymbolicName=PSCR_ERROR_CLAIM_RESOURCES +Language=English +Resources can not be claimed or an resource conflict exists. +. +MessageId=0x0007 Facility=Io Severity=Error SymbolicName=PSCR_NO_MEMORY +Language=English +The system does not have enough memory. +. +MessageId=0x0007 Facility=Smartcard Severity=Warning SymbolicName=PSCR_WRONG_FIRMWARE +Language=English +Your reader needs firmware version 2.30 or higher to work with this driver. +. +;#endif // __PSCRLOG_H__ diff --git a/smartcrd/pscr/pscrnt.c b/smartcrd/pscr/pscrnt.c new file mode 100644 index 00000000..75d37304 --- /dev/null +++ b/smartcrd/pscr/pscrnt.c @@ -0,0 +1,1687 @@ +/*++ + +Copyright (c) 1997 - 1999 SCM Microsystems, Inc. + +Module Name: + + PscrNT.c + +Abstract: + + Main Driver Module - NT Version + +Author: + + Andreas Straub + +Notes: + + The file pscrnt.c was reviewed by LCA in June 2011 and per license is + acceptable for Microsoft use under Dealpoint ID 178449. + +Revision History: + + + Andreas Straub 1.00 8/18/1997 Initial Version + Klaus Schuetz 1.01 9/20/1997 Timing changed + Andreas Straub 1.02 9/24/1997 Low Level error handling, + minor bugfixes, clanup + Andreas Straub 1.03 10/8/1997 Timing changed, generic SCM + interface changed + Andreas Straub 1.04 10/18/1997 Interrupt handling changed + Andreas Straub 1.05 10/19/1997 Generic IOCTL's added + Andreas Straub 1.06 10/25/1997 Timeout limit for FW update variable + Andreas Straub 1.07 11/7/1997 Version information added + Klaus Schuetz 1.08 11/10/1997 PnP capabilities added + Klaus Schuetz Cleanup added + Calai Bhoopathi 6/12/2006 Changed retry count in Dpc routine + Eliyas Yakub 10/6/2006 Ported to KMDF + +--*/ + +#include +#include +#include +#include +#include + +#pragma alloc_text(INIT, DriverEntry) +#pragma alloc_text(PAGE, PscrEvtDeviceAdd) +#pragma alloc_text(PAGE, PscrRegisterWithSmcLib) +#pragma alloc_text(PAGE, PscrEvtDevicePrepareHardware) +#pragma alloc_text(PAGE, PscrEvtDeviceD0Exit) +#pragma alloc_text(PAGE, PscrEvtFileCleanup) +#pragma alloc_text(PAGE, PscrGetRegistryValue) + +NTSTATUS +DriverEntry( + PDRIVER_OBJECT DriverObject, + PUNICODE_STRING RegistryPath + ) +/*++ + +DriverEntry: + entry function of the driver. setup the callbacks for the OS and try to + initialize a device object for every device in the system + +Arguments: + DriverObject context of the driver + RegistryPath path to the registry entry for the driver + +Return Value: + STATUS_SUCCESS + STATUS_UNSUCCESSFUL + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + WDF_DRIVER_CONFIG config; + + SmartcardDebug( + DEBUG_TRACE, + ( "PSCR!DriverEntry: Enter - KMDF Version Built %s %s\n", + __DATE__, __TIME__ ) + ); + + WDF_DRIVER_CONFIG_INIT(&config, PscrEvtDeviceAdd); + + + // + // Create a framework driver object to represent our driver. + // + status = WdfDriverCreate(DriverObject, + RegistryPath, + WDF_NO_OBJECT_ATTRIBUTES, // Driver Attributes + &config, // Driver Config Info + WDF_NO_HANDLE + ); + + if (!NT_SUCCESS(status)) { + KdPrint( ("WdfDriverCreate failed with status 0x%x\n", status)); + } + + SmartcardDebug( + DEBUG_TRACE, + ("PSCR!DriverEntry: Exit %x\n", + status) + ); + + return status; +} + +NTSTATUS +PscrEvtDeviceAdd( + IN WDFDRIVER Driver, + IN PWDFDEVICE_INIT DeviceInit + ) +/*++ + +Routine Description: + + PscrEvtDeviceAdd is called by the framework in response to AddDevice + call from the PnP manager. We create and initialize a WDF device object to + represent a new instance of toaster device. + +Arguments: + + Driver - Handle to a framework driver object created in DriverEntry + + DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure. + +Return Value: + + NTSTATUS +--*/ +{ + NTSTATUS status; + WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks; + WDF_OBJECT_ATTRIBUTES attributes; + WDFDEVICE device; + PDEVICE_EXTENSION DeviceExtension; + WDF_IO_QUEUE_CONFIG ioQueueConfig; + WDF_INTERRUPT_CONFIG interruptConfig; + WDF_FILEOBJECT_CONFIG fileobjectConfig; + + UNREFERENCED_PARAMETER(Driver); + + PAGED_CODE(); + + SmartcardDebug( + DEBUG_TRACE, + ( "PSCR!PscrAddDevice: Enter\n" ) + ); + + WdfDeviceInitSetDeviceType(DeviceInit, FILE_DEVICE_SMARTCARD); + + WdfDeviceInitSetExclusive(DeviceInit, TRUE); + + WdfDeviceInitSetIoType(DeviceInit, WdfDeviceIoBuffered); + + WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks); + + pnpPowerCallbacks.EvtDevicePrepareHardware = PscrEvtDevicePrepareHardware; + + pnpPowerCallbacks.EvtDeviceD0Entry = PscrEvtDeviceD0Entry; + pnpPowerCallbacks.EvtDeviceD0Exit = PscrEvtDeviceD0Exit; + + WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks); + + // + // Register close callback so that we can clear the notification irp. + // + WDF_FILEOBJECT_CONFIG_INIT( + &fileobjectConfig, + WDF_NO_EVENT_CALLBACK, // Create + WDF_NO_EVENT_CALLBACK, // Close + PscrEvtFileCleanup // Cleanup + ); + + WdfDeviceInitSetFileObjectConfig( + DeviceInit, + &fileobjectConfig, + WDF_NO_OBJECT_ATTRIBUTES + ); + // + // Initialize attributes and a context area for the device object. + // + // + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, DEVICE_EXTENSION); + attributes.EvtCleanupCallback = PscrEvtDeviceContextCleanup; + + // + // Create a framework device object.This call will in turn create + // a WDM device object, attach to the lower stack, and set the + // appropriate flags and attributes. + // + status = WdfDeviceCreate(&DeviceInit, &attributes, &device); + if (!NT_SUCCESS(status)) { + SmartcardLogError( + WdfDriverWdmGetDriverObject(WdfGetDriver()), + PSCR_INSUFFICIENT_RESOURCES, + NULL, + 0 + ); + return status; + } + + // + // Get the device context by using the accessor function specified in + // the WDF_DECLARE_CONTEXT_TYPE_WITH_NAME macro for DEVICE_EXTENSION. + // + DeviceExtension = GetDeviceExtension(device); + + DeviceExtension->Device = device; + + InterlockedIncrement((PLONG)&DeviceExtension->DeviceInstanceNo); + + // + // Add an extra stack location to the IRP disaptched to our device so + // that we can use that to workaround the problem of scmlib completing + // ioctl IRPs. + // + WdfDeviceWdmGetDeviceObject(DeviceExtension->Device)->StackSize++; + + // + // Tell the Framework that this device will need an interface + // + status = WdfDeviceCreateDeviceInterface( + device, + &SmartCardReaderGuid, + NULL // ReferenceString + ); + + if (!NT_SUCCESS (status)) { + SmartcardLogError( + WdfDriverWdmGetDriverObject(WdfGetDriver()), + PSCR_INSUFFICIENT_RESOURCES, + NULL, + 0 + ); + + return status; + } + + // + // Create a parallel queue for dispatching ioctl requests. + // + + WDF_IO_QUEUE_CONFIG_INIT( + &ioQueueConfig, + WdfIoQueueDispatchParallel + ); + + ioQueueConfig.EvtIoDeviceControl = PscrEvtIoDeviceControl; + + + status = WdfIoQueueCreate ( + device, + &ioQueueConfig, + WDF_NO_OBJECT_ATTRIBUTES, + &DeviceExtension->IoctlQueue + ); + + if(!NT_SUCCESS (status)){ + return status; + } + + status = WdfDeviceConfigureRequestDispatching( + device, + DeviceExtension->IoctlQueue, + WdfRequestTypeDeviceControl); + + if(!NT_SUCCESS (status)){ + return status; + } + + // + // Manual queue for parking smartcard notification request. + // + WDF_IO_QUEUE_CONFIG_INIT( + &ioQueueConfig, + WdfIoQueueDispatchManual + ); + + // + // Since this request dispatch from this queue doesn't touch the + // hardware, it doesn't have to be power managed. + // + ioQueueConfig.PowerManaged = WdfFalse; + + // + // Smartcard library keeps track of last outstanding notification + // request provided to the client driver. When the client driver + // completes the request, it has to clear the field in the data- + // structure maintained by the library. Since we keep the request + // in a queue, we need a notification from the framework when the + // request is cancelled so that we can clear the field. + // + ioQueueConfig.EvtIoCanceledOnQueue = PscrEvtIoCanceledOnQueue; + + status = WdfIoQueueCreate ( + device, + &ioQueueConfig, + WDF_NO_OBJECT_ATTRIBUTES, + &DeviceExtension->NotificationQueue + ); + + if(!NT_SUCCESS (status)){ + return status; + } + + // + // Create WDFINTERRUPT object. Framework will take care of parsing + // the interrupt resource and connecting and disconnecting the ISR + // at the appropriate PNP/POWER state changes. + // + + WDF_INTERRUPT_CONFIG_INIT(&interruptConfig, + PscrEvtInterruptServiceRoutine, + PscrEvtInterruptDpc); + + status = WdfInterruptCreate(device, + &interruptConfig, + WDF_NO_OBJECT_ATTRIBUTES, + &DeviceExtension->Interrupt); + if (!NT_SUCCESS (status)) { + return status; + } + + // + // Register with smartcard libarary. + // + status = PscrRegisterWithSmcLib(DeviceExtension); + if (!NT_SUCCESS (status)) { + return status; + } + + SmartcardDebug( + DEBUG_TRACE, + ( "PSCR!PscrAddDevice: Exit %x\n", + status) + ); + + return status; +} + +VOID +PscrEvtDeviceContextCleanup ( + WDFOBJECT Object + ) +/*++ + +Routine Description: + + Called when the device object is deleted by the framework in response + to REMOVE_DEVICE request. Here, free up all the resources that wouldn't + cleaned up by the framework automatically due to parent child relationship. + +Arguments: + + Device - Handle to a framework device object. + +Return Value: + + VOID + +--*/ +{ + WDFDEVICE Device; + PDEVICE_EXTENSION DeviceExtension; + + Device = (WDFDEVICE)Object; + DeviceExtension = GetDeviceExtension(Device); + + InterlockedDecrement((PLONG)&DeviceExtension->DeviceInstanceNo); + + if (DeviceExtension->SmartcardExtension.ReaderExtension != NULL) { + + ExFreePoolWithTag(DeviceExtension->SmartcardExtension.ReaderExtension, + SMARTCARD_POOL_TAG); + + DeviceExtension->SmartcardExtension.ReaderExtension = NULL; + } +} + +NTSTATUS +PscrRegisterWithSmcLib( + PDEVICE_EXTENSION DeviceExtension + ) +{ + PREADER_EXTENSION ReaderExtension; + PSMARTCARD_EXTENSION SmartcardExtension; + UNICODE_STRING vendorNameU, ifdTypeU; + ANSI_STRING vendorNameA, ifdTypeA; + WDFSTRING vendorNameStr, ifdTypeStr; + NTSTATUS status; + + PAGED_CODE(); + + vendorNameStr = NULL; + ifdTypeStr = NULL; + + RtlZeroMemory(&vendorNameA, sizeof(vendorNameA)); + RtlZeroMemory(&ifdTypeA, sizeof(ifdTypeA)); + + // set up the device extension. + SmartcardExtension = &DeviceExtension->SmartcardExtension; + + // allocate the reader extension + ReaderExtension = ExAllocatePoolWithTag( + NonPagedPool, + sizeof( READER_EXTENSION ), + SMARTCARD_POOL_TAG + ); + + if ( ReaderExtension == NULL ) { + SmartcardLogError( + WdfDriverWdmGetDriverObject(WdfGetDriver()), + PSCR_INSUFFICIENT_RESOURCES, + NULL, + 0 + ); + status = STATUS_INSUFFICIENT_RESOURCES; + return status; + } + + RtlZeroMemory( ReaderExtension, sizeof( READER_EXTENSION )); + + SmartcardExtension->ReaderExtension = ReaderExtension; + + ReaderExtension->CompletionRoutine = CBUpdateCardState; + ReaderExtension->TrackingContext = SmartcardExtension; + + ReaderExtension->dataRatesSupported[0] = (ULONG) 9600; + ReaderExtension->dataRatesSupported[1] = (ULONG) 38400; + ReaderExtension->dataRatesSupported[2] = (ULONG) 57600; + ReaderExtension->dataRatesSupported[3] = (ULONG) 115200; + + // Initialize the RequestInterrupt flag + ReaderExtension->RequestInterrupt = FALSE; + + // setup smartcard extension - callback's + SmartcardExtension->ReaderFunction[RDF_CARD_POWER] = CBCardPower; + SmartcardExtension->ReaderFunction[RDF_TRANSMIT] = CBTransmit; + SmartcardExtension->ReaderFunction[RDF_CARD_TRACKING] = CBCardTracking; + SmartcardExtension->ReaderFunction[RDF_SET_PROTOCOL] = CBSetProtocol; + SmartcardExtension->ReaderFunction[RDF_IOCTL_VENDOR] = PscrGenericIOCTL; + + // setup smartcard extension - vendor attribute + RtlCopyMemory( + SmartcardExtension->VendorAttr.VendorName.Buffer, + PSCR_VENDOR_NAME, + sizeof( PSCR_VENDOR_NAME ) + ); + SmartcardExtension->VendorAttr.VendorName.Length = + sizeof( PSCR_VENDOR_NAME ); + + RtlCopyMemory( + SmartcardExtension->VendorAttr.IfdType.Buffer, + PSCR_IFD_TYPE, + sizeof( PSCR_IFD_TYPE ) + ); + SmartcardExtension->VendorAttr.IfdType.Length = + sizeof( PSCR_IFD_TYPE ); + + SmartcardExtension->VendorAttr.UnitNo = DeviceExtension->DeviceInstanceNo; + + SmartcardExtension->VendorAttr.IfdVersion.BuildNumber = 0; + + // store firmware revision in ifd version + SmartcardExtension->VendorAttr.IfdVersion.VersionMajor = + ReaderExtension->FirmwareMajor; + SmartcardExtension->VendorAttr.IfdVersion.VersionMinor = + ReaderExtension->FirmwareMinor; + SmartcardExtension->VendorAttr.IfdSerialNo.Length = 0; + + // setup smartcard extension - reader capabilities + SmartcardExtension->ReaderCapabilities.SupportedProtocols = + SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1; + + SmartcardExtension->ReaderCapabilities.ReaderType = + SCARD_READER_TYPE_PCMCIA; + SmartcardExtension->ReaderCapabilities.MechProperties = 0; + SmartcardExtension->ReaderCapabilities.Channel = 0; + + SmartcardExtension->ReaderCapabilities.CLKFrequency.Default = 4000; + SmartcardExtension->ReaderCapabilities.CLKFrequency.Max = 4000; + + // reader could support higher data rates + SmartcardExtension->ReaderCapabilities.DataRatesSupported.List = + ReaderExtension->dataRatesSupported; + SmartcardExtension->ReaderCapabilities.DataRatesSupported.Entries = MAX_DATARATES; + SmartcardExtension->ReaderCapabilities.DataRate.Default = ReaderExtension->dataRatesSupported[0]; + SmartcardExtension->ReaderCapabilities.DataRate.Max = + ReaderExtension->dataRatesSupported[ MAX_DATARATES-1 ]; + + // enter correct version of the lib + SmartcardExtension->Version = SMCLIB_VERSION; + SmartcardExtension->SmartcardRequest.BufferSize = MIN_BUFFER_SIZE; + SmartcardExtension->SmartcardReply.BufferSize = MIN_BUFFER_SIZE; + + SmartcardExtension->ReaderExtension->ReaderPowerState = PowerReaderWorking; + + status = SmartcardInitialize(SmartcardExtension); + + if (status != STATUS_SUCCESS) { + + SmartcardLogError( + WdfDriverWdmGetDriverObject(WdfGetDriver()), + PSCR_INSUFFICIENT_RESOURCES, + NULL, + 0 + ); + // + // No need to worry about freeing the pool we allocated earlier. + // It will be freed in the cleanup callback when the device is + // deleted by the framework as a result of failing this call. + // + return status; + } + + SmartcardExtension->OsData->DeviceObject = + WdfDeviceWdmGetDeviceObject(DeviceExtension->Device); + + vendorNameStr = PscrGetRegistryValue(DeviceExtension->Device, L"VendorName"); + if (vendorNameStr != NULL) { + + WdfStringGetUnicodeString(vendorNameStr, &vendorNameU); + + status = RtlUnicodeStringToAnsiString( + &vendorNameA, + &vendorNameU, + TRUE + ); + if (NT_SUCCESS(status)) { + if (vendorNameA.Length > 0 && vendorNameA.Length < MAXIMUM_ATTR_STRING_LENGTH) { + RtlCopyMemory( + SmartcardExtension->VendorAttr.VendorName.Buffer, + vendorNameA.Buffer, + vendorNameA.Length + ); + SmartcardExtension->VendorAttr.VendorName.Length = vendorNameA.Length; + } + RtlFreeAnsiString(&vendorNameA); + } + + // + // We have copied the string to the extension. No need to keep the object + // around and waste memory. + // + WdfObjectDelete(vendorNameStr); + vendorNameStr = NULL; + } else { + status = STATUS_UNSUCCESSFUL; + } + + if (!NT_SUCCESS(status)) { + return status; + } + + ifdTypeStr = PscrGetRegistryValue(DeviceExtension->Device, L"IfdType"); + if (ifdTypeStr != NULL) { + + WdfStringGetUnicodeString(ifdTypeStr, &ifdTypeU); + + status = RtlUnicodeStringToAnsiString( + &ifdTypeA, + &ifdTypeU, + TRUE + ); + if (NT_SUCCESS(status)) { + if (ifdTypeA.Length > 0 && ifdTypeA.Length < MAXIMUM_ATTR_STRING_LENGTH) { + RtlCopyMemory( + SmartcardExtension->VendorAttr.IfdType.Buffer, + ifdTypeA.Buffer, + ifdTypeA.Length + ); + SmartcardExtension->VendorAttr.IfdType.Length = ifdTypeA.Length; + } + RtlFreeAnsiString(&ifdTypeA); + } + + WdfObjectDelete(ifdTypeStr); + ifdTypeStr = NULL; + } else { + status = STATUS_UNSUCCESSFUL; + } + + return status; +} + + +NTSTATUS +PscrEvtDevicePrepareHardware ( + WDFDEVICE Device, + WDFCMRESLIST Resources, + WDFCMRESLIST ResourcesTranslated + ) +/*++ + +Routine Description: + + EvtDevicePrepareHardware event callback performs operations that are necessary + to make the driver's device operational. The framework calls the driver's + EvtDeviceStart callback when the PnP manager sends an IRP_MN_START_DEVICE + request to the driver stack. + +Arguments: + + Device - Handle to a framework device object. + + Resources - Handle to a collection of framework resource objects. + This collection identifies the raw (bus-relative) hardware + resources that have been assigned to the device. + + ResourcesTranslated - Handle to a collection of framework resource objects. + This collection identifies the translated (system-physical) + hardware resources that have been assigned to the device. + The resources appear from the CPU's point of view. + Use this list of resources to map I/O space and + device-accessible memory into virtual address space + +Return Value: + + WDF status code + +--*/ +{ + PCM_PARTIAL_RESOURCE_DESCRIPTOR descriptor; + PDEVICE_EXTENSION DeviceExtension = GetDeviceExtension(Device); + PSMARTCARD_EXTENSION SmartcardExtension = &DeviceExtension->SmartcardExtension; + PREADER_EXTENSION ReaderExtension = SmartcardExtension->ReaderExtension; + NTSTATUS status; + ULONG i; + + UNREFERENCED_PARAMETER(Resources); + UNREFERENCED_PARAMETER(ResourcesTranslated); + + PAGED_CODE(); + + for (i=0; i < WdfCmResourceListGetCount(ResourcesTranslated); i++) { + + descriptor = WdfCmResourceListGetDescriptor(ResourcesTranslated, i); + + switch(descriptor->Type) { + + case CmResourceTypePort: + + KdPrint(("I/O Port: (%x) Length: (%d)\n", + descriptor->u.Port.Start.LowPart, + descriptor->u.Port.Length)); + + ReaderExtension->IOBase = + (PPSCR_REGISTERS) UlongToPtr(descriptor->u.Port.Start.LowPart); + + NT_ASSERT(descriptor->u.Port.Length >= 4); + + break; + + case CmResourceTypeMemory: + + KdPrint(("Memory: (%x) Length: (%d)\n", + descriptor->u.Memory.Start.LowPart, + descriptor->u.Memory.Length)); + break; + case CmResourceTypeInterrupt: + // + // Framework will parse the interrupt resource and connect and + // disconnect interrupt. We don't have to do anything here. + // + KdPrint(("Interrupt level: 0x%0x, Vector: 0x%0x, Affinity: 0x%0x\n", + descriptor->u.Interrupt.Level, + descriptor->u.Interrupt.Vector, + descriptor->u.Interrupt.Affinity)); + + break; + + default: + break; + } + + } + + + if ( ReaderExtension->IOBase == NULL ) { + SmartcardLogError( + WdfDriverWdmGetDriverObject(WdfGetDriver()), + PSCR_ERROR_IO_PORT, + NULL, + 0 + ); + + status = STATUS_INSUFFICIENT_RESOURCES; + return status; + } + + + ReaderExtension->Device = DEVICE_ICC1; + ReaderExtension->MaxRetries = PSCR_MAX_RETRIES; + status = CmdResetInterface( ReaderExtension ); + + SmartcardExtension->ReaderCapabilities.MaxIFSD = + ReaderExtension->MaxIFSD; + + if (status != STATUS_SUCCESS) { + + SmartcardLogError( + WdfDriverWdmGetDriverObject(WdfGetDriver()), + PSCR_CANT_INITIALIZE_READER, + NULL, + 0 + ); + + return status; + } + + status = CmdReset( + ReaderExtension, + 0x00, // reader + FALSE, // cold reset + NULL, // no atr + NULL + ); + + if (status != STATUS_SUCCESS) { + + SmartcardLogError( + WdfDriverWdmGetDriverObject(WdfGetDriver()), + PSCR_CANT_INITIALIZE_READER, + NULL, + 0 + ); + + return status; + } + + PscrFlushInterface(DeviceExtension->SmartcardExtension.ReaderExtension); + + CmdGetFirmwareRevision( + DeviceExtension->SmartcardExtension.ReaderExtension + ); + + // If you change the min. firmware version here, please update + // the .mc file for the correct error message, too + if (SmartcardExtension->ReaderExtension->FirmwareMajor < 2 || + SmartcardExtension->ReaderExtension->FirmwareMajor == 2 && + SmartcardExtension->ReaderExtension->FirmwareMinor < 0x34) { + + SmartcardLogError( + WdfDriverWdmGetDriverObject(WdfGetDriver()), + PSCR_WRONG_FIRMWARE, + NULL, + 0 + ); + } + + // store firmware revision in ifd version + SmartcardExtension->VendorAttr.IfdVersion.VersionMajor = + ReaderExtension->FirmwareMajor; + SmartcardExtension->VendorAttr.IfdVersion.VersionMinor = + ReaderExtension->FirmwareMinor; + + // reader could support higher data rates + SmartcardExtension->ReaderCapabilities.DataRatesSupported.List = + ReaderExtension->dataRatesSupported; + SmartcardExtension->ReaderCapabilities.DataRate.Default = ReaderExtension->dataRatesSupported[0]; + + SmartcardExtension->ReaderCapabilities.DataRatesSupported.Entries = 2; + SmartcardExtension->ReaderCapabilities.DataRate.Max = + ReaderExtension->dataRatesSupported[ 1 ]; + + NT_ASSERT(status == STATUS_SUCCESS); + + return status; +} + +NTSTATUS +PscrEvtDeviceD0Entry( + IN WDFDEVICE Device, + IN WDF_POWER_DEVICE_STATE PreviousState + ) +/*++ + +Routine Description: + + EvtDeviceD0Entry event callback must perform any operations that are + necessary before the specified device is used. It will be called every + time the hardware needs to be (re-)initialized. This includes after + IRP_MN_START_DEVICE, IRP_MN_CANCEL_STOP_DEVICE, IRP_MN_CANCEL_REMOVE_DEVICE, + IRP_MN_SET_POWER-D0. + + This function runs at PASSIVE_LEVEL, though it is generally not paged. A + driver can optionally make this function pageable if DO_POWER_PAGABLE is set. + + Even if DO_POWER_PAGABLE isn't set, this function still runs at + PASSIVE_LEVEL. In this case, though, the function absolutely must not do + anything that will cause a page fault. + +Arguments: + + Device - Handle to a framework device object. + + PreviousState - Device power state which the device was in most recently. + If the device is being newly started, this will be + PowerDeviceUnspecified. + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status; + PDEVICE_EXTENSION DeviceExtension; + PSMARTCARD_EXTENSION SmartcardExtension; + UCHAR state; + WDF_INTERRUPT_INFO interruptInfo; + + // + //MikeTs(10/15/2008): http://msdn.microsoft.com/en-us/library/bb725862.aspx + // explains although the callback function is called at PASSIVE_LEVEL, + // callback functions that leave a lower device state returning to + // working state should not be pageable. + // + DeviceExtension = GetDeviceExtension(Device); + + // + // Find out if the interrupt is shared. + // + WDF_INTERRUPT_INFO_INIT(&interruptInfo); + WdfInterruptGetInfo(DeviceExtension->Interrupt, &interruptInfo); + DeviceExtension->bSharedIRQ = + (interruptInfo.ShareDisposition == CmResourceShareShared); + + SmartcardExtension = (PSMARTCARD_EXTENSION) &DeviceExtension->SmartcardExtension; + + status = CmdResetInterface(SmartcardExtension->ReaderExtension); + NT_ASSERT(status == STATUS_SUCCESS); + + SmartcardExtension->ReaderExtension->StatusFileSelected = FALSE; + state = CBGetCardState(SmartcardExtension); + + + // save the current power state of the reader + SmartcardExtension->ReaderExtension->ReaderPowerState = PowerReaderWorking; + + // + // We will use PreviousState to differetiate whether EvtDeviceD0Entry is + // called due to implicit power when the device is first started or when + // the device is resume power a low power state (due to explicit power up). + // + if (PreviousState != WdfPowerDeviceD3Final) { + // + // The device is resuming from a suspended state. + // + CBUpdateCardState(SmartcardExtension, state, TRUE); + } else { + // + // The device is starting up for the first time. + // + CBUpdateCardState(SmartcardExtension, state, FALSE); + } + + return STATUS_SUCCESS; +} + + +NTSTATUS +PscrEvtDeviceD0Exit( + IN WDFDEVICE Device, + IN WDF_POWER_DEVICE_STATE TargetState + ) +/*++ + +Routine Description: + + This routine undoes anything done in EvtDeviceD0Entry. It is called + whenever the device leaves the D0 state, which happens when the device is + stopped, when it is removed, and when it is powered off. + + The device is still in D0 when this callback is invoked, which means that + the driver can still touch hardware in this routine. + + Note that interrupts have already been disabled by the time that this + callback is invoked. + + EvtDeviceD0Exit event callback must perform any operations that are + necessary before the specified device is moved out of the D0 state. If the + driver needs to save hardware state before the device is powered down, then + that should be done here. + + This function runs at PASSIVE_LEVEL, though it is generally not paged. A + driver can optionally make this function pageable if DO_POWER_PAGABLE is set. + + Even if DO_POWER_PAGABLE isn't set, this function still runs at + PASSIVE_LEVEL. In this case, though, the function absolutely must not do + anything that will cause a page fault. + +Arguments: + + Device - Handle to a framework device object. + + TargetState - Device power state which the device will be put in once this + callback is complete. + +Return Value: + + Success implies that the device can be used. Failure will result in the + device stack being torn down. + +--*/ +{ + NTSTATUS status; + PDEVICE_EXTENSION DeviceExtension; + PSMARTCARD_EXTENSION smartcardExtension; + + PAGED_CODE(); + + DeviceExtension = GetDeviceExtension(Device); + smartcardExtension = (PSMARTCARD_EXTENSION) &DeviceExtension->SmartcardExtension; + + switch (TargetState) { + case WdfPowerDeviceD1: + case WdfPowerDeviceD2: + case WdfPowerDeviceD3: + + smartcardExtension->ReaderExtension->CardPresent = + smartcardExtension->ReaderCapabilities.CurrentState > SCARD_ABSENT ? TRUE: FALSE; + + if (smartcardExtension->ReaderExtension->CardPresent) { + smartcardExtension->MinorIoControlCode = SCARD_POWER_DOWN; + status = CBCardPower(smartcardExtension); + NT_ASSERT(NT_SUCCESS(status)); + } + // save the current power state of the reader + smartcardExtension->ReaderExtension->ReaderPowerState = PowerReaderOff; + break; + + case WdfPowerDevicePrepareForHibernation: + + // + // Fill in any code to save hardware state here. Do not put in any + // code to shut the device off. If this device cannot support being + // in the paging path (or being a parent or grandparent of a paging + // path device) then this whole case can be deleted. + // + NT_ASSERT(FALSE); // This driver shouldn't get this. + break; + + case WdfPowerDeviceD3Final: + // + // Reset and put the device into a known initial state we're shutting + // down for the last time. + // + break; + + default: + break; + } + + return STATUS_SUCCESS; +} + + +VOID +PscrEvtFileCleanup( + IN WDFFILEOBJECT FileObject + ) +/*++ + + EvtFileClose is called when all the handles represented by the FileObject + is closed and all the references to FileObject is removed. This callback + may get called in an arbitrary thread context instead of the thread that + called CloseHandle. If you want to delete any per FileObject context that + must be done in the context of the user thread that made the Create call, + you should do that in the EvtDeviceCleanp callback. + +Arguments: + + FileObject - Pointer to fileobject that represents the open handle. + +Return Value: + + VOID + +--*/ + +{ + PDEVICE_EXTENSION DeviceExtension; + PSMARTCARD_EXTENSION smartcardExtension; + NTSTATUS status; + WDFREQUEST request; + + PAGED_CODE(); + + //KdPrint(("PscrEvtFileCleanup called\n")); + + // + // After cleanup callback is invoked, framework flushes all the queues + // by fileobject to cancel irps belonging to the file handle being closed. + // Since framework version 1.5 and less have a bug in that on cleanup- + // flush the EvtIoCanceledOnQueue callback is not invoked, we will + // retrive the request by fileobject ourselves and complete the request + // and clear the NotificaitonIrp field. + // + DeviceExtension = GetDeviceExtension(WdfFileObjectGetDevice(FileObject)); + smartcardExtension = (PSMARTCARD_EXTENSION) &DeviceExtension->SmartcardExtension; + + do { + status = WdfIoQueueRetrieveRequestByFileObject( + DeviceExtension->NotificationQueue, + FileObject, + &request); + + if (NT_SUCCESS(status)) { + + NT_ASSERT(smartcardExtension->OsData->NotificationIrp == + WdfRequestWdmGetIrp(request)); + + InterlockedExchangePointer( + &(smartcardExtension->OsData->NotificationIrp), + NULL + ); + + WdfRequestComplete(request, STATUS_CANCELLED); + } + }while (NT_SUCCESS(status)); + + NT_ASSERT(status == STATUS_NO_MORE_ENTRIES); + + return; +} + +_Function_class_(IO_COMPLETION_ROUTINE) +NTSTATUS +PscrSmcLibComplete ( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Context + ) +/*++ + +Routine Description: + + Completion routine is called when the IRP is completed by the smclib. + We will interrupt the completion of the IRP, and inturn complete the + WDFREQUEST given to us by the framework. + +--*/ +{ + UNREFERENCED_PARAMETER(DeviceObject); + + //KdPrint(("<-- PscrSmcLibComplete called %x Request %x\n", + // Irp->IoStatus.Status, Context)); + + WdfRequestComplete((WDFREQUEST)Context, Irp->IoStatus.Status); + + return STATUS_MORE_PROCESSING_REQUIRED; +} + + +VOID +PscrEvtIoDeviceControl( + IN WDFQUEUE Queue, + IN WDFREQUEST Request, + IN size_t OutputBufferLength, + IN size_t InputBufferLength, + IN ULONG IoControlCode + ) +/*++ + +Routine Description: + + This event is called when the framework receives IRP_MJ_DEVICE_CONTROL + requests from the system. + +Arguments: + + Queue - Handle to the framework queue object that is associated + with the I/O request. + Request - Handle to a framework request object. + + OutputBufferLength - length of the request's output buffer, + if an output buffer is available. + InputBufferLength - length of the request's input buffer, + if an input buffer is available. + + IoControlCode - the driver-defined or system-defined I/O control code + (IOCTL) that is associated with the request. +Return Value: + + VOID + +--*/ +{ + PDEVICE_EXTENSION deviceExtension; + PIRP irp; + + UNREFERENCED_PARAMETER(OutputBufferLength); + UNREFERENCED_PARAMETER(InputBufferLength); + UNREFERENCED_PARAMETER(IoControlCode); + + //KdPrint(("--> PscrEvtIoDeviceControl called %s Request 0x%x\n", + // GetIoctlName(IoControlCode), Request)); + + deviceExtension = GetDeviceExtension(WdfIoQueueGetDevice(Queue)); + + // + // Since smartcard library expects an IRP, we will get the underlying + // irp. + // + irp = WdfRequestWdmGetIrp(Request); + + // + // We will store the Request handle in the IRP DriverContext field so + // that we can get the handle back in vendor-ioctl callback routine. + // + SET_REQUEST_IN_IRP(irp, Request); + + // + // To workaround the problem of smartcard completing the IRP we provided. + // we will use the extra stack location to set a completion routine so that + // when it completes the IRP, our completion routine will be called, where + // we can interrupt the completion and complete the actual WDFREQUEST. + // + IoCopyCurrentIrpStackLocationToNext(irp); + + IoSetCompletionRoutine (irp, + PscrSmcLibComplete, + Request, + TRUE, + TRUE, + TRUE + ); + + IoSetNextIrpStackLocation(irp); + + // + // Ignore the return value because framework has marked the irp pending + // and will return status-pending when we return from this routine. + // + (VOID) SmartcardDeviceControl(&(deviceExtension->SmartcardExtension), irp); + + return; +} + +NTSTATUS +PscrGenericIOCTL( + PSMARTCARD_EXTENSION SmartcardExtension + ) +/*++ + +PscrGenericIOCTL: + Performs generic callbacks to the reader + +Arguments: + SmartcardExtension context of the call + +Return Value: + STATUS_SUCCESS + +--*/ +{ + NTSTATUS status; + PIRP Irp; + WDFREQUEST request; + ULONG bytesTransfered; + size_t inBufLen, outBufLen; + PVOID inBuf, outBuf; + PIO_STACK_LOCATION IrpStack; + + SmartcardDebug( + DEBUG_TRACE, + ( "PSCR!PscrGenericIOCTL: Enter\n" ) + ); + + // + // get pointer to current IRP stack location + // + Irp = SmartcardExtension->OsData->CurrentIrp; + IrpStack = IoGetCurrentIrpStackLocation( Irp ); + + // + // Get the request from the IRP so that we can call framework functions + // to retreive the buffers. + // + request = GET_WDFREQUEST_FROM_IRP(SmartcardExtension->OsData->CurrentIrp); + + status = WdfRequestRetrieveInputBuffer(request, 0, &inBuf, &inBufLen); + if (!NT_SUCCESS(status)) { + return status; + } + + status = WdfRequestRetrieveOutputBuffer(request, 0, &outBuf, &outBufLen); + if (!NT_SUCCESS(status)) { + return status; + } + + // + // assume error + // + status = STATUS_INVALID_DEVICE_REQUEST; + bytesTransfered = 0; + + // + // dispatch IOCTL + // + switch ( IrpStack->Parameters.DeviceIoControl.IoControlCode ) { + case IOCTL_PSCR_COMMAND: + + status = CmdPscrCommand( + SmartcardExtension->ReaderExtension, + (PUCHAR) inBuf, + (ULONG) inBufLen, + (PUCHAR) outBuf, + (ULONG) outBufLen, + (PULONG) &bytesTransfered + ); + // + // the command could change the active file in the reader file + // system, so make sure that the status file will be selected + // before the next read + // + SmartcardExtension->ReaderExtension->StatusFileSelected = FALSE; + break; + + case IOCTL_GET_VERSIONS: + + if ( outBufLen < SIZEOF_VERSION_CONTROL ) { + status = STATUS_BUFFER_TOO_SMALL; + } else { + PVERSION_CONTROL VersionControl; + + VersionControl = (PVERSION_CONTROL)outBufLen; + + VersionControl->SmclibVersion = SmartcardExtension->Version; + VersionControl->DriverMajor = PSCR_MAJOR_VERSION; + VersionControl->DriverMinor = PSCR_MINOR_VERSION; + + // update firmware version (changed after update) + CmdGetFirmwareRevision( + SmartcardExtension->ReaderExtension + ); + VersionControl->FirmwareMajor = + SmartcardExtension->ReaderExtension->FirmwareMajor; + + VersionControl->FirmwareMinor = + SmartcardExtension->ReaderExtension->FirmwareMinor; + + VersionControl->UpdateKey = + SmartcardExtension->ReaderExtension->UpdateKey; + + bytesTransfered = SIZEOF_VERSION_CONTROL; + status = STATUS_SUCCESS; + } + break; + + case IOCTL_SET_TIMEOUT: + { + ULONG NewLimit; + // + // get new timeout limit + // + if ( inBufLen == sizeof( ULONG )) { + NewLimit = *(PULONG)inBuf; + } else { + NewLimit = 0; + } + + // + // report actual timeout limit + // + if (outBufLen == sizeof( ULONG )) { + + *(PULONG)outBuf = SmartcardExtension->ReaderExtension->MaxRetries + * DELAY_PSCR_WAIT; + bytesTransfered = sizeof( ULONG ); + } + + // + // set new timeout limit + // + if ( (NewLimit != 0) || + (NewLimit == MAXULONG-DELAY_PSCR_WAIT+2 )) { + SmartcardExtension->ReaderExtension->MaxRetries = + (NewLimit + DELAY_PSCR_WAIT - 1) / DELAY_PSCR_WAIT; + } + } + status = STATUS_SUCCESS; + break; + + case IOCTL_GET_CONFIGURATION: + // + // return IOBase and IRQ + // + if (outBufLen < SIZEOF_PSCR_CONFIGURATION ) { + status = STATUS_BUFFER_TOO_SMALL; + } else { + PPSCR_CONFIGURATION PSCRConfiguration; + + PSCRConfiguration = (PPSCR_CONFIGURATION) outBuf; + PSCRConfiguration->IOBase = + SmartcardExtension->ReaderExtension->IOBase; + PSCRConfiguration->IRQ = + SmartcardExtension->ReaderExtension->CurrentIRQ; + + bytesTransfered = SIZEOF_PSCR_CONFIGURATION; + status = STATUS_SUCCESS; + } + break; + + default: + break; + } + + // + // set status of the packet + // + Irp->IoStatus.Status = status; + Irp->IoStatus.Information = bytesTransfered; + + // + // The request will be completed the smartcard library. + // + SmartcardDebug( + DEBUG_TRACE, + ( "PSCR!PscrGenericIOCTL: Exit\n" ) + ); + + return( status ); +} + + +VOID +PscrEvtIoCanceledOnQueue( + IN WDFQUEUE Queue, + IN WDFREQUEST Request + ) +/*++ + +PscrEvtIoCanceledOnQueue: + + This routine is called when the request is cancelled on the queue. + + We will use the notificatio to clear the NotificationIrp field set by + the smartcard library. + +Arguments: + +Return Value: + VOID + +--*/ +{ + PDEVICE_EXTENSION DeviceExtension; + PSMARTCARD_EXTENSION smartcardExtension; + + DeviceExtension = GetDeviceExtension(WdfIoQueueGetDevice(Queue)); + smartcardExtension = (PSMARTCARD_EXTENSION) &DeviceExtension->SmartcardExtension; + + //KdPrint(("Cancelled on queue 0x%x\n", WdfRequestWdmGetIrp(Request))); + + InterlockedExchangePointer( + &(smartcardExtension->OsData->NotificationIrp), + NULL + ); + + WdfRequestComplete(Request, STATUS_CANCELLED); +} + +BOOLEAN +PscrEvtInterruptServiceRoutine( + IN WDFINTERRUPT Interrupt, + IN ULONG MessageID + ) +/*++ + +PscrIrqServiceRoutine: + + Because the device not supports shared interrupts, the call is passed + to the DPC routine immediately and the IRQ is reported as served. + +Arguments: + +Return Value: + STATUS_SUCCESS + +--*/ +{ + LARGE_INTEGER Time; + TIME_FIELDS TimeFields; + TIME_FIELDS SaveTimeFields; + BOOLEAN Status = TRUE; + PDEVICE_EXTENSION DeviceExtension; + + UNREFERENCED_PARAMETER(MessageID); + + DeviceExtension= GetDeviceExtension(WdfInterruptGetDevice(Interrupt)); + + KeQuerySystemTime( &Time ); + RtlTimeToTimeFields( &Time, &TimeFields ); + RtlTimeToTimeFields( &DeviceExtension->SaveTime, &SaveTimeFields ); + + SmartcardDebug( + DEBUG_TRACE, + ("PSCR!PscrIrqServiceRoutine: Enter\n") + ); + + // if the interrupt is shared the PscrIrqServiceRoutine shall return always FALSE + // since te driver can't detect if the interrupt was sending from the reader when + // the firmware <2.50 is using + // if the interrupt is used exclusiv and the PscrIrqServiceRoutine returns FALSE, + // no more interrupts will be sended + if(( DeviceExtension->bSharedIRQ ) && + ( TimeFields.Minute == SaveTimeFields.Minute ) && + ( TimeFields.Second == SaveTimeFields.Second ) && + ( TimeFields.Milliseconds < SaveTimeFields.Milliseconds+50 )) + { + KdPrint(( "****** Status FALSE ******\n" )); + SysDelay( 5 ); + Status = FALSE; + } + else + { + // + // When someone yanks out the card the interrupt handler gets called, + // but since there is no card anymore when don't need to schedule a DPC + // + + // + // the interrupt is caused by a freeze event. the interface will be + // cleared either by PscrRead() or the DPC routine (depending on + // which is called first) + // + // DeviceExtension->SmartcardExtension.ReaderExtension->FreezePending = TRUE; + + InterlockedIncrement((PLONG)&DeviceExtension->PendingInterrupts); + + WdfInterruptQueueDpcForIsr( Interrupt ); + + if( DeviceExtension->bSharedIRQ ) { + Status = FALSE; + } + } + + DeviceExtension->SaveTime.QuadPart = Time.QuadPart; + + SmartcardDebug( + DEBUG_TRACE, + ( "PSCR!PscrIrqServiceRoutine: Exit\n" ) + ); + + return Status ; +} + +VOID +PscrEvtInterruptDpc( + IN WDFINTERRUPT Interrupt, + IN WDFOBJECT Device + ) +/*++ + +PscrDpcRoutine: + finishes interrupt requests. the freeze event data of the reader will be read + & the card state will be updated if data valid + +Arguments: + +Return Value: + void + +--*/ +{ + PDEVICE_EXTENSION DeviceExtension; + PSMARTCARD_EXTENSION SmartcardExtension; + + UNREFERENCED_PARAMETER(Interrupt); + + DeviceExtension= GetDeviceExtension(Device); + SmartcardExtension = (PSMARTCARD_EXTENSION) &DeviceExtension->SmartcardExtension; + SmartcardDebug( + DEBUG_TRACE, + ( "PSCR!PscrInterruptEvent: IoBase %p\n", + SmartcardExtension->ReaderExtension->IOBase) + ); + + // + // In case of a card change the reader provides a TLV packet describing + // the event ('freeze event'). If PscrRead was called before the DPC + // routine is called, this event was cleared; in this case the card state + // will be updated by reading the card status file + // + do { + + + NT_ASSERT(DeviceExtension->PendingInterrupts < 10); + + SmartcardDebug( + DEBUG_TRACE, + ( "PSCR!PscrInterruptEvent: PendingInterrupts = %ld\n", + DeviceExtension->PendingInterrupts) + ); + + if( !SmartcardExtension->ReaderExtension->RequestPending ) + { + PscrFreeze( SmartcardExtension ); + } + else + { + // sometimes the fw doesn't send the freeze data + SmartcardExtension->ReaderExtension->RequestInterrupt = TRUE; + } + + } while (InterlockedDecrement((PLONG)&DeviceExtension->PendingInterrupts) > 0); +} + +void +PscrFreeze( + PSMARTCARD_EXTENSION SmartcardExtension + ) + +/*++ +PscrFreeze: + Read & evaluate freeze data + +Arguments: + ReaderExtension context of call + pDevice device which causes the freeze event + +Return Value: + STATUS_SUCCESS + STATUS_UNSUCCESSFUL + +--*/ +{ + NTSTATUS NTStatus = STATUS_UNSUCCESSFUL; + UCHAR TLVList[9]; + ULONG NBytes; + ULONG Retries; + UCHAR ReadFreeze[] = { 0x12, 0x00, 0x05, 0x00, 0xB0, 0x00, 0x00, 0x01, 0xA6}; + + for (Retries = 0; Retries < 2; Retries++) // CB - code sync - 7/13/2006 + { + + PscrWriteDirect( + SmartcardExtension->ReaderExtension, + (PUCHAR)ReadFreeze, + sizeof( ReadFreeze ), + &NBytes + ); + + SysDelay( 20 ); + + NTStatus = PscrRead( + SmartcardExtension->ReaderExtension, + (PUCHAR) TLVList, + sizeof( TLVList ), + &NBytes + ); + + if( NT_SUCCESS( NTStatus )) + { + // + // get result + // + if( ( TLVList[ PSCR_NAD ] == 0x21 ) && + ( TLVList[ PSCR_INF ] == TAG_FREEZE_EVENTS )) + { + break; + } + } + } +} + +WDFSTRING +PscrGetRegistryValue( + _In_ WDFDEVICE Device, + _In_ LPCWSTR Name + ) +/*++ + +Routine Description: + + Get the registry values from the device parameters key. + +Arguments: + + +Return Value: + +--*/ +{ + WDFKEY hKey = NULL; + NTSTATUS status; + UNICODE_STRING valueName; + WDFSTRING string = NULL; + + PAGED_CODE(); + + status = WdfDeviceOpenRegistryKey(Device, + PLUGPLAY_REGKEY_DEVICE, + STANDARD_RIGHTS_ALL, + WDF_NO_OBJECT_ATTRIBUTES, + &hKey); + if (NT_SUCCESS (status)) { + + status = WdfStringCreate( + NULL, + WDF_NO_OBJECT_ATTRIBUTES, + &string + ); + if (NT_SUCCESS (status)) { + RtlInitUnicodeString(&valueName, Name); + + status = WdfRegistryQueryString(hKey, &valueName, string); + if (!NT_SUCCESS (status)) { + WdfObjectDelete(string); + string = NULL; + } + } + + WdfRegistryClose(hKey); + } + + return string; +} + +void +SysDelay( + ULONG Timeout + ) +/*++ + +SysDelay: + performs a required delay. The usage of KeStallExecutionProcessor is + very nasty, but it happends only if SysDelay is called in the context of + our DPC routine (which is only called if a card change was detected). + + For 'normal' IO we have Irql < DISPATCH_LEVEL, so if the reader is polled + while waiting for response we will not block the entire system + +Arguments: + Timeout delay in milli seconds + +Return Value: + void + +--*/ +{ + LARGE_INTEGER SysTimeout; + + if ( KeGetCurrentIrql() >= DISPATCH_LEVEL ) { + ULONG Cnt = 20 * Timeout; + + while ( Cnt-- ) { + // KeStallExecutionProcessor: counted in us + KeStallExecutionProcessor( 50 ); + } + } else { + SysTimeout.QuadPart = (LONGLONG)-10 * 1000 * Timeout; + + // KeDelayExecutionThread: counted in 100 ns + KeDelayExecutionThread( KernelMode, FALSE, &SysTimeout ); + } + return; +} + +PCHAR +GetIoctlName( + ULONG IoControlCode + ) +{ + switch (IoControlCode) { + case IOCTL_SMARTCARD_POWER: return "IOCTL_SMARTCARD_POWER"; + case IOCTL_SMARTCARD_GET_ATTRIBUTE: return "IOCTL_SMARTCARD_GET_ATTRIBUTE"; + case IOCTL_SMARTCARD_SET_ATTRIBUTE: return "IOCTL_SMARTCARD_SET_ATTRIBUTE"; + case IOCTL_SMARTCARD_CONFISCATE: return "IOCTL_SMARTCARD_CONFISCATE"; + case IOCTL_SMARTCARD_TRANSMIT: return "IOCTL_SMARTCARD_TRANSMIT"; + case IOCTL_SMARTCARD_EJECT: return "IOCTL_SMARTCARD_EJECT"; + case IOCTL_SMARTCARD_SWALLOW: return "IOCTL_SMARTCARD_SWALLOW"; + case IOCTL_SMARTCARD_IS_PRESENT: return "IOCTL_SMARTCARD_IS_PRESENT"; + case IOCTL_SMARTCARD_IS_ABSENT: return "IOCTL_SMARTCARD_IS_ABSENT"; + case IOCTL_SMARTCARD_SET_PROTOCOL: return "IOCTL_SMARTCARD_SET_PROTOCOL"; + case IOCTL_SMARTCARD_GET_STATE: return "IOCTL_SMARTCARD_GET_STATE"; + case IOCTL_SMARTCARD_GET_LAST_ERROR: return "IOCTL_SMARTCARD_GET_LAST_ERROR"; + default: return "Unknow_ioctl"; + } +} diff --git a/smartcrd/pscr/pscrnt.h b/smartcrd/pscr/pscrnt.h new file mode 100644 index 00000000..959b9b22 --- /dev/null +++ b/smartcrd/pscr/pscrnt.h @@ -0,0 +1,187 @@ +/*++ + +Copyright (c) 1997 - 1999 SCM Microsystems, Inc. + +Module Name: + + PscrNT.h + +Abstract: + + Driver header - NT Version + +Author: + + Andreas Straub (SCM Microsystems, Inc.) + Klaus Schuetz (Microsoft Corp.) + +Notes: + + The file pscrnt.h was reviewed by LCA in June 2011 and per license is + acceptable for Microsoft use under Dealpoint ID 178449. + +Revision History: + + Andreas Straub 1.00 8/18/1997 Initial Version + Klaus Schuetz 1.01 9/20/1997 Timing changed + Andreas Straub 1.02 9/24/1997 Low Level error handling, + minor bugfixes, clanup + Andreas Straub 1.03 10/8/1997 Timing changed, generic SCM + interface changed + Andreas Straub 1.04 10/18/1997 Interrupt handling changed + Andreas Straub 1.05 10/19/1997 Generic IOCTL's added + Andreas Straub 1.06 10/25/1997 Timeout limit for FW update variable + Andreas Straub 1.07 11/7/1997 Version information added + Andreas Straub 1.08 11/10/1997 Generic IOCTL GET_CONFIGURATION + Klaus Schuetz 1998 PnP and Power Management added + +--*/ + +#if !defined ( __PSCR_NT_DRV_H__ ) +#define __PSCR_NT_DRV_H__ +#define SMARTCARD_POOL_TAG '4SCS' + +#include +#include +#include + +#pragma warning(push) +#pragma warning(disable:4201) +#include "SMCLIB.h" +#pragma warning(pop) + +#include "PscrRdWr.h" + +_Analysis_mode_(_Analysis_code_type_kernel_driver_) + +#if !defined( STATUS_DEVICE_REMOVED ) +#define STATUS_DEVICE_REMOVED STATUS_UNSUCCESSFUL +#endif + +#define SysCompareMemory( p1, p2, Len ) ( RtlCompareMemory( p1,p2, Len ) != Len ) +#define SysCopyMemory( pDest, pSrc, Len ) RtlCopyMemory( pDest, pSrc, Len ) +#define SysFillMemory( pDest, Value, Len ) RtlFillMemory( pDest, Len, Value ) + +#define DELAY_WRITE_PSCR_REG 1 +#define DELAY_PSCR_WAIT 5 + +#define LOBYTE( any ) ((UCHAR)( any & 0xFF ) ) +#define HIBYTE( any ) ((UCHAR)( ( any >> 8) & 0xFF )) + +// +// These macros will store and retrieve the request handle from the IRP. +// We will use the first slot of DriverContext because framework reserves +// the use of 3rd & 4rd slot of DriverContext for its own purpose. +// +#define GET_WDFREQUEST_FROM_IRP(Irp) (WDFREQUEST)Irp->Tail.Overlay.DriverContext[0] +#define SET_REQUEST_IN_IRP(Irp, Request) {Irp->Tail.Overlay.DriverContext[0] = (PVOID)Request;} + +typedef struct _DEVICE_EXTENSION +{ + SMARTCARD_EXTENSION SmartcardExtension; + + WDFDEVICE Device; + + // Out interrupt resource + WDFINTERRUPT Interrupt; + + WDFQUEUE IoctlQueue; + + WDFQUEUE NotificationQueue; + + // Flag that indicates if we need to unmap the port upon stop + BOOLEAN UnMapPort; + + // Number of pending card tracking interrupts + ULONG PendingInterrupts; + + // If the PCMCIA works in PCI mode, check the time between two interrupts + BOOLEAN bSharedIRQ; + LARGE_INTEGER SaveTime; + + ULONG DeviceInstanceNo; +} DEVICE_EXTENSION, *PDEVICE_EXTENSION; + +// +// This macro defines an accessor function which will be used to get the context +// pointer from the device handle. +// +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(DEVICE_EXTENSION, GetDeviceExtension) + +#define IOCTL_PSCR_COMMAND SCARD_CTL_CODE( 0x8000 ) +#define IOCTL_GET_VERSIONS SCARD_CTL_CODE( 0x8001 ) +#define IOCTL_SET_TIMEOUT SCARD_CTL_CODE( 0x8002 ) +#define IOCTL_GET_CONFIGURATION SCARD_CTL_CODE( 0x8003 ) + +typedef struct _VERSION_CONTROL +{ + ULONG SmclibVersion; + UCHAR DriverMajor, + DriverMinor, + FirmwareMajor, + FirmwareMinor, + UpdateKey; +} VERSION_CONTROL, *PVERSION_CONTROL; + +#define SIZEOF_VERSION_CONTROL sizeof( VERSION_CONTROL ) + +typedef struct _PSCR_CONFIGURATION +{ + PPSCR_REGISTERS IOBase; + ULONG IRQ; + +} PSCR_CONFIGURATION, *PPSCR_CONFIGURATION; + +#define SIZEOF_PSCR_CONFIGURATION sizeof( PSCR_CONFIGURATION ) + + +DRIVER_INITIALIZE DriverEntry; + +EVT_WDF_DRIVER_DEVICE_ADD PscrEvtDeviceAdd; + +EVT_WDF_OBJECT_CONTEXT_CLEANUP PscrEvtDeviceContextCleanup; + +EVT_WDF_DEVICE_D0_ENTRY PscrEvtDeviceD0Entry; +EVT_WDF_DEVICE_D0_EXIT PscrEvtDeviceD0Exit; +EVT_WDF_DEVICE_PREPARE_HARDWARE PscrEvtDevicePrepareHardware; + +EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL PscrEvtIoDeviceControl; +EVT_WDF_IO_QUEUE_IO_CANCELED_ON_QUEUE PscrEvtIoCanceledOnQueue; + +EVT_WDF_FILE_CLEANUP PscrEvtFileCleanup; + +EVT_WDF_INTERRUPT_ISR PscrEvtInterruptServiceRoutine; +EVT_WDF_INTERRUPT_DPC PscrEvtInterruptDpc; + +NTSTATUS +PscrGenericIOCTL( + PSMARTCARD_EXTENSION SmartcardExtension + ); + +VOID +PscrFreeze( + PSMARTCARD_EXTENSION SmartcardExtension + ); + +VOID +SysDelay( + ULONG Timeout + ); + +NTSTATUS +PscrRegisterWithSmcLib( + PDEVICE_EXTENSION DeviceExtension + ); + +WDFSTRING +PscrGetRegistryValue( + _In_ WDFDEVICE Device, + _In_ LPCWSTR Name + ); + +PCHAR +GetIoctlName( + ULONG IoControlCode + ); + +#endif // __PSCR_NT_DRV_H__ diff --git a/smartcrd/pscr/pscrrdwr.c b/smartcrd/pscr/pscrrdwr.c new file mode 100644 index 00000000..82ebb03d --- /dev/null +++ b/smartcrd/pscr/pscrrdwr.c @@ -0,0 +1,509 @@ +/*++ + +Copyright (c) 1997 - 1999 SCM Microsystems, Inc. + +Module Name: + + PscrRdWr.c + +Abstract: + + Hardware access functions for SCM PSCR smartcard reader + +Author: + + Andreas Straub + +Environment: + + Win 95 Sys... calls are resolved by Pscr95Wrap.asm functions and + Pscr95Wrap.h macros, resp. + + NT 4.0 Sys... functions resolved by PscrNTWrap.c functions and + PscrNTWrap.h macros, resp. + +Notes: + + The file pscrrdwr.c was reviewed by LCA in June 2011 and per license is + acceptable for Microsoft use under Dealpoint ID 178449. + +Revision History: + + Andreas Straub 7/16/1997 1.00 Initial Version + Klaus Schuetz 9/20/1997 1.01 Timing changed + Andreas Straub 9/24/1997 1.02 Low Level error handling, + minor bugfixes, clanup + +--*/ + +#include +#include +#include + +#pragma optimize( "", off ) +VOID +PscrFlushInterface( PREADER_EXTENSION ReaderExtension ) +/*++ + +PscrFlushInterface: + Read & discard data from the pcmcia interface + +Arguments: + ReaderExtension context of call + +Return Value: + void + +--*/ +{ + UCHAR Status; + ULONG Length; + PPSCR_REGISTERS IOBase; + + IOBase = ReaderExtension->IOBase; + + Status = READ_PORT_UCHAR( &IOBase->CmdStatusReg ); + if (( Status & PSCR_DATA_AVAIL_BIT ) && ( Status & PSCR_FREE_BIT )) { + + // take control over + WRITE_PORT_UCHAR( &IOBase->CmdStatusReg, PSCR_HOST_CONTROL_BIT ); + + // get number of available bytes + Length = ((ULONG)READ_PORT_UCHAR( &IOBase->SizeMSReg )) << 8; + Length |= READ_PORT_UCHAR( &IOBase->SizeLSReg ); + + // perform a dummy read + while ( Length-- ) { + READ_PORT_UCHAR( &IOBase->DataReg ); + } + WRITE_PORT_UCHAR( &IOBase->CmdStatusReg, CLEAR_BIT ); + } + return; +} + + +NTSTATUS +PscrRead( + _In_ PREADER_EXTENSION ReaderExtension, // context of call + _Out_writes_bytes_(DataLen) PUCHAR pData, // ptr to data buffer + _In_ ULONG DataLen, // length of data + _Out_ PULONG pNBytes // number of bytes read + ) +/*++ +PscrRead: + wait until data available & transfer data from reader to host + +Arguments: + ReaderExtension context of call + pData ptr to data buffer + DataLen length of data buffer + pNBytes number of bytes returned + +Return Value: + STATUS_SUCCESS + STATUS_BUFFER_TOO_SMALL + STATUS_UNSUCCESSFUL + +--*/ +{ + NTSTATUS NTStatus = STATUS_UNSUCCESSFUL; + ULONG NBytes = 0; + + NTStatus = PscrReadDirect( + ReaderExtension, + pData, + DataLen, + &NBytes + ); + + if( NTStatus == STATUS_SUCCESS ) + { + // error check + if( pData[ NBytes - 1 ] != + PscrCalculateLRC( pData, (USHORT)( NBytes-1 ))) + { + NTStatus = STATUS_CRC_ERROR; + } + else + { + USHORT ReaderStatus; + // + // Evaluation of reader errors. A reader error is indicated + // if the T1 length is 2 and the Nad indicates that this + // packet came from the reader + // + if( ( ( pData[ PSCR_NAD ] & 0x0F ) == 0x01 ) && + ( pData[ PSCR_LEN ] == 0x02 ) + ) + { + ReaderStatus = (( USHORT ) pData[3] ) << 8; + ReaderStatus |= (( USHORT ) pData[4] ); + + if( ( ReaderStatus != 0x9000 ) && + ( ReaderStatus != 0x9001 ) + ) + { + NBytes = 0; + + if( ReaderStatus == PSCR_SW_PROTOCOL_ERROR ) + { + NTStatus = STATUS_IO_TIMEOUT; + } + else if( ReaderStatus == PSCR_SW_NO_ICC ) + { + NTStatus = STATUS_NO_MEDIA; + } + else + { + NTStatus = STATUS_UNSUCCESSFUL; + } + } + } + + // check freeze data + if( ( NBytes == 9 ) && + ( pData[ PSCR_NAD ] == 0x21 ) && + ( pData[ PSCR_INF ] == TAG_FREEZE_EVENTS )) + { + UCHAR CardState; + + CardState = pData[PSCR_INF + 2] == DEVICE_ICC1 ? + PSCR_ICC_PRESENT : PSCR_ICC_ABSENT; + + if( ( ReaderExtension->CompletionRoutine != NULL ) && + ( ReaderExtension->TrackingContext != NULL )) + { + + // Freeze Data read + ReaderExtension->RequestInterrupt = FALSE; // set in DPC/reset here + + (ReaderExtension->CompletionRoutine)( + ReaderExtension->TrackingContext, + CardState, + FALSE + ); + } + NBytes = 0; + + if( CardState == PSCR_ICC_ABSENT ) + { + NTStatus = STATUS_NO_MEDIA; + } + } + } + } + + // write number of bytes received + *pNBytes = NBytes; + + if( NBytes ) + { + NTStatus = STATUS_SUCCESS; + } + + return ( NTStatus ); +} + + +NTSTATUS +PscrReadDirect( + PREADER_EXTENSION ReaderExtension, + _Out_writes_bytes_(DataLen) PUCHAR pData, + ULONG DataLen, + PULONG pNBytes + ) +/*++ +PscrReadDirect: + wait until data available & transfer data from reader to host + +Arguments: + ReaderExtension context of call + pData ptr to data buffer + DataLen length of data buffer + pNBytes number of bytes returned + +Return Value: + STATUS_SUCCESS + STATUS_BUFFER_TOO_SMALL + STATUS_UNSUCCESSFUL + +--*/ +{ + NTSTATUS NTStatus = STATUS_UNSUCCESSFUL; + PPSCR_REGISTERS IOBase; + USHORT InDataLen; + ULONG Idx; + + IOBase = ReaderExtension->IOBase; + + // wait until interface is ready to transfer + InDataLen = 0; + + if( NT_SUCCESS( NTStatus = PscrWait( ReaderExtension, PSCR_DATA_AVAIL_BIT | PSCR_FREE_BIT ))) + { + + // take control over + + SysDelay( DELAY_PSCR_WAIT ); + WRITE_PORT_UCHAR( &IOBase->CmdStatusReg, PSCR_HOST_CONTROL_BIT ); + SysDelay( DELAY_PSCR_WAIT ); + + // get number of available bytes + InDataLen = ( READ_PORT_UCHAR( &IOBase->SizeMSReg ) << 8 ); + InDataLen |= READ_PORT_UCHAR( &IOBase->SizeLSReg ); + + // check buffer size. if buffer to small, the data will be discarded + if( ( ULONG )InDataLen <= DataLen ) + { + // read data + for (Idx = 0; Idx < InDataLen; Idx++) { + + pData[ Idx ] = READ_PORT_UCHAR( &IOBase->DataReg ); + if(( READ_PORT_UCHAR( &IOBase->CmdStatusReg )) == 0x02 ) + { + Idx++; + break; + } + + } + + if( Idx < ( ULONG )InDataLen ) + { + if(( InDataLen - Idx ) == 1 ) + { + pData[ Idx ] = PscrCalculateLRC( pData, ( USHORT ) Idx ); + } + else + { + InDataLen = 0; + NTStatus = STATUS_UNSUCCESSFUL; + } + } + } + else + { + // flush interface in case of wrong buffer size + do + { + READ_PORT_UCHAR( &IOBase->DataReg ); + } while( --InDataLen ); + NTStatus = STATUS_BUFFER_TOO_SMALL; + } + // clean up + WRITE_PORT_UCHAR( &IOBase->CmdStatusReg, CLEAR_BIT ); + + } + + ReaderExtension->RequestPending = FALSE; + + // write number of bytes received + if( InDataLen ) + { + if( pNBytes != NULL ) + { + ( *pNBytes ) = ( ULONG ) InDataLen; + } + NTStatus = STATUS_SUCCESS; + } + return ( NTStatus ); +} + +NTSTATUS +PscrWrite( + PREADER_EXTENSION ReaderExtension, + PUCHAR pData, + ULONG DataLen, + PULONG pNBytes + ) +/*++ +PscrWrite: + calculates the LRC of the buffer & sends command to the reader + +Arguments: + ReaderExtension context of call + pData ptr to data buffer + DataLen length of data buffer (exclusive LRC!) + pNBytes number of bytes written + +Return Value: + return value of PscrWriteDirect + +--*/ +{ + NTSTATUS NTStatus; + + // Add the EDC field to the end of the data + pData[ DataLen ] = PscrCalculateLRC( pData, ( USHORT ) DataLen ); + + // Send buffer + NTStatus = PscrWriteDirect( + ReaderExtension, + pData, + DataLen + PSCR_EPILOGUE_LENGTH, + pNBytes + ); + + return( NTStatus ); +} + +NTSTATUS +PscrWriteDirect( + PREADER_EXTENSION ReaderExtension, + PUCHAR pData, + ULONG DataLen, + PULONG pNBytes + ) + +/*++ +PscrWriteDirect: + sends command to the reader. The LRC / CRC must be calculated by caller! + +Arguments: + ReaderExtension context of call + pData ptr to data buffer + DataLen length of data buffer (exclusive LRC!) + pNBytes number of bytes written + +Return Value: + STATUS_SUCCESS + STATUS_DEVICE_BUSY + +--*/ +{ + NTSTATUS NTStatus = STATUS_SUCCESS; + UCHAR Status; + PPSCR_REGISTERS IOBase; + + IOBase = ReaderExtension->IOBase; + + // in case of card change, there may be data available + Status = READ_PORT_UCHAR( &IOBase->CmdStatusReg ); + if ( Status & PSCR_DATA_AVAIL_BIT ) { + NTStatus = STATUS_DEVICE_BUSY; + + } else { + // + // wait until reader is ready + // + ReaderExtension->RequestPending = TRUE; + + WRITE_PORT_UCHAR( &IOBase->CmdStatusReg, PSCR_HOST_CONTROL_BIT ); + NTStatus = PscrWait( ReaderExtension, PSCR_FREE_BIT ); + + if ( NT_SUCCESS( NTStatus )) { + ULONG Idx; + + // take control over + WRITE_PORT_UCHAR( &IOBase->CmdStatusReg, PSCR_HOST_CONTROL_BIT ); + + // write the buffer size + WRITE_PORT_UCHAR( &IOBase->SizeMSReg, ( UCHAR )( DataLen >> 8 )); + SysDelay( DELAY_WRITE_PSCR_REG ); + WRITE_PORT_UCHAR( &IOBase->SizeLSReg, ( UCHAR )( DataLen & 0x00FF )); + SysDelay( DELAY_WRITE_PSCR_REG ); + + // write data + for (Idx = 0; Idx < DataLen; Idx++) { + + WRITE_PORT_UCHAR( &IOBase->DataReg, pData[ Idx ] ); + } + + if ( pNBytes != NULL ) { + *pNBytes = DataLen; + } + } + + // clean up + WRITE_PORT_UCHAR( &IOBase->CmdStatusReg, CLEAR_BIT ); + } + + return( NTStatus ); +} + +UCHAR +PscrCalculateLRC( + PUCHAR pData, + USHORT DataLen + ) +/*++ + +PscrCalculateLRC: + calculates the XOR LRC of a buffer. + +Arguments: + pData ptr to data buffer + DataLen length of range + +Return Value: + LRC + +--*/ +{ + UCHAR Lrc; + USHORT Idx; + + // + // Calculate LRC by XORing all the bytes. + // + Lrc = pData[ 0 ]; + for ( Idx = 1 ; Idx < DataLen; Idx++ ) { + Lrc ^= pData[ Idx ]; + } + return( Lrc ); +} + +NTSTATUS +PscrWait( + PREADER_EXTENSION ReaderExtension, + UCHAR Mask + ) +/*++ +PscrWait: + Test the status port of the reader until ALL bits in the mask are set. + The maximum of time until DEVICE_BUSY is returned is approx. + MaxRetries * DELAY_PSCR_WAIT if MaxRetries != 0. + If MaxRetries = 0 the driver waits until the requested status is reported or the + user defines a timeout. + +Arguments: + ReaderExtension context of call + Mask mask of bits to test the status register + +Return Value: + STATUS_SUCCESS + STATUS_DEVICE_BUSY + +--*/ +{ + NTSTATUS NTStatus; + PPSCR_REGISTERS IOBase; + ULONG Retries; + + IOBase = ReaderExtension->IOBase; + NTStatus = STATUS_DEVICE_BUSY; + + // wait until condition fulfilled or specified timeout expired + for ( Retries = 0; Retries < ReaderExtension->MaxRetries; Retries++) { + + if (( (READ_PORT_UCHAR( &IOBase->CmdStatusReg )) == 0x01) && + ReaderExtension->InvalidStatus) { + NTStatus = STATUS_CANCELLED; + break; + } + + // test requested bits + if (( (READ_PORT_UCHAR( &IOBase->CmdStatusReg )) & Mask ) == Mask ) { + NTStatus = STATUS_SUCCESS; + break; + } + SysDelay( DELAY_PSCR_WAIT ); + } + + (void) READ_PORT_UCHAR( &IOBase->CmdStatusReg ); + + return NTStatus; +} + +#pragma optimize( "", on ) + + diff --git a/smartcrd/pscr/pscrrdwr.h b/smartcrd/pscr/pscrrdwr.h new file mode 100644 index 00000000..4a1a2bff --- /dev/null +++ b/smartcrd/pscr/pscrrdwr.h @@ -0,0 +1,366 @@ +/*++ + +Copyright (c) 1997 - 1999 SCM Microsystems, Inc. + +Module Name: + + PscrRdWr.h + +Abstract: + + Constants & access function prototypes for SCM PSCR smartcard reader + +Author: + + Andreas Straub + +Notes: + + The file pscrrdwr.h was reviewed by LCA in June 2011 and per license is + acceptable for Microsoft use under Dealpoint ID 178449. + +Revision History: + + Andreas Straub 7/16/1997 Initial Version + +--*/ + +#if !defined( __PSCR_RDWR_H__ ) +#define __PSCR_RDWR_H__ + +#pragma pack( 1 ) +// +// The usage of the PSCR_REGISTERS struct is a little bit tricky: +// We set the address of that stucture to the IO Base Port, then +// the other reg's can accessed by their address. +// p.E. &PscrRegs = 0x320 --> &PscrRegs->CmdStatusReg = 0x321... +// +typedef struct _PSCR_REGISTERS { + + UCHAR DataReg; + UCHAR CmdStatusReg; + UCHAR SizeLSReg; + UCHAR SizeMSReg; + + } PSCR_REGISTERS, *PPSCR_REGISTERS; + +#define SIZEOF_PSCR_REGISTERS ( sizeof( PSCR_REGISTERS ) + +#pragma pack() + + +typedef enum _READER_POWER_STATE { + PowerReaderUnspecified = 0, + PowerReaderWorking, + PowerReaderOff +} READER_POWER_STATE, *PREADER_POWER_STATE; + +typedef void ( *PTRACKING_COMPLETION )( PVOID TrackingContext, UCHAR Status, BOOLEAN Wakeup ); + +#define MAX_DATARATES 4 + +typedef struct _READER_EXTENSION { + + // I/O address where the reader is configured. + PPSCR_REGISTERS IOBase; + ULONG IOWindow; + ULONG MaxIFSD; + + // IRQ assigned by the system + ULONG CurrentIRQ; + + // + // limit for read timeout. the absolute timeout limit is + // MaxRetries * DELAY_PSCR_WAIT + // + + ULONG MaxRetries; + + // Source/Destination byte always used by the PCMCIA (PC Card) reader. + UCHAR Device; + + // Software revision ID of the SwapSmart firmware. + UCHAR FirmwareMajor, FirmwareMinor, UpdateKey; + + // + // Interrupt status; the flag is raised if an freeze event was detected + // and cleared if the interface was cleared (int service routine or + // PscrRead) + // + BOOLEAN FreezePending; + + // + // Selected file in the reader file system; the flag is raised if the + // ICC1 status file was selected & is cleared if any generic ioctl was + // issued (in this case another file may be selected) + // + BOOLEAN StatusFileSelected; + + // used to cancel a read request + BOOLEAN RequestPending; + // set TRUE if an interrupt is sending, but the reader is busy + BOOLEAN RequestInterrupt; + + BOOLEAN InvalidStatus; + + BOOLEAN CardPresent; + + // Current reader power state. + READER_POWER_STATE ReaderPowerState; + + PTRACKING_COMPLETION CompletionRoutine; + + PVOID TrackingContext; + + ULONG dataRatesSupported[MAX_DATARATES]; + +} READER_EXTENSION, *PREADER_EXTENSION; + +#define SIZEOF_READER_EXTENSION ( sizeof( READER_EXTENSION )) + +// +// Constants ----------------------------------------------------------------- +// +#define PSCR_ID_STRING "SCM SwapSmart 2." + +#define TLV_BUFFER_SIZE 0x20 +#define ATR_SIZE 0x40 // TS + 32 + SW + PROLOGUE + EPILOGUE... + +#define PSCR_MAX_RETRIES 1000 + +#define CLEAR_BIT 0x00 + +#define DEFAULT_WAIT_TIME 0x01 + +#define PSCR_PROLOGUE_LENGTH 0x03 +#define PSCR_EXT_PROLOGUE_LENGTH 0x05 +#define PSCR_STATUS_LENGTH 0x02 + +#define PSCR_LRC_LENGTH 0x01 +#define PSCR_CRC_LENGTH 0x02 + +#define PSCR_EPILOGUE_LENGTH PSCR_LRC_LENGTH + +#define PCB_DEFAULT 0x00 + +#define MAX_T1_BLOCK_SIZE 270 +// +// data buffer idx +// +#define PSCR_NAD 0x00 +#define PSCR_PCB 0x01 +#define PSCR_LEN 0x02 +#define PSCR_INF 0x03 +#define PSCR_APDU PSCR_INF +// +// device identifier for reset, deactivate +// +#define DEVICE_READER 0x00 +#define DEVICE_ICC1 0x01 +#define DEVICE_ICC2 0x02 +// +// NAD's +// +#define NAD_TO_ICC1 0x02 +#define NAD_TO_ICC2 0x42 +#define NAD_TO_PSCR 0x12 +#define REMOTE_NAD_TO_ICC1 0x03 +#define REMOTE_NAD_TO_ICC2 0x43 +#define REMOTE_NAD_TO_PSCR 0x13 +// +// PSCR Commands +// +#define CLA_SET_INTERFACE_PARAM 0x80 +#define CLA_FREEZE 0x80 +#define CLA_RESET 0x20 +#define CLA_DEACTIVATE 0x20 +#define CLA_SELECT_FILE 0x00 +#define CLA_READ_BINARY 0x00 +#define CLA_WRITE_BINARY 0x00 +#define CLA_VERIFY 0x00 +#define CLA_WARM_RESET 0x20 +#define CLA_SOFTWARE_UPDATE 0x80 +#define CLA_SET_MODE 0x80 + +#define INS_SET_INTERFACE_PARAM 0x60 +#define INS_FREEZE 0x70 +#define INS_RESET 0x10 +#define INS_DEACTIVATE 0x14 +#define INS_SELECT_FILE 0xA4 +#define INS_READ_BINARY 0xB0 +#define INS_WRITE_BINARY 0xD0 +#define INS_VERIFY 0x20 +#define INS_WARM_RESET 0x1F +#define INS_SOFTWARE_UPDATE 0xFF +#define INS_SET_MODE 0x61 + +// +// Status Read Only Register +// +#define PSCR_DATA_AVAIL_BIT 0x80 +#define PSCR_FREE_BIT 0x40 +#define PSCR_WRITE_ERROR_BIT 0x02 +#define PSCR_READ_ERROR_BIT 0x01 +// +// Command Write Only Register... +// +#define PSCR_RESET_BIT 0x08 +#define PSCR_SIZE_READ_BIT 0x04 +#define PSCR_SIZE_WRITE_BIT 0x02 +#define PSCR_HOST_CONTROL_BIT 0x01 +// +// Tags... +// +#define TAG_MODULE 0x02 +#define TAG_MEMORY_SIZE 0x03 +#define TAG_UPDATE_KEY 0x08 +#define TAG_SOFTWARE_REV 0x0F +#define TAG_BLOCK_COMP_OPTION 0x13 +#define TAG_READER_MECH_OPTIONS 0x20 +#define TAG_READER_STATUS 0x21 +#define TAG_ICC_PROTOCOLS 0x22 +#define TAG_BI 0x23 +#define TAG_FI 0x24 +#define TAG_PTS_PARAM 0x25 +#define TAG_PROTOCOL_STATUS 0x26 +#define TAG_SET_NULL_BYTES 0x2d +#define TAG_FREEZE_EVENTS 0x30 +#define TAG_BIT_LENGTH 0x40 +#define TAG_CGT 0x41 +#define TAG_BWT 0x42 +#define TAG_CWT 0x43 +#define TAG_PROTOCOL_PARAM 0x44 +// +// card power definitions ( Tag 0x21 ) +// +#define PSCR_ICC_ABSENT 0x00 +#define PSCR_ICC_PRESENT 0x01 +#define PSCR_ICC_POWERED 0x02 +#define PSCR_ICC_IN_TRANSP_MODE 0xA0 +#define PSCR_ICC_UNKNOWN 0xFF +// +// protocol definitions ( Tag 0x22 ) +// +#define PSCR_PROTOCOL_UNDEFINED 0x00 +#define PSCR_PROTOCOL_T0 0x01 +#define PSCR_PROTOCOL_T1 0x02 +#define PSCR_PROTOCOL_T14 0x03 +#define PSCR_PROTOCOL_I2C 0x80 +#define PSCR_PROTOCOL_3WIRE 0x81 +#define PSCR_PROTOCOL_2WIRE 0x81 + +#define WTX_REQUEST 0xC3 +#define WTX_REPLY 0xE3 +// +// File ID's +// +#define FILE_MASTER 0x3F00 +#define FILE_PSCR_CONFIG 0x0020 +#define FILE_PSCR_DIR 0x7F60 +#define FILE_PSCR_DIR_CONFIG 0x6020 +#define FILE_PSCR_DIR_STATUS 0x6021 +#define FILE_PSCR_DIR_FREEZE_CONFIG 0x6030 +#define FILE_PSCR_DIR_FREEZE_STATUS 0x6031 +#define FILE_ICC1_DIR 0x7F70 +#define FILE_ICC1_DIR_CONFIG 0x7020 +#define FILE_ICC1_DIR_STATUS 0x7021 +#define FILE_ICC2_DIR_CONFIG 0x7120 +#define FILE_ICC2_DIR_STATUS 0x7121 +// +// Status Word Definitions +// +#define PSCR_SW_COMMAND_FAIL 0x6985 +#define PSCR_SW_INVALID_PARAM 0x6A80 +#define PSCR_SW_INCONSISTENT_DATA 0x6A85 +#define PSCR_SW_NO_PROTOCOL_SUPPORT 0x62A3 +#define PSCR_SW_SYNC_ATR_SUCCESS 0x9000 +#define PSCR_SW_ASYNC_ATR_SUCCESS 0x9001 +#define PSCR_SW_NO_PROTOCOL 0x62A5 +#define PSCR_SW_NO_ATR 0x62A6 +#define PSCR_SW_NO_ATR_OR_PROTOCOL 0x62A7 +#define PSCR_SW_NO_ICC 0x64A1 +#define PSCR_SW_ICC_NOT_ACTIVE 0x64A2 +#define PSCR_SW_NON_SUPPORTED_PROTOCOL 0x64A3 +#define PSCR_SW_PROTOCOL_ERROR 0x64A8 +#define PSCR_SW_NO_ATR_OR_PROTOCOL2 0x64A7 +#define PSCR_SW_FILE_NOT_FOUND 0x6A82 +#define PSCR_SW_FILE_NO_ACCEPPTED_AUTH 0x6982 +#define PSCR_SW_FILE_NO_ACCESS 0x6985 +#define PSCR_SW_FILE_BAD_OFFSET 0x6B00 +#define PSCR_SW_END_OF_FILE_READ 0x6282 +#define PSCR_SW_END_OF_FILE_WRITE 0x6301 +#define PSCR_SW_WRITE_FILE_FAIL 0x6500 +#define PSCR_SW_NO_PASSWORD 0x6200 +#define PSCR_SW_WRONG_PASSWORD 0x6300 +#define PSCR_SW_VERIFY_COUNTER_FAIL 0x6983 +#define PSCR_SW_NO_REF_DATA 0x6A88 +#define PSCR_SW_FLASH_MEM_ERROR 0x6481 +#define PSCR_SW_FLASH_MEM_ERR2 0x6581 +#define PSCR_SW_WRONG_LENGTH 0x6700 +#define PSCR_SW_UNKNOWN_ICC_ERROR 0x64A0 +#define PSCR_SW_UNKNOWN_PROTOCOL_ERROR 0x64A9 +#define PSCR_SW_NO_PROTOCOL_SELECTED 0x64A5 +#define PSCR_SW_PTS_PROTOCOL_ERROR 0x64AA +#define PSCR_SW_WTX_ERROR 0x64AB +#define PSCR_SW_WTX_ERR2 0x65AB +#define PSCR_SW_INVALID_SOURCE_ADDR 0x6F82 + +// +// Prototypes for access functions ------------------------------------------- +// + + +VOID +PscrFlushInterface( + PREADER_EXTENSION ReaderExtension // context of call + ); + +NTSTATUS +PscrRead( + _In_ PREADER_EXTENSION ReaderExtension, // context of call + _Out_writes_bytes_(DataLen) PUCHAR pData, // ptr to data buffer + _In_ ULONG DataLen, // length of data + _Out_ PULONG pNBytes // number of bytes read + ); + +NTSTATUS +PscrReadDirect( + PREADER_EXTENSION ReaderExtension, // context of call + _Out_writes_bytes_(DataLen) PUCHAR pData, // ptr to data buffer + ULONG DataLen, // length of data + PULONG pNBytes // number of bytes read + ); + +NTSTATUS +PscrWrite( + PREADER_EXTENSION ReaderExtension, // context of call + PUCHAR pData, // ptr to data buffer + ULONG DataLength, // length of data + PULONG pNBytes // number of bytes written + ); + +NTSTATUS +PscrWriteDirect( + PREADER_EXTENSION ReaderExtension, // context of call + PUCHAR pData, // ptr to data buffer + ULONG DataLength, // length of data + PULONG pNBytes // number of bytes written + ); + +UCHAR +PscrCalculateLRC( + PUCHAR pData, // ptr to data buffer + USHORT DataLength // length of data + ); + +NTSTATUS +PscrWait( + PREADER_EXTENSION ReaderExtension, // context of call + UCHAR Mask // mask of requested bits + ); + +#endif // __PSCR_RDWR_H__ + +// ------------------------------- END OF FILE ------------------------------- + + diff --git a/smartcrd/pscr/pscrvers.h b/smartcrd/pscr/pscrvers.h new file mode 100644 index 00000000..0ee8b0a8 --- /dev/null +++ b/smartcrd/pscr/pscrvers.h @@ -0,0 +1,43 @@ +/*++ + +Copyright (c) 1997 - 1999 SCM Microsystems, Inc. + +Module Name: + + PscrVers.h + +Abstract: + + header file for version information + +Author: + + Andreas Straub + +Environment: + + Win 95, Win NT + +Notes: + + The file pscrvers.h was reviewed by LCA in June 2011 and per license is + acceptable for Microsoft use under Dealpoint ID 178449. + +Revision History: + +--*/ +#if !defined( __PSCRVERS_H__ ) +#define __PSCRVERS_H__ + +#define PSCR_VERSION_STR "1.26" +#define PSCR_MAJOR_VERSION 1 +#define PSCR_MINOR_VERSION 26 + +#define PSCR_NAME "PSCR" +#define PSCR_PRODUCT_NAME "PSCR SmartCard Reader" +#define PSCR_VENDOR_NAME "PSCR" +#define PSCR_IFD_TYPE "PCMCIA Reader" +#define PSCR_VXD_NAME "PSCR.VXD" +#define PSCR_DEVICE_NAME "PSCR_0" + +#endif // __PSCRVERS_H__ diff --git a/smartcrd/smartcrd.sln b/smartcrd/smartcrd.sln new file mode 100644 index 00000000..c0f3b05e --- /dev/null +++ b/smartcrd/smartcrd.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0 +MinimumVisualStudioVersion = 12.0 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Pscr", "pscr\Pscr.vcxproj", "{E963C756-D675-4202-A229-6B3ADB94B252}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E963C756-D675-4202-A229-6B3ADB94B252}.Debug|Win32.ActiveCfg = Debug|Win32 + {E963C756-D675-4202-A229-6B3ADB94B252}.Debug|Win32.Build.0 = Debug|Win32 + {E963C756-D675-4202-A229-6B3ADB94B252}.Release|Win32.ActiveCfg = Release|Win32 + {E963C756-D675-4202-A229-6B3ADB94B252}.Release|Win32.Build.0 = Release|Win32 + {E963C756-D675-4202-A229-6B3ADB94B252}.Debug|x64.ActiveCfg = Debug|x64 + {E963C756-D675-4202-A229-6B3ADB94B252}.Debug|x64.Build.0 = Debug|x64 + {E963C756-D675-4202-A229-6B3ADB94B252}.Release|x64.ActiveCfg = Release|x64 + {E963C756-D675-4202-A229-6B3ADB94B252}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/spb/SkeletonI2C/SkeletonI2C.sln b/spb/SkeletonI2C/SkeletonI2C.sln index 308053bb..17f4527d 100644 --- a/spb/SkeletonI2C/SkeletonI2C.sln +++ b/spb/SkeletonI2C/SkeletonI2C.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "skeletoni2c", "skeletoni2c.vcxproj", "{B890FE48-579C-41BF-9D89-064D4C8291D3}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "skeletoni2c", "skeletoni2c.vcxproj", "{77250DF0-F449-4C59-9081-B87E6D14E311}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +13,14 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {B890FE48-579C-41BF-9D89-064D4C8291D3}.Debug|Win32.ActiveCfg = Debug|Win32 - {B890FE48-579C-41BF-9D89-064D4C8291D3}.Debug|Win32.Build.0 = Debug|Win32 - {B890FE48-579C-41BF-9D89-064D4C8291D3}.Release|Win32.ActiveCfg = Release|Win32 - {B890FE48-579C-41BF-9D89-064D4C8291D3}.Release|Win32.Build.0 = Release|Win32 - {B890FE48-579C-41BF-9D89-064D4C8291D3}.Debug|x64.ActiveCfg = Debug|x64 - {B890FE48-579C-41BF-9D89-064D4C8291D3}.Debug|x64.Build.0 = Debug|x64 - {B890FE48-579C-41BF-9D89-064D4C8291D3}.Release|x64.ActiveCfg = Release|x64 - {B890FE48-579C-41BF-9D89-064D4C8291D3}.Release|x64.Build.0 = Release|x64 + {77250DF0-F449-4C59-9081-B87E6D14E311}.Debug|Win32.ActiveCfg = Debug|Win32 + {77250DF0-F449-4C59-9081-B87E6D14E311}.Debug|Win32.Build.0 = Debug|Win32 + {77250DF0-F449-4C59-9081-B87E6D14E311}.Release|Win32.ActiveCfg = Release|Win32 + {77250DF0-F449-4C59-9081-B87E6D14E311}.Release|Win32.Build.0 = Release|Win32 + {77250DF0-F449-4C59-9081-B87E6D14E311}.Debug|x64.ActiveCfg = Debug|x64 + {77250DF0-F449-4C59-9081-B87E6D14E311}.Debug|x64.Build.0 = Debug|x64 + {77250DF0-F449-4C59-9081-B87E6D14E311}.Release|x64.ActiveCfg = Release|x64 + {77250DF0-F449-4C59-9081-B87E6D14E311}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/spb/SkeletonI2C/device.cpp b/spb/SkeletonI2C/device.cpp index 5666465f..7b6747e2 100644 --- a/spb/SkeletonI2C/device.cpp +++ b/spb/SkeletonI2C/device.cpp @@ -84,10 +84,10 @@ OnPrepareHardware( if (res->Type == CmResourceTypeMemory) { pDevice->pRegisters = - (PSKELETONI2C_REGISTERS) MmMapIoSpace( + (PSKELETONI2C_REGISTERS) MmMapIoSpaceEx( res->u.Memory.Start, res->u.Memory.Length, - MmNonCached); + PAGE_NOCACHE | PAGE_READWRITE); pDevice->RegistersCb = res->u.Memory.Length; diff --git a/spb/SkeletonI2C/skeletoni2c.vcxproj b/spb/SkeletonI2C/skeletoni2c.vcxproj index e8f46d2d..6bdda24b 100644 --- a/spb/SkeletonI2C/skeletoni2c.vcxproj +++ b/spb/SkeletonI2C/skeletoni2c.vcxproj @@ -19,12 +19,12 @@
- {B890FE48-579C-41BF-9D89-064D4C8291D3} + {77250DF0-F449-4C59-9081-B87E6D14E311} $(MSBuildProjectName) 1 Debug Win32 - {B140B15C-7C0A-4E6F-B705-355E8491EFD1} + {B0247A4A-90C2-48D8-AC68-F6265E298B6B} diff --git a/spb/SkeletonI2C/skeletoni2c.vcxproj.Filters b/spb/SkeletonI2C/skeletoni2c.vcxproj.Filters index cadb17b1..5833a276 100644 --- a/spb/SkeletonI2C/skeletoni2c.vcxproj.Filters +++ b/spb/SkeletonI2C/skeletoni2c.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {37426773-F628-425E-981B-E4265FDB33F9} + {8A872C5C-6393-442C-B35C-2ED1A0D0B371} h;hpp;hxx;hm;inl;inc;xsd - {C7EFBD4E-0814-4137-BC2F-E62AEC040D23} + {248FB7FE-BE5E-4C18-8D1E-F9E61E52E9F9} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {C68A1A41-6F14-4755-9338-C517FFC56AC6} + {03825A97-CBC2-4083-ABEE-A7048E343989} inf;inv;inx;mof;mc; - {9455FD0C-B897-4788-A02B-5CE9F02EEE04} + {C23BD71F-B503-41AF-A8FF-9282357B5CAF} diff --git a/spb/SpbTestTool/SpbTestTool.htm b/spb/SpbTestTool/SpbTestTool.htm new file mode 100644 index 00000000..5cab8aaa --- /dev/null +++ b/spb/SpbTestTool/SpbTestTool.htm @@ -0,0 +1,2688 @@ + + + + + + + + + + + + + + + + + + +
+ +

SpbTestTool

+ +

Summary

+ +

The SpbTestTool sample serves two purposes.  One, it demonstrates how to open a handle to +the SPB controller, use the SPB interface from a KMDF driver, and employ GPIO +passive-level interrupts.  Two, it allows +for communication with a peripheral using SPB commands to aide in debugging.

+ +

This sample is incomplete as a driver and merely +demonstrates use of the SPB API and GPIO interrupts.  It is not intended for use in a production +environment.

+ +

Building the Sample

+ +

Peripheral driver

+ +

1.       +Navigate to src\SPB\SpbTestTool\sys and launch +the vcxproj file

+ +

2.       +Modify SpbTestTool.inx

+ +

a.       +Replace ACPI\SpbTestTool with appropriate +peripheral HWID

+ +

b.      +Set the “ConnectInterrupt registery” setting to +1 to connect the first interrupt resource found, otherwise leave at 0 to leave +disconnected.  See SpbTestTool_AddReg +section.

+ +

3.       +Build the project in Visual Studio

+ +

a.       +Produces SpbTestTool.inf and SpbTestTool.sys

+ +

Application

+ +

1.       +Navigate to src\SPB\SpbTestTool\exe and launch +the vcxproj file

+ +

2.       +Build the project in Visual Studio

+ +

a.       +Produces SpbTestTool.exe

+ +

Installation

+ +

To install the SpbTestTool driver:

+ +

1.       +Ensure that the driver builds without errors

+ +

2.       +Copy the SYS and INF files to a separate folder

+ +

3.       +Run devcon.exe.  You can find this program in the tools\devcon +folder where you installed the WDK.  Type +the following command in the command window.

+ +

a.       +devcon.exe +update SpbTestTool.inf ACPI\<hwid>

+ +

Code Tour

+ +

The following are relevant functions in the SpbTestTool +peripheral for using the SPB interface from a KMDF driver.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Function

+
+

Description

+
+

OnPrepareHardware

+
+

Traverses the driver’s start resources and caches + the connection ID of the I2C or SPI resource.  + This ID will be used to open the SPB controller later on.

+
+

SpbPeripheralOpen

+
+

Opens a handle to the underlying SPB controller via + the resource hub.  This allows the + peripheral driver to be developed without any underlying knowledge of the + platform or hardware connections.  + Instead, the dependency between controller and peripheral is described + in ACPI.

+
+

SpbPeripheralClose

+
+

Closes the handle to the SPB controller.

+
+

SpbPeripheralLock

+
+

Sends IOCTL_SPB_LOCK_CONTROLLER to the SPB + controller to lock the bus for exclusive access by this peripheral.

+
+

SpbPeripheralUnlock

+
+

Sends IOCTL_SPB_UNLOCK_CONTROLLER to the SPB + controller to unlock the bus from exclusive access by this peripheral.

+
+

SpbPeripheralLockConnection

+
+

Sends IOCTL_SPB_LOCK_CONNECTION to the SPB + controller to lock the shared connection for exclusive access by this target + (file handle).

+
+

SpbPeripheralUnlockConnection

+
+

Sends IOCTL_SPB_UNLOCK_CONNECTION to the SPB + controller to unlock the shared connection from exclusive access by this + target (file handle).

+
+

SpbPeripheralRead

+
+

Sends a read request to the SPB controller.

+
+

SpbPeripheralWrite

+
+

Sends a write request to the SPB controller.

+
+

SpbPeripheralWriteRead

+
+

Builds a write-read sequence and sends + IOCTL_SPB_EXECUTE_SEQUENCE to the SPB controller.

+
+

SpbPeripheralFullDuplex

+
+

Builds a full duplex IO and sends + IOCTL_SPB_FULL_DUPLEX to the SPB controller.

+
+

SpbPeripheralOnComplete

+
+

Completion callback for all IO.

+
+ +

 

+ +

The following are relevant functions in the SpbTestTool +peripheral for managing GPIO passive-level interrupts from a KMDF driver.

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Function

+
+

Description

+
+

OnPrepareHardware

+
+

Traverses the driver’s start resources. If + “ConnectInterrupt” is set to 1 in the registry, the driver connects the first + interrupt resource found and registers an interrupt service routine.

+
+

OnInterruptIsr

+
+

The interrupt service routine, which has been configured + to run at passive-level.  Doing so + enables the driver to acknowledge or quiesce the interrupt using the SPB interface, which cannot be + called at DIRQL.

+

 

+

Typically a driver will clear the hardware + interrupt and save any volatile information in its ISR, and then it will + queue a workitem to continue processing.  + Our sample driver instead notifies the SpbTestTool app that an + interrupt has occurred and calls KeWaitForSingleObject to wait until the + interrupt is handled before returning. A ‘real’ driver should never stall in + the ISR like this.

+
+

SpbPeripheralWaitOnInterrupt

+
+

Called to pend a WaitOnInterrupt request in the + driver, which will be completed when the next interrupt occurs.

+
+

SpbPeripheralInterruptNotify

+
+

Completes an outstanding WaitOnInterrupt request to + inform the SpbTestTool app that an interrupt has occurred.

+
+

SpbPeripheralSignalInterrupt

+
+

Notifies the interrupt service routine that the + interrupt has been handled and the ISR should return.

+
+ +

Application Walkthrough

+ +

Launching the app

+ +

To launch the SpbTestTool application:

+ +

1.       +Navigate to the directory with SpbTestTool.exe

+ +

2.       +Type the following command in the command +window:

+ +

a.       +SpbTestTool.exe

+ +

3.       +An alternate peripheral driver path can also be +used.  Note, this driver must implement +the private SpbTestTool interface

+ +

a.       +SpbTestTool.exe +/p \\.\<alternate_path>

+ +

4.       +An input script can used instead of an +interactive prompt.  The format is one +command per line.  See below for +commands.

+ +

a.       +SpbTestTool.exe +/i <script.txt>

+ +

Executing commands

+ +

The application will loop indefinitely waiting for one of +the following commands.  The commands are +translated to the appropriate SPB API action without any state tracking in the +driver.  Transfer status, buffers, and +error codes are returned as necessary.  +Type ‘help’ at any time to display this list.  Press Ctrl-C at any time to cancel the +current command and exit the application.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Command

+
+

Description

+
+

open

+
+

Open handle to SPB controller

+
+

close

+
+

Close handle to SPB controller

+
+

lock

+
+

Lock the bus for exclusive access

+
+

unlock

+
+

Unlock the bus

+
+

lockconn

+
+

Lock the shared connection for exclusive access. + This primitive is used to synchronize with op-region accesses by firmware.

+
+

unlockconn

+
+

Unlock the shared connection

+
+

write {}

+
+

Write byte array to peripherl

+

  > write + {01, 02, 03}

+
+

read <numBytes>

+
+

Read <numBytes> from peripheral

+

  > read 5

+
+

writeread {} <numBytes>

+
+

Atomically write byte array to peripheral and read + <numBytes> back

+

  > + writeread {01, 02, 03} 5

+
+

fullduplex {} <numBytes>

+
+

Simultaneously write byte array to peripheral and + read <numBytes> back

+

  > full + duplex {01, 02, 03} 5

+
+

signal

+
+

Inform the SpbTestTool driver that the interrupt has + been handled

+
+

help

+
+

Display the list of supported commands

+
+

Ctrl-C

+
+

Press Ctrl-C at any time to cancel the outstanding + command and exit the application.

+
+ +

File Manifest

+ +

Peripheral driver (spbtesttool.sys)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

File

+
+

Description

+
+

driver.h, driver.cpp

+
+

DriverEntry and Events on the Driver Object.

+
+

device.h, device.cpp

+
+

Events on the Device Object, and read, write, and + IOCTLs from the SpbTestTool application. Implements the driver’s interrupt + service routine.

+
+

internal.h

+
+

Common includes and typedefs

+
+

makefile

+
+

Redirects to the real makefile that is shared  by all components of the WDK

+
+

makefile.inc

+
+

Defines custom build actions.  Includes the conversion of the .INX file + into a .INF file

+
+

peripheral.h, peripheral.cpp

+
+

Reflection of the SpbTestTool IOCTLs to the SPB + API, including opening the controller via the resource hub and using lock, + unlock, read, write, and sequence

+
+

resource.rc

+
+

Resource descriptor file used for versioning

+
+

sources

+
+

Lists source files and build options

+
+

sources.dep

+
+

Defines build dependencies

+
+

spbtesttool.asl

+
+

Sample ASL file for a peripheral device node. It declares + I2C and GPIO interrupt resources. Note each macro specifies an ACPI path to + describe direct dependencies.

+
+

spbtesttool.h

+
+

Private SpbTestTool IOCTLs for use between the + application and peripheral driver, and driver path names

+
+

spbtesttool.inx

+
+

Describes the installation of the driver.  The build process converts this into a .INF

+
+

trace.h

+
+

Sets up WPP tracing

+
+ +

Application (spbtesttool.exe)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

File

+
+

Description

+
+

command.h, command.cpp

+
+

Classes respresenting each of the SpbTestTool + commands.  See Executing commands above

+
+

internal.h

+
+

Common includes and function definitions

+
+

main.cpp

+
+

Application entry point, input parsing, and main + execution loop. Also contains the interrupt notification thread.

+
+

makefile

+
+

Redirects to the real makefile that is shared by + all components of the WDK

+
+

sources

+
+

Lists source files and build options

+
+

util.cpp

+
+

Helper functions

+
+ +

 

+ +

Copyright © Microsoft Corporation.  All Rights Reserved.

+ +
+ + + + diff --git a/spb/SpbTestTool/SpbTestTool.sln b/spb/SpbTestTool/SpbTestTool.sln index a2403ff8..78093615 100644 --- a/spb/SpbTestTool/SpbTestTool.sln +++ b/spb/SpbTestTool/SpbTestTool.sln @@ -3,13 +3,13 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Exe", "Exe", "{4A32006C-4D25-4879-A039-E17F5CBCC8E6}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Exe", "Exe", "{F3AE97B3-4892-4B4F-BC6A-2BD54D73E455}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Sys", "Sys", "{82E8C888-5416-4EBA-A956-D127B2464614}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Sys", "Sys", "{13A0DE9D-F4EC-442A-97A5-246D5F2012B4}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SpbTestTool", "exe\SpbTestTool.vcxproj", "{9FC1A48C-5079-4B38-9775-C7623687EF41}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SpbTestTool", "exe\SpbTestTool.vcxproj", "{57CB2DD4-0C4A-42B2-AF1C-CA8D0BB7CF88}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SpbTestTool", "sys\SpbTestTool.vcxproj", "{F7BF1596-9FD8-40AC-8F50-0B3E40DD2E1A}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SpbTestTool", "sys\SpbTestTool.vcxproj", "{9164F300-DAA4-40F6-B7CA-8523CC819138}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -19,28 +19,28 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {9FC1A48C-5079-4B38-9775-C7623687EF41}.Debug|Win32.ActiveCfg = Debug|Win32 - {9FC1A48C-5079-4B38-9775-C7623687EF41}.Debug|Win32.Build.0 = Debug|Win32 - {9FC1A48C-5079-4B38-9775-C7623687EF41}.Release|Win32.ActiveCfg = Release|Win32 - {9FC1A48C-5079-4B38-9775-C7623687EF41}.Release|Win32.Build.0 = Release|Win32 - {9FC1A48C-5079-4B38-9775-C7623687EF41}.Debug|x64.ActiveCfg = Debug|x64 - {9FC1A48C-5079-4B38-9775-C7623687EF41}.Debug|x64.Build.0 = Debug|x64 - {9FC1A48C-5079-4B38-9775-C7623687EF41}.Release|x64.ActiveCfg = Release|x64 - {9FC1A48C-5079-4B38-9775-C7623687EF41}.Release|x64.Build.0 = Release|x64 - {F7BF1596-9FD8-40AC-8F50-0B3E40DD2E1A}.Debug|Win32.ActiveCfg = Debug|Win32 - {F7BF1596-9FD8-40AC-8F50-0B3E40DD2E1A}.Debug|Win32.Build.0 = Debug|Win32 - {F7BF1596-9FD8-40AC-8F50-0B3E40DD2E1A}.Release|Win32.ActiveCfg = Release|Win32 - {F7BF1596-9FD8-40AC-8F50-0B3E40DD2E1A}.Release|Win32.Build.0 = Release|Win32 - {F7BF1596-9FD8-40AC-8F50-0B3E40DD2E1A}.Debug|x64.ActiveCfg = Debug|x64 - {F7BF1596-9FD8-40AC-8F50-0B3E40DD2E1A}.Debug|x64.Build.0 = Debug|x64 - {F7BF1596-9FD8-40AC-8F50-0B3E40DD2E1A}.Release|x64.ActiveCfg = Release|x64 - {F7BF1596-9FD8-40AC-8F50-0B3E40DD2E1A}.Release|x64.Build.0 = Release|x64 + {57CB2DD4-0C4A-42B2-AF1C-CA8D0BB7CF88}.Debug|Win32.ActiveCfg = Debug|Win32 + {57CB2DD4-0C4A-42B2-AF1C-CA8D0BB7CF88}.Debug|Win32.Build.0 = Debug|Win32 + {57CB2DD4-0C4A-42B2-AF1C-CA8D0BB7CF88}.Release|Win32.ActiveCfg = Release|Win32 + {57CB2DD4-0C4A-42B2-AF1C-CA8D0BB7CF88}.Release|Win32.Build.0 = Release|Win32 + {57CB2DD4-0C4A-42B2-AF1C-CA8D0BB7CF88}.Debug|x64.ActiveCfg = Debug|x64 + {57CB2DD4-0C4A-42B2-AF1C-CA8D0BB7CF88}.Debug|x64.Build.0 = Debug|x64 + {57CB2DD4-0C4A-42B2-AF1C-CA8D0BB7CF88}.Release|x64.ActiveCfg = Release|x64 + {57CB2DD4-0C4A-42B2-AF1C-CA8D0BB7CF88}.Release|x64.Build.0 = Release|x64 + {9164F300-DAA4-40F6-B7CA-8523CC819138}.Debug|Win32.ActiveCfg = Debug|Win32 + {9164F300-DAA4-40F6-B7CA-8523CC819138}.Debug|Win32.Build.0 = Debug|Win32 + {9164F300-DAA4-40F6-B7CA-8523CC819138}.Release|Win32.ActiveCfg = Release|Win32 + {9164F300-DAA4-40F6-B7CA-8523CC819138}.Release|Win32.Build.0 = Release|Win32 + {9164F300-DAA4-40F6-B7CA-8523CC819138}.Debug|x64.ActiveCfg = Debug|x64 + {9164F300-DAA4-40F6-B7CA-8523CC819138}.Debug|x64.Build.0 = Debug|x64 + {9164F300-DAA4-40F6-B7CA-8523CC819138}.Release|x64.ActiveCfg = Release|x64 + {9164F300-DAA4-40F6-B7CA-8523CC819138}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {9FC1A48C-5079-4B38-9775-C7623687EF41} = {4A32006C-4D25-4879-A039-E17F5CBCC8E6} - {F7BF1596-9FD8-40AC-8F50-0B3E40DD2E1A} = {82E8C888-5416-4EBA-A956-D127B2464614} + {57CB2DD4-0C4A-42B2-AF1C-CA8D0BB7CF88} = {F3AE97B3-4892-4B4F-BC6A-2BD54D73E455} + {9164F300-DAA4-40F6-B7CA-8523CC819138} = {13A0DE9D-F4EC-442A-97A5-246D5F2012B4} EndGlobalSection EndGlobal diff --git a/spb/SpbTestTool/exe/SpbTestTool.vcxproj b/spb/SpbTestTool/exe/SpbTestTool.vcxproj index 89c45a63..aade66fc 100644 --- a/spb/SpbTestTool/exe/SpbTestTool.vcxproj +++ b/spb/SpbTestTool/exe/SpbTestTool.vcxproj @@ -19,11 +19,11 @@
- {9FC1A48C-5079-4B38-9775-C7623687EF41} + {57CB2DD4-0C4A-42B2-AF1C-CA8D0BB7CF88} $(MSBuildProjectName) Debug Win32 - {624E577D-6233-4F5C-A2DB-76C73310E478} + {1F37BEE4-37DF-4FFF-AE29-19EB3043B696} diff --git a/spb/SpbTestTool/exe/SpbTestTool.vcxproj.Filters b/spb/SpbTestTool/exe/SpbTestTool.vcxproj.Filters index 2f7455d1..3247ab25 100644 --- a/spb/SpbTestTool/exe/SpbTestTool.vcxproj.Filters +++ b/spb/SpbTestTool/exe/SpbTestTool.vcxproj.Filters @@ -3,15 +3,15 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {4EE46FAD-BE22-4954-BF04-9F8262309790} + {2FB2155E-8ED8-434F-9145-27D7AF8E91AA} h;hpp;hxx;hm;inl;inc;xsd - {6BFD6FCC-FA62-42A5-9060-D9F8D0E56AEB} + {C8220CFA-6854-4211-A434-EB211E4F307F} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {6EE9FC61-6E28-4E6C-AAFC-00F9DF2F34EB} + {FB1A6735-E65A-45FB-886E-F357664D28C3} diff --git a/spb/SpbTestTool/sys/SpbTestTool.vcxproj b/spb/SpbTestTool/sys/SpbTestTool.vcxproj index c79c2fc3..f9df87dd 100644 --- a/spb/SpbTestTool/sys/SpbTestTool.vcxproj +++ b/spb/SpbTestTool/sys/SpbTestTool.vcxproj @@ -19,12 +19,12 @@ - {F7BF1596-9FD8-40AC-8F50-0B3E40DD2E1A} + {9164F300-DAA4-40F6-B7CA-8523CC819138} $(MSBuildProjectName) 1 Debug Win32 - {94D82B59-F741-453B-ADA8-F7394427ED16} + {6185C64E-9336-44A4-80EB-86AF71C788B1} diff --git a/spb/SpbTestTool/sys/SpbTestTool.vcxproj.Filters b/spb/SpbTestTool/sys/SpbTestTool.vcxproj.Filters index 637381d0..f03b774b 100644 --- a/spb/SpbTestTool/sys/SpbTestTool.vcxproj.Filters +++ b/spb/SpbTestTool/sys/SpbTestTool.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {BCBB1C45-9E44-4421-AA82-B522FF1D13DF} + {91FD9DF9-6894-438F-9FE7-54F26AAE0251} h;hpp;hxx;hm;inl;inc;xsd - {9B409A5B-0FF8-44B1-8827-A0E2ED848AED} + {773429C3-6E0E-4E2B-B859-13563580C523} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {0CD7CABF-642D-4525-BB60-6A5534613E34} + {D591E539-1E9D-44A8-B13D-6D5217A95A29} inf;inv;inx;mof;mc; - {B7A5B324-3FC1-4A11-B5BA-4F64EEE4B619} + {5A587D2B-32E7-4FAD-BF91-69C37B635B94} diff --git a/storage/class/cdrom/ReadMe.md b/storage/class/cdrom/ReadMe.md new file mode 100644 index 00000000..53f623a0 --- /dev/null +++ b/storage/class/cdrom/ReadMe.md @@ -0,0 +1,57 @@ +CDROM Storage Class Driver +========================== + +The CD ROM driver is used to provide access to CD, DVD and Blu-ray drives. It supports Plug and Play, Power Management, and AutoRun (media change notification). + +Build the sample +---------------- + +You can build the sample in two ways: using Microsoft Visual Studio or the command line (*MSBuild*). + +Building a Driver Using Visual Studio +------------------------------------- + +You build a driver the same way you build any project or solution in Visual Studio. When you create a new driver project using a Windows driver template, the template defines a default (active) project configuration and a default (active) solution build configuration. When you create a project from existing driver sources or convert existing driver code that was built with previous versions of the WDK, the conversion process preserves the target version information (operating systems and platform). + +The default Solution build configuration is Visual Studio Debug and Win32. + +### To select a configuration and build a driver or an application + +1. Open the driver project or solution in Visual Studio (find *samplename*.sln or *samplename*.vcxproj). +2. Right-click the solution in the **Solutions Explorer** and select **Configuration Manager**. +3. From the **Configuration Manager**, select the **Active Solution Configuration** (for example, Windows 8.1 Debug or Windows 8.1 Release) and the **Active Solution Platform** (for example, Win32) that correspond to the type of build you are interested in. +4. From the Build menu, click **Build Solution** (Ctrl+Shift+B). + +Building a Driver Using the Command Line (MSBuild) +-------------------------------------------------- + +You can build a driver from the command line using the Visual Studio Command Prompt window and the Microsoft Build Engine (MSBuild.exe) Previous versions of the WDK used the Windows Build utility (Build.exe) and provided separate build environment windows for each of the supported build configurations. You can now use the Visual Studio Command Prompt window for all build configurations. + +### To select a configuration and build a driver or an application + +1. Open a Visual Studio Command Prompt window at the **Start** screen. From this window you can use MsBuild.exe to build any Visual Studio project by specifying the project (.VcxProj) or solutions (.Sln) file. +2. Navigate to the project directory and enter the **MSbuild** command for your target. For example, to perform a clean build of a Visual Studio driver project called *filtername*.vcxproj, navigate to the project directory and enter the following MSBuild command: **msbuild /t:clean /t:build .\\***samplename***.vcxproj**. + +Run the sample +-------------- + +Installation and Operation +-------------------------- + +The in-box CD ROM driver is protected by the system, and thus a normal device driver update attempt through the Device Manager will fail. Users are not encouraged to replace the in-box CD ROM driver. The following work-around is provided in case there is a need, but the users are warned that this may harm the system. + +1. Locate the "cdrom.inf" file in the binary output directory, and update the file by replacing all "cdrom.sys" occurrences with "mycdrom.sys". +2. Rename the "cdrom.inf" file to "mycdrom.inf". +3. Copy "mycdrom.sys" and "mycdrom.inf" from the binary output directory to the test machine, if applicable. +4. Launch the Device Manager +5. Select the appropriate device under the "DVD/CD-ROM drives" category. +6. On the right-click menu, select "Update Driver Software...". +7. Select "Browse my computer for driver software". +8. Select "Let me pick from a list of device drivers on my computer". +9. Click "Have Disk...", and point to the directory that contains "mycdrom.inf" and "mycdrom.sys". +10. Click "Next". If you get a warning dialog about installing unsigned driver, click "Yes". +11. Click "Next" to complete the driver upgrade. +12. After installation completes successfully, "mycdrom.sys" will be the effective driver for the device, "cdrom.sys" will no longer be used. + +For more information, see [CD-ROM Drivers](http://msdn.microsoft.com/en-us/library/windows/hardware/ff551391) in the storage technologies design guide. + diff --git a/storage/class/cdrom/cdrom.sln b/storage/class/cdrom/cdrom.sln new file mode 100644 index 00000000..2af29cc6 --- /dev/null +++ b/storage/class/cdrom/cdrom.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0 +MinimumVisualStudioVersion = 12.0 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cdrom", "src\cdrom.vcxproj", "{1683D068-B3E1-4216-8BA9-A8ADC10DBAC6}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {1683D068-B3E1-4216-8BA9-A8ADC10DBAC6}.Debug|Win32.ActiveCfg = Debug|Win32 + {1683D068-B3E1-4216-8BA9-A8ADC10DBAC6}.Debug|Win32.Build.0 = Debug|Win32 + {1683D068-B3E1-4216-8BA9-A8ADC10DBAC6}.Release|Win32.ActiveCfg = Release|Win32 + {1683D068-B3E1-4216-8BA9-A8ADC10DBAC6}.Release|Win32.Build.0 = Release|Win32 + {1683D068-B3E1-4216-8BA9-A8ADC10DBAC6}.Debug|x64.ActiveCfg = Debug|x64 + {1683D068-B3E1-4216-8BA9-A8ADC10DBAC6}.Debug|x64.Build.0 = Debug|x64 + {1683D068-B3E1-4216-8BA9-A8ADC10DBAC6}.Release|x64.ActiveCfg = Release|x64 + {1683D068-B3E1-4216-8BA9-A8ADC10DBAC6}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/storage/class/cdrom/src/aacs.c b/storage/class/cdrom/src/aacs.c new file mode 100644 index 00000000..191ba6b0 --- /dev/null +++ b/storage/class/cdrom/src/aacs.c @@ -0,0 +1,1481 @@ +/*-- + +Copyright (C) Microsoft Corporation. All rights reserved. + +Module Name: + + aacs.c + +Abstract: + + The CDROM class driver implementation of handling AACS IOCTLs. + +Environment: + + kernel mode only + +Notes: + + +Revision History: + +--*/ + +#include "stddef.h" +#include "string.h" + +#include "ntddk.h" +#include "ntddstor.h" +#include "cdrom.h" +#include "ioctl.h" +#include "scratch.h" + +#ifdef DEBUG_USE_WPP +#include "aacs.tmh" +#endif + +#ifdef ALLOC_PRAGMA + +#pragma alloc_text(PAGE, DeviceHandleAacsReadMediaKeyBlock) +#pragma alloc_text(PAGE, DeviceHandleAacsStartSession) +#pragma alloc_text(PAGE, DeviceHandleAacsEndSession) +#pragma alloc_text(PAGE, DeviceHandleAacsSendCertificate) +#pragma alloc_text(PAGE, DeviceHandleAacsGetCertificate) +#pragma alloc_text(PAGE, DeviceHandleAacsGetChallengeKey) +#pragma alloc_text(PAGE, DeviceHandleAacsReadSerialNumber) +#pragma alloc_text(PAGE, DeviceHandleAacsReadMediaId) +#pragma alloc_text(PAGE, DeviceHandleAacsReadBindingNonce) +#pragma alloc_text(PAGE, DeviceHandleAacsGenerateBindingNonce) +#pragma alloc_text(PAGE, DeviceHandleReadVolumeId) +#pragma alloc_text(PAGE, DeviceHandleSendChallengeKey) + +#endif + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DeviceHandleAacsReadMediaKeyBlock( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + This routine is used to process IOCTLs: + IOCTL_AACS_READ_MEDIA_KEY_BLOCK_SIZE + IOCTL_AACS_READ_MEDIA_KEY_BLOCK +Arguments: + DeviceExtension - device context + + Request - the request that will be formatted + + RequestParameters - request parameter structur + + DataLength - data transferred length + +Return Value: + NTSTATUS + + --*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PAACS_LAYER_NUMBER layerNumber = NULL; + PVOID outputBuffer = NULL; + ULONG transferSize = sizeof(READ_DVD_STRUCTURES_HEADER); + + PAGED_CODE(); + + *DataLength = 0; + + status = WdfRequestRetrieveInputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.InputBufferLength, + (PVOID*)&layerNumber, + NULL); + + if (NT_SUCCESS(status)) + { + status = WdfRequestRetrieveOutputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, + (PVOID*)&outputBuffer, + NULL); + } + + if (NT_SUCCESS(status)) + { + if (RequestParameters.Parameters.DeviceIoControl.IoControlCode == IOCTL_AACS_READ_MEDIA_KEY_BLOCK) + { + // maximum size for this transfer is one pack + header + transferSize += AACS_MKB_PACK_SIZE; + } + + if (transferSize > DeviceExtension->ScratchContext.ScratchBufferSize) + { + // rare case. normally the size of scratch buffer is 64k. + status = STATUS_INTERNAL_ERROR; + } + } + + if (NT_SUCCESS(status)) + { + UCHAR rmdBlockNumber = 0; + BOOLEAN sendChangedCommand = TRUE; + BOOLEAN shouldRetry = TRUE; + CDB cdb; + + ScratchBuffer_BeginUse(DeviceExtension); + + RtlZeroMemory(&cdb, sizeof(CDB)); + // Set up the CDB + cdb.READ_DVD_STRUCTURE.OperationCode = SCSIOP_READ_DVD_STRUCTURE; + // cdb->AsByte[1] = 0x01; // AACS sub-command not required for this + + cdb.READ_DVD_STRUCTURE.LayerNumber = (UCHAR)(*layerNumber); + cdb.READ_DVD_STRUCTURE.Format = 0x83; // MKB + cdb.READ_DVD_STRUCTURE.AllocationLength[0] = (UCHAR)(transferSize >> (8*1)); + cdb.READ_DVD_STRUCTURE.AllocationLength[1] = (UCHAR)(transferSize >> (8*0)); + + while (sendChangedCommand) + { + // RMDBlockNumber is set to zero.... + // RMDBlockNumber[3] maybe changed for other blocks. + cdb.READ_DVD_STRUCTURE.RMDBlockNumber[3] = rmdBlockNumber; + + if (shouldRetry) + { + status = ScratchBuffer_ExecuteCdb(DeviceExtension, Request, transferSize, TRUE, &cdb, 12); + } + + #ifdef ENABLE_AACS_TESTING + if (RequestParameters.Parameters.DeviceIoControl.IoControlCode == IOCTL_AACS_READ_MEDIA_KEY_BLOCK_SIZE) + { + static const UCHAR results[] = { 0x80, 0x02, 0x00, 0x02 }; + RtlCopyMemory(DeviceExtension->ScratchContext.ScratchBuffer, results, SIZEOF_ARRAY(results)); + status = STATUS_SUCCESS; + } + else if (RequestParameters.Parameters.DeviceIoControl.IoControlCode == IOCTL_AACS_READ_MEDIA_KEY_BLOCK) + { + static const UCHAR results[] = { 0x80, 0x02, 0x00, 0x02 }; + static const UCHAR defaultFill = 0x30; // '0' + RtlFillMemory(DeviceExtension->ScratchContext.ScratchBuffer, 0x8004, defaultFill); + RtlCopyMemory(DeviceExtension->ScratchContext.ScratchBuffer, results, SIZEOF_ARRAY(results)); + status = STATUS_SUCCESS; + } + #endif //ENABLE_AACS_TESTING + + if (NT_SUCCESS(status)) + { + // command succeeded, process data... + PDVD_DESCRIPTOR_HEADER header = DeviceExtension->ScratchContext.ScratchBuffer; + UCHAR thisPackNumber = cdb.READ_DVD_STRUCTURE.RMDBlockNumber[3]; + UCHAR otherPacks = header->Reserved[1]; + + // validate and zero-base the otherPacks + if (otherPacks == 0) + { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT, + "AACS: Device is reporting zero total packs (invalid)\n")); + *DataLength = 0; + status = STATUS_IO_DEVICE_ERROR; + } + else + { + otherPacks--; + + if (RequestParameters.Parameters.DeviceIoControl.IoControlCode == IOCTL_AACS_READ_MEDIA_KEY_BLOCK_SIZE) + { + // if not already requested last pack, do so now + if (otherPacks != thisPackNumber) + { + // re-send the command for the other pack number. + // this is safe here because NT_SUCCESS() is TRUE, + // and all the rest of this routine does is SetHardError() + // and release of resources we're still about to use. + + // re-zero the output buffer + RtlZeroMemory(DeviceExtension->ScratchContext.ScratchBuffer, sizeof(READ_DVD_STRUCTURES_HEADER)); + + // modify the CDB to get the very last pack of the MKB + rmdBlockNumber = otherPacks; + + transferSize = sizeof(READ_DVD_STRUCTURES_HEADER); + + // keep items clean + ScratchBuffer_ResetItems(DeviceExtension, TRUE); + + // make sure the loop will be executed for modified command. + sendChangedCommand = TRUE; + shouldRetry = TRUE; + } + else + { + // this request already got the last pack + // so just interpret the data + REVERSE_SHORT(&header->Length); + if (header->Length < sizeof(DVD_DESCRIPTOR_HEADER) - RTL_SIZEOF_THROUGH_FIELD(DVD_DESCRIPTOR_HEADER, Length)) + { + *DataLength = 0; + status = STATUS_IO_DEVICE_ERROR; + } + else + { + ULONG totalSize = header->Length; + // subtract out any remaining bytes in the header + // to get the number of usable bytes in this pack + totalSize -= sizeof(DVD_DESCRIPTOR_HEADER) - RTL_SIZEOF_THROUGH_FIELD(DVD_DESCRIPTOR_HEADER, Length); + totalSize += otherPacks * AACS_MKB_PACK_SIZE; + + // save the result and complete the request + *((PULONG)outputBuffer) = totalSize; + *DataLength = sizeof(ULONG); + status = STATUS_SUCCESS; + } + // This will exit the loop of sendChangedCommand + sendChangedCommand = FALSE; + shouldRetry = FALSE; + } + } + else if (RequestParameters.Parameters.DeviceIoControl.IoControlCode == IOCTL_AACS_READ_MEDIA_KEY_BLOCK) + { + // make length field native byte ordering + REVERSE_SHORT(&header->Length); + + // exit if getting invalid data from the drive + if (header->Length < sizeof(DVD_DESCRIPTOR_HEADER) - RTL_SIZEOF_THROUGH_FIELD(DVD_DESCRIPTOR_HEADER, Length)) + { + *DataLength = 0; + status = STATUS_IO_DEVICE_ERROR; + } + else + { + // success, how many bytes to copy for this pack? + ULONG totalSize = header->Length; + size_t originalBufferSize; + + // subtract out any remaining bytes in the header + // to get the number of usable bytes in this pack + totalSize -= sizeof(DVD_DESCRIPTOR_HEADER) - RTL_SIZEOF_THROUGH_FIELD(DVD_DESCRIPTOR_HEADER, Length); + + // if not the final pack, this should be a full transfer per spec + NT_ASSERT( (totalSize == AACS_MKB_PACK_SIZE) || (thisPackNumber == otherPacks) ); + + // validate the user's buffer is large enough to accept the full data + originalBufferSize = RequestParameters.Parameters.DeviceIoControl.OutputBufferLength; + + if (originalBufferSize < (totalSize + (AACS_MKB_PACK_SIZE*thisPackNumber))) + { + // just return a slightly bigger-than-normal size + *DataLength = (otherPacks + 1)*AACS_MKB_PACK_SIZE; + status = STATUS_BUFFER_TOO_SMALL; + } + else + { + PUCHAR whereToCopy; + // determine where to copy to the user's memory + whereToCopy = outputBuffer; + whereToCopy += AACS_MKB_PACK_SIZE * thisPackNumber; + + RtlCopyMemory(whereToCopy, header->Data, totalSize); + + // update the Information field here because we already + // have calculated the size of the block + *DataLength = totalSize + (AACS_MKB_PACK_SIZE * thisPackNumber); + status = STATUS_SUCCESS; + + // if there are more packs to get from the device, send it again.... + if (thisPackNumber != otherPacks) + { + // re-send the command for the next pack number. + // this is safe here because NT_SUCCESS() is TRUE, + // and all the rest of this routine does is SetHardError() + // and release of resources we're still about to use. + + // re-zero the output buffer + RtlZeroMemory(DeviceExtension->ScratchContext.ScratchBuffer, sizeof(READ_DVD_STRUCTURES_HEADER)); + + // modify the CDB to get the next pack of the MKB + rmdBlockNumber = cdb.READ_DVD_STRUCTURE.RMDBlockNumber[3]++; + + // modify the SRB to be resent + // + transferSize = AACS_MKB_PACK_SIZE + sizeof(READ_DVD_STRUCTURES_HEADER); + + // keep items clean + ScratchBuffer_ResetItems(DeviceExtension, FALSE); + + // make sure the loop will be executed for modified command. + sendChangedCommand = TRUE; + shouldRetry = TRUE; + } + else + { + // else, that was the end of the transfer, so just complete the request + sendChangedCommand = FALSE; + } + } + } + + } // end of IOCTL_AACS_READ_MEDIA_KEY_BLOCK + } + } // end of NT_SUCCESS(status) + + if (!NT_SUCCESS(status)) + { + // command failed. + sendChangedCommand = FALSE; + } + } //end of while (sendChangedCommand) + + ScratchBuffer_EndUse(DeviceExtension); + } + + return status; +} + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DeviceHandleAacsStartSession( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + This routine is used to process IOCTL: + IOCTL_AACS_START_SESSION +Arguments: + DeviceExtension - device context + + Request - the request that will be formatted + + RequestParameters - request parameter structur + + DataLength - data transferred length + +Return Value: + NTSTATUS + + --*/ +{ + //AacsGetAgid + + NTSTATUS status = STATUS_SUCCESS; + PDVD_SESSION_ID sessionId = NULL; + + PAGED_CODE(); + + *DataLength = 0; + + status = WdfRequestRetrieveOutputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, + (PVOID*)&sessionId, + NULL); + + if (NT_SUCCESS(status)) + { + ULONG dataTransferLength = sizeof(CDVD_KEY_HEADER) + sizeof(CDVD_REPORT_AGID_DATA); + CDB cdb; + + ScratchBuffer_BeginUse(DeviceExtension); + + RtlZeroMemory(&cdb, sizeof(CDB)); + // Set up the CDB + cdb.REPORT_KEY.OperationCode = SCSIOP_REPORT_KEY; + cdb.AsByte[7] = 0x02; // AACS key class + cdb.REPORT_KEY.AllocationLength[0] = (UCHAR)(dataTransferLength >> (8*1)); + cdb.REPORT_KEY.AllocationLength[1] = (UCHAR)(dataTransferLength >> (8*0)); + cdb.REPORT_KEY.KeyFormat = 0x00; // DVD_REPORT_AGID? + + status = ScratchBuffer_ExecuteCdb(DeviceExtension, Request, dataTransferLength, TRUE, &cdb, 12); + +#ifdef ENABLE_AACS_TESTING + static const UCHAR results[] = { 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0 }; + RtlCopyMemory(DeviceExtension->ScratchContext.ScratchBuffer, results, SIZEOF_ARRAY(results)); + status = STATUS_SUCCESS; +#endif + if (NT_SUCCESS(status)) + { + PCDVD_KEY_HEADER keyHeader = DeviceExtension->ScratchContext.ScratchBuffer; + PCDVD_REPORT_AGID_DATA keyData = (PCDVD_REPORT_AGID_DATA)keyHeader->Data; + + *sessionId = (DVD_SESSION_ID)(keyData->AGID); + *DataLength = sizeof(DVD_SESSION_ID); + } + + ScratchBuffer_EndUse(DeviceExtension); + } + + return status; +} + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DeviceHandleAacsEndSession( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + This routine is used to process IOCTL: + IOCTL_AACS_END_SESSION +Arguments: + DeviceExtension - device context + + Request - the request that will be formatted + + RequestParameters - request parameter structur + + DataLength - data transferred length + +Return Value: + NTSTATUS + + --*/ +{ + //AacsReleaseAgid + + NTSTATUS status = STATUS_SUCCESS; + PDVD_SESSION_ID sessionId = NULL; + + PAGED_CODE(); + + *DataLength = 0; + + status = WdfRequestRetrieveInputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.InputBufferLength, + (PVOID*)&sessionId, + NULL); + + if (NT_SUCCESS(status)) + { + ULONG transferSize = 0; + CDB cdb; + DVD_SESSION_ID currentSession = 0; + DVD_SESSION_ID limitSession = 0; + + if(*sessionId == DVD_END_ALL_SESSIONS) + { + currentSession = 0; + limitSession = MAX_COPY_PROTECT_AGID - 1; + } + else + { + currentSession = *sessionId; + limitSession = *sessionId; + } + + ScratchBuffer_BeginUse(DeviceExtension); + + do + { + RtlZeroMemory(&cdb, sizeof(CDB)); + // Set up the CDB + cdb.SEND_KEY.OperationCode = SCSIOP_SEND_KEY; + cdb.AsByte[7] = 0x02; // AACS key class + cdb.SEND_KEY.AGID = (UCHAR)(currentSession); + cdb.SEND_KEY.KeyFormat = DVD_INVALIDATE_AGID; + + status = ScratchBuffer_ExecuteCdb(DeviceExtension, Request, transferSize, FALSE, &cdb, 12); + + currentSession++; + } while ((currentSession <= limitSession) && NT_SUCCESS(status)); + +#ifdef ENABLE_AACS_TESTING + status = STATUS_SUCCESS; +#endif + + ScratchBuffer_EndUse(DeviceExtension); + } + + return status; +} + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DeviceHandleAacsSendCertificate( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + This routine is used to process IOCTL: + IOCTL_AACS_SEND_CERTIFICATE +Arguments: + DeviceExtension - device context + + Request - the request that will be formatted + + RequestParameters - request parameter structur + + DataLength - data transferred length + +Return Value: + NTSTATUS + + --*/ +{ + //AacsSendHostCertificate + + NTSTATUS status = STATUS_SUCCESS; + PAACS_SEND_CERTIFICATE input = NULL; + + PAGED_CODE(); + + *DataLength = 0; + + status = WdfRequestRetrieveInputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.InputBufferLength, + (PVOID*)&input, + NULL); + + if (NT_SUCCESS(status)) + { + ULONG dataTransferLength = sizeof(CDVD_KEY_HEADER) + sizeof(AACS_CERTIFICATE); + CDB cdb; + + ScratchBuffer_BeginUse(DeviceExtension); + + // copy the input buffer to the data buffer for the transfer + { + PCDVD_KEY_HEADER header = (PCDVD_KEY_HEADER)DeviceExtension->ScratchContext.ScratchBuffer; + ULONG tmp = dataTransferLength; + + tmp -= RTL_SIZEOF_THROUGH_FIELD(CDVD_KEY_HEADER, DataLength); + + header->DataLength[0] = (UCHAR)(tmp >> (8*1)); + header->DataLength[1] = (UCHAR)(tmp >> (8*0)); + RtlCopyMemory(header->Data, &(input->Certificate), sizeof(AACS_CERTIFICATE)); + } + + RtlZeroMemory(&cdb, sizeof(CDB)); + // Set up the CDB + cdb.SEND_KEY.OperationCode = SCSIOP_SEND_KEY; + cdb.AsByte[7] = 0x02; // AACS key class + cdb.SEND_KEY.ParameterListLength[0] = (UCHAR)(dataTransferLength >> (8*1)); + cdb.SEND_KEY.ParameterListLength[1] = (UCHAR)(dataTransferLength >> (8*0)); + cdb.SEND_KEY.AGID = (UCHAR)( input->SessionId ); + cdb.SEND_KEY.KeyFormat = 0x01; // Send Host Challenge Certificate + + status = ScratchBuffer_ExecuteCdb(DeviceExtension, Request, dataTransferLength, FALSE, &cdb, 12); + +#ifdef ENABLE_AACS_TESTING + status = STATUS_SUCCESS; +#endif + if (NT_SUCCESS(status)) + { + *DataLength = 0; + } + + ScratchBuffer_EndUse(DeviceExtension); + } + + return status; +} + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DeviceHandleAacsGetCertificate( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + This routine is used to process IOCTL: + IOCTL_AACS_GET_CERTIFICATE +Arguments: + DeviceExtension - device context + + Request - the request that will be formatted + + RequestParameters - request parameter structur + + DataLength - data transferred length + +Return Value: + NTSTATUS + + --*/ +{ + //AacsGetDriveCertificate + + NTSTATUS status = STATUS_SUCCESS; + PDVD_SESSION_ID input = NULL; + PVOID outputBuffer = NULL; + + PAGED_CODE(); + + *DataLength = 0; + + status = WdfRequestRetrieveInputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.InputBufferLength, + (PVOID*)&input, + NULL); + + if (NT_SUCCESS(status)) + { + status = WdfRequestRetrieveOutputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, + (PVOID*)&outputBuffer, + NULL); + } + + if (NT_SUCCESS(status)) + { + ULONG dataTransferLength = sizeof(CDVD_KEY_HEADER) + sizeof(AACS_CERTIFICATE); + CDB cdb; + + ScratchBuffer_BeginUse(DeviceExtension); + + RtlZeroMemory(&cdb, sizeof(CDB)); + // Set up the CDB + cdb.REPORT_KEY.OperationCode = SCSIOP_REPORT_KEY; + cdb.AsByte[7] = 0x02; // AACS key class + cdb.REPORT_KEY.AllocationLength[0] = (UCHAR)(dataTransferLength >> (8*1)); + cdb.REPORT_KEY.AllocationLength[1] = (UCHAR)(dataTransferLength >> (8*0)); + cdb.REPORT_KEY.AGID = (UCHAR)(*input); + cdb.REPORT_KEY.KeyFormat = 0x01; // Return a drive certificate challenge + + status = ScratchBuffer_ExecuteCdb(DeviceExtension, Request, dataTransferLength, TRUE, &cdb, 12); + +#ifdef ENABLE_AACS_TESTING + static const UCHAR results[] = { 0x00, 0x72, 0x00, 0x00 }; + static const UCHAR defaultFill = 0x31; // '1' + RtlFillMemory(DeviceExtension->ScratchContext.ScratchBuffer, 0x0074, defaultFill); + RtlCopyMemory(DeviceExtension->ScratchContext.ScratchBuffer, results, SIZEOF_ARRAY(results)); + status = STATUS_SUCCESS; +#endif + if (NT_SUCCESS(status)) + { + PDVD_DESCRIPTOR_HEADER header = DeviceExtension->ScratchContext.ScratchBuffer; + ULONG dataLengthToCopy = sizeof(AACS_CERTIFICATE); + + // make length field native byte ordering + REVERSE_SHORT(&header->Length); + + // exit if getting invalid data from the drive + if (header->Length < (sizeof(DVD_DESCRIPTOR_HEADER) - RTL_SIZEOF_THROUGH_FIELD(DVD_DESCRIPTOR_HEADER, Length))) + { + *DataLength = 0; + status = STATUS_IO_DEVICE_ERROR; + } + + if (NT_SUCCESS(status)) + { + // adjust data length to reflect only the addition data + header->Length -= sizeof(DVD_DESCRIPTOR_HEADER) - RTL_SIZEOF_THROUGH_FIELD(DVD_DESCRIPTOR_HEADER, Length); + + // exit if the drive is returning an unexpected data size + if (header->Length != dataLengthToCopy) + { + *DataLength = 0; + status = STATUS_IO_DEVICE_ERROR; + } + } + + if (NT_SUCCESS(status)) + { + // else copy the data to the user's buffer + RtlCopyMemory(outputBuffer, header->Data, dataLengthToCopy); + *DataLength = dataLengthToCopy; + } + } + + ScratchBuffer_EndUse(DeviceExtension); + } + + return status; +} + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DeviceHandleAacsGetChallengeKey( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + This routine is used to process IOCTL: + IOCTL_AACS_GET_CHALLENGE_KEY +Arguments: + DeviceExtension - device context + + Request - the request that will be formatted + + RequestParameters - request parameter structur + + DataLength - data transferred length + +Return Value: + NTSTATUS + + --*/ +{ + //AacsGetChallengeKey + + NTSTATUS status = STATUS_SUCCESS; + PDVD_SESSION_ID input = NULL; + PVOID outputBuffer = NULL; + + PAGED_CODE(); + + *DataLength = 0; + + status = WdfRequestRetrieveInputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.InputBufferLength, + (PVOID*)&input, + NULL); + + if (NT_SUCCESS(status)) + { + status = WdfRequestRetrieveOutputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, + (PVOID*)&outputBuffer, + NULL); + } + + if (NT_SUCCESS(status)) + { + ULONG dataTransferLength = sizeof(CDVD_KEY_HEADER) + sizeof(AACS_CHALLENGE_KEY); + CDB cdb; + + ScratchBuffer_BeginUse(DeviceExtension); + + RtlZeroMemory(&cdb, sizeof(CDB)); + // Set up the CDB + cdb.REPORT_KEY.OperationCode = SCSIOP_REPORT_KEY; + cdb.AsByte[7] = 0x02; // AACS key class + cdb.REPORT_KEY.AllocationLength[0] = (UCHAR)(dataTransferLength >> (8*1)); + cdb.REPORT_KEY.AllocationLength[1] = (UCHAR)(dataTransferLength >> (8*0)); + cdb.REPORT_KEY.AGID = (UCHAR)(*input); + cdb.REPORT_KEY.KeyFormat = 0x02; // Return a drive certificate challenge + + status = ScratchBuffer_ExecuteCdb(DeviceExtension, Request, dataTransferLength, TRUE, &cdb, 12); + +#ifdef ENABLE_AACS_TESTING + static const UCHAR results[] = { 0x00, 0x52, 0x00, 0x00 }; + static const UCHAR defaultFill = 0x32; // '2' + RtlFillMemory(DeviceExtension->ScratchContext.ScratchBuffer, 0x0054, defaultFill); + RtlCopyMemory(DeviceExtension->ScratchContext.ScratchBuffer, results, SIZEOF_ARRAY(results)); + status = STATUS_SUCCESS; +#endif + if (NT_SUCCESS(status)) + { + PDVD_DESCRIPTOR_HEADER header = DeviceExtension->ScratchContext.ScratchBuffer; + ULONG dataLengthToCopy = sizeof(AACS_CHALLENGE_KEY); + + // make length field native byte ordering + REVERSE_SHORT(&header->Length); + + // exit if getting invalid data from the drive + if (header->Length < sizeof(DVD_DESCRIPTOR_HEADER) - RTL_SIZEOF_THROUGH_FIELD(DVD_DESCRIPTOR_HEADER, Length)) + { + *DataLength = 0; + status = STATUS_IO_DEVICE_ERROR; + } + + if (NT_SUCCESS(status)) + { + // adjust data length to reflect only the addition data + header->Length -= sizeof(DVD_DESCRIPTOR_HEADER) - RTL_SIZEOF_THROUGH_FIELD(DVD_DESCRIPTOR_HEADER, Length); + + // exit if the drive is returning an unexpected data size + if (header->Length != dataLengthToCopy) + { + *DataLength = 0; + status = STATUS_IO_DEVICE_ERROR; + } + } + + if (NT_SUCCESS(status)) + { + // else copy the data to the user's buffer + RtlCopyMemory(outputBuffer, header->Data, dataLengthToCopy); + *DataLength = dataLengthToCopy; + } + } + + ScratchBuffer_EndUse(DeviceExtension); + } + + return status; +} + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DeviceHandleSendChallengeKey( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + This routine is used to process IOCTL: + IOCTL_AACS_SEND_CHALLENGE_KEY +Arguments: + DeviceExtension - device context + + Request - the request that will be formatted + + RequestParameters - request parameter structur + + DataLength - data transferred length + +Return Value: + NTSTATUS + + --*/ +{ + //AacsSendChallengeKey + + NTSTATUS status = STATUS_SUCCESS; + PAACS_SEND_CHALLENGE_KEY input = NULL; + + PAGED_CODE(); + + *DataLength = 0; + + status = WdfRequestRetrieveInputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.InputBufferLength, + (PVOID*)&input, + NULL); + + if (NT_SUCCESS(status)) + { + ULONG dataTransferLength = sizeof(CDVD_KEY_HEADER) + sizeof(AACS_CHALLENGE_KEY); + CDB cdb; + + ScratchBuffer_BeginUse(DeviceExtension); + + // copy the input buffer to the data buffer for the transfer + { + PCDVD_KEY_HEADER header = DeviceExtension->ScratchContext.ScratchBuffer; + ULONG tmp = dataTransferLength; + tmp -= RTL_SIZEOF_THROUGH_FIELD(CDVD_KEY_HEADER, DataLength); + + header->DataLength[0] = (UCHAR)(tmp >> (8*1)); + header->DataLength[1] = (UCHAR)(tmp >> (8*0)); + RtlCopyMemory(header->Data, &(input->ChallengeKey), sizeof(AACS_CHALLENGE_KEY)); + } + + RtlZeroMemory(&cdb, sizeof(CDB)); + // Set up the CDB + cdb.SEND_KEY.OperationCode = SCSIOP_SEND_KEY; + cdb.AsByte[7] = 0x02; // AACS key class + cdb.SEND_KEY.ParameterListLength[0] = (UCHAR)(dataTransferLength >> (8*1)); + cdb.SEND_KEY.ParameterListLength[1] = (UCHAR)(dataTransferLength >> (8*0)); + cdb.SEND_KEY.AGID = (UCHAR)( input->SessionId ); + cdb.SEND_KEY.KeyFormat = 0x02; // Send Host Challenge Certificate + + status = ScratchBuffer_ExecuteCdb(DeviceExtension, Request, dataTransferLength, FALSE, &cdb, 12); + +#ifdef ENABLE_AACS_TESTING + status = STATUS_SUCCESS; +#endif + if (NT_SUCCESS(status)) + { + *DataLength = 0; + } + + ScratchBuffer_EndUse(DeviceExtension); + } + + return status; +} + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DeviceHandleReadVolumeId( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + This routine is used to process IOCTL: + IOCTL_AACS_READ_VOLUME_ID +Arguments: + DeviceExtension - device context + + Request - the request that will be formatted + + RequestParameters - request parameter structur + + DataLength - data transferred length + +Return Value: + NTSTATUS + + --*/ +{ + //AacsReadVolumeID + + NTSTATUS status = STATUS_SUCCESS; + PDVD_SESSION_ID input = NULL; + PVOID outputBuffer = NULL; + + PAGED_CODE(); + + *DataLength = 0; + + status = WdfRequestRetrieveInputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.InputBufferLength, + (PVOID*)&input, + NULL); + + if (NT_SUCCESS(status)) + { + status = WdfRequestRetrieveOutputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, + (PVOID*)&outputBuffer, + NULL); + } + + if (NT_SUCCESS(status)) + { + ULONG dataTransferLength = sizeof(CDVD_KEY_HEADER) + sizeof(AACS_VOLUME_ID); + CDB cdb; + + ScratchBuffer_BeginUse(DeviceExtension); + + RtlZeroMemory(&cdb, sizeof(CDB)); + // Set up the CDB + cdb.READ_DVD_STRUCTURE.OperationCode = SCSIOP_READ_DVD_STRUCTURE; + cdb.READ_DVD_STRUCTURE.Format = 0x80; // Return the AACS volumeID + cdb.READ_DVD_STRUCTURE.AllocationLength[0] = (UCHAR)(dataTransferLength >> (8*1)); + cdb.READ_DVD_STRUCTURE.AllocationLength[1] = (UCHAR)(dataTransferLength >> (8*0)); + cdb.READ_DVD_STRUCTURE.AGID = (UCHAR)(*input); + + status = ScratchBuffer_ExecuteCdb(DeviceExtension, Request, dataTransferLength, TRUE, &cdb, 12); + +#ifdef ENABLE_AACS_TESTING + static const UCHAR results[] = { 0x00, 0x22, 0x00, 0x00 }; + static const UCHAR defaultFill = 0x33; // '3' + RtlFillMemory(DeviceExtension->ScratchContext.ScratchBuffer, 0x0024, defaultFill); + RtlCopyMemory(DeviceExtension->ScratchContext.ScratchBuffer, results, SIZEOF_ARRAY(results)); + status = STATUS_SUCCESS; +#endif + if (NT_SUCCESS(status)) + { + PDVD_DESCRIPTOR_HEADER header = DeviceExtension->ScratchContext.ScratchBuffer; + ULONG dataLengthToCopy = sizeof(AACS_VOLUME_ID); + + // make length field native byte ordering + REVERSE_SHORT(&header->Length); + + // exit if getting invalid data from the drive + if (header->Length < sizeof(DVD_DESCRIPTOR_HEADER) - RTL_SIZEOF_THROUGH_FIELD(DVD_DESCRIPTOR_HEADER, Length)) + { + *DataLength = 0; + status = STATUS_IO_DEVICE_ERROR; + } + + if (NT_SUCCESS(status)) + { + // adjust data length to reflect only the addition data + header->Length -= sizeof(DVD_DESCRIPTOR_HEADER) - RTL_SIZEOF_THROUGH_FIELD(DVD_DESCRIPTOR_HEADER, Length); + + // exit if the drive is returning an unexpected data size + if (header->Length != dataLengthToCopy) + { + *DataLength = 0; + status = STATUS_IO_DEVICE_ERROR; + } + } + + if (NT_SUCCESS(status)) + { + // else copy the data to the user's buffer + RtlCopyMemory(outputBuffer, header->Data, dataLengthToCopy); + *DataLength = dataLengthToCopy; + } + } + + ScratchBuffer_EndUse(DeviceExtension); + } + + return status; +} + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DeviceHandleAacsReadSerialNumber( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + This routine is used to process IOCTL: + IOCTL_AACS_READ_SERIAL_NUMBER +Arguments: + DeviceExtension - device context + + Request - the request that will be formatted + + RequestParameters - request parameter structur + + DataLength - data transferred length + +Return Value: + NTSTATUS + + --*/ +{ + //AacsReadSerialNumber + + NTSTATUS status = STATUS_SUCCESS; + PDVD_SESSION_ID input = NULL; + PVOID outputBuffer = NULL; + + PAGED_CODE(); + + *DataLength = 0; + + status = WdfRequestRetrieveInputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.InputBufferLength, + (PVOID*)&input, + NULL); + + if (NT_SUCCESS(status)) + { + status = WdfRequestRetrieveOutputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, + (PVOID*)&outputBuffer, + NULL); + } + + if (NT_SUCCESS(status)) + { + ULONG dataTransferLength = sizeof(CDVD_KEY_HEADER) + sizeof(AACS_SERIAL_NUMBER); + CDB cdb; + + ScratchBuffer_BeginUse(DeviceExtension); + + RtlZeroMemory(&cdb, sizeof(CDB)); + // Set up the CDB + cdb.READ_DVD_STRUCTURE.OperationCode = SCSIOP_READ_DVD_STRUCTURE; + cdb.READ_DVD_STRUCTURE.Format = 0x81; // Return the AACS volumeID + cdb.READ_DVD_STRUCTURE.AllocationLength[0] = (UCHAR)(dataTransferLength >> (8*1)); + cdb.READ_DVD_STRUCTURE.AllocationLength[1] = (UCHAR)(dataTransferLength >> (8*0)); + cdb.READ_DVD_STRUCTURE.AGID = (UCHAR)(*input); + + status = ScratchBuffer_ExecuteCdb(DeviceExtension, Request, dataTransferLength, TRUE, &cdb, 12); + +#ifdef ENABLE_AACS_TESTING + static const UCHAR results[] = { 0x00, 0x22, 0x00, 0x00 }; + static const UCHAR defaultFill = 0x34; // '4' + RtlFillMemory(DeviceExtension->ScratchContext.ScratchBuffer, 0x0024, defaultFill); + RtlCopyMemory(DeviceExtension->ScratchContext.ScratchBuffer, results, SIZEOF_ARRAY(results)); + status = STATUS_SUCCESS; +#endif + if (NT_SUCCESS(status)) + { + PDVD_DESCRIPTOR_HEADER header = DeviceExtension->ScratchContext.ScratchBuffer; + ULONG dataLengthToCopy = sizeof(AACS_SERIAL_NUMBER); + + // make length field native byte ordering + REVERSE_SHORT(&header->Length); + + // exit if getting invalid data from the drive + if (header->Length < sizeof(DVD_DESCRIPTOR_HEADER) - RTL_SIZEOF_THROUGH_FIELD(DVD_DESCRIPTOR_HEADER, Length)) + { + *DataLength = 0; + status = STATUS_IO_DEVICE_ERROR; + } + + if (NT_SUCCESS(status)) + { + // adjust data length to reflect only the addition data + header->Length -= sizeof(DVD_DESCRIPTOR_HEADER) - RTL_SIZEOF_THROUGH_FIELD(DVD_DESCRIPTOR_HEADER, Length); + + // exit if the drive is returning an unexpected data size + if (header->Length != dataLengthToCopy) + { + *DataLength = 0; + status = STATUS_IO_DEVICE_ERROR; + } + } + + if (NT_SUCCESS(status)) + { + // else copy the data to the user's buffer + RtlCopyMemory(outputBuffer, header->Data, dataLengthToCopy); + *DataLength = dataLengthToCopy; + } + } + + ScratchBuffer_EndUse(DeviceExtension); + } + + return status; +} + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DeviceHandleAacsReadMediaId( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + This routine is used to process IOCTL: + IOCTL_AACS_READ_MEDIA_ID +Arguments: + DeviceExtension - device context + + Request - the request that will be formatted + + RequestParameters - request parameter structur + + DataLength - data transferred length + +Return Value: + NTSTATUS + + --*/ +{ + //AacsReadMediaID + + NTSTATUS status = STATUS_SUCCESS; + PDVD_SESSION_ID input = NULL; + PVOID outputBuffer = NULL; + + PAGED_CODE(); + + *DataLength = 0; + + status = WdfRequestRetrieveInputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.InputBufferLength, + (PVOID*)&input, + NULL); + + if (NT_SUCCESS(status)) + { + status = WdfRequestRetrieveOutputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, + (PVOID*)&outputBuffer, + NULL); + } + + if (NT_SUCCESS(status)) + { + ULONG dataTransferLength = sizeof(CDVD_KEY_HEADER) + sizeof(AACS_MEDIA_ID); + CDB cdb; + + ScratchBuffer_BeginUse(DeviceExtension); + + RtlZeroMemory(&cdb, sizeof(CDB)); + // Set up the CDB + cdb.READ_DVD_STRUCTURE.OperationCode = SCSIOP_READ_DVD_STRUCTURE; + cdb.READ_DVD_STRUCTURE.Format = 0x82; // Return the AACS volumeID + cdb.READ_DVD_STRUCTURE.AllocationLength[0] = (UCHAR)(dataTransferLength >> (8*1)); + cdb.READ_DVD_STRUCTURE.AllocationLength[1] = (UCHAR)(dataTransferLength >> (8*0)); + cdb.READ_DVD_STRUCTURE.AGID = (UCHAR)(*input); + + status = ScratchBuffer_ExecuteCdb(DeviceExtension, Request, dataTransferLength, TRUE, &cdb, 12); + +#ifdef ENABLE_AACS_TESTING + static const UCHAR results[] = { 0x00, 0x22, 0x00, 0x00 }; + static const UCHAR defaultFill = 0x35; // '5' + RtlFillMemory(DeviceExtension->ScratchContext.ScratchBuffer, 0x0024, defaultFill); + RtlCopyMemory(DeviceExtension->ScratchContext.ScratchBuffer, results, SIZEOF_ARRAY(results)); + status = STATUS_SUCCESS; +#endif + if (NT_SUCCESS(status)) + { + PDVD_DESCRIPTOR_HEADER header = DeviceExtension->ScratchContext.ScratchBuffer; + ULONG dataLengthToCopy = sizeof(AACS_MEDIA_ID); + + // make length field native byte ordering + REVERSE_SHORT(&header->Length); + + // exit if getting invalid data from the drive + if (header->Length < sizeof(DVD_DESCRIPTOR_HEADER) - RTL_SIZEOF_THROUGH_FIELD(DVD_DESCRIPTOR_HEADER, Length)) + { + *DataLength = 0; + status = STATUS_IO_DEVICE_ERROR; + } + + if (NT_SUCCESS(status)) + { + // adjust data length to reflect only the addition data + header->Length -= sizeof(DVD_DESCRIPTOR_HEADER) - RTL_SIZEOF_THROUGH_FIELD(DVD_DESCRIPTOR_HEADER, Length); + + // exit if the drive is returning an unexpected data size + if (header->Length != dataLengthToCopy) + { + *DataLength = 0; + status = STATUS_IO_DEVICE_ERROR; + } + } + + if (NT_SUCCESS(status)) + { + // else copy the data to the user's buffer + RtlCopyMemory(outputBuffer, header->Data, dataLengthToCopy); + *DataLength = dataLengthToCopy; + } + } + + ScratchBuffer_EndUse(DeviceExtension); + } + + return status; +} + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DeviceHandleAacsReadBindingNonce( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + This routine is used to process IOCTL: + IOCTL_AACS_READ_BINDING_NONCE +Arguments: + DeviceExtension - device context + + Request - the request that will be formatted + + RequestParameters - request parameter structur + + DataLength - data transferred length + +Return Value: + NTSTATUS + + --*/ +{ + //AacsReadBindingNonce + + NTSTATUS status = STATUS_SUCCESS; + PAACS_READ_BINDING_NONCE input = NULL; + PVOID outputBuffer = NULL; + + PAGED_CODE(); + + *DataLength = 0; + + status = WdfRequestRetrieveInputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.InputBufferLength, + (PVOID*)&input, + NULL); + + if (NT_SUCCESS(status)) + { + status = WdfRequestRetrieveOutputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, + (PVOID*)&outputBuffer, + NULL); + } + + if (NT_SUCCESS(status)) + { + ULONG dataTransferLength = sizeof(CDVD_KEY_HEADER) + sizeof(AACS_BINDING_NONCE); + CDB cdb; + + ScratchBuffer_BeginUse(DeviceExtension); + + RtlZeroMemory(&cdb, sizeof(CDB)); + // Set up the CDB + cdb.REPORT_KEY.OperationCode = SCSIOP_REPORT_KEY; + cdb.REPORT_KEY.LogicalBlockAddress[0] = (UCHAR)( input->StartLba >> (3*8) ); + cdb.REPORT_KEY.LogicalBlockAddress[1] = (UCHAR)( input->StartLba >> (2*8) ); + cdb.REPORT_KEY.LogicalBlockAddress[2] = (UCHAR)( input->StartLba >> (1*8) ); + cdb.REPORT_KEY.LogicalBlockAddress[3] = (UCHAR)( input->StartLba >> (0*8) ); + cdb.AsByte[6] = (UCHAR)( input->NumberOfSectors ); + cdb.AsByte[7] = 0x02; // AACS key class + cdb.REPORT_KEY.AllocationLength[0] = (UCHAR)(dataTransferLength >> (8*1)); + cdb.REPORT_KEY.AllocationLength[1] = (UCHAR)(dataTransferLength >> (8*0)); + cdb.REPORT_KEY.AGID = (UCHAR)( input->SessionId ); + cdb.REPORT_KEY.KeyFormat = 0x21; // Return an existing binding nonce + + status = ScratchBuffer_ExecuteCdb(DeviceExtension, Request, dataTransferLength, TRUE, &cdb, 12); + +#ifdef ENABLE_AACS_TESTING + static const UCHAR results[] = { 0x00, 0x22, 0x00, 0x00 }; + static const UCHAR defaultFill = 0x36; // '6' + RtlFillMemory(DeviceExtension->ScratchContext.ScratchBuffer, 0x0024, defaultFill); + RtlCopyMemory(DeviceExtension->ScratchContext.ScratchBuffer, results, SIZEOF_ARRAY(results)); + status = STATUS_SUCCESS; +#endif + if (NT_SUCCESS(status)) + { + PDVD_DESCRIPTOR_HEADER header = DeviceExtension->ScratchContext.ScratchBuffer; + ULONG dataLengthToCopy = sizeof(AACS_BINDING_NONCE); + + // make length field native byte ordering + REVERSE_SHORT(&header->Length); + + // exit if getting invalid data from the drive + if (header->Length < sizeof(DVD_DESCRIPTOR_HEADER) - RTL_SIZEOF_THROUGH_FIELD(DVD_DESCRIPTOR_HEADER, Length)) + { + *DataLength = 0; + status = STATUS_IO_DEVICE_ERROR; + } + + if (NT_SUCCESS(status)) + { + // adjust data length to reflect only the addition data + header->Length -= sizeof(DVD_DESCRIPTOR_HEADER) - RTL_SIZEOF_THROUGH_FIELD(DVD_DESCRIPTOR_HEADER, Length); + + // exit if the drive is returning an unexpected data size + if (header->Length != dataLengthToCopy) + { + *DataLength = 0; + status = STATUS_IO_DEVICE_ERROR; + } + } + + if (NT_SUCCESS(status)) + { + // else copy the data to the user's buffer + RtlCopyMemory(outputBuffer, header->Data, dataLengthToCopy); + *DataLength = dataLengthToCopy; + } + } + + ScratchBuffer_EndUse(DeviceExtension); + } + + return status; +} + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DeviceHandleAacsGenerateBindingNonce( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + This routine is used to process IOCTL: + IOCTL_AACS_GENERATE_BINDING_NONCE +Arguments: + DeviceExtension - device context + + Request - the request that will be formatted + + RequestParameters - request parameter structur + + DataLength - data transferred length + +Return Value: + NTSTATUS + + --*/ +{ + //AacsGenerateBindingNonce + + NTSTATUS status = STATUS_SUCCESS; + PAACS_READ_BINDING_NONCE input = NULL; + PVOID outputBuffer = NULL; + + PAGED_CODE(); + + *DataLength = 0; + + status = WdfRequestRetrieveInputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.InputBufferLength, + (PVOID*)&input, + NULL); + + if (NT_SUCCESS(status)) + { + status = WdfRequestRetrieveOutputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, + (PVOID*)&outputBuffer, + NULL); + } + + if (NT_SUCCESS(status)) + { + ULONG dataTransferLength = sizeof(CDVD_KEY_HEADER) + sizeof(AACS_BINDING_NONCE); + CDB cdb; + + ScratchBuffer_BeginUse(DeviceExtension); + + RtlZeroMemory(&cdb, sizeof(CDB)); + // Set up the CDB + + status = ScratchBuffer_ExecuteCdb(DeviceExtension, Request, dataTransferLength, TRUE, &cdb, 12); + +#ifdef ENABLE_AACS_TESTING + static const UCHAR results[] = { 0x00, 0x22, 0x00, 0x00 }; + static const UCHAR defaultFill = 0x37; // '7' + RtlFillMemory(DeviceExtension->ScratchContext.ScratchBuffer, 0x0024, defaultFill); + RtlCopyMemory(DeviceExtension->ScratchContext.ScratchBuffer, results, SIZEOF_ARRAY(results)); + status = STATUS_SUCCESS; +#endif + if (NT_SUCCESS(status)) + { + PDVD_DESCRIPTOR_HEADER header = DeviceExtension->ScratchContext.ScratchBuffer; + ULONG dataLengthToCopy = sizeof(AACS_BINDING_NONCE); + + // make length field native byte ordering + REVERSE_SHORT(&header->Length); + + // exit if getting invalid data from the drive + if (header->Length < sizeof(DVD_DESCRIPTOR_HEADER) - RTL_SIZEOF_THROUGH_FIELD(DVD_DESCRIPTOR_HEADER, Length)) + { + *DataLength = 0; + status = STATUS_IO_DEVICE_ERROR; + } + + if (NT_SUCCESS(status)) + { + // adjust data length to reflect only the addition data + header->Length -= sizeof(DVD_DESCRIPTOR_HEADER) - RTL_SIZEOF_THROUGH_FIELD(DVD_DESCRIPTOR_HEADER, Length); + + // exit if the drive is returning an unexpected data size + if (header->Length != dataLengthToCopy) + { + *DataLength = 0; + status = STATUS_IO_DEVICE_ERROR; + } + } + + if (NT_SUCCESS(status)) + { + // else copy the data to the user's buffer + RtlCopyMemory(outputBuffer, header->Data, dataLengthToCopy); + *DataLength = dataLengthToCopy; + } + } + + ScratchBuffer_EndUse(DeviceExtension); + } + + return status; +} + diff --git a/storage/class/cdrom/src/autorun.c b/storage/class/cdrom/src/autorun.c new file mode 100644 index 00000000..a1c6d9d9 --- /dev/null +++ b/storage/class/cdrom/src/autorun.c @@ -0,0 +1,3076 @@ +/*++ + +Copyright (C) Microsoft Corporation. All rights reserved. + +Module Name: + + autorun.c + +Abstract: + + Code for support of media change detection in the cd/dvd driver + +Environment: + + kernel mode only + +Notes: + + +Revision History: + +--*/ + +#include "stddef.h" +#include "string.h" + +#include "ntddk.h" +#include "ntddstor.h" +#include "cdrom.h" +#include "mmc.h" +#include "ioctl.h" + +#include "ntstrsafe.h" + +#ifdef DEBUG_USE_WPP +#include "autorun.tmh" +#endif + +#define GESN_TIMEOUT_VALUE (0x4) +#define GESN_BUFFER_SIZE (0x8) +#define GESN_DEVICE_BUSY_LOWER_THRESHOLD_100_MS (2) + +#define MAXIMUM_IMMEDIATE_MCN_RETRIES (0x20) +#define MCN_REG_SUBKEY_NAME (L"MediaChangeNotification") +#define MCN_REG_AUTORUN_DISABLE_INSTANCE_NAME (L"AlwaysDisableMCN") +#define MCN_REG_AUTORUN_ENABLE_INSTANCE_NAME (L"AlwaysEnableMCN") + +// +// Only send polling irp when device is fully powered up and a +// power down irp is not in progress. +// +// NOTE: This helps close a window in time where a polling irp could cause +// a drive to spin up right after it has powered down. The problem is +// that SCSIPORT, ATAPI and SBP2 will be in the process of powering +// down (which may take a few seconds), but won't know that. It would +// then get a polling irp which will be put into its queue since it +// the disk isn't powered down yet. Once the disk is powered down it +// will find the polling irp in the queue and then power up the +// device to do the poll. They do not want to check if the polling +// irp has the SRB_NO_KEEP_AWAKE flag here since it is in a critical +// path and would slow down all I/Os. A better way to fix this +// would be to serialize the polling and power down irps so that +// only one of them is sent to the device at a time. +// + +_IRQL_requires_max_(PASSIVE_LEVEL) +BOOLEAN +DeviceIsMediaChangeDisabledDueToHardwareLimitation( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +BOOLEAN +DeviceIsMediaChangeDisabledForClass( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +DeviceMediaChangeDeviceInstanceOverride( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _Out_ PBOOLEAN Enabled + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +DeviceInitializeMcn( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ BOOLEAN AllowDriveToSleep + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +DeviceInitializeGesn( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension + ); + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +GesnDataInterpret( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ PNOTIFICATION_EVENT_STATUS_HEADER Header, + _Out_ PBOOLEAN ResendImmediately + ); + +RTL_QUERY_REGISTRY_ROUTINE DeviceMediaChangeRegistryCallBack; + +EVT_WDF_WORKITEM DeviceDisableGesn; + +#if ALLOC_PRAGMA + +#pragma alloc_text(PAGE, DeviceInitializeMediaChangeDetection) +#pragma alloc_text(PAGE, DeviceEnableMediaChangeDetection) +#pragma alloc_text(PAGE, DeviceDisableMediaChangeDetection) +#pragma alloc_text(PAGE, DeviceSendDelayedMediaChangeNotifications) +#pragma alloc_text(PAGE, DeviceReleaseMcnResources) +#pragma alloc_text(PAGE, DeviceMediaChangeRegistryCallBack) +#pragma alloc_text(PAGE, DeviceInitializeMcn) +#pragma alloc_text(PAGE, DeviceDisableGesn) + +#pragma alloc_text(PAGE, DeviceIsMediaChangeDisabledDueToHardwareLimitation) +#pragma alloc_text(PAGE, DeviceMediaChangeDeviceInstanceOverride) +#pragma alloc_text(PAGE, DeviceIsMediaChangeDisabledForClass) + +#pragma alloc_text(PAGE, DeviceDisableMainTimer) + +#pragma alloc_text(PAGE, GesnDataInterpret) + +#pragma alloc_text(PAGE, RequestSetupMcnRequest) +#pragma alloc_text(PAGE, RequestPostWorkMcnRequest) +#pragma alloc_text(PAGE, RequestSendMcnRequest) + +// +// DeviceEnableMainTimer is called by EvtDeviceD0Entry which can't be made pageable +// so neither is DeviceEnableMainTimer +// +//#pragma alloc_text(PAGE, DeviceEnableMainTimer) + +#pragma alloc_text(PAGE, DeviceInitializeGesn) + +#pragma alloc_text(PAGE, RequestHandleMcnControl) + +#endif + +#pragma warning(push) +#pragma warning(disable:4152) // nonstandard extension, function/data pointer conversion in expression + + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +GesnDataInterpret( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ PNOTIFICATION_EVENT_STATUS_HEADER Header, + _Out_ PBOOLEAN ResendImmediately + ) +/*++ + +Routine Description: + + This routine will interpret the data returned for a GESN command, and + (if appropriate) set the media change event, and broadcast the + appropriate events to user mode for applications who care. + +Arguments: + + DeviceExtension - the device extension + + Header - the resulting data from a GESN event. + requires at least EIGHT valid bytes (header == 4, data == 4) + + ResendImmediately - whether or not to immediately resend the request. + this should be FALSE if there was no event, FALSE if the reported + event was of the DEVICE BUSY class, else true. + +Return Value: + + STATUS_SUCCESS if successful, an error code otherwise + +Notes: + + DataBuffer must be at least four bytes of valid data (header == 4 bytes), + and have at least eight bytes of allocated memory (all events == 4 bytes). + + The call to StartNextPacket may occur before this routine is completed. + the operational change notifications are informational in nature, and + while useful, are not neccessary to ensure proper operation. For example, + if the device morphs to no longer supporting WRITE commands, all further + write commands will fail. There exists a small timing window wherein + IOCTL_IS_DISK_WRITABLE may be called and get an incorrect response. If + a device supports software write protect, it is expected that the + application can handle such a case. + + NOTE: perhaps setting the updaterequired byte to one should be done here. + if so, it relies upon the setting of a 32-byte value to be an atomic + operation. unfortunately, there is no simple way to notify a class driver + which wants to know that the device behavior requires updating. + + Not ready events may be sent every second. For example, if we were + to minimize the number of asynchronous notifications, an application may + register just after a large busy time was reported. This would then + prevent the application from knowing the device was busy until some + arbitrarily chosen timeout has occurred. Also, the GESN request would + have to still occur, since it checks for non-busy events (such as user + keybutton presses and media change events) as well. The specification + states that the lower-numered events get reported first, so busy events, + while repeating, will only be reported when all other events have been + cleared from the device. + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PMEDIA_CHANGE_DETECTION_INFO info = DeviceExtension->MediaChangeDetectionInfo; + LONG dataLength = 0; + LONG requiredLength = 0; + BOOLEAN inHomePosition = FALSE; + + PAGED_CODE(); + + // note: don't allocate anything in this routine so that we can + // always just 'return'. + *ResendImmediately = FALSE; + + if (Header->NEA) + { + return status; + } + if (Header->NotificationClass == NOTIFICATION_NO_CLASS_EVENTS) + { + return status; + } + + // HACKHACK - REF #0001 + // This loop is only taken initially, due to the inability to reliably + // auto-detect drives that report events correctly at boot. When we + // detect this behavior during the normal course of running, we will + // disable the hack, allowing more efficient use of the system. This + // should occur "nearly" instantly, as the drive should have multiple + // events queue'd (ie. power, morphing, media). + if (info->Gesn.HackEventMask) + { + // all events use the low four bytes of zero to indicate + // that there was no change in status. + UCHAR thisEvent = Header->ClassEventData[0] & 0xf; + UCHAR lowestSetBit; + UCHAR thisEventBit = (1 << Header->NotificationClass); + + if (!TEST_FLAG(info->Gesn.EventMask, thisEventBit)) + { + // The drive is reporting an event that wasn't requested + return STATUS_DEVICE_PROTOCOL_ERROR; + } + + // some bit magic here... this results in the lowest set bit only + lowestSetBit = info->Gesn.EventMask; + lowestSetBit &= (info->Gesn.EventMask - 1); + lowestSetBit ^= (info->Gesn.EventMask); + + if (thisEventBit != lowestSetBit) + { + // HACKHACK - REF #0001 + // the first time we ever see an event set that is not the lowest + // set bit in the request (iow, highest priority), we know that the + // hack is no longer required, as the device is ignoring "no change" + // events when a real event is waiting in the other requested queues. + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, + "GESN::NONE: Compliant drive found, " + "removing GESN hack (%x, %x)\n", + thisEventBit, info->Gesn.EventMask)); + + info->Gesn.HackEventMask = FALSE; + } + else if (thisEvent == 0) // NOTIFICATION_*_EVENT_NO_CHANGE + { + // HACKHACK - REF #0001 + // note: this hack prevents poorly implemented firmware from constantly + // returning "No Event". we do this by cycling through the + // supported list of events here. + SET_FLAG(info->Gesn.NoChangeEventMask, thisEventBit); + CLEAR_FLAG(info->Gesn.EventMask, thisEventBit); + + // if we have cycled through all supported event types, then + // we need to reset the events we are asking about. else we + // want to resend this request immediately in case there was + // another event pending. + if (info->Gesn.EventMask == 0) + { + info->Gesn.EventMask = info->Gesn.NoChangeEventMask; + info->Gesn.NoChangeEventMask = 0; + } + else + { + *ResendImmediately = TRUE; + } + return status; + } + + } // end if (info->Gesn.HackEventMask) + + dataLength = (Header->EventDataLength[0] << 8) | + (Header->EventDataLength[1] & 0xff); + dataLength -= 2; + requiredLength = 4; // all events are four bytes + + if (dataLength < requiredLength) + { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_MCN, + "error - GESN returned only %x bytes data for fdo %p\n", + dataLength, DeviceExtension->DeviceObject)); + + return STATUS_DEVICE_PROTOCOL_ERROR; + } + + if (dataLength > requiredLength) + { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_MCN, + "error - GESN returned too many (%x) bytes data for fdo %p\n", + dataLength, DeviceExtension->DeviceObject)); + } + + if ((Header->ClassEventData[0] & 0xf) == 0) + { + // a zero event is a "no change event, so do not retry + return status; + } + + // because a event other than "no change" occurred, + // we should immediately resend this request. + *ResendImmediately = TRUE; + + switch (Header->NotificationClass) + { + + case NOTIFICATION_OPERATIONAL_CHANGE_CLASS_EVENTS: // 0x01 + { + PNOTIFICATION_OPERATIONAL_STATUS opChangeInfo = + (PNOTIFICATION_OPERATIONAL_STATUS)(Header->ClassEventData); + ULONG event; + + if (opChangeInfo->OperationalEvent == NOTIFICATION_OPERATIONAL_EVENT_CHANGE_REQUESTED) + { + break; + } + + event = (opChangeInfo->Operation[0] << 8) | + (opChangeInfo->Operation[1] ) ; + + // Workaround some hardware that is buggy but prevalent in the market + // This hardware has the property that it will report OpChange events repeatedly, + // causing us to retry immediately so quickly that we will eventually disable + // GESN to prevent an infinite loop. + // (only one valid OpChange event type now, only two ever defined) + if (info->MediaChangeRetryCount >= 4) + { + // + // HACKHACK - REF #0002 + // Some drives incorrectly report OpChange/Change (001b/0001h) events + // continuously when the tray has been ejected. This causes this routine + // to set ResendImmediately to "TRUE", and that results in our cycling + // 32 times immediately resending. At that point, we give up detecting + // the infinite retry loop, and disable GESN on these drives. This + // prevents Media Eject Request (from eject button) from being reported. + // Thus, instead we should attempt to workaround this issue by detecting + // this behavior. + // + + static UCHAR const OpChangeMask = 0x02; + + // At least one device reports "temporarily busy" (which is useless) on eject + // At least one device reports "OpChange" repeatedly when re-inserting media + // All seem to work well using this workaround + + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_MCN, + "GESN OpChange events are broken. Working around this problem in software (for WDFDEVICE %p)\n", + DeviceExtension->Device)); + + // OpChange is not the only bit set -- Media class is required.... + NT_ASSERT(CountOfSetBitsUChar(info->Gesn.EventMask) != 1); + + // Force the use of the hackhack (ref #0001) to workaround the + // issue noted this hackhack (ref #0002). + SET_FLAG(info->Gesn.NoChangeEventMask, OpChangeMask); + CLEAR_FLAG(info->Gesn.EventMask, OpChangeMask); + info->Gesn.HackEventMask = TRUE; + + // don't request the opChange event again. use the method + // defined by hackhack (ref #0001) as the workaround. + if (info->Gesn.EventMask == 0) + { + info->Gesn.EventMask = info->Gesn.NoChangeEventMask; + info->Gesn.NoChangeEventMask = 0; + *ResendImmediately = FALSE; + } + else + { + *ResendImmediately = TRUE; + } + + break; + } + + + if ((event == NOTIFICATION_OPERATIONAL_OPCODE_FEATURE_ADDED) | + (event == NOTIFICATION_OPERATIONAL_OPCODE_FEATURE_CHANGE)) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, + "GESN says features added/changed for WDFDEVICE %p\n", + DeviceExtension->Device)); + + // don't notify that new media arrived, just set the + // DO_VERIFY to force a FS reload. + + if (IsVolumeMounted(DeviceExtension->DeviceObject)) + { + SET_FLAG(DeviceExtension->DeviceObject->Flags, DO_VERIFY_VOLUME); + } + + // Call error handler with + // a "fake" media change error in case it needs to update + // internal structures as though a media change occurred. + { + SCSI_REQUEST_BLOCK srb = {0}; + SENSE_DATA sense = {0}; + NTSTATUS tempStatus; + BOOLEAN retry; + + tempStatus = STATUS_MEDIA_CHANGED; + retry = FALSE; + + srb.CdbLength = 6; + srb.Length = sizeof(SCSI_REQUEST_BLOCK); + srb.SrbStatus = SRB_STATUS_AUTOSENSE_VALID | SRB_STATUS_ERROR; + srb.SenseInfoBuffer = &sense; + srb.SenseInfoBufferLength = sizeof(SENSE_DATA); + + sense.AdditionalSenseLength = sizeof(SENSE_DATA) - + RTL_SIZEOF_THROUGH_FIELD(SENSE_DATA, AdditionalSenseLength); + + sense.SenseKey = SCSI_SENSE_UNIT_ATTENTION; + sense.AdditionalSenseCode = SCSI_ADSENSE_MEDIUM_CHANGED; + + if (DeviceExtension->DeviceAdditionalData.ErrorHandler) + { + DeviceExtension->DeviceAdditionalData.ErrorHandler(DeviceExtension, + &srb, + &tempStatus, + &retry); + } + } // end error handler + + } + break; + } + + case NOTIFICATION_EXTERNAL_REQUEST_CLASS_EVENTS: // 0x3 + { + PNOTIFICATION_EXTERNAL_STATUS externalInfo = + (PNOTIFICATION_EXTERNAL_STATUS)(Header->ClassEventData); + DEVICE_EVENT_EXTERNAL_REQUEST externalData = {0}; + + // unfortunately, due to time constraints, we will only notify + // about keys being pressed, and not released. this makes keys + // single-function, but simplifies the code significantly. + if (externalInfo->ExternalEvent != NOTIFICATION_EXTERNAL_EVENT_BUTTON_DOWN) + { + break; + } + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, + "GESN::EXTERNAL: Event: %x Status %x Req %x\n", + externalInfo->ExternalEvent, externalInfo->ExternalStatus, + (externalInfo->Request[0] << 8) | externalInfo->Request[1] + )); + + externalData.Version = 1; + externalData.DeviceClass = 0; + externalData.ButtonStatus = externalInfo->ExternalEvent; + externalData.Request = (externalInfo->Request[0] << 8) | + (externalInfo->Request[1] & 0xff); + KeQuerySystemTime(&(externalData.SystemTime)); + externalData.SystemTime.QuadPart *= (LONGLONG)KeQueryTimeIncrement(); + + DeviceSendNotification(DeviceExtension, + &GUID_IO_DEVICE_EXTERNAL_REQUEST, + sizeof(DEVICE_EVENT_EXTERNAL_REQUEST), + &externalData); + + return status; + } + + case NOTIFICATION_MEDIA_STATUS_CLASS_EVENTS: // 0x4 + { + PNOTIFICATION_MEDIA_STATUS mediaInfo = + (PNOTIFICATION_MEDIA_STATUS)(Header->ClassEventData); + + if ((mediaInfo->MediaEvent == NOTIFICATION_MEDIA_EVENT_NEW_MEDIA) || + (mediaInfo->MediaEvent == NOTIFICATION_MEDIA_EVENT_MEDIA_CHANGE)) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, + "GESN::MEDIA ARRIVAL, Status %x\n", + mediaInfo->MediaStatus)); + + if (IsVolumeMounted(DeviceExtension->DeviceObject)) + { + SET_FLAG(DeviceExtension->DeviceObject->Flags, DO_VERIFY_VOLUME); + } + DeviceSetMediaChangeStateEx(DeviceExtension, + MediaPresent, + NULL); + + // If media is inserted into slot loading type, mark the device active + // to not power off. + if ((DeviceExtension->ZeroPowerODDInfo != NULL) && + (DeviceExtension->ZeroPowerODDInfo->LoadingMechanism == LOADING_MECHANISM_CADDY) && + (DeviceExtension->ZeroPowerODDInfo->Load == 0)) // Slot + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, + "GesnDataInterpret: MediaArrival event detected, device marked as active\n")); + + DeviceMarkActive(DeviceExtension, TRUE, FALSE); + } + } + else if (mediaInfo->MediaEvent == NOTIFICATION_MEDIA_EVENT_MEDIA_REMOVAL) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, + "GESN::MEDIA REMOVAL, Status %x\n", + mediaInfo->MediaStatus)); + + DeviceSetMediaChangeStateEx(DeviceExtension, + MediaNotPresent, + NULL); + + // If media is removed from slot loading type, start powering off the device + // if it is ZPODD capable. + if ((DeviceExtension->ZeroPowerODDInfo != NULL) && + (DeviceExtension->ZeroPowerODDInfo->LoadingMechanism == LOADING_MECHANISM_CADDY) && + (DeviceExtension->ZeroPowerODDInfo->Load == 0)) // Slot + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, + "GesnDataInterpret: MediaRemoval event detected, device marked as idle\n")); + + DeviceMarkActive(DeviceExtension, FALSE, FALSE); + } + } + else if (mediaInfo->MediaEvent == NOTIFICATION_MEDIA_EVENT_EJECT_REQUEST) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, + "GESN::MEDIA EJECTION, Status %x\n", + mediaInfo->MediaStatus)); + + DeviceSendNotification(DeviceExtension, + &GUID_IO_MEDIA_EJECT_REQUEST, + 0, + NULL); + } + + break; + } + + case NOTIFICATION_DEVICE_BUSY_CLASS_EVENTS: // lowest priority events... + { + PNOTIFICATION_BUSY_STATUS busyInfo = + (PNOTIFICATION_BUSY_STATUS)(Header->ClassEventData); + DEVICE_EVENT_BECOMING_READY busyData = {0}; + + // else we want to report the approximated time till it's ready. + busyData.Version = 1; + busyData.Reason = busyInfo->DeviceBusyStatus; + busyData.Estimated100msToReady = (busyInfo->Time[0] << 8) | + (busyInfo->Time[1] & 0xff); + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, + "GESN::BUSY: Event: %x Status %x Time %x\n", + busyInfo->DeviceBusyEvent, busyInfo->DeviceBusyStatus, + busyData.Estimated100msToReady + )); + + // Ignore the notification if the time is small + if (busyData.Estimated100msToReady >= GESN_DEVICE_BUSY_LOWER_THRESHOLD_100_MS) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, + "GesnDataInterpret: media BECOMING_READY\n")); + + DeviceSendNotification(DeviceExtension, + &GUID_IO_DEVICE_BECOMING_READY, + sizeof(DEVICE_EVENT_BECOMING_READY), + &busyData); + } + + // If manual loading operation is observed for slot loading type, start powering off the device + // if it is ZPODD capable. + if ((DeviceExtension->ZeroPowerODDInfo != NULL) && + (DeviceExtension->ZeroPowerODDInfo->LoadingMechanism == LOADING_MECHANISM_TRAY) && + (DeviceExtension->ZeroPowerODDInfo->Load == 0) && // Drawer + (busyInfo->DeviceBusyEvent == NOTIFICATION_BUSY_EVENT_LO_CHANGE) && + (busyInfo->DeviceBusyStatus == NOTIFICATION_BUSY_STATUS_NO_EVENT)) + { + inHomePosition = DeviceZPODDIsInHomePosition(DeviceExtension); + + if (inHomePosition == FALSE) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, + "GesnDataInterpret: LoChange event detected, device marked as active\n")); + + DeviceMarkActive(DeviceExtension, TRUE, FALSE); + } + else + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, + "GesnDataInterpret: LoChange event detected, device marked as idle\n")); + + DeviceMarkActive(DeviceExtension, FALSE, FALSE); + } + } + + break; + } + + default: + { + break; + } + + } // end switch on notification class + + return status; +} + + +VOID +DeviceInternalSetMediaChangeState( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ MEDIA_CHANGE_DETECTION_STATE NewState, + _Inout_opt_ PMEDIA_CHANGE_DETECTION_STATE OldState + ) +/*++ + +Routine Description: + + This routine will (if appropriate) set the media change event for the + device. The event will be set if the media state is changed and + media change events are enabled. Otherwise the media state will be + tracked but the event will not be set. + + This routine will lock out the other media change routines if possible + but if not a media change notification may be lost after the enable has + been completed. + +Arguments: + + DeviceExtension - the device extension + + NewState - new state for setting + + OldState - optional storage for the old state + +Return Value: + + none + +--*/ +{ +#if DBG + LPCSTR states[] = {"Unknown", "Present", "Not Present", "Unavailable"}; +#endif + MEDIA_CHANGE_DETECTION_STATE oldMediaState; + PMEDIA_CHANGE_DETECTION_INFO info = DeviceExtension->MediaChangeDetectionInfo; + CLASS_MEDIA_CHANGE_CONTEXT mcnContext; + + if (!((NewState >= MediaUnknown) && (NewState <= MediaUnavailable))) + { + return; + } + + if (info == NULL) + { + return; + } + + oldMediaState = info->LastKnownMediaDetectionState; + if (OldState) + { + *OldState = oldMediaState; + } + + info->LastKnownMediaDetectionState = NewState; + + // Increment MediaChangeCount on transition to MediaPresent + if (NewState == MediaPresent && oldMediaState != NewState) + { + InterlockedIncrement((PLONG)&DeviceExtension->MediaChangeCount); + } + + if (info->MediaChangeDetectionDisableCount != 0) + { +#if DBG + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, + "DeviceInternalSetMediaChangeState: MCN not enabled, state " + "changed from %s to %s\n", + states[oldMediaState], states[NewState])); +#endif + return; + } +#if DBG + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, + "DeviceInternalSetMediaChangeState: State change from %s to %s\n", + states[oldMediaState], states[NewState])); +#endif + + if (info->LastReportedMediaDetectionState == info->LastKnownMediaDetectionState) + { + // Media is in the same state as we reported last time, no need to report again. + return; + } + + // make the data useful -- it used to always be zero. + mcnContext.MediaChangeCount = DeviceExtension->MediaChangeCount; + mcnContext.NewState = NewState; + + if (NewState == MediaPresent) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, + "DeviceInternalSetMediaChangeState: Reporting media ARRIVAL\n")); + + DeviceSendNotification(DeviceExtension, + &GUID_IO_MEDIA_ARRIVAL, + sizeof(CLASS_MEDIA_CHANGE_CONTEXT), + &mcnContext); + } + else if ((NewState == MediaNotPresent) || (NewState == MediaUnavailable)) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, + "DeviceInternalSetMediaChangeState: Reporting media REMOVAL\n")); + DeviceSendNotification(DeviceExtension, + &GUID_IO_MEDIA_REMOVAL, + sizeof(CLASS_MEDIA_CHANGE_CONTEXT), + &mcnContext); + } + else + { + // Don't notify of changed going to unknown. + return; + } + + info->LastReportedMediaDetectionState = info->LastKnownMediaDetectionState; + + return; +} // end DeviceInternalSetMediaChangeState() + + +VOID +DeviceSetMediaChangeStateEx( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ MEDIA_CHANGE_DETECTION_STATE NewState, + _Inout_opt_ PMEDIA_CHANGE_DETECTION_STATE OldState + ) +/*++ + +Routine Description: + + This routine will (if appropriate) set the media change event for the + device. The event will be set if the media state is changed and + media change events are enabled. Otherwise the media state will be + tracked but the event will not be set. + +Arguments: + + DeviceExtension - the device extension + + NewState - new state for setting + + OldState - optional storage for the old state + +Return Value: + + none + +--*/ +{ + PMEDIA_CHANGE_DETECTION_INFO info = DeviceExtension->MediaChangeDetectionInfo; + LARGE_INTEGER zero; + NTSTATUS status; + + // timeout value must be 0, as this function can be called at DISPATCH_LEVEL. + zero.QuadPart = 0; + + if (info == NULL) + { + return; + } + + status = KeWaitForMutexObject(&info->MediaChangeMutex, + Executive, + KernelMode, + FALSE, + &zero); + + if (status == STATUS_TIMEOUT) + { + // Someone else is in the process of setting the media state. + return; + } + + // Change the media present state and signal an event, if applicable + DeviceInternalSetMediaChangeState(DeviceExtension, NewState, OldState); + + KeReleaseMutex(&info->MediaChangeMutex, FALSE); + + return; +} // end DeviceSetMediaChangeStateEx() + + +_IRQL_requires_max_(APC_LEVEL) +VOID +DeviceSendDelayedMediaChangeNotifications( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension + ) +/*++ + +Routine Description: + + This routine sends the so-called delayed media change notifications. + These notifications get accumulated while the MCN mechanism is disabled + and need to be sent to the application on MCN enabling, if MCN enabling + happens as a part of exclusive access unlock and the application has not + requested us explicitly to not send the delayed notifications. + +Arguments: + + DeviceExtension - the device extension + +Return Value: + + none + +--*/ +{ + PMEDIA_CHANGE_DETECTION_INFO info = DeviceExtension->MediaChangeDetectionInfo; + LARGE_INTEGER zero; + NTSTATUS status; + + PAGED_CODE(); + + zero.QuadPart = 0; + + if (info == NULL) + { + return; + } + + status = KeWaitForMutexObject(&info->MediaChangeMutex, + Executive, + KernelMode, + FALSE, + &zero); + + if (status == STATUS_TIMEOUT) + { + // Someone else is in the process of setting the media state. + // That's totally okay, we'll send delayed notifications later. + return; + } + + // If the last reported state and the last known state are different and + // MCN is enabled, generate a notification based on the last known state. + if ((info->LastKnownMediaDetectionState != info->LastReportedMediaDetectionState) && + (info->MediaChangeDetectionDisableCount == 0)) + { + DeviceInternalSetMediaChangeState(DeviceExtension, info->LastKnownMediaDetectionState, NULL); + } + + KeReleaseMutex(&info->MediaChangeMutex, FALSE); + + return; +} + + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +RequestSetupMcnRequest( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ BOOLEAN UseGesn +) +/*++ + +Routine Description: + + This routine sets up the fields of the request for MCN + +Arguments: + DeviceExtension - device context + + UseGesn - If TRUE, the device supports GESN and it's currently the mechanism for MCN + +Return Value: + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PSCSI_REQUEST_BLOCK srb; + PIRP irp; + PIO_STACK_LOCATION nextIrpStack; + PCDB cdb; + PVOID buffer; + WDF_REQUEST_REUSE_PARAMS params; + PMEDIA_CHANGE_DETECTION_INFO info = DeviceExtension->MediaChangeDetectionInfo; + + PAGED_CODE(); + + irp = WdfRequestWdmGetIrp(info->MediaChangeRequest); + NT_ASSERT(irp != NULL); + + // deassign the MdlAddress, this is the value we assign explicitly. + // this is to prevent WdfRequestReuse to release the Mdl unexpectly. + if (irp->MdlAddress) + { + irp->MdlAddress = NULL; + } + + if (NT_SUCCESS(status)) + { + // Setup the IRP to perform a test unit ready. + WDF_REQUEST_REUSE_PARAMS_INIT(¶ms, + WDF_REQUEST_REUSE_NO_FLAGS, + STATUS_NOT_SUPPORTED); + + status = WdfRequestReuse(info->MediaChangeRequest, ¶ms); + } + + if (NT_SUCCESS(status)) + { + // Format the request. + status = WdfIoTargetFormatRequestForInternalIoctlOthers(DeviceExtension->IoTarget, + info->MediaChangeRequest, + IOCTL_SCSI_EXECUTE_IN, + NULL, NULL, + NULL, NULL, + NULL, NULL); + + if (!NT_SUCCESS(status)) + { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, + "RequestSetupMcnRequest: WdfIoTargetFormatRequestForInternalIoctlOthers failed, %!STATUS!\n", + status)); + } + } + + if (NT_SUCCESS(status)) + { + RequestClearSendTime(info->MediaChangeRequest); + + nextIrpStack = IoGetNextIrpStackLocation(irp); + + nextIrpStack->Flags = SL_OVERRIDE_VERIFY_VOLUME; + nextIrpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; + nextIrpStack->Parameters.Scsi.Srb = &(info->MediaChangeSrb); + + // Prepare the SRB for execution. + srb = nextIrpStack->Parameters.Scsi.Srb; + buffer = info->SenseBuffer; + RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK)); + RtlZeroMemory(buffer, SENSE_BUFFER_SIZE); + + srb->QueueTag = SP_UNTAGGED; + srb->QueueAction = SRB_SIMPLE_TAG_REQUEST; + srb->Length = sizeof(SCSI_REQUEST_BLOCK); + srb->Function = SRB_FUNCTION_EXECUTE_SCSI; + srb->SenseInfoBuffer = buffer; + srb->SrbStatus = 0; + srb->ScsiStatus = 0; + srb->OriginalRequest = irp; + srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE; + + srb->SrbFlags = DeviceExtension->SrbFlags; + SET_FLAG(srb->SrbFlags, info->SrbFlags); + + if (!UseGesn) + { + srb->TimeOutValue = CDROM_TEST_UNIT_READY_TIMEOUT; + srb->CdbLength = 6; + srb->DataTransferLength = 0; + SET_FLAG(srb->SrbFlags, SRB_FLAGS_NO_DATA_TRANSFER); + nextIrpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_NONE; + srb->DataBuffer = NULL; + srb->DataTransferLength = 0; + irp->MdlAddress = NULL; + + cdb = (PCDB) &srb->Cdb[0]; + cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY; + } + else + { + NT_ASSERT(info->Gesn.Buffer); + + srb->TimeOutValue = GESN_TIMEOUT_VALUE; // much shorter timeout for GESN + + srb->CdbLength = 10; + SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_IN); + nextIrpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_IN; + srb->DataBuffer = info->Gesn.Buffer; + srb->DataTransferLength = info->Gesn.BufferSize; + irp->MdlAddress = info->Gesn.Mdl; + + cdb = (PCDB) &srb->Cdb[0]; + cdb->GET_EVENT_STATUS_NOTIFICATION.OperationCode = SCSIOP_GET_EVENT_STATUS; + cdb->GET_EVENT_STATUS_NOTIFICATION.Immediate = 1; + cdb->GET_EVENT_STATUS_NOTIFICATION.EventListLength[0] = (UCHAR)((info->Gesn.BufferSize) >> 8); + cdb->GET_EVENT_STATUS_NOTIFICATION.EventListLength[1] = (UCHAR)((info->Gesn.BufferSize) & 0xff); + cdb->GET_EVENT_STATUS_NOTIFICATION.NotificationClassRequest = info->Gesn.EventMask; + } + } + + return status; +} + + +VOID +DeviceDisableGesn( + _In_ WDFWORKITEM WorkItem + ) +/*++ + +Routine Description: + + Work item routine to set the hack flag in the registry to disable GESN + This routine is invoked when the device reports TOO many events that affects system + +Arguments: + WorkItem - the work item be perfromed. + +Return Value: + None + +--*/ +{ + WDFDEVICE device = WdfWorkItemGetParentObject(WorkItem); + PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(device); + + PAGED_CODE(); + + // + // Set the hack flag in the registry + // + DeviceSetParameter(deviceExtension, + CLASSP_REG_SUBKEY_NAME, + CLASSP_REG_MMC_DETECTION_VALUE_NAME, + CdromDetectionUnsupported); + + WdfObjectDelete(WorkItem); + + return; +} + +_IRQL_requires_max_(APC_LEVEL) +BOOLEAN +RequestPostWorkMcnRequest( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension + ) +/*++ + +Routine Description: + + This routine handles the completion of the test unit ready irps used to + determine if the media has changed. If the media has changed, this code + signals the named event to wake up other system services that react to + media change (aka AutoPlay). + +Arguments: + + DeviceExtension - the device context + +Return Value: + + BOOLEAN - TRUE (needs retry); FALSE (shoule not retry) + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PMEDIA_CHANGE_DETECTION_INFO info = DeviceExtension->MediaChangeDetectionInfo; + PIRP irp; + BOOLEAN retryImmediately = FALSE; + + PAGED_CODE(); + + NT_ASSERT(info->MediaChangeRequest != NULL); + irp = WdfRequestWdmGetIrp(info->MediaChangeRequest); + + NT_ASSERT(!TEST_FLAG(info->MediaChangeSrb.SrbStatus, SRB_STATUS_QUEUE_FROZEN)); + + // use InterpretSenseInfo routine to check for media state, and also + // to call ClassError() with correct parameters. + if (SRB_STATUS(info->MediaChangeSrb.SrbStatus) != SRB_STATUS_SUCCESS) + { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_MCN, "MCN request - failed - srb status=%x, sense=%x/%x/%x.\n", + info->MediaChangeSrb.SrbStatus, + ((PSENSE_DATA)(info->MediaChangeSrb.SenseInfoBuffer))->SenseKey, + ((PSENSE_DATA)(info->MediaChangeSrb.SenseInfoBuffer))->AdditionalSenseCode, + ((PSENSE_DATA)(info->MediaChangeSrb.SenseInfoBuffer))->AdditionalSenseCodeQualifier)); + + if (SRB_STATUS(info->MediaChangeSrb.SrbStatus) != SRB_STATUS_NOT_POWERED) + { + // Release the queue if it is frozen. + if (info->MediaChangeSrb.SrbStatus & SRB_STATUS_QUEUE_FROZEN) + { + DeviceReleaseQueue(DeviceExtension->Device); + } + + RequestSenseInfoInterpret(DeviceExtension, + info->MediaChangeRequest, + &info->MediaChangeSrb, + 0, + &status, + NULL); + } + } + else + { + DeviceExtension->PrivateFdoData->LoggedTURFailureSinceLastIO = FALSE; + + if (!info->Gesn.Supported) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, + "MCN request - succeeded (GESN NOT supported, setting MediaPresent).\n")); + + // success != media for GESN case + DeviceSetMediaChangeStateEx(DeviceExtension, + MediaPresent, + NULL); + } + else + { + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_MCN, + "MCN request - succeeded (GESN supported).\n")); + } + } + + if (info->Gesn.Supported) + { + if (status == STATUS_DATA_OVERRUN) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, "MCN Request - Data Overrun\n")); + status = STATUS_SUCCESS; + } + + if (!NT_SUCCESS(status)) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, "MCN Request: GESN failed with status %x\n", status)); + } + else + { + // for GESN, need to interpret the results of the data. + // this may also require an immediate retry + if (irp->IoStatus.Information == 8 ) + { + GesnDataInterpret(DeviceExtension, + (PVOID)info->Gesn.Buffer, + &retryImmediately); + } + + } // end of NT_SUCCESS(status) + + } // end of Info->Gesn.Supported + + // free port-allocated sense buffer, if any. + if (PORT_ALLOCATED_SENSE(DeviceExtension, &info->MediaChangeSrb)) + { + FREE_PORT_ALLOCATED_SENSE_BUFFER(DeviceExtension, &info->MediaChangeSrb); + } + + // Remember the IRP and SRB for use the next time. + NT_ASSERT(IoGetNextIrpStackLocation(irp)); + IoGetNextIrpStackLocation(irp)->Parameters.Scsi.Srb = &info->MediaChangeSrb; + + // run a sanity check to make sure we're not recursing continuously + if (retryImmediately) + { + info->MediaChangeRetryCount++; + + if (info->MediaChangeRetryCount > MAXIMUM_IMMEDIATE_MCN_RETRIES) + { + // Disable GESN on this device. + // Create a work item to set the value in the registry + WDF_OBJECT_ATTRIBUTES attributes; + WDF_WORKITEM_CONFIG workitemConfig; + WDFWORKITEM workItem; + + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + attributes.ParentObject = DeviceExtension->Device; + + WDF_WORKITEM_CONFIG_INIT(&workitemConfig, DeviceDisableGesn); + workitemConfig.AutomaticSerialization = FALSE; + + status = WdfWorkItemCreate(&workitemConfig, + &attributes, + &workItem); + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, "MCN Request: Disabling GESN for WDFDEVICE %p\n", DeviceExtension->Device)); + + if (NT_SUCCESS(status)) + { + WdfWorkItemEnqueue(workItem); + } + + info->Gesn.Supported = FALSE; + info->Gesn.EventMask = 0; + info->Gesn.BufferSize = 0; + info->MediaChangeRetryCount = 0; + retryImmediately = FALSE; + // should we log an error in event log? + } + } + else + { + info->MediaChangeRetryCount = 0; + } + + return retryImmediately; +} + + +_IRQL_requires_max_(APC_LEVEL) +BOOLEAN +RequestSendMcnRequest( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension + ) +/*++ + +Routine Description: + + This routine sends the formatted MCN request sychronizely to lower driver. + +Arguments: + + DeviceExtension - the device context + +Return Value: + BOOLEAN - TRUE (requst successfully sent); FALSE (request failed to send) + +--*/ +{ + BOOLEAN requestSent = FALSE; + PMEDIA_CHANGE_DETECTION_INFO info = DeviceExtension->MediaChangeDetectionInfo; + + PAGED_CODE(); + + RequestSend(DeviceExtension, + info->MediaChangeRequest, + DeviceExtension->IoTarget, + WDF_REQUEST_SEND_OPTION_SYNCHRONOUS, + &requestSent); + + return requestSent; +} // end RequestSendMcnRequest() + + + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +DeviceInitializeMcn( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ BOOLEAN AllowDriveToSleep + ) +/*++ + +Routine Description: + + This routine initialize the contents of MCN structure. + +Arguments: + + DeviceExtension - the device extension + + AllowDriveToSleep - for CDROM, this parameter should be always FALSE + +Return Value: + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PMEDIA_CHANGE_DETECTION_INFO mediaChangeInfo = NULL; + PIRP irp = NULL; + PVOID senseBuffer = NULL; + WDF_OBJECT_ATTRIBUTES attributes; + + PAGED_CODE(); + + if (DeviceExtension->MediaChangeDetectionInfo != NULL) + { + //Already initialized. + return STATUS_SUCCESS; + } + + DeviceExtension->KernelModeMcnContext.FileObject = (PVOID)-1; + DeviceExtension->KernelModeMcnContext.DeviceObject = (PVOID)-1; + DeviceExtension->KernelModeMcnContext.LockCount = 0; + DeviceExtension->KernelModeMcnContext.McnDisableCount = 0; + + mediaChangeInfo = ExAllocatePoolWithTag(NonPagedPoolNx, + sizeof(MEDIA_CHANGE_DETECTION_INFO), + CDROM_TAG_MEDIA_CHANGE_DETECTION); + + if (mediaChangeInfo == NULL) + { + status = STATUS_INSUFFICIENT_RESOURCES; + } + else + { + RtlZeroMemory(mediaChangeInfo, sizeof(MEDIA_CHANGE_DETECTION_INFO)); + } + + if (NT_SUCCESS(status)) + { + if ((DeviceExtension->PowerDescriptor != NULL) && + (DeviceExtension->PowerDescriptor->AsynchronousNotificationSupported != FALSE) && + (!TEST_FLAG(DeviceExtension->PrivateFdoData->HackFlags, FDO_HACK_NO_ASYNCHRONOUS_NOTIFICATION))) + { + mediaChangeInfo->AsynchronousNotificationSupported = TRUE; + } + } + + // Allocate an IRP to carry the IOCTL_MCN_SYNC_FAKE_IOCTL. + if (NT_SUCCESS(status)) + { + irp = IoAllocateIrp(DeviceExtension->DeviceObject->StackSize, FALSE); + + if (irp == NULL) + { + status = STATUS_INSUFFICIENT_RESOURCES; + } + } + + if (NT_SUCCESS(status)) + { + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, + CDROM_REQUEST_CONTEXT); + attributes.ParentObject = DeviceExtension->Device; + status = WdfRequestCreate(&attributes, + DeviceExtension->IoTarget, + &mediaChangeInfo->MediaChangeRequest); + } + + if (NT_SUCCESS(status)) + { + // Preformat the media change request. With this being done, we never need to worry about + // WdfIoTargetFormatRequestForInternalIoctlOthers ever failing later. + status = WdfIoTargetFormatRequestForInternalIoctlOthers(DeviceExtension->IoTarget, + mediaChangeInfo->MediaChangeRequest, + IOCTL_SCSI_EXECUTE_IN, + NULL, NULL, + NULL, NULL, + NULL, NULL); + } + + if (NT_SUCCESS(status)) + { + senseBuffer = ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned, + SENSE_BUFFER_SIZE, + CDROM_TAG_MEDIA_CHANGE_DETECTION); + if (senseBuffer == NULL) + { + status = STATUS_INSUFFICIENT_RESOURCES; + } + } + + if (NT_SUCCESS(status)) + { + mediaChangeInfo->MediaChangeSyncIrp = irp; + mediaChangeInfo->SenseBuffer = senseBuffer; + + // Set default values for the media change notification + // configuration. + mediaChangeInfo->MediaChangeDetectionDisableCount = 0; + + // Assume that there is initially no media in the device + // only notify upper layers if there is something there + mediaChangeInfo->LastKnownMediaDetectionState = MediaUnknown; + mediaChangeInfo->LastReportedMediaDetectionState = MediaUnknown; + + // setup all extra flags we'll be setting for this irp + mediaChangeInfo->SrbFlags = 0; + + SET_FLAG(mediaChangeInfo->SrbFlags, SRB_CLASS_FLAGS_LOW_PRIORITY); + SET_FLAG(mediaChangeInfo->SrbFlags, SRB_FLAGS_NO_QUEUE_FREEZE); + SET_FLAG(mediaChangeInfo->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER); + + if (AllowDriveToSleep) //FALSE for CD/DVD devices + { + SET_FLAG(mediaChangeInfo->SrbFlags, SRB_FLAGS_NO_KEEP_AWAKE); + } + + KeInitializeMutex(&mediaChangeInfo->MediaChangeMutex, 0x100); + + // It is ok to support media change events on this device. + DeviceExtension->MediaChangeDetectionInfo = mediaChangeInfo; + + // check the device supports GESN or not, initialize GESN structure if it supports. + { + // This is only valid for type5 devices. + NTSTATUS tempStatus = STATUS_SUCCESS; + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, + "DeviceInitializeMcn: Testing for GESN\n")); + tempStatus = DeviceInitializeGesn(DeviceExtension); + + if (NT_SUCCESS(tempStatus)) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, + "DeviceInitializeMcn: GESN available for %p\n", + DeviceExtension->DeviceObject)); + NT_ASSERT(mediaChangeInfo->Gesn.Supported ); + NT_ASSERT(mediaChangeInfo->Gesn.Buffer != NULL); + NT_ASSERT(mediaChangeInfo->Gesn.BufferSize != 0); + NT_ASSERT(mediaChangeInfo->Gesn.EventMask != 0); + } + else + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, + "DeviceInitializeMcn: GESN *NOT* available for %p\n", + DeviceExtension->DeviceObject)); + NT_ASSERT(!mediaChangeInfo->Gesn.Supported); + NT_ASSERT(mediaChangeInfo->Gesn.Buffer == NULL); + NT_ASSERT(mediaChangeInfo->Gesn.BufferSize == 0); + NT_ASSERT(mediaChangeInfo->Gesn.EventMask == 0); + mediaChangeInfo->Gesn.Supported = FALSE; // just in case.... + } + } + } + + if (NT_SUCCESS(status)) + { + // Register for display state change on AOAC capable systems so we can put the + // device to low power state when not required. + if (mediaChangeInfo->DisplayStateCallbackHandle == NULL) + { + POWER_PLATFORM_INFORMATION PlatformInfo = {0}; + + status = ZwPowerInformation(PlatformInformation, + NULL, + 0, + &PlatformInfo, + sizeof(PlatformInfo)); + + if (NT_SUCCESS(status) && PlatformInfo.AoAc) + { + PoRegisterPowerSettingCallback(DeviceExtension->DeviceObject, + &GUID_CONSOLE_DISPLAY_STATE, + &DevicePowerSettingCallback, + DeviceExtension, + &mediaChangeInfo->DisplayStateCallbackHandle); + } + + // Ignore any failures above. + status = STATUS_SUCCESS; + } + } + + if (!NT_SUCCESS(status)) + { + if (irp != NULL) + { + IoFreeIrp(irp); + } + FREE_POOL(senseBuffer); + FREE_POOL(mediaChangeInfo); + } + + return status; + +} // end DeviceInitializeMcn() + + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +DeviceInitializeGesn( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension + ) +/*++ + +Routine Description: + + This routine initialize the contents of GESN structure. + +Arguments: + + DeviceExtension - the device extension + +Return Value: + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PNOTIFICATION_EVENT_STATUS_HEADER header = NULL; + CDROM_DETECTION_STATE detectionState = CdromDetectionUnknown; + PSTORAGE_DEVICE_DESCRIPTOR deviceDescriptor = DeviceExtension->DeviceDescriptor; + BOOLEAN retryImmediately = TRUE; + ULONG i = 0; + ULONG atapiResets = 0; + PMEDIA_CHANGE_DETECTION_INFO info = DeviceExtension->MediaChangeDetectionInfo; + + PAGED_CODE(); + + NT_ASSERT(info != NULL); + + // read if we already know the abilities of the device + DeviceGetParameter(DeviceExtension, + CLASSP_REG_SUBKEY_NAME, + CLASSP_REG_MMC_DETECTION_VALUE_NAME, + (PULONG)&detectionState); + + if (detectionState == CdromDetectionUnsupported) + { + status = STATUS_NOT_SUPPORTED; + } + + // check if the device has a hack flag saying never to try this. + if (NT_SUCCESS(status) && + (TEST_FLAG(DeviceExtension->PrivateFdoData->HackFlags, FDO_HACK_GESN_IS_BAD)) ) + { + DeviceSetParameter(DeviceExtension, + CLASSP_REG_SUBKEY_NAME, + CLASSP_REG_MMC_DETECTION_VALUE_NAME, + CdromDetectionUnsupported); + status = STATUS_NOT_SUPPORTED; + } + + // else go through the process since we allocate buffers and + // get all sorts of device settings. + if (NT_SUCCESS(status)) + { + if (info->Gesn.Buffer == NULL) + { + info->Gesn.Buffer = ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned, + GESN_BUFFER_SIZE, + CDROM_TAG_GESN); + } + + if (info->Gesn.Buffer == NULL) + { + status = STATUS_INSUFFICIENT_RESOURCES; + } + } + + if (NT_SUCCESS(status)) + { + if (info->Gesn.Mdl != NULL) + { + IoFreeMdl(info->Gesn.Mdl); + } + + info->Gesn.Mdl = IoAllocateMdl(info->Gesn.Buffer, + GESN_BUFFER_SIZE, + FALSE, + FALSE, + NULL); + if (info->Gesn.Mdl == NULL) + { + status = STATUS_INSUFFICIENT_RESOURCES; + } + } + + if (NT_SUCCESS(status)) + { + MmBuildMdlForNonPagedPool(info->Gesn.Mdl); + info->Gesn.BufferSize = GESN_BUFFER_SIZE; + info->Gesn.EventMask = 0; + + // all items are prepared to use GESN (except the event mask, so don't + // optimize this part out!). + // + // now see if it really works. we have to loop through this because + // many SAMSUNG (and one COMPAQ) drives timeout when requesting + // NOT_READY events, even when the IMMEDIATE bit is set. :( + // + // using a drive list is cumbersome, so this might fix the problem. + for (i = 0; (i < 16) && retryImmediately; i++) + { + status = RequestSetupMcnRequest(DeviceExtension, TRUE); + + if (!NT_SUCCESS(status)) + { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_MCN, + "Setup Mcn request failed %x for WDFDEVICE %p\n", + status, DeviceExtension->Device)); + break; + } + + NT_ASSERT(TEST_FLAG(info->MediaChangeSrb.SrbFlags, SRB_FLAGS_NO_QUEUE_FREEZE)); + + status = DeviceSendRequestSynchronously(DeviceExtension->Device, info->MediaChangeRequest, TRUE); + + if (SRB_STATUS(info->MediaChangeSrb.SrbStatus) != SRB_STATUS_SUCCESS) + { + // Release the queue if it is frozen. + if (info->MediaChangeSrb.SrbStatus & SRB_STATUS_QUEUE_FROZEN) + { + DeviceReleaseQueue(DeviceExtension->Device); + } + + RequestSenseInfoInterpret(DeviceExtension, + info->MediaChangeRequest, + &(info->MediaChangeSrb), + 0, + &status, + NULL); + } + + if ((deviceDescriptor->BusType == BusTypeAtapi) && + (info->MediaChangeSrb.SrbStatus == SRB_STATUS_BUS_RESET)) + { + // + // ATAPI unfortunately returns SRB_STATUS_BUS_RESET instead + // of SRB_STATUS_TIMEOUT, so we cannot differentiate between + // the two. if we get this status four time consecutively, + // stop trying this command. it is too late to change ATAPI + // at this point, so special-case this here. (07/10/2001) + // NOTE: any value more than 4 may cause the device to be + // marked missing. + // + atapiResets++; + if (atapiResets >= 4) + { + status = STATUS_IO_DEVICE_ERROR; + break; + } + } + + if (status == STATUS_DATA_OVERRUN) + { + status = STATUS_SUCCESS; + } + + if ((status == STATUS_INVALID_DEVICE_REQUEST) || + (status == STATUS_TIMEOUT) || + (status == STATUS_IO_DEVICE_ERROR) || + (status == STATUS_IO_TIMEOUT)) + { + // with these error codes, we don't ever want to try this command + // again on this device, since it reacts poorly. + DeviceSetParameter( DeviceExtension, + CLASSP_REG_SUBKEY_NAME, + CLASSP_REG_MMC_DETECTION_VALUE_NAME, + CdromDetectionUnsupported); + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_MCN, + "GESN test failed %x for WDFDEVICE %p\n", + status, DeviceExtension->Device)); + break; + } + + if (!NT_SUCCESS(status)) + { + // this may be other errors that should not disable GESN + // for all future start_device calls. + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_MCN, + "GESN test failed %x for WDFDEVICE %p\n", + status, DeviceExtension->Device)); + break; + } + else if (i == 0) + { + // the first time, the request was just retrieving a mask of + // available bits. use this to mask future requests. + header = (PNOTIFICATION_EVENT_STATUS_HEADER)(info->Gesn.Buffer); + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, + "WDFDEVICE %p supports event mask %x\n", + DeviceExtension->Device, header->SupportedEventClasses)); + + if (TEST_FLAG(header->SupportedEventClasses, + NOTIFICATION_MEDIA_STATUS_CLASS_MASK)) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, + "GESN supports MCN\n")); + } + if (TEST_FLAG(header->SupportedEventClasses, + NOTIFICATION_DEVICE_BUSY_CLASS_MASK)) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, + "GESN supports DeviceBusy\n")); + } + if (TEST_FLAG(header->SupportedEventClasses, + NOTIFICATION_OPERATIONAL_CHANGE_CLASS_MASK)) + { + if (TEST_FLAG(DeviceExtension->PrivateFdoData->HackFlags, + FDO_HACK_GESN_IGNORE_OPCHANGE)) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, + "GESN supports OpChange, but must ignore these events for compatibility\n")); + CLEAR_FLAG(header->SupportedEventClasses, + NOTIFICATION_OPERATIONAL_CHANGE_CLASS_MASK); + } + else + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, + "GESN supports OpChange\n")); + } + } + info->Gesn.EventMask = header->SupportedEventClasses; + + // + // realistically, we are only considering the following events: + // EXTERNAL REQUEST - this is being tested for play/stop/etc. + // MEDIA STATUS - autorun and ejection requests. + // DEVICE BUSY - to allow us to predict when media will be ready. + // therefore, we should not bother querying for the other, + // unknown events. clear all but the above flags. + // + info->Gesn.EventMask &= NOTIFICATION_OPERATIONAL_CHANGE_CLASS_MASK | + NOTIFICATION_EXTERNAL_REQUEST_CLASS_MASK | + NOTIFICATION_MEDIA_STATUS_CLASS_MASK | + NOTIFICATION_DEVICE_BUSY_CLASS_MASK ; + + + // + // HACKHACK - REF #0001 + // Some devices will *never* report an event if we've also requested + // that it report lower-priority events. this is due to a + // misunderstanding in the specification wherein a "No Change" is + // interpreted to be a real event. what should occur is that the + // device should ignore "No Change" events when multiple event types + // are requested unless there are no other events waiting. this + // greatly reduces the number of requests that the host must send + // to determine if an event has occurred. Since we must work on all + // drives, default to enabling the hack until we find evidence of + // proper firmware. + // + if (info->Gesn.EventMask == 0) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, + "GESN supported, but not mask we care about (%x) for FDO %p\n", + header->SupportedEventClasses, + DeviceExtension->DeviceObject)); + // NOTE: the status is still status_sucess. + break; + } + else if (CountOfSetBitsUChar(info->Gesn.EventMask) == 1) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, + "GESN hack not required for FDO %p\n", + DeviceExtension->DeviceObject)); + } + else + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, + "GESN hack enabled for FDO %p\n", + DeviceExtension->DeviceObject)); + info->Gesn.HackEventMask = 1; + } + } + else + { + // i > 0; not the first time looping through, so interpret the results. + status = GesnDataInterpret(DeviceExtension, + (PVOID)info->Gesn.Buffer, + &retryImmediately); + + if (!NT_SUCCESS(status)) + { + // This drive does not support GESN correctly + DeviceSetParameter( DeviceExtension, + CLASSP_REG_SUBKEY_NAME, + CLASSP_REG_MMC_DETECTION_VALUE_NAME, + CdromDetectionUnsupported); + break; + } + } + } // end 'for' loop of GESN requests.... + } + + if (NT_SUCCESS(status)) + { + // + // we can only use this if it can be relied upon for media changes, + // since we are (by definition) no longer going to be polling via + // a TEST_UNIT_READY irp, and drives will not report UNIT ATTENTION + // for this command (although a filter driver, such as one for burning + // cd's, might still fake those errors). + // + // since we also rely upon NOT_READY events to change the cursor + // into a "wait" cursor; GESN is still more reliable than other + // methods, and includes eject button requests, so we'll use it + // without DEVICE_BUSY in Windows Vista. + // + + if (TEST_FLAG(info->Gesn.EventMask, NOTIFICATION_MEDIA_STATUS_CLASS_MASK)) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, + "Enabling GESN support for WDFDEVICE %p\n", + DeviceExtension->Device)); + info->Gesn.Supported = TRUE; + + DeviceSetParameter( DeviceExtension, + CLASSP_REG_SUBKEY_NAME, + CLASSP_REG_MMC_DETECTION_VALUE_NAME, + CdromDetectionSupported); + } + else + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, + "GESN available but not enabled for WDFDEVICE %p\n", + DeviceExtension->Device)); + status = STATUS_NOT_SUPPORTED; + } + } + + if (!NT_SUCCESS(status)) + { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_MCN, + "GESN support detection failed for WDFDEVICE %p with status %08x\n", + DeviceExtension->Device, status)); + + if (info->Gesn.Mdl) + { + PIRP irp = WdfRequestWdmGetIrp(info->MediaChangeRequest); + + IoFreeMdl(info->Gesn.Mdl); + info->Gesn.Mdl = NULL; + irp->MdlAddress = NULL; + } + + FREE_POOL(info->Gesn.Buffer); + info->Gesn.Supported = FALSE; + info->Gesn.EventMask = 0; + info->Gesn.BufferSize = 0; + } + + return status; +} + + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +DeviceInitializeMediaChangeDetection( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension + ) +/*++ + +Routine Description: + + This routine checks to see if it is safe to initialize MCN (the back end + to autorun) for a given device. It will then check the device-type wide + key "Autorun" in the service key (for legacy reasons), and then look in + the device-specific key to potentially override that setting. + + If MCN is to be enabled, all neccessary structures and memory are + allocated and initialized. + + This routine MUST be called only from the DeviceInit...() . + +Arguments: + + DeviceExtension - the device to initialize MCN for, if appropriate + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + + BOOLEAN disabled = FALSE; + BOOLEAN instanceOverride; + + PAGED_CODE(); + + // NOTE: This assumes that DeviceInitializeMediaChangeDetection is always + // called in the context of the DeviceInitDevicePhase2. If called + // after then this check will have already been made and the + // once a second timer will not have been enabled. + + disabled = DeviceIsMediaChangeDisabledDueToHardwareLimitation(DeviceExtension); + + if (disabled) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, + "DeviceInitializeMediaChangeDetection: Disabled due to hardware" + "limitations for this device\n")); + } + else + { + // autorun should now be enabled by default for all media types. + disabled = DeviceIsMediaChangeDisabledForClass(DeviceExtension); + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, + "DeviceInitializeMediaChangeDetection: MCN is %s\n", + (disabled ? "disabled" : "enabled"))); + + status = DeviceMediaChangeDeviceInstanceOverride(DeviceExtension, + &instanceOverride); // default value + + if (!NT_SUCCESS(status)) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, + "DeviceInitializeMediaChangeDetection: Instance using default\n")); + } + else + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, + "DeviceInitializeMediaChangeDetection: Instance override: %s MCN\n", + (instanceOverride ? "Enabling" : "Disabling"))); + disabled = !instanceOverride; + } + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, + "DeviceInitializeMediaChangeDetection: Instance MCN is %s\n", + (disabled ? "disabled" : "enabled"))); + } + + if (!disabled) + { + // if the drive is not a CDROM, allow the drive to sleep + status = DeviceInitializeMcn(DeviceExtension, FALSE); + } + + return status; +} // end DeviceInitializeMediaChangeDetection() + + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +DeviceMediaChangeDeviceInstanceOverride( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _Out_ PBOOLEAN Enabled + ) +/*++ + +Routine Description: + + The user can override the global setting to enable or disable Autorun on a + specific cdrom device via the control panel. This routine checks and/or + sets this value. + +Arguments: + + DeviceExtension - the device to set/get the value for + + Enabled - TRUE (Autorun is enabled) + FALSE (Autorun is disabled) +Return Value: + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_UNSUCCESSFUL; + WDFKEY deviceKey = NULL; + WDFKEY subKey = NULL; + + UNICODE_STRING subkeyName; + UNICODE_STRING enableMcnValueName; + UNICODE_STRING disableMcnValueName; + ULONG alwaysEnable = 0; + ULONG alwaysDisable = 0; + + PAGED_CODE(); + + status = WdfDeviceOpenRegistryKey(DeviceExtension->Device, + PLUGPLAY_REGKEY_DEVICE, + KEY_ALL_ACCESS, + WDF_NO_OBJECT_ATTRIBUTES, + &deviceKey); + if (!NT_SUCCESS(status)) + { + // this can occur when a new device is added to the system + // this is due to cdrom.sys being an 'essential' driver + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, + "DeviceMediaChangeDeviceInstanceOverride: " + "Could not open device registry key [%lx]\n", status)); + } + else + { + RtlInitUnicodeString(&subkeyName, MCN_REG_SUBKEY_NAME); + + status = WdfRegistryOpenKey(deviceKey, + &subkeyName, + KEY_READ, + WDF_NO_OBJECT_ATTRIBUTES, + &subKey); + } + + if (!NT_SUCCESS(status)) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, + "DeviceMediaChangeDeviceInstanceOverride: " + "subkey could not be created. %lx\n", status)); + } + else + { + // Default to not changing autorun behavior, based upon setting + // registryValue to zero. + RtlInitUnicodeString(&enableMcnValueName, MCN_REG_AUTORUN_ENABLE_INSTANCE_NAME); + RtlInitUnicodeString(&disableMcnValueName, MCN_REG_AUTORUN_DISABLE_INSTANCE_NAME); + + // Ignore failures on reading of subkeys + (VOID) WdfRegistryQueryULong(subKey, + &enableMcnValueName, + &alwaysEnable); + (VOID) WdfRegistryQueryULong(subKey, + &disableMcnValueName, + &alwaysDisable); + } + + // set return value and cleanup + + if (subKey != NULL) + { + WdfRegistryClose(subKey); + } + + if (deviceKey != NULL) + { + WdfRegistryClose(deviceKey); + } + + if (alwaysEnable && alwaysDisable) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, + "DeviceMediaChangeDeviceInstanceOverride: %s selected\n", + "Both Enable and Disable set -- DISABLE")); + NT_ASSERT(NT_SUCCESS(status)); + status = STATUS_SUCCESS; + *Enabled = FALSE; + } + else if (alwaysDisable) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, + "DeviceMediaChangeDeviceInstanceOverride: %s selected\n", + "DISABLE")); + NT_ASSERT(NT_SUCCESS(status)); + status = STATUS_SUCCESS; + *Enabled = FALSE; + } + else if (alwaysEnable) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, + "DeviceMediaChangeDeviceInstanceOverride: %s selected\n", + "ENABLE")); + NT_ASSERT(NT_SUCCESS(status)); + status = STATUS_SUCCESS; + *Enabled = TRUE; + } + else + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, + "DeviceMediaChangeDeviceInstanceOverride: %s selected\n", + "DEFAULT")); + status = STATUS_UNSUCCESSFUL; + } + + return status; +} // end DeviceMediaChangeDeviceInstanceOverride() + + +NTSTATUS +DeviceMediaChangeRegistryCallBack( + _In_z_ PWSTR ValueName, + _In_ ULONG ValueType, + _In_reads_bytes_opt_(ValueLength) PVOID ValueData, + _In_ ULONG ValueLength, + _In_opt_ PVOID Context, + _In_opt_ PVOID EntryContext + ) +/*++ + +Routine Description: + + This callback for a registry SZ or MULTI_SZ is called once for each + SZ in the value. It will attempt to match the data with the + UNICODE_STRING passed in as Context, and modify EntryContext if a + match is found. Written for ClasspCheckRegistryForMediaChangeCompletion + +Arguments: + + ValueName - name of the key that was opened + ValueType - type of data stored in the value (REG_SZ for this routine) + ValueData - data in the registry, in this case a wide string + ValueLength - length of the data including the terminating null + Context - unicode string to compare against ValueData + EntryContext - should be initialized to 0, will be set to 1 if match found + +Return Value: + + STATUS_SUCCESS + EntryContext will be 1 if found + +--*/ +{ + PULONG valueFound; + PUNICODE_STRING deviceString; + PWSTR keyValue; + + PAGED_CODE(); + + UNREFERENCED_PARAMETER(ValueName); + + if ((Context == NULL) || (EntryContext == NULL)) + { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_MCN, + "DeviceMediaChangeRegistryCallBack: NULL context should never be passed to registry call-back!\n")); + + return STATUS_SUCCESS; + } + + // if we have already set the value to true, exit + valueFound = EntryContext; + if ((*valueFound) != 0) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, + "DeviceMediaChangeRegistryCallBack: already set to true\n")); + return STATUS_SUCCESS; + } + + if (ValueLength == sizeof(WCHAR)) + { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_MCN, + "DeviceMediaChangeRegistryCallBack: NULL string should never be passed to registry call-back!\n")); + return STATUS_SUCCESS; + } + + // if the data is not a terminated string, exit + if (ValueType != REG_SZ) + { + return STATUS_SUCCESS; + } + + deviceString = Context; + keyValue = ValueData; + ValueLength -= sizeof(WCHAR); // ignore the null character + + // do not compare more memory than is in deviceString + if (ValueLength > deviceString->Length) + { + ValueLength = deviceString->Length; + } + + if (keyValue == NULL) + { + return STATUS_SUCCESS; + } + + // if the strings match, disable autorun + if (RtlCompareMemory(deviceString->Buffer, keyValue, ValueLength) == ValueLength) + { + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_MCN, "DeviceMediaChangeRegistryCallBack: Match found\n")); + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_MCN, "DeviceMediaChangeRegistryCallBack: DeviceString at %p\n", + deviceString->Buffer)); + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_MCN, + "DeviceMediaChangeRegistryCallBack: KeyValue at %p\n", + keyValue)); + (*valueFound) = TRUE; + } + + return STATUS_SUCCESS; +} // end DeviceMediaChangeRegistryCallBack() + + +_IRQL_requires_max_(PASSIVE_LEVEL) +BOOLEAN +DeviceIsMediaChangeDisabledDueToHardwareLimitation( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension + ) +/*++ + +Routine Description: + + The key AutoRunAlwaysDisable contains a MULTI_SZ of hardware IDs for + which to never enable MediaChangeNotification. + + The user can override the global setting to enable or disable Autorun on a + specific cdrom device via the control panel. + + NOTE: It's intended that not use WdfRegistryQueryMultiString in this funciton, + as it's much more complicated.(needs WDFCOLLECTION, WDFSTRING other than + UNICODE_STRING) + +Arguments: + + FdoExtension - + RegistryPath - pointer to the unicode string inside + ...\CurrentControlSet\Services\Cdrom + +Return Value: + + TRUE - no autorun. + FALSE - Autorun may be enabled + +--*/ +{ + NTSTATUS status; + + PSTORAGE_DEVICE_DESCRIPTOR deviceDescriptor = DeviceExtension->DeviceDescriptor; + WDFKEY wdfKey; + HANDLE serviceKey = NULL; + RTL_QUERY_REGISTRY_TABLE parameters[2] = {0}; + + UNICODE_STRING deviceUnicodeString = {0}; + ANSI_STRING deviceString = {0}; + ULONG mediaChangeNotificationDisabled = 0; + + PAGED_CODE(); + + // open the service key. + status = WdfDriverOpenParametersRegistryKey(WdfGetDriver(), + KEY_ALL_ACCESS, + WDF_NO_OBJECT_ATTRIBUTES, + &wdfKey); + + if(!NT_SUCCESS(status)) + { + NT_ASSERT(FALSE); + + // always take the safe path. if we can't open the service key, disable autorun + return TRUE; + } + + if(NT_SUCCESS(status)) + { + // Determine if drive is in a list of those requiring + // autorun to be disabled. this is stored in a REG_MULTI_SZ + // named AutoRunAlwaysDisable. this is required as some autochangers + // must load the disc to reply to ChkVerify request, causing them + // to cycle discs continuously. + + PWSTR nullMultiSz; + PUCHAR vendorId = NULL; + PUCHAR productId = NULL; + PUCHAR revisionId = NULL; + size_t length; + size_t offset; + + deviceString.Buffer = NULL; + deviceUnicodeString.Buffer = NULL; + + serviceKey = WdfRegistryWdmGetHandle(wdfKey); + + // there may be nothing to check against + if ((deviceDescriptor->VendorIdOffset == 0) && + (deviceDescriptor->ProductIdOffset == 0)) + { + // no valid data in device extension. + status = STATUS_INTERNAL_ERROR; + } + + // build deviceString using VendorId, Model and Revision. + // this string will be used to checked if it's one of devices in registry disable list. + if (NT_SUCCESS(status)) + { + length = 0; + + if (deviceDescriptor->VendorIdOffset == 0) + { + vendorId = NULL; + } + else + { + vendorId = (PUCHAR) deviceDescriptor + deviceDescriptor->VendorIdOffset; + length = strlen((LPCSTR)vendorId); + } + + if ( deviceDescriptor->ProductIdOffset == 0 ) + { + productId = NULL; + } + else + { + productId = (PUCHAR) deviceDescriptor + deviceDescriptor->ProductIdOffset; + length += strlen((LPCSTR)productId); + } + + if ( deviceDescriptor->ProductRevisionOffset == 0 ) + { + revisionId = NULL; + } + else + { + revisionId = (PUCHAR) deviceDescriptor + deviceDescriptor->ProductRevisionOffset; + length += strlen((LPCSTR)revisionId); + } + + // allocate a buffer for the string + deviceString.Length = (USHORT)( length ); + deviceString.MaximumLength = deviceString.Length + 1; + deviceString.Buffer = (PCHAR)ExAllocatePoolWithTag( NonPagedPoolNx, + deviceString.MaximumLength, + CDROM_TAG_AUTORUN_DISABLE + ); + if (deviceString.Buffer == NULL) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, + "DeviceIsMediaChangeDisabledDueToHardwareLimitation: Unable to alloc string buffer\n" )); + status = STATUS_INTERNAL_ERROR; + } + } + + if (NT_SUCCESS(status)) + { + // copy strings to the buffer + offset = 0; + + if (vendorId != NULL) + { + RtlCopyMemory(deviceString.Buffer + offset, + vendorId, + strlen((LPCSTR)vendorId)); + offset += strlen((LPCSTR)vendorId); + } + + if ( productId != NULL ) + { + RtlCopyMemory(deviceString.Buffer + offset, + productId, + strlen((LPCSTR)productId)); + offset += strlen((LPCSTR)productId); + } + if ( revisionId != NULL ) + { + RtlCopyMemory(deviceString.Buffer + offset, + revisionId, + strlen((LPCSTR)revisionId)); + offset += strlen((LPCSTR)revisionId); + } + + NT_ASSERT(offset == deviceString.Length); + + #pragma warning(suppress:6386) // Not an issue as deviceString.Buffer is of size deviceString.MaximumLength, which is equal to (deviceString.Length + 1) + deviceString.Buffer[deviceString.Length] = '\0'; // Null-terminated + + // convert to unicode as registry deals with unicode strings + status = RtlAnsiStringToUnicodeString( &deviceUnicodeString, + &deviceString, + TRUE + ); + if (!NT_SUCCESS(status)) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, + "DeviceIsMediaChangeDisabledDueToHardwareLimitation: cannot convert " + "to unicode %lx\n", status)); + } + } + + if (NT_SUCCESS(status)) + { + // query the value, setting valueFound to true if found + nullMultiSz = L"\0"; + parameters[0].QueryRoutine = DeviceMediaChangeRegistryCallBack; + parameters[0].Flags = RTL_QUERY_REGISTRY_REQUIRED; + parameters[0].Name = L"AutoRunAlwaysDisable"; + parameters[0].EntryContext = &mediaChangeNotificationDisabled; + parameters[0].DefaultType = REG_MULTI_SZ; + parameters[0].DefaultData = nullMultiSz; + parameters[0].DefaultLength = 0; + + status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE, + serviceKey, + parameters, + &deviceUnicodeString, + NULL); + UNREFERENCED_PARAMETER(status); //defensive coding, avoid PREFAST warning. + } + } + + // Cleanup + { + + FREE_POOL( deviceString.Buffer ); + if (deviceUnicodeString.Buffer != NULL) + { + RtlFreeUnicodeString( &deviceUnicodeString ); + } + + // handle serviceKey will be closed by framework while it closes registry key. + WdfRegistryClose(wdfKey); + } + + if (mediaChangeNotificationDisabled > 0) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, + "DeviceIsMediaChangeDisabledDueToHardwareLimitation: Device is on MCN disable list\n")); + } + + return (mediaChangeNotificationDisabled > 0); + +} // end DeviceIsMediaChangeDisabledDueToHardwareLimitation() + + +_IRQL_requires_max_(PASSIVE_LEVEL) +BOOLEAN +DeviceIsMediaChangeDisabledForClass( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension + ) +/*++ + +Routine Description: + + The user must specify that AutoPlay is to run on the platform + by setting the registry value HKEY_LOCAL_MACHINE\System\CurrentControlSet\ + Services\\Autorun:REG_DWORD:1. + + The user can override the global setting to enable or disable Autorun on a + specific cdrom device via the control panel. + +Arguments: + + DeviceExtension - device extension + +Return Value: + + TRUE - Autorun is disabled for this class + FALSE - Autorun is enabled for this class + +--*/ +{ + NTSTATUS status; + WDFKEY serviceKey = NULL; + WDFKEY parametersKey = NULL; + + UNICODE_STRING parameterKeyName; + UNICODE_STRING valueName; + + // Default to ENABLING MediaChangeNotification (!) + ULONG mcnRegistryValue = 1; + + PAGED_CODE(); + + // open the service key. + status = WdfDriverOpenParametersRegistryKey(WdfGetDriver(), + KEY_ALL_ACCESS, + WDF_NO_OBJECT_ATTRIBUTES, + &serviceKey); + if(!NT_SUCCESS(status)) + { + // return the default value, which is the inverse of the registry setting default + // since this routine asks if it's disabled + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, + "DeviceIsMediaChangeDisabledForClass: Defaulting to %s\n", + (mcnRegistryValue ? "Enabled" : "Disabled"))); + return (BOOLEAN)(mcnRegistryValue == 0); + } + else + { + // Open the parameters key (if any) beneath the services key. + RtlInitUnicodeString(¶meterKeyName, L"Parameters"); + + status = WdfRegistryOpenKey(serviceKey, + ¶meterKeyName, + KEY_READ, + WDF_NO_OBJECT_ATTRIBUTES, + ¶metersKey); + } + + if (!NT_SUCCESS(status)) + { + parametersKey = NULL; + } + + RtlInitUnicodeString(&valueName, L"Autorun"); + // ignore failures + status = WdfRegistryQueryULong(serviceKey, + &valueName, + &mcnRegistryValue); + + if (NT_SUCCESS(status)) + { + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_MCN, + "DeviceIsMediaChangeDisabledForClass: /Autorun flag = %d\n", + mcnRegistryValue)); + } + + if (parametersKey != NULL) + { + status = WdfRegistryQueryULong(parametersKey, + &valueName, + &mcnRegistryValue); + + if (NT_SUCCESS(status)) + { + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_MCN, + "DeviceIsMediaChangeDisabledForClass: /Parameters/Autorun flag = %d\n", + mcnRegistryValue)); + } + + WdfRegistryClose(parametersKey); + } + + WdfRegistryClose(serviceKey); + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, + "DeviceIsMediaChangeDisabledForClass: Autoplay for device %p is %s\n", + DeviceExtension->DeviceObject, + (mcnRegistryValue ? "on" : "off") + )); + + // return if it is _disabled_, which is the + // inverse of the registry setting + + return (BOOLEAN)(!mcnRegistryValue); +} // end DeviceIsMediaChangeDisabledForClass() + + +_IRQL_requires_max_(APC_LEVEL) +VOID +DeviceEnableMediaChangeDetection( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _Inout_ PFILE_OBJECT_CONTEXT FileObjectContext, + _In_ BOOLEAN IgnorePreviousMediaChanges + ) +/*++ + +Routine Description: + + When the disable count decrease to 0, enable the MCN + +Arguments: + + DeviceExtension - the device context + + FileObjectContext - the file object context + + IgnorePreviousMediaChanges - ignore all previous media changes + +Return Value: + None. + +--*/ +{ + PMEDIA_CHANGE_DETECTION_INFO info = DeviceExtension->MediaChangeDetectionInfo; + LONG oldCount; + + PAGED_CODE(); + + if (FileObjectContext) + { + InterlockedDecrement((PLONG)&(FileObjectContext->McnDisableCount)); + } + + if (info == NULL) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, + "DeviceEnableMediaChangeDetection: not initialized\n")); + return; + } + + (VOID) KeWaitForMutexObject(&info->MediaChangeMutex, + UserRequest, + KernelMode, + FALSE, + NULL); + + oldCount = --info->MediaChangeDetectionDisableCount; + + NT_ASSERT(oldCount >= 0); + + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_MCN, + "DeviceEnableMediaChangeDetection: Disable count reduced to %d - \n", + info->MediaChangeDetectionDisableCount)); + + if (oldCount == 0) + { + if (IgnorePreviousMediaChanges) + { + info->LastReportedMediaDetectionState = info->LastKnownMediaDetectionState; + } + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, "MCN is enabled\n")); + } + else + { + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_MCN, "MCD still disabled\n")); + } + + // Let something else run. + KeReleaseMutex(&info->MediaChangeMutex, FALSE); + + return; +} // end DeviceEnableMediaChangeDetection() + + +_IRQL_requires_max_(APC_LEVEL) +VOID +DeviceDisableMediaChangeDetection( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _Inout_ PFILE_OBJECT_CONTEXT FileObjectContext + ) +/*++ + +Routine Description: + + Increase the disable count. + +Arguments: + + DeviceExtension - the device context + + FileObjectContext - the file object context + +Return Value: + None. + +--*/ +{ + PMEDIA_CHANGE_DETECTION_INFO info = DeviceExtension->MediaChangeDetectionInfo; + + PAGED_CODE(); + + if (FileObjectContext) + { + InterlockedIncrement((PLONG)&(FileObjectContext->McnDisableCount)); + } + + if (info == NULL) + { + return; + } + + (VOID) KeWaitForMutexObject(&info->MediaChangeMutex, + UserRequest, + KernelMode, + FALSE, + NULL); + + info->MediaChangeDetectionDisableCount++; + + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_MCN, + "DisableMediaChangeDetection: disable count is %d\n", + info->MediaChangeDetectionDisableCount)); + + KeReleaseMutex(&info->MediaChangeMutex, FALSE); + + return; +} // end DeviceDisableMediaChangeDetection() + + +_IRQL_requires_max_(APC_LEVEL) +VOID +DeviceReleaseMcnResources( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension + ) +/*++ + +Routine Description: + + This routine will cleanup any resources allocated for MCN. It is called + by classpnp during remove device, and therefore is not typically required + by external drivers. + +Arguments: + + DeviceExtension - the device context + +Return Value: + None. + +--*/ +{ + PMEDIA_CHANGE_DETECTION_INFO info = DeviceExtension->MediaChangeDetectionInfo; + + PAGED_CODE() + + if(info == NULL) + { + return; + } + + if (info->Gesn.Mdl) + { + PIRP irp = WdfRequestWdmGetIrp(info->MediaChangeRequest); + IoFreeMdl(info->Gesn.Mdl); + irp->MdlAddress = NULL; + } + IoFreeIrp(info->MediaChangeSyncIrp); + FREE_POOL(info->Gesn.Buffer); + FREE_POOL(info->SenseBuffer); + + if (info->DisplayStateCallbackHandle) + { + PoUnregisterPowerSettingCallback(info->DisplayStateCallbackHandle); + info->DisplayStateCallbackHandle = NULL; + } + + FREE_POOL(info); + + DeviceExtension->MediaChangeDetectionInfo = NULL; + + return; +} // end DeviceReleaseMcnResources() + + +IO_COMPLETION_ROUTINE RequestMcnSyncIrpCompletion; + +NTSTATUS +RequestMcnSyncIrpCompletion( + _In_ PDEVICE_OBJECT DeviceObject, + _In_ PIRP Irp, + _In_reads_opt_(_Inexpressible_("varies")) PVOID Context + ) +/*++ + +Routine Description: + + The MCN work finishes, reset the fields to allow another MCN request + be scheduled. + +Arguments: + + DeviceObject - device that the completion routine fires on. + + Irp - The irp to be completed. + + Context - IRP context + +Return Value: + NTSTATUS + +--*/ +{ + PCDROM_DEVICE_EXTENSION DeviceExtension = NULL; + PMEDIA_CHANGE_DETECTION_INFO info = NULL; + + if (Context == NULL) + { + // this will never happen, but code must be there to prevent OACR warnings. + return STATUS_MORE_PROCESSING_REQUIRED; + } + + DeviceExtension = (PCDROM_DEVICE_EXTENSION) Context; + info = DeviceExtension->MediaChangeDetectionInfo; + +#ifndef DEBUG + UNREFERENCED_PARAMETER(Irp); +#endif + UNREFERENCED_PARAMETER(DeviceObject); + + NT_ASSERT(Irp == info->MediaChangeSyncIrp); + + IoReuseIrp(info->MediaChangeSyncIrp, STATUS_NOT_SUPPORTED); + + // reset the value to let timer routine be able to send the next request. + InterlockedCompareExchange((PLONG)&(info->MediaChangeRequestInUse), 0, 1); + + return STATUS_MORE_PROCESSING_REQUIRED; +} + + +VOID +RequestSetupMcnSyncIrp( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension + ) +/*++ + +Routine Description: + + setup the MCN synchronization irp. + +Arguments: + + DeviceExtension - the device context + +Return Value: + None + +--*/ +{ + PIRP irp = NULL; + PIO_STACK_LOCATION irpStack = NULL; + PIO_STACK_LOCATION nextIrpStack = NULL; + + irp = DeviceExtension->MediaChangeDetectionInfo->MediaChangeSyncIrp; + NT_ASSERT(irp != NULL); + + // + // For the driver that creates an IRP, there is no 'current' stack location. + // Step down one IRP stack location so that the extra top one + // becomes our 'current' one. + // + IoSetNextIrpStackLocation(irp); + + /* + * Cache our device object in the extra top IRP stack location + * so we have it in our completion routine. + */ + irpStack = IoGetCurrentIrpStackLocation(irp); + irpStack->DeviceObject = DeviceExtension->DeviceObject; + + // + // If the irp is sent down when the volume needs to be + // verified, CdRomUpdateGeometryCompletion won't complete + // it since it's not associated with a thread. Marking + // it to override the verify causes it always be sent + // to the port driver + // + nextIrpStack = IoGetNextIrpStackLocation(irp); + + SET_FLAG(nextIrpStack->Flags, SL_OVERRIDE_VERIFY_VOLUME); + + nextIrpStack->MajorFunction = IRP_MJ_DEVICE_CONTROL; + // pick up this IOCTL code as it's not normaly seen for CD/DVD drive and does not require input. + // set other fields to make this IOCTL recognizable by CDROM.SYS + nextIrpStack->Parameters.Others.Argument1 = RequestSetupMcnSyncIrp; + nextIrpStack->Parameters.Others.Argument2 = RequestSetupMcnSyncIrp; + nextIrpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_MCN_SYNC_FAKE_IOCTL; //Argument3. + nextIrpStack->Parameters.Others.Argument4 = RequestSetupMcnSyncIrp; + + IoSetCompletionRoutine(irp, + RequestMcnSyncIrpCompletion, + DeviceExtension, + TRUE, + TRUE, + TRUE); + + return; +} + + +VOID +DeviceMainTimerTickHandler( + _In_ WDFTIMER Timer + ) +/*++ + +Routine Description: + + This routine setup a sync irp and send it to the serial queue. + Serial queue will process MCN when receive this sync irp. + +Arguments: + + Timer - the timer object that fires. + +Return Value: + None + +--*/ +{ + PCDROM_DEVICE_EXTENSION deviceExtension = NULL; + size_t dataLength = 0; + + deviceExtension = WdfObjectGetTypedContext(WdfTimerGetParentObject(Timer), CDROM_DEVICE_EXTENSION); + + (void) RequestHandleEventNotification(deviceExtension, NULL, NULL, &dataLength); + + return; +} // end DeviceMainTimerTickHandler() + + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DeviceEnableMainTimer( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension + ) +/*++ + +Routine Description: + + This routine will allocate timer related resources on the first time call. + Start the timer. + +Arguments: + + DeviceExtension - the device context + +Return Value: + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + + if ((DeviceExtension->MediaChangeDetectionInfo == NULL) || + (DeviceExtension->MediaChangeDetectionInfo->AsynchronousNotificationSupported != FALSE)) + { + // Asynchronous Notification is enabled, timer not needed. + return status; + } + + if (DeviceExtension->MainTimer == NULL) + { + //create main timer object. + WDF_TIMER_CONFIG timerConfig; + WDF_OBJECT_ATTRIBUTES timerAttributes; + + WDF_TIMER_CONFIG_INIT(&timerConfig, DeviceMainTimerTickHandler); + + // Polling frequently on virtual optical devices created by Hyper-V will + // cause a significant perf / power hit. These devices need to be polled + // less frequently for device state changes. + if (TEST_FLAG(DeviceExtension->DeviceAdditionalData.HackFlags, CDROM_HACK_MSFT_VIRTUAL_ODD)) + { + timerConfig.Period = 2000; // 2 seconds, in milliseconds. + } + else + { + timerConfig.Period = 1000; // 1 second, in milliseconds. + } + + timerConfig.TolerableDelay = 500; // 0.5 seconds, in milliseconds + + //Set the autoSerialization to FALSE, as the parent device's + //execute level is WdfExecutionLevelPassive. + timerConfig.AutomaticSerialization = FALSE; + + WDF_OBJECT_ATTRIBUTES_INIT(&timerAttributes); + timerAttributes.ParentObject = DeviceExtension->Device; + timerAttributes.ExecutionLevel = WdfExecutionLevelInheritFromParent; + + status = WdfTimerCreate(&timerConfig, + &timerAttributes, + &DeviceExtension->MainTimer); + } + + if (NT_SUCCESS(status)) + { + WdfTimerStart(DeviceExtension->MainTimer,WDF_REL_TIMEOUT_IN_MS(100)); + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, + "DeviceEnableMainTimer: Once a second timer enabled for WDFDEVICE %p\n", + DeviceExtension->Device)); + } + else + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, + "DeviceEnableMainTimer: WDFDEVICE %p, Status %lx initializing timer\n", + DeviceExtension->Device, status)); + } + + return status; +} // end DeviceEnableMainTimer() + + +_IRQL_requires_max_(PASSIVE_LEVEL) +VOID +DeviceDisableMainTimer( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension + ) +/*++ + +Routine Description: + + stop the timer. + +Arguments: + + DeviceExtension - device context + +Return Value: + None + +--*/ +{ + PAGED_CODE(); + + if ((DeviceExtension->MediaChangeDetectionInfo == NULL) || + (DeviceExtension->MediaChangeDetectionInfo->AsynchronousNotificationSupported != FALSE)) + { + // Asynchronous Notification is enabled, timer not needed. + return; + } + + if (DeviceExtension->MainTimer != NULL) + { + // + // we are only going to stop the actual timer in remove device routine. + // it is the responsibility of the code within the timer routine to + // check if the device is removed and not processing io for the final + // call. + // this keeps the code clean and prevents lots of bugs. + // + WdfTimerStop(DeviceExtension->MainTimer,TRUE); + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, + "DeviceDisableMainTimer: Once a second timer disabled for device %p\n", + DeviceExtension->Device)); + } + else + { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_MCN, + "DeviceDisableMainTimer: Timer never enabled\n")); + } + + return; +} // end DeviceDisableMainTimer() + + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +RequestHandleMcnControl( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + This routine handles the process of IOCTL_STORAGE_MCN_CONTROL + +Arguments: + + DeviceExtension - device context + + Request - request object + + RequestParameters - request parameters + + DataLength - data transferred + +Return Value: + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + WDFFILEOBJECT fileObject = NULL; + PFILE_OBJECT_CONTEXT fileObjectContext = NULL; + PPREVENT_MEDIA_REMOVAL mediaRemoval = NULL; + + PAGED_CODE(); + + *DataLength = 0; + + status = WdfRequestRetrieveInputBuffer(Request, + sizeof(PREVENT_MEDIA_REMOVAL), + &mediaRemoval, + NULL); + + if (NT_SUCCESS(status)) + { + fileObject = WdfRequestGetFileObject(Request); + + // Check to make sure we have a file object extension to keep track of this + // request. If not we'll fail it before synchronizing. + if (fileObject != NULL) + { + fileObjectContext = FileObjectGetContext(fileObject); + } + + if ((fileObjectContext == NULL) && + (WdfRequestGetRequestorMode(Request) == KernelMode)) + { + fileObjectContext = &DeviceExtension->KernelModeMcnContext; + } + + if (fileObjectContext == NULL) + { + // This handle isn't setup correctly. We can't let the + // operation go. + status = STATUS_INVALID_PARAMETER; + } + } + + if (NT_SUCCESS(status)) + { + if (mediaRemoval->PreventMediaRemoval) + { + // This is a lock command. Reissue the command in case bus or + // device was reset and the lock was cleared. + DeviceDisableMediaChangeDetection(DeviceExtension, fileObjectContext); + } + else + { + if (fileObjectContext->McnDisableCount == 0) + { + status = STATUS_INVALID_DEVICE_STATE; + } + else + { + DeviceEnableMediaChangeDetection(DeviceExtension, fileObjectContext, TRUE); + } + } + } + + return status; +} // end RequestHandleMcnControl() + +#pragma warning(pop) // un-sets any local warning changes + diff --git a/storage/class/cdrom/src/cdrom.c b/storage/class/cdrom/src/cdrom.c new file mode 100644 index 00000000..a93646ba --- /dev/null +++ b/storage/class/cdrom/src/cdrom.c @@ -0,0 +1,4225 @@ +/*-- + +Copyright (C) Microsoft Corporation. All rights reserved. + +Module Name: + + cdrom.c + +Abstract: + + The CDROM class driver tranlates IRPs to SRBs with embedded CDBs + and sends them to its devices through the port driver. + +Environment: + + kernel mode only + +Notes: + + +Revision History: + +--*/ + +// this definition is used to link _StorDebugPrint() function. +#define DEBUG_MAIN_SOURCE 1 + + +#include "ntddk.h" +#include "ntstrsafe.h" + +#include "ntddstor.h" +#include "ntddtape.h" +#include "wdfcore.h" +#include "devpkey.h" + +#include "cdrom.h" +#include "ioctl.h" +#include "mmc.h" +#include "scratch.h" + + +#ifdef DEBUG_USE_WPP +#include "cdrom.tmh" +#endif + +BOOLEAN +BootEnvironmentIsWinPE( + VOID + ); + +#ifdef ALLOC_PRAGMA + +#pragma alloc_text(INIT, DriverEntry) +#pragma alloc_text(INIT, BootEnvironmentIsWinPE) + +#pragma alloc_text(PAGE, DriverEvtCleanup) +#pragma alloc_text(PAGE, DriverEvtDeviceAdd) +#pragma alloc_text(PAGE, DeviceEvtCleanup) +#pragma alloc_text(PAGE, DeviceEvtSelfManagedIoCleanup) +#pragma alloc_text(PAGE, DeviceEvtD0Exit) +#pragma alloc_text(PAGE, CreateQueueEvtIoDefault) +#pragma alloc_text(PAGE, DeviceEvtFileClose) +#pragma alloc_text(PAGE, DeviceCleanupProtectedLocks) +#pragma alloc_text(PAGE, DeviceCleanupDisableMcn) +#pragma alloc_text(PAGE, RequestProcessSerializedIoctl) +#pragma alloc_text(PAGE, ReadWriteWorkItemRoutine) +#pragma alloc_text(PAGE, IoctlWorkItemRoutine) +#pragma alloc_text(PAGE, DeviceEvtSurpriseRemoval) + +#endif + +NTSTATUS +DriverEntry( + _In_ PDRIVER_OBJECT DriverObject, + _In_ PUNICODE_STRING RegistryPath + ) +/*++ + +Routine Description: + + Installable driver initialization entry point. + This entry point is called directly by the I/O system. + +Arguments: + + DriverObject - pointer to the driver object + + RegistryPath - pointer to a unicode string representing the path, + to driver-specific key in the registry. + +Return Value: + + STATUS_SUCCESS if successful, + STATUS_UNSUCCESSFUL otherwise. + +--*/ +{ + NTSTATUS status; + WDF_DRIVER_CONFIG config; + WDF_OBJECT_ATTRIBUTES attributes; + WDFDRIVER driverObject = NULL; + + PAGED_CODE(); + + // Initialize WPP Tracing + WPP_INIT_TRACING(DriverObject, RegistryPath); + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, + "CDROM.SYS DriverObject %p loading\n", + DriverObject)); + + // Register DeviceAdd and DriverEvtCleanup callback. + // WPP_CLEANUP will be called in DriverEvtCleanup + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, CDROM_DRIVER_EXTENSION); + attributes.EvtCleanupCallback = DriverEvtCleanup; + + WDF_DRIVER_CONFIG_INIT(&config, DriverEvtDeviceAdd); + + status = WdfDriverCreate(DriverObject, + RegistryPath, + &attributes, + &config, + &driverObject); + + if (!NT_SUCCESS(status)) + { + TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_INIT, + "WdfDriverCreate failed. %x\n", + status)); + + // Cleanup tracing here because DriverUnload will not be called + // as we have failed to create WDFDRIVER object itself. + WPP_CLEANUP(DriverObject); + + } + else + { + PCDROM_DRIVER_EXTENSION driverExtension = DriverGetExtension(driverObject); + + // Copy the registry path into the driver extension so we can use it later + driverExtension->Version = 0x01; + driverExtension->DriverObject = DriverObject; + + if (BootEnvironmentIsWinPE()) { + + SET_FLAG(driverExtension->Flags, CDROM_FLAG_WINPE_MODE); + } + + } + + return status; +} + + +BOOLEAN +BootEnvironmentIsWinPE( + VOID + ) +/*++ + +Routine Description: + + This routine determines if the boot enviroment is WinPE + +Arguments: + + None + +Return Value: + + BOOLEAN - TRUE if the environment is WinPE; FALSE otherwise + +--*/ +{ + NTSTATUS status; + WDFKEY registryKey = NULL; + + DECLARE_CONST_UNICODE_STRING(registryKeyName, WINPE_REG_KEY_NAME); + + PAGED_CODE(); + + status = WdfRegistryOpenKey(NULL, + ®istryKeyName, + KEY_READ, + WDF_NO_OBJECT_ATTRIBUTES, + ®istryKey); + + if (!NT_SUCCESS(status)) + { + return FALSE; + } + + WdfRegistryClose(registryKey); + return TRUE; +} // end BootEnvironmentIsWinPE() + + +VOID +DriverEvtCleanup( + _In_ WDFOBJECT Driver + ) +/*++ +Routine Description: + + Free all the resources allocated in DriverEntry. + +Arguments: + + Driver - handle to a WDF Driver object. + +Return Value: + + VOID. + +--*/ +{ + WDFDRIVER driver = (WDFDRIVER)Driver; + + PAGED_CODE (); + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, + "CDROM.SYS DriverObject %p cleanup. Will be unloaded soon\n", + driver)); + + // Stop WPP Tracing + WPP_CLEANUP( WdfDriverWdmGetDriverObject(driver) ); + + + return; +} + + +NTSTATUS +DriverEvtDeviceAdd( + _In_ WDFDRIVER Driver, + _Inout_ PWDFDEVICE_INIT DeviceInit + ) +/*++ + +Routine Description: + + EvtDeviceAdd is called by the framework in response to AddDevice + call from the PnP manager. + + +Arguments: + + Driver - Handle to a framework driver object created in DriverEntry + + DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure. + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PCDROM_DRIVER_EXTENSION driverExtension = NULL; + WDFDEVICE device = NULL; + PCDROM_DEVICE_EXTENSION deviceExtension = NULL; + BOOLEAN deviceClaimed = FALSE; + + WDF_OBJECT_ATTRIBUTES attributes; + WDF_FILEOBJECT_CONFIG fileObjectConfig; + WDF_IO_TARGET_OPEN_PARAMS ioTargetOpenParams; + WDF_IO_QUEUE_CONFIG queueConfig; + WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks; + WDF_REMOVE_LOCK_OPTIONS removeLockOptions; + PWCHAR wideDeviceName = NULL; + UNICODE_STRING unicodeDeviceName; + PDEVICE_OBJECT lowerPdo = NULL; + ULONG deviceNumber = 0; + ULONG devicePropertySessionId = INVALID_SESSION; + ULONG devicePropertySize = 0; + DEVPROPTYPE devicePropertyType = DEVPROP_TYPE_EMPTY; + + PAGED_CODE(); + + driverExtension = DriverGetExtension(Driver); + + // 0. Initialize the objects that we're going to use + RtlInitUnicodeString(&unicodeDeviceName, NULL); + + // 1. Register PnP&Power callbacks for any we are interested in. + // If a callback isn't set, Framework will take the default action by itself. + { + // Zero out the PnpPowerCallbacks structure. + WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks); + + // Use this callback to init resources that are used by the device and only needs to be called once. + pnpPowerCallbacks.EvtDeviceSelfManagedIoInit = DeviceEvtSelfManagedIoInit; + + // Use this callback to prepare device for coming back from a lower power mode to D0. + pnpPowerCallbacks.EvtDeviceD0Entry = DeviceEvtD0Entry; + + // Use this callback to prepare device for entering into a lower power mode. + pnpPowerCallbacks.EvtDeviceD0Exit = DeviceEvtD0Exit; + + // Use this callback to free any resources used by device and will be called when the device is + // powered down. + pnpPowerCallbacks.EvtDeviceSelfManagedIoCleanup = DeviceEvtSelfManagedIoCleanup; + + pnpPowerCallbacks.EvtDeviceSurpriseRemoval = DeviceEvtSurpriseRemoval; + + // Register the PnP and power callbacks. + WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks); + } + + // 2. Register the EvtIoInCallerContext to deal with IOCTLs that need to stay in original context. + WdfDeviceInitSetIoInCallerContextCallback(DeviceInit, + DeviceEvtIoInCallerContext); + + // 3. Register PreprocessCallback for IRP_MJ_POWER, IRP_MJ_FLUSH_BUFFERS and IRP_MJ_SHUTDOWN + { + UCHAR minorFunctions[1]; + + minorFunctions[0] = IRP_MN_SET_POWER; + + status = WdfDeviceInitAssignWdmIrpPreprocessCallback(DeviceInit, + RequestProcessSetPower, + IRP_MJ_POWER, + minorFunctions, + RTL_NUMBER_OF(minorFunctions)); + if (!NT_SUCCESS(status)) + { + TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_PNP, + "DriverEvtDeviceAdd: Assign IrpPreprocessCallback for IRP_MJ_POWER failed, " + "status: 0x%X\n", status)); + + goto Exit; + } + + status = WdfDeviceInitAssignWdmIrpPreprocessCallback(DeviceInit, + RequestProcessShutdownFlush, + IRP_MJ_FLUSH_BUFFERS, + NULL, + 0); + if (!NT_SUCCESS(status)) + { + TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_PNP, + "DriverEvtDeviceAdd: Assign IrpPreprocessCallback for IRP_MJ_FLUSH_BUFFERS failed, " + "status: 0x%X\n", status)); + + goto Exit; + } + + status = WdfDeviceInitAssignWdmIrpPreprocessCallback(DeviceInit, + RequestProcessShutdownFlush, + IRP_MJ_SHUTDOWN, + NULL, + 0); + if (!NT_SUCCESS(status)) + { + TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_PNP, + "DriverEvtDeviceAdd: Assign IrpPreprocessCallback for IRP_MJ_SHUTDOWN failed, " + "status: 0x%X\n", status)); + + goto Exit; + } + } + + // 4. Set attributes to create Request Context area. + { + //Reuse this structure. + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, + CDROM_REQUEST_CONTEXT); + attributes.EvtCleanupCallback = RequestEvtCleanup; + + WdfDeviceInitSetRequestAttributes(DeviceInit, + &attributes); + } + + // 5. Register FileObject related callbacks + { + // Add FILE_OBJECT_EXTENSION as the context to the file object. + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, FILE_OBJECT_CONTEXT); + + // Set Entry points for Create and Close.. + + // The framework doesn't sync the file create requests with pnp/power + // state. Re-direct all the file create requests to a dedicated + // queue, which will be purged manually during removal. + WDF_FILEOBJECT_CONFIG_INIT(&fileObjectConfig, + NULL, //CreateQueueEvtIoDefault, + DeviceEvtFileClose, + WDF_NO_EVENT_CALLBACK); // No callback for Cleanup + + fileObjectConfig.FileObjectClass = WdfFileObjectWdfCannotUseFsContexts; + + // Since we are registering file events and fowarding create request + // ourself, we must also set AutoForwardCleanupClose so that cleanup + // and close can also get forwarded. + fileObjectConfig.AutoForwardCleanupClose = WdfTrue; + attributes.SynchronizationScope = WdfSynchronizationScopeNone; + attributes.ExecutionLevel = WdfExecutionLevelPassive; + + // Indicate that file object is optional. + fileObjectConfig.FileObjectClass |= WdfFileObjectCanBeOptional; + + WdfDeviceInitSetFileObjectConfig(DeviceInit, + &fileObjectConfig, + &attributes); + } + + // 6. Initialize device-wide attributes + { + // Declare ourselves as NOT owning power policy. + // The power policy owner in storage stack is port driver. + WdfDeviceInitSetPowerPolicyOwnership(DeviceInit, FALSE); + + // Set other DeviceInit attributes. + WdfDeviceInitSetExclusive(DeviceInit, FALSE); + WdfDeviceInitSetDeviceType(DeviceInit, FILE_DEVICE_CD_ROM); + WdfDeviceInitSetCharacteristics(DeviceInit, FILE_REMOVABLE_MEDIA, FALSE); + WdfDeviceInitSetIoType(DeviceInit, WdfDeviceIoDirect); + WdfDeviceInitSetPowerPageable(DeviceInit); + + // We require the framework to acquire a remove lock before delivering all IRP types + WDF_REMOVE_LOCK_OPTIONS_INIT(&removeLockOptions, + WDF_REMOVE_LOCK_OPTION_ACQUIRE_FOR_IO); + + WdfDeviceInitSetRemoveLockOptions(DeviceInit, &removeLockOptions); + + // save the PDO for later reference + lowerPdo = WdfFdoInitWdmGetPhysicalDevice(DeviceInit); + + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, + CDROM_DEVICE_EXTENSION); + + // We have a parallel queue, so WdfSynchronizationScopeNone is our only choice. + attributes.SynchronizationScope = WdfSynchronizationScopeNone; + attributes.ExecutionLevel = WdfExecutionLevelDispatch; + + // Provide a cleanup callback which will release memory allocated with ExAllocatePool* + attributes.EvtCleanupCallback = DeviceEvtCleanup; + } + + // 7. Now, the device can be created. + { + wideDeviceName = ExAllocatePoolWithTag(NonPagedPoolNx, + 64 * sizeof(WCHAR), + CDROM_TAG_STRINGS); + + if (wideDeviceName == NULL) + { + status = STATUS_INSUFFICIENT_RESOURCES; + goto Exit; + } + + // Find the lowest device number currently available. + do { + status = RtlStringCchPrintfW((NTSTRSAFE_PWSTR)wideDeviceName, + 64, + L"\\Device\\CdRom%d", + deviceNumber); + + if (!NT_SUCCESS(status)) { + TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_PNP, + "DriverEvtDeviceAdd: Format device name failed with error: 0x%X\n", status)); + + goto Exit; + } + + RtlInitUnicodeString(&unicodeDeviceName, wideDeviceName); + + status = WdfDeviceInitAssignName(DeviceInit, &unicodeDeviceName); + if (!NT_SUCCESS(status)) + { + TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_PNP, + "DriverEvtDeviceAdd: WdfDeviceInitAssignName() failed with error: 0x%X\n", status)); + + goto Exit; + } + + status = WdfDeviceCreate(&DeviceInit, &attributes, &device); + + deviceNumber++; + + } while (status == STATUS_OBJECT_NAME_COLLISION); + + // When this loop exits the count is inflated by one - fix that. + deviceNumber--; + + if (!NT_SUCCESS(status)) + { + TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_PNP, + "DriverEvtDeviceAdd: Can not create a new device, status: 0x%X\n", + status)); + + goto Exit; + } + } + + // 8. Fill up basic Device Extension settings and create a remote I/O target for the next-lower driver. + // The reason why we do not use the local I/O target is because we want to be able to close the + // I/O target on surprise removal. + { + deviceExtension = DeviceGetExtension(device); + + deviceExtension->Version = 0x01; + deviceExtension->Size = sizeof(CDROM_DEVICE_EXTENSION); + + deviceExtension->DeviceObject = WdfDeviceWdmGetDeviceObject(device); + deviceExtension->Device = device; + deviceExtension->DriverExtension = driverExtension; + + deviceExtension->LowerPdo = lowerPdo; + + deviceExtension->DeviceType = FILE_DEVICE_CD_ROM; //Always a FILE_DEVICE_CD_ROM for all device it manages. + deviceExtension->DeviceName = unicodeDeviceName; + + deviceExtension->DeviceNumber = deviceNumber; + } + { + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + attributes.ParentObject = deviceExtension->Device; + + status = WdfIoTargetCreate(deviceExtension->Device, + &attributes, + &deviceExtension->IoTarget); + + if (!NT_SUCCESS(status)) + { + TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_PNP, + "DriverEvtDeviceAdd: Can not create a remote I/O target object, status: 0x%X\n", + status)); + goto Exit; + } + + WDF_IO_TARGET_OPEN_PARAMS_INIT_EXISTING_DEVICE(&ioTargetOpenParams, + WdfDeviceWdmGetAttachedDevice(deviceExtension->Device)); + + status = WdfIoTargetOpen(deviceExtension->IoTarget, + &ioTargetOpenParams); + if (!NT_SUCCESS(status)) + { + TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_PNP, + "DriverEvtDeviceAdd: Can not open a remote I/O target for the next-lower device, status: 0x%X\n", + status)); + + WdfObjectDelete(deviceExtension->IoTarget); + deviceExtension->IoTarget = NULL; + + goto Exit; + } + } + + // 9. Claim the device, so that port driver will only accept the commands from CDROM.SYS for this device. + // NOTE: The I/O should be issued after the device is started. But we would like to claim + // the device as soon as possible, so this legacy behavior is kept. + status = DeviceClaimRelease(deviceExtension, FALSE); + + if (!NT_SUCCESS(status)) + { + // Someone already had this device - we're in trouble + goto Exit; + } + else + { + deviceClaimed = TRUE; + } + + // + // CDROM Queueing Structure + // + // a. EvtIoInCallerContext (prior to queueing): + // This event will be used ONLY to forward down IOCTLs that come in at PASSIVE LEVEL + // and need to be forwarded down the stack in the original context. + // + // b. Main input queue: serial queue for main dispatching + // This queue will be used to do all dispatching of requests to serialize + // access to the device. Any request that was previously completed in + // the Dispatch routines will be completed here. Anything requiring device + // I/O will be sent through the serial I/O queue. + // + // 10. Set up IO queues after device being created. + // + { + WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&queueConfig, + WdfIoQueueDispatchSequential); + + queueConfig.PowerManaged = WdfFalse; + +#pragma prefast(push) +#pragma prefast(disable: 28155, "a joint handler for read/write cannot be EVT_WDF_IO_QUEUE_IO_READ and EVT_WDF_IO_QUEUE_IO_WRITE simultaneously") +#pragma prefast(disable: 28023, "a joint handler for read/write cannot be EVT_WDF_IO_QUEUE_IO_READ and EVT_WDF_IO_QUEUE_IO_WRITE simultaneously") + queueConfig.EvtIoRead = SequentialQueueEvtIoReadWrite; + queueConfig.EvtIoWrite = SequentialQueueEvtIoReadWrite; +#pragma prefast(pop) + + queueConfig.EvtIoDeviceControl = SequentialQueueEvtIoDeviceControl; + queueConfig.EvtIoCanceledOnQueue = SequentialQueueEvtCanceledOnQueue; + + status = WdfIoQueueCreate(device, + &queueConfig, + WDF_NO_OBJECT_ATTRIBUTES, + &(deviceExtension->SerialIOQueue)); + if (!NT_SUCCESS(status)) + { + goto Exit; + } + + // this queue is dedicated for file create requests. + WDF_IO_QUEUE_CONFIG_INIT(&queueConfig, WdfIoQueueDispatchParallel); + + queueConfig.PowerManaged = WdfFalse; + queueConfig.EvtIoDefault = CreateQueueEvtIoDefault; + + //Reuse this structure. + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, + CDROM_REQUEST_CONTEXT); + + attributes.SynchronizationScope = WdfSynchronizationScopeNone; + attributes.ExecutionLevel = WdfExecutionLevelPassive; + + status = WdfIoQueueCreate(device, + &queueConfig, + &attributes, + &(deviceExtension->CreateQueue)); + + if (!NT_SUCCESS(status)) + { + goto Exit; + } + + // Configure the device to use driver created queue for dispatching create. + status = WdfDeviceConfigureRequestDispatching(device, + deviceExtension->CreateQueue, + WdfRequestTypeCreate); + + if (!NT_SUCCESS(status)) + { + goto Exit; + } + } + + // 11. Set the alignment requirements for the device based on the host adapter requirements. + // + // NOTE: this should have been set when device is attached on device stack, + // by keeping this legacy code, we could avoid issue that this value was not correctly set at that time. + if (deviceExtension->LowerPdo->AlignmentRequirement > deviceExtension->DeviceObject->AlignmentRequirement) + { + WdfDeviceSetAlignmentRequirement(deviceExtension->Device, + deviceExtension->LowerPdo->AlignmentRequirement); + } + + // 12. Initialization of miscellaneous internal properties + + // CDROMs are not partitionable so starting offset is 0. + deviceExtension->StartingOffset.LowPart = 0; + deviceExtension->StartingOffset.HighPart = 0; + + // Set the default geometry for the cdrom to match what NT 4 used. + // these values will be used to compute the cylinder count rather + // than using it's NT 5.0 defaults. + deviceExtension->DiskGeometry.MediaType = RemovableMedia; + deviceExtension->DiskGeometry.TracksPerCylinder = 0x40; + deviceExtension->DiskGeometry.SectorsPerTrack = 0x20; + + deviceExtension->DeviceAdditionalData.ReadWriteRetryDelay100nsUnits = WRITE_RETRY_DELAY_DVD_1x; + + // Clear the SrbFlags and disable synchronous transfers + deviceExtension->SrbFlags = SRB_FLAGS_DISABLE_SYNCH_TRANSFER; + + // Set timeout value in seconds. + deviceExtension->TimeOutValue = DeviceGetTimeOutValueFromRegistry(); + if ((deviceExtension->TimeOutValue > 30 * 60) || // longer than 30 minutes + (deviceExtension->TimeOutValue == 0)) + { + deviceExtension->TimeOutValue = SCSI_CDROM_TIMEOUT; + } + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, + "DriverEvtDeviceAdd: device timeout is set to %x seconds", + deviceExtension->TimeOutValue + )); + +#if (NTDDI_VERSION >= NTDDI_WIN8) + deviceExtension->IsVolumeOnlinePending = TRUE; + + WDF_IO_QUEUE_CONFIG_INIT(&queueConfig, WdfIoQueueDispatchManual); + + queueConfig.PowerManaged = WdfFalse; + + status = WdfIoQueueCreate(device, + &queueConfig, + WDF_NO_OBJECT_ATTRIBUTES, + &deviceExtension->ManualVolumeReadyQueue); + + if (!NT_SUCCESS(status)) + { + goto Exit; + } +#endif + + // 13. Initialize the stuff related to media locking + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + attributes.ParentObject = deviceExtension->Device; + status = WdfWaitLockCreate(&attributes, + &deviceExtension->EjectSynchronizationLock); + + deviceExtension->LockCount = 0; + + // 14. Initialize context structures needed for asynchronous release queue and power requests + + if (NT_SUCCESS(status)) + { + status = DeviceInitReleaseQueueContext(deviceExtension); + } + + if (NT_SUCCESS(status)) + { + status = DeviceInitPowerContext(deviceExtension); + } + + // 15. Create external access points other than device name. + if (NT_SUCCESS(status)) + { + status = DeviceCreateWellKnownName(deviceExtension); + } + + // 16. Query session id from the PDO. + if (NT_SUCCESS(status)) + { + status = IoGetDevicePropertyData(deviceExtension->LowerPdo, + &DEVPKEY_Device_SessionId, + 0, + 0, + sizeof(devicePropertySessionId), + &devicePropertySessionId, + &devicePropertySize, + &devicePropertyType); + + if (!NT_SUCCESS(status)) + { + // The device is global. + devicePropertySessionId = INVALID_SESSION; + status = STATUS_SUCCESS; + } + } + + // 17. Register interfaces for this device. + if (NT_SUCCESS(status)) + { + status = DeviceRegisterInterface(deviceExtension, CdRomDeviceInterface); + } + + if (NT_SUCCESS(status)) + { + // If this is a per-session DO, don't register for mount interface so that + // mountmgr will not automatically assign a drive letter. + if (devicePropertySessionId == INVALID_SESSION) + { + status = DeviceRegisterInterface(deviceExtension, MountedDeviceInterface); + } + } + + // 18. Initialize the shutdown/flush lock + if (NT_SUCCESS(status)) + { + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + attributes.ParentObject = deviceExtension->Device; + + status = WdfWaitLockCreate(&attributes, &deviceExtension->ShutdownFlushWaitLock); + if (!NT_SUCCESS(status)) + { + TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_PNP, + "DriverEvtDeviceAdd: Cannot create shutdown/flush waitlock, status: 0x%X\n", + status)); + } + } + + // 19. Initialize the work item that is used to initiate asynchronous reads/writes + if (NT_SUCCESS(status)) + { + WDF_WORKITEM_CONFIG workItemConfig; + WDF_OBJECT_ATTRIBUTES workItemAttributes; + + WDF_WORKITEM_CONFIG_INIT(&workItemConfig, + ReadWriteWorkItemRoutine + ); + + WDF_OBJECT_ATTRIBUTES_INIT(&workItemAttributes); + workItemAttributes.ParentObject = deviceExtension->Device; + + status = WdfWorkItemCreate(&workItemConfig, + &workItemAttributes, + &deviceExtension->ReadWriteWorkItem + ); + + if (!NT_SUCCESS(status)) + { + TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_INIT, + "DriverEvtDeviceAdd: Cannot create read/write work item, status: 0x%X\n", + status)); + } + } + + // 20. Initialize the work item that is used to process most IOCTLs at PASSIVE_LEVEL. + if (NT_SUCCESS(status)) + { + WDF_WORKITEM_CONFIG workItemConfig; + WDF_OBJECT_ATTRIBUTES workItemAttributes; + + WDF_WORKITEM_CONFIG_INIT(&workItemConfig, + IoctlWorkItemRoutine + ); + + WDF_OBJECT_ATTRIBUTES_INIT(&workItemAttributes); + workItemAttributes.ParentObject = deviceExtension->Device; + + status = WdfWorkItemCreate(&workItemConfig, + &workItemAttributes, + &deviceExtension->IoctlWorkItem + ); + + if (!NT_SUCCESS(status)) + { + TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_INIT, + "DriverEvtDeviceAdd: Cannot create ioctl work item, status: 0x%X\n", + status)); + } + } + + +Exit: + + if (!NT_SUCCESS(status)) + { + FREE_POOL(wideDeviceName); + + if (deviceExtension != NULL) + { + RtlInitUnicodeString(&deviceExtension->DeviceName, NULL); + } + + // Release the device with the port driver, if it was claimed + if ((deviceExtension != NULL) && deviceClaimed) + { + DeviceClaimRelease(deviceExtension, TRUE); + } + deviceClaimed = FALSE; + } + + return status; +} + + +VOID +DeviceEvtCleanup( + _In_ WDFOBJECT Device + ) +/*++ +Routine Description: + + Free all the resources allocated in DriverEvtDeviceAdd. + +Arguments: + + Device - handle to a WDF Device object. + +Return Value: + + VOID. + +--*/ +{ + WDFDEVICE device = (WDFDEVICE)Device; + PCDROM_DEVICE_EXTENSION deviceExtension = NULL; + + PAGED_CODE (); + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, + "WDFDEVICE %p cleanup: The device is about to be destroyed.\n", + device)); + + deviceExtension = DeviceGetExtension(device); + + FREE_POOL(deviceExtension->DeviceName.Buffer); + RtlInitUnicodeString(&deviceExtension->DeviceName, NULL); + + if (deviceExtension->DeviceAdditionalData.WellKnownName.Buffer != NULL) + { + IoDeleteSymbolicLink(&deviceExtension->DeviceAdditionalData.WellKnownName); + } + + FREE_POOL(deviceExtension->DeviceAdditionalData.WellKnownName.Buffer); + RtlInitUnicodeString(&deviceExtension->DeviceAdditionalData.WellKnownName, NULL); + + return; +} + + +VOID +DeviceEvtSelfManagedIoCleanup( + _In_ WDFDEVICE Device + ) +/*++ + +Routine Description: + + this function is called when the device is removed. + release the ownership of the device, release allocated resources. + +Arguments: + + Device - Handle to device object + +Return Value: + + None. + +--*/ +{ + NTSTATUS status; + PCDROM_DEVICE_EXTENSION deviceExtension = NULL; + + PAGED_CODE (); + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, + "DeviceEvtSelfManagedIoCleanup: WDFDEVICE %p is being stopped.\n", + Device)); + + // extract the device and driver extensions + deviceExtension = DeviceGetExtension(Device); + + // Purge unprocessed requests, stop the IO queues. + // Incoming request will be completed with STATUS_INVALID_DEVICE_STATE status. + WdfIoQueuePurge(deviceExtension->SerialIOQueue, WDF_NO_EVENT_CALLBACK, WDF_NO_CONTEXT); + WdfIoQueuePurge(deviceExtension->CreateQueue, WDF_NO_EVENT_CALLBACK, WDF_NO_CONTEXT); + + // Close the IoTarget so that we are sure there are no outstanding I/Os in the stack. + if (deviceExtension->IoTarget) + { + WdfIoTargetClose(deviceExtension->IoTarget); + } + + // Release the device + if (!deviceExtension->SurpriseRemoved) + { + status = DeviceClaimRelease(deviceExtension, TRUE); //status is mainly for debugging. we don't really care. + UNREFERENCED_PARAMETER(status); //defensive coding, avoid PREFAST warning. + } + + // Be sure to flush the DPCs as the READ/WRITE timer routine may still be running + // during device removal. This call may take a while to complete. + KeFlushQueuedDpcs(); + + // Release all the memory that we have allocated. + + DeviceDeallocateMmcResources(Device); + ScratchBuffer_Deallocate(deviceExtension); + RtlZeroMemory(&(deviceExtension->DeviceAdditionalData.Mmc), sizeof(CDROM_MMC_EXTENSION)); + + FREE_POOL(deviceExtension->DeviceDescriptor); + FREE_POOL(deviceExtension->AdapterDescriptor); + FREE_POOL(deviceExtension->PowerDescriptor); + FREE_POOL(deviceExtension->SenseData); + + if (deviceExtension->DeviceAdditionalData.CachedInquiryData != NULL) + { + FREE_POOL(deviceExtension->DeviceAdditionalData.CachedInquiryData); + deviceExtension->DeviceAdditionalData.CachedInquiryDataByteCount = 0; + } + + FREE_POOL(deviceExtension->PrivateFdoData); + + DeviceReleaseMcnResources(deviceExtension); + + DeviceReleaseZPODDResources(deviceExtension); + + // Keep the system-wide CDROM count accurate, as programs use this info to + // know when they have found all the cdroms in a system. + IoGetConfigurationInformation()->CdRomCount--; + + deviceExtension->PartitionLength.QuadPart = 0; + + // All WDF objects related to Device will be automatically released + // when the root object is deleted. No need to release them manually. + + return; +} + +NTSTATUS +DeviceEvtD0Entry( + _In_ WDFDEVICE Device, + _In_ WDF_POWER_DEVICE_STATE PreviousState + ) +/*++ + +Routine Description: + + This function is called when the device is coming back from a lower power state to D0. + This function cannot be placed in a pageable section. + +Arguments: + + Device - Handle to device object + PreviousState - Power state the device was in. + +Return Value: + + NTSTATUS: alway STATUS_SUCCESS + +--*/ +{ + PCDROM_DEVICE_EXTENSION deviceExtension; + NTSTATUS status = STATUS_SUCCESS; + PZERO_POWER_ODD_INFO zpoddInfo = NULL; + STORAGE_IDLE_POWERUP_REASON powerupReason = {0}; + + UNREFERENCED_PARAMETER(PreviousState); + deviceExtension = DeviceGetExtension(Device); + + // Make certain not to do anything before properly initialized + if (deviceExtension->IsInitialized) + { + zpoddInfo = deviceExtension->ZeroPowerODDInfo; + + if (zpoddInfo != NULL) + { + if (zpoddInfo->InZeroPowerState != FALSE) + { + // We just woke up from Zero Power state + zpoddInfo->InZeroPowerState = FALSE; + zpoddInfo->RetryFirstCommand = TRUE; + zpoddInfo->BecomingReadyRetryCount = BECOMING_READY_RETRY_COUNT; + + status = DeviceZPODDGetPowerupReason(deviceExtension, &powerupReason); + + if (NT_SUCCESS(status) && + (powerupReason.PowerupReason == StoragePowerupDeviceAttention)) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, + "DeviceEvtD0Entry: Device has left zero power state due to eject button pressed\n" + )); + + // This wake-up is caused by user pressing the eject button. + // In case of drawer type, we need to soft eject the tray to emulate the effect. + // Note that the first command to the device after power resumed will + // be terminated with CHECK CONDITION status with sense code 6/29/00, + // but we already have a retry logic to handle this. + if ((zpoddInfo->LoadingMechanism == LOADING_MECHANISM_TRAY) && (zpoddInfo->Load == 0)) // Drawer + { + DeviceSendIoctlAsynchronously(deviceExtension, IOCTL_STORAGE_EJECT_MEDIA, deviceExtension->DeviceObject); + } + } + else + { + // This wake-up is caused by non-cached CDB received or a 3rd-party driver + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, + "DeviceEvtD0Entry: Device has left zero power state due to IO received\n" + )); + + } + } + } + + DeviceEnableMainTimer(deviceExtension); + } + + return STATUS_SUCCESS; +} + +NTSTATUS +DeviceEvtD0Exit( + _In_ WDFDEVICE Device, + _In_ WDF_POWER_DEVICE_STATE TargetState + ) +/*++ + +Routine Description: + + This function is called when the device is entering lower powe state from D0 or it's removed. + We only care about the case of device entering D3. + The purpose of this function is to send SYNC CACHE command and STOP UNIT command if it's necessary. + +Arguments: + + Device - Handle to device object + TargetState - Power state the device is entering. + +Return Value: + + NTSTATUS: alway STATUS_SUCCESS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PCDROM_DEVICE_EXTENSION deviceExtension = NULL; + PZERO_POWER_ODD_INFO zpoddInfo = NULL; + + PAGED_CODE (); + + deviceExtension = DeviceGetExtension(Device); + zpoddInfo = deviceExtension->ZeroPowerODDInfo; + + // we only process the situation that the device is going into D3. + if ((TargetState != WdfPowerDeviceD3) && + (TargetState != WdfPowerDeviceD3Final)) + { + return STATUS_SUCCESS; + } + + // Stop the main timer + DeviceDisableMainTimer(deviceExtension); + + // note: do not stop CreateQueue as the create request can be handled by port driver even the device is in D3 status. + + // If initialization was not finished or the device was removed, we cannot interact + // with it device, so we have to exit + if ((!deviceExtension->IsInitialized) || deviceExtension->SurpriseRemoved) + { + return STATUS_SUCCESS; + } + + +#ifdef DBG + #if (WINVER >= 0x0601) + // this API is introduced in Windows7 + { + ULONG secondsRemaining = 0; + BOOLEAN watchdogTimeSupported = FALSE; + + watchdogTimeSupported = PoQueryWatchdogTime(deviceExtension->LowerPdo, &secondsRemaining); + UNREFERENCED_PARAMETER(watchdogTimeSupported); + } + #endif +#endif + + deviceExtension->PowerDownInProgress = TRUE; + + status = PowerContextBeginUse(deviceExtension); + + deviceExtension->PowerContext.Options.PowerDown = TRUE; + + // Step 1. LOCK QUEUE + if (NT_SUCCESS(status) && + (TargetState != WdfPowerDeviceD3Final)) + { + status = DeviceSendPowerDownProcessRequest(deviceExtension, NULL, NULL); + + if (NT_SUCCESS(status)) + { + deviceExtension->PowerContext.Options.LockQueue = TRUE; + } + + // Ignore failure. + status = STATUS_SUCCESS; + } + + deviceExtension->PowerContext.PowerChangeState.PowerDown++; + + // Step 2. QUIESCE QUEUE + if (NT_SUCCESS(status) && + (TargetState != WdfPowerDeviceD3Final)) + { + status = DeviceSendPowerDownProcessRequest(deviceExtension, NULL, NULL); + UNREFERENCED_PARAMETER(status); + // We don't care about the status. + status = STATUS_SUCCESS; + } + + deviceExtension->PowerContext.PowerChangeState.PowerDown++; + + // Step 3. SYNC CACHE command should be sent to drive if the media is currently writable. + if (NT_SUCCESS(status) && + deviceExtension->DeviceAdditionalData.Mmc.WriteAllowed) + { + status = DeviceSendPowerDownProcessRequest(deviceExtension, NULL, NULL); + UNREFERENCED_PARAMETER(status); + status = STATUS_SUCCESS; + } + + deviceExtension->PowerContext.PowerChangeState.PowerDown++; + + // Step 4. STOP UNIT + if (NT_SUCCESS(status) && + !TEST_FLAG(deviceExtension->ScanForSpecialFlags, CDROM_SPECIAL_DISABLE_SPIN_DOWN)) + { + status = DeviceSendPowerDownProcessRequest(deviceExtension, NULL, NULL); + UNREFERENCED_PARAMETER(status); + status = STATUS_SUCCESS; + } + + if (TargetState == WdfPowerDeviceD3Final) + { + // We're done with the power context. + PowerContextEndUse(deviceExtension); + } + + // Bumping the media change count will force the file system to verify the volume when we resume + SET_FLAG(deviceExtension->DeviceObject->Flags, DO_VERIFY_VOLUME); + InterlockedIncrement((PLONG)&deviceExtension->MediaChangeCount); + + // If this power down is caused by Zero Power ODD, we should mark the device as in ZPODD mode. + if (zpoddInfo != NULL) + { + zpoddInfo->InZeroPowerState = TRUE; + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, + "Device has entered zero power state\n" + )); + } + + deviceExtension->PowerDownInProgress = FALSE; + + return STATUS_SUCCESS; +} + + +VOID +DeviceEvtSurpriseRemoval( + _In_ WDFDEVICE Device + ) +/*++ + +Routine Description: + + this function is called when the device is surprisely removed. + Stop all IO queues so that there will be no more request being sent down. + +Arguments: + + Device - Handle to device object + +Return Value: + + None. + +--*/ +{ + PCDROM_DEVICE_EXTENSION deviceExtension = NULL; + + PAGED_CODE(); + + deviceExtension = DeviceGetExtension(Device); + + deviceExtension->SurpriseRemoved = TRUE; + + // Stop the main timer + DeviceDisableMainTimer(deviceExtension); + + // legacy behavior to set partition length to be 0. + deviceExtension->PartitionLength.QuadPart = 0; + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, + "Surprisely remove a WDFDEVICE %p\n", Device)); + + return; +} + + +VOID +CreateQueueEvtIoDefault( + _In_ WDFQUEUE Queue, + _In_ WDFREQUEST Request + ) +/*++ + +Routine Description: + + this function is called when CREATE irp comes. + setup FileObject context fields, so it can be used to track MCN or exclusive lock/unlock. + +Arguments: + + Queue - Handle to device queue + + Request - the creation request + +Return Value: + + None + +--*/ +{ + WDFFILEOBJECT fileObject = WdfRequestGetFileObject(Request); + WDFDEVICE device = WdfIoQueueGetDevice(Queue); + NTSTATUS status = STATUS_SUCCESS; + PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(device); + PFILE_OBJECT_CONTEXT fileObjectContext = NULL; + + PAGED_CODE(); + + if (fileObject == NULL) { + + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_QUEUE, + "Error: received a file create request with file object set to NULL\n")); + + RequestCompletion(deviceExtension, Request, STATUS_INTERNAL_ERROR, 0); + return; + } + + fileObjectContext = FileObjectGetContext(fileObject); + + // Initialize this WDFFILEOBJECT's context + fileObjectContext->DeviceObject = device; + fileObjectContext->FileObject = fileObject; + fileObjectContext->LockCount = 0; + fileObjectContext->McnDisableCount = 0; + fileObjectContext->EnforceStreamingRead = FALSE; + fileObjectContext->EnforceStreamingWrite = FALSE; + + // send down the create synchronously + status = DeviceSendRequestSynchronously(device, Request, FALSE); + + // Need to complete the request in this routine. + RequestCompletion(deviceExtension, Request, status, WdfRequestGetInformation(Request)); + + return; +} + +VOID +DeviceEvtFileClose( + _In_ WDFFILEOBJECT FileObject + ) +/*++ + +Routine Description: + + this function is called when CLOSE irp comes. + clean up MCN / Lock if necessary + +Arguments: + + FileObject - WDF file object created for the irp. + +Return Value: + + None + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + + PAGED_CODE(); + + if (FileObject != NULL) + { + WDFDEVICE device = WdfFileObjectGetDevice(FileObject); + PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(device); + PCDROM_DATA cdData = &(deviceExtension->DeviceAdditionalData); + PFILE_OBJECT_CONTEXT fileObjectContext = FileObjectGetContext(FileObject); + + // cleanup locked media tray + status = DeviceCleanupProtectedLocks(deviceExtension, fileObjectContext); + if (!NT_SUCCESS(status)) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, + "Failed to cleanup protected locks for WDFDEVICE %p, %!STATUS!\n", device, status)); + } + + // cleanup disabled MCN + status = DeviceCleanupDisableMcn(deviceExtension, fileObjectContext); + if (!NT_SUCCESS(status)) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, + "Failed to disable MCN for WDFDEVICE %p, %!STATUS!\n", device, status)); + } + + // cleanup exclusive access + if (EXCLUSIVE_MODE(cdData) && EXCLUSIVE_OWNER(cdData, FileObject)) + { + status = DeviceUnlockExclusive(deviceExtension, FileObject, FALSE); + if (!NT_SUCCESS(status)) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, + "Failed to release exclusive lock for WDFDEVICE %p, %!STATUS!\n", device, status)); + } + } + } + + return; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +DeviceCleanupProtectedLocks( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ PFILE_OBJECT_CONTEXT FileObjectContext + ) +/*++ + +Routine Description: + + this function removes protected locks for the handle + +Arguments: + + DeviceExtension - device context + + FileObject - WDF file object created for the irp. + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + + PAGED_CODE(); + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, + "CleanupProtectedLocks called for WDFDEVICE %p, WDFFILEOBJECT %p, locked %d times.\n", + DeviceExtension->Device, FileObjectContext->FileObject, FileObjectContext->LockCount)); + + // Synchronize with ejection and ejection control requests. + WdfWaitLockAcquire(DeviceExtension->EjectSynchronizationLock, NULL); + + // For each secure lock on this handle decrement the secured lock count + // for the FDO. Keep track of the new value. + if (FileObjectContext->LockCount != 0) + { + DeviceExtension->ProtectedLockCount -= FileObjectContext->LockCount; + FileObjectContext->LockCount = 0; + + // If the new lock count has been dropped to zero then issue a lock + // command to the device. + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, + "FDO secured lock count = %d " + "lock count = %d\n", + DeviceExtension->ProtectedLockCount, + DeviceExtension->LockCount)); + + if ((DeviceExtension->ProtectedLockCount == 0) && (DeviceExtension->LockCount == 0)) + { + SCSI_REQUEST_BLOCK srb = {0}; + PCDB cdb = (PCDB) &(srb.Cdb); + + srb.CdbLength = 6; + + cdb->MEDIA_REMOVAL.OperationCode = SCSIOP_MEDIUM_REMOVAL; + + // TRUE - prevent media removal. + // FALSE - allow media removal. + cdb->MEDIA_REMOVAL.Prevent = FALSE; + + // Set timeout value. + srb.TimeOutValue = DeviceExtension->TimeOutValue; + status = DeviceSendSrbSynchronously(DeviceExtension->Device, + &srb, + NULL, + 0, + FALSE, + NULL); + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, + "Allow media removal (unlock) request to drive returned %!STATUS!\n", + status)); + } + } + + WdfWaitLockRelease(DeviceExtension->EjectSynchronizationLock); + + return status; +} + + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DeviceCleanupDisableMcn( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ PFILE_OBJECT_CONTEXT FileObjectContext + ) +/*++ + +Routine Description: + + cleanup the MCN disable count for the handle + +Arguments: + + DeviceExtension - device context + + FileObject - WDF file object created for the irp. + +Return Value: + + NTSTATUS + +--*/ +{ + PAGED_CODE(); + + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT, + "CleanupDisableMcn called for WDFDEVICE %p, WDFFILEOBJECT %p, locked %d times.\n", + DeviceExtension->Device, FileObjectContext->FileObject, FileObjectContext->McnDisableCount)); + + // For each secure lock on this handle decrement the secured lock count + // for the FDO. Keep track of the new value. + while (FileObjectContext->McnDisableCount != 0) + { + DeviceEnableMediaChangeDetection(DeviceExtension, FileObjectContext, TRUE); + } + + return STATUS_SUCCESS; +} + +VOID +NormalizeIoctl( + _Inout_ PWDF_REQUEST_PARAMETERS requestParameters + ) +{ + ULONG ioctlCode; + ULONG baseCode; + ULONG functionCode; + + // if this is a class driver ioctl then we need to change the base code + // to IOCTL_STORAGE_BASE so that the switch statement can handle it. + // + // WARNING - currently the scsi class ioctl function codes are between + // 0x200 & 0x300. this routine depends on that fact + ioctlCode = requestParameters->Parameters.DeviceIoControl.IoControlCode; + baseCode = DEVICE_TYPE_FROM_CTL_CODE(ioctlCode); + functionCode = (ioctlCode & (~0xffffc003)) >> 2; + + if ((baseCode == IOCTL_SCSI_BASE) || + (baseCode == IOCTL_DISK_BASE) || + (baseCode == IOCTL_TAPE_BASE) || + (baseCode == IOCTL_DVD_BASE) || + (baseCode == IOCTL_CDROM_BASE)) + //IOCTL_STORAGE_BASE does not need to be converted. + { + if((functionCode >= 0x200) && (functionCode <= 0x300)) + { + ioctlCode = (ioctlCode & 0x0000ffff) | CTL_CODE(IOCTL_STORAGE_BASE, 0, 0, 0); + + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL, + "IOCTL code recalibrate, New ioctl code is %lx\n", + ioctlCode)); + + // Set the code into request parameters, then "requestParameters" needs to be used for dispatch functions. + requestParameters->Parameters.DeviceIoControl.IoControlCode = ioctlCode; + } + } +} + +VOID +DeviceEvtIoInCallerContext( + _In_ WDFDEVICE Device, + _In_ WDFREQUEST Request + ) +/*++ +Routine Description: + + Responds to EvtIoInCallerContext events from KMDF + It calls different functions to process different type of IOCTLs. + +Arguments: + + Device - handle to a WDF Device object + + Request - handle to the incoming WDF Request object + +Return Value: + + VOID. + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(Device); + PCDROM_REQUEST_CONTEXT requestContext = RequestGetContext(Request); + WDF_REQUEST_PARAMETERS requestParameters; + + requestContext->DeviceExtension = deviceExtension; + + // set the received time + RequestSetReceivedTime(Request); + + // get the request parameters + WDF_REQUEST_PARAMETERS_INIT(&requestParameters); + WdfRequestGetParameters(Request, &requestParameters); + + if (requestParameters.Type == WdfRequestTypeDeviceControl) + { + BOOLEAN processed = FALSE; + PCDROM_DATA cdData = &(deviceExtension->DeviceAdditionalData); + PMEDIA_CHANGE_DETECTION_INFO info = deviceExtension->MediaChangeDetectionInfo; + + if (requestParameters.Parameters.DeviceIoControl.IoControlCode != IOCTL_MCN_SYNC_FAKE_IOCTL) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, + "Receiving IOCTL: %lx\n", + requestParameters.Parameters.DeviceIoControl.IoControlCode)); + } + else + { + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL, + "Receiving IOCTL: %lx\n", + requestParameters.Parameters.DeviceIoControl.IoControlCode)); + } + + // If the device is in exclusive mode, check whether the request is from + // the handle that locked the device. + if (EXCLUSIVE_MODE(cdData) && !EXCLUSIVE_OWNER(cdData, WdfRequestGetFileObject(Request))) + { + BOOLEAN isBlocked = FALSE; + + status = RequestIsIoctlBlockedByExclusiveAccess(Request, &isBlocked); + UNREFERENCED_PARAMETER(status); //defensive coding, avoid PREFAST warning. + + if (isBlocked) + { + if ((requestParameters.Parameters.DeviceIoControl.IoControlCode == IOCTL_STORAGE_EVENT_NOTIFICATION) && + (info != NULL) && (info->AsynchronousNotificationSupported != FALSE)) + { + // If AN is supported and we receive a signal but we can't send down GESN + // due to exclusive lock, we should save it and fire a GESN when it's unlocked. + // We just need true/false here and don't need count because we will keep sending + // GESN until we deplete all events. + info->ANSignalPendingDueToExclusiveLock = TRUE; + } + + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, + "Access Denied! Device in exclusive mode.Failing Ioctl %lx\n", + requestParameters.Parameters.DeviceIoControl.IoControlCode)); + RequestCompletion(deviceExtension, Request, STATUS_ACCESS_DENIED, 0); + + return; + } + } + + NormalizeIoctl(&requestParameters); + + // 1. All requests that don't need to access device can be processed immediately + if (!processed) + { + processed = RequestDispatchProcessDirectly(Device, Request, requestParameters); + } + + // 2. Requests that should be put in sequential queue. + if (!processed) + { + processed = RequestDispatchToSequentialQueue(Device, Request, requestParameters); + } + + // 3. Requests that need to be processed sequentially and in caller's context. + if (!processed) + { + processed = RequestDispatchSyncWithSequentialQueue(Device, Request, requestParameters); + } + + // 4. Special requests that needs different process in different cases. + if (!processed) + { + processed = RequestDispatchSpecialIoctls(Device, Request, requestParameters); + } + + // 5. This is default behavior for unknown IOCTLs. To pass it to lower level. + if (!processed) + { + processed = RequestDispatchUnknownRequests(Device, Request, requestParameters); + } + + // All requests should be processed already. + NT_ASSERT(processed); + UNREFERENCED_PARAMETER(processed); //defensive coding, avoid PREFAST warning. + } + else if (requestParameters.Type == WdfRequestTypeDeviceControlInternal) + { + RequestProcessInternalDeviceControl(Request, deviceExtension); + } + else + { + // Requests other than IOCTLs will be forwarded to default queue. + status = WdfDeviceEnqueueRequest(Device, Request); + if (!NT_SUCCESS(status)) + { + RequestCompletion(deviceExtension, Request, status, WdfRequestGetInformation(Request)); + } + } + + return; +} + + +BOOLEAN +RequestDispatchProcessDirectly( + _In_ WDFDEVICE Device, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters + ) +/*++ +Routine Description: + + These requests can be processed in a non-serialized manner, most of them don't need to access device. + +Arguments: + + Device - handle to a WDF Device object + + Request - handle to the incoming WDF Request object + + RequestParameters - request parameters + +Return Value: + + BOOLEAN - TRUE (request processed); FALSE (request is not processed in this function). + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + BOOLEAN processed = FALSE; + size_t dataLength = 0; + + PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(Device); + ULONG ioctlCode = RequestParameters.Parameters.DeviceIoControl.IoControlCode; + + switch (ioctlCode) + { + + case IOCTL_CDROM_GET_INQUIRY_DATA: + { + status = RequestHandleGetInquiryData(deviceExtension, Request, RequestParameters, &dataLength); + + processed = TRUE; + break; // complete the irp + } + + case IOCTL_STORAGE_GET_MEDIA_TYPES_EX: + { + status = RequestHandleGetMediaTypeEx(deviceExtension, Request, &dataLength); + + processed = TRUE; + break; // complete the irp + } + + case IOCTL_MOUNTDEV_QUERY_UNIQUE_ID: + { + status = RequestHandleMountQueryUniqueId(deviceExtension, Request, RequestParameters, &dataLength); + + processed = TRUE; + break; // complete the irp + } + + case IOCTL_MOUNTDEV_QUERY_DEVICE_NAME: + { + status = RequestHandleMountQueryDeviceName(deviceExtension, Request, RequestParameters, &dataLength); + + processed = TRUE; + break; // complete the irp + } + + case IOCTL_MOUNTDEV_QUERY_SUGGESTED_LINK_NAME: + { + status = RequestHandleMountQuerySuggestedLinkName(deviceExtension, Request, RequestParameters, &dataLength); + + processed = TRUE; + break; // complete the irp + } + + case IOCTL_STORAGE_GET_DEVICE_NUMBER: + { + status = RequestHandleGetDeviceNumber(deviceExtension, Request, RequestParameters, &dataLength); + + processed = TRUE; + break; // complete the irp + } + + case IOCTL_STORAGE_GET_HOTPLUG_INFO: + { + status = RequestHandleGetHotPlugInfo(deviceExtension, Request, RequestParameters, &dataLength); + + processed = TRUE; + break; // complete the irp + } + + case IOCTL_STORAGE_SET_HOTPLUG_INFO: + { + status = RequestHandleSetHotPlugInfo(deviceExtension, Request, RequestParameters, &dataLength); + + processed = TRUE; + break; // complete the irp + } + + case IOCTL_STORAGE_EVENT_NOTIFICATION: + { + status = RequestHandleEventNotification(deviceExtension, Request, &RequestParameters, &dataLength); + + processed = TRUE; + break; // complete the irp + } + +#if (NTDDI_VERSION >= NTDDI_WIN8) + case IOCTL_VOLUME_ONLINE: + { + // + // Mount manager and volume manager will + // follow this online with a post online + // but other callers may not. In those + // cases, we process this request right + // away. We approximate that these other + // callers are from user mode + // + + if (WdfRequestGetRequestorMode(Request) == KernelMode) + { + processed = TRUE; + } + break; + } +#endif + + default: + { + processed = FALSE; + break; + } + + } //end of switch (ioctlCode) + + if (processed) + { + UCHAR currentStackLocationFlags = 0; + currentStackLocationFlags = RequestGetCurrentStackLocationFlags(Request); + + if ((status == STATUS_VERIFY_REQUIRED) && + (currentStackLocationFlags & SL_OVERRIDE_VERIFY_VOLUME)) + { + // If the status is verified required and this request + // should bypass verify required then retry the request. + status = STATUS_IO_DEVICE_ERROR; + UNREFERENCED_PARAMETER(status); // disables prefast warning; defensive coding... + + processed = RequestDispatchProcessDirectly(Device, Request, RequestParameters); + } + else + { + // Complete the request after processing it. + RequestCompletion(deviceExtension, Request, status, dataLength); + } + } + + return processed; +} + + +BOOLEAN +RequestDispatchToSequentialQueue( + _In_ WDFDEVICE Device, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters + ) +/*++ +Routine Description: + + These requests can be processed in a non-serialized manner, most of them don't need to access device. + +Arguments: + + Device - handle to a WDF Device object + + Request - handle to the incoming WDF Request object + + RequestParameters - request parameters + +Return Value: + + BOOLEAN - TRUE (request processed); FALSE (request is not processed in this function). + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + BOOLEAN processed = FALSE; + size_t dataLength = 0; + BOOLEAN inZeroPowerState = FALSE; + + PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(Device); + ULONG ioctlCode = RequestParameters.Parameters.DeviceIoControl.IoControlCode; + PZERO_POWER_ODD_INFO zpoddInfo = deviceExtension->ZeroPowerODDInfo; + + if ((zpoddInfo != NULL) && + (zpoddInfo->InZeroPowerState != FALSE)) + { + inZeroPowerState = TRUE; + } + + switch (ioctlCode) + { + + case IOCTL_CDROM_RAW_READ: + { + status = RequestValidateRawRead(deviceExtension, Request, RequestParameters, &dataLength); + + processed = TRUE; + break; + } + + case IOCTL_DISK_GET_DRIVE_GEOMETRY_EX: + case IOCTL_CDROM_GET_DRIVE_GEOMETRY_EX: + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, + "RequestDispatchToSequentialQueue: Get drive geometryEx\n")); + if ( RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < + (ULONG)FIELD_OFFSET(DISK_GEOMETRY_EX, Data)) + { + status = STATUS_BUFFER_TOO_SMALL; + dataLength = FIELD_OFFSET(DISK_GEOMETRY_EX, Data); + } + else if (inZeroPowerState != FALSE) + { + status = STATUS_NO_MEDIA_IN_DEVICE; + } + else + { + status = STATUS_SUCCESS; + } + + processed = TRUE; + break; + } + + case IOCTL_DISK_GET_DRIVE_GEOMETRY: + case IOCTL_CDROM_GET_DRIVE_GEOMETRY: + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, + "RequestDispatchToSequentialQueue: Get drive geometry\n")); + if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < + sizeof(DISK_GEOMETRY)) + { + status = STATUS_BUFFER_TOO_SMALL; + dataLength = sizeof(DISK_GEOMETRY); + } + else if (inZeroPowerState != FALSE) + { + status = STATUS_NO_MEDIA_IN_DEVICE; + } + else + { + status = STATUS_SUCCESS; + } + + processed = TRUE; + break; + } + + case IOCTL_CDROM_READ_TOC_EX: + { + status = RequestValidateReadTocEx(deviceExtension, Request, RequestParameters, &dataLength); + + if (inZeroPowerState != FALSE) + { + status = STATUS_NO_MEDIA_IN_DEVICE; + } + + processed = TRUE; + break; + } + + case IOCTL_CDROM_READ_TOC: + { + status = RequestValidateReadToc(deviceExtension, RequestParameters, &dataLength); + + if (inZeroPowerState != FALSE) + { + status = STATUS_NO_MEDIA_IN_DEVICE; + } + + processed = TRUE; + break; + } + + case IOCTL_CDROM_GET_LAST_SESSION: + { + status = RequestValidateGetLastSession(deviceExtension, RequestParameters, &dataLength); + + processed = TRUE; + break; + } + + case IOCTL_CDROM_PLAY_AUDIO_MSF: + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, + "RequestDispatchToSequentialQueue: Play audio MSF\n")); + + if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength < + sizeof(CDROM_PLAY_AUDIO_MSF)) + { + status = STATUS_INFO_LENGTH_MISMATCH; + } + else + { + status = STATUS_SUCCESS; + } + + processed = TRUE; + break; + } + + case IOCTL_CDROM_SEEK_AUDIO_MSF: + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, + "RequestDispatchToSequentialQueue: Seek audio MSF\n")); + + if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength < + sizeof(CDROM_SEEK_AUDIO_MSF)) + { + status = STATUS_INFO_LENGTH_MISMATCH; + } + else + { + status = STATUS_SUCCESS; + } + + processed = TRUE; + break; + } + + case IOCTL_CDROM_PAUSE_AUDIO: + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, + "RequestDispatchToSequentialQueue: Pause audio\n")); + + status = STATUS_SUCCESS; + processed = TRUE; + break; + } + + case IOCTL_CDROM_RESUME_AUDIO: + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, + "RequestDispatchToSequentialQueue: Resume audio\n")); + + status = STATUS_SUCCESS; + processed = TRUE; + break; + } + + case IOCTL_CDROM_READ_Q_CHANNEL: + { + status = RequestValidateReadQChannel(Request, RequestParameters, &dataLength); + + processed = TRUE; + break; + } + + case IOCTL_CDROM_GET_VOLUME: + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, + "RequestDispatchToSequentialQueue: Get volume control\n")); + + if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < + sizeof(VOLUME_CONTROL)) + { + status = STATUS_BUFFER_TOO_SMALL; + dataLength = sizeof(VOLUME_CONTROL); + } + else + { + status = STATUS_SUCCESS; + } + + processed = TRUE; + break; + } + + case IOCTL_CDROM_SET_VOLUME: + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, + "RequestDispatchToSequentialQueue: Set volume control\n")); + + if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength < + sizeof(VOLUME_CONTROL)) + { + status = STATUS_INFO_LENGTH_MISMATCH; + } + else + { + status = STATUS_SUCCESS; + } + + processed = TRUE; + break; + } + + case IOCTL_CDROM_STOP_AUDIO: + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, + "RequestDispatchToSequentialQueue: Stop audio\n")); + + status = STATUS_SUCCESS; + processed = TRUE; + break; + } + + case IOCTL_STORAGE_CHECK_VERIFY: + case IOCTL_STORAGE_CHECK_VERIFY2: + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, + "RequestDispatchToSequentialQueue: [%p] Check Verify\n", Request)); + + // Following check will let the condition "OutputBufferLength == 0" pass. + // Since it's legacy behavior in classpnp, we need to keep it. + if ((RequestParameters.Parameters.DeviceIoControl.OutputBufferLength > 0) && + (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG))) + { + status = STATUS_BUFFER_TOO_SMALL; + dataLength = sizeof(ULONG); + } + else if (inZeroPowerState != FALSE) + { + status = STATUS_NO_MEDIA_IN_DEVICE; + } + else + { + status = STATUS_SUCCESS; + } + + processed = TRUE; + break; + } + + case IOCTL_DVD_GET_REGION: + { + // validation will be done when process it. + status = STATUS_SUCCESS; + processed = TRUE; + break; + } + + case IOCTL_DVD_READ_STRUCTURE: + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, + "RequestDispatchToSequentialQueue: [%p] IOCTL_DVD_READ_STRUCTURE\n", Request)); + + status = RequestValidateDvdReadStructure(deviceExtension, RequestParameters, &dataLength); + + processed = TRUE; + break; + } + + case IOCTL_DVD_READ_KEY: + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, + "RequestDispatchToSequentialQueue: [%p] IOCTL_DVD_READ_KEY\n", Request)); + + status = RequestValidateDvdReadKey(deviceExtension, Request, RequestParameters, &dataLength); + + processed = TRUE; + break; + } + + case IOCTL_DVD_START_SESSION: + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, + "RequestDispatchToSequentialQueue: [%p] IOCTL_DVD_START_SESSION\n", Request)); + + status = RequestValidateDvdStartSession(deviceExtension, RequestParameters, &dataLength); + + processed = TRUE; + break; + } + + case IOCTL_DVD_SEND_KEY: + case IOCTL_DVD_SEND_KEY2: + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, + "RequestDispatchToSequentialQueue: [%p] IOCTL_DVD_SEND_KEY\n", Request)); + + status = RequestValidateDvdSendKey(deviceExtension, Request, RequestParameters, &dataLength); + + processed = TRUE; + break; + } + + case IOCTL_STORAGE_SET_READ_AHEAD: + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, + "RequestDispatchToSequentialQueue: [%p] SetReadAhead\n", Request)); + + if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength < + sizeof(STORAGE_SET_READ_AHEAD)) + { + status = STATUS_INVALID_PARAMETER; + } + else + { + status = STATUS_SUCCESS; + } + + processed = TRUE; + break; + } + + case IOCTL_DISK_IS_WRITABLE: + { + status = STATUS_SUCCESS; + + processed = TRUE; + break; + } + + case IOCTL_DISK_GET_DRIVE_LAYOUT: + { + ULONG requiredSize = 0; + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, + "RequestDispatchToSequentialQueue: Get drive layout\n")); + + requiredSize = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION, PartitionEntry[1]); + + if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < + requiredSize) + { + status = STATUS_BUFFER_TOO_SMALL; + dataLength = requiredSize; + } + else + { + status = STATUS_SUCCESS; + } + + processed = TRUE; + break; + } + + case IOCTL_DISK_GET_DRIVE_LAYOUT_EX: + { + ULONG requiredSize = 0; + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, + "RequestDispatchToSequentialQueue: Get drive layoutEx\n")); + + requiredSize = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry[1]); + + if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < + requiredSize) + { + status = STATUS_BUFFER_TOO_SMALL; + dataLength = requiredSize; + } + else + { + status = STATUS_SUCCESS; + } + + processed = TRUE; + break; + } + + case IOCTL_DISK_GET_PARTITION_INFO: + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, + "RequestDispatchToSequentialQueue: Get Partition Info\n")); + + if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < + sizeof(PARTITION_INFORMATION)) + { + status = STATUS_BUFFER_TOO_SMALL; + dataLength = sizeof(PARTITION_INFORMATION); + } + else + { + status = STATUS_SUCCESS; + } + + processed = TRUE; + break; + } + + case IOCTL_DISK_GET_PARTITION_INFO_EX: + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, + "RequestDispatchToSequentialQueue: Get Partition InfoEx\n")); + + if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < + sizeof(PARTITION_INFORMATION_EX)) + { + status = STATUS_BUFFER_TOO_SMALL; + dataLength = sizeof(PARTITION_INFORMATION_EX); + } + else + { + status = STATUS_SUCCESS; + } + + processed = TRUE; + break; + } + + case IOCTL_DISK_VERIFY: + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, + "RequestDispatchToSequentialQueue: IOCTL_DISK_VERIFY to device %p through request %p\n", + Device, + Request)); + + if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength < + sizeof(VERIFY_INFORMATION)) + { + status = STATUS_INVALID_PARAMETER; + } + else + { + status = STATUS_SUCCESS; + } + + processed = TRUE; + break; + } + + case IOCTL_DISK_GET_LENGTH_INFO: + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, + "RequestDispatchToSequentialQueue: Disk Get Length InfoEx\n")); + + if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < + sizeof(GET_LENGTH_INFORMATION)) + { + status = STATUS_BUFFER_TOO_SMALL; + dataLength = sizeof(GET_LENGTH_INFORMATION); + } + else if (inZeroPowerState != FALSE) + { + status = STATUS_NO_MEDIA_IN_DEVICE; + } + else + { + status = STATUS_SUCCESS; + } + + processed = TRUE; + break; + } + + case IOCTL_CDROM_GET_CONFIGURATION: + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, + "RequestDispatchToSequentialQueue: [%p] IOCTL_CDROM_GET_CONFIGURATION\n", Request)); + + status = RequestValidateGetConfiguration(deviceExtension, Request, RequestParameters, &dataLength); + + processed = TRUE; + break; + } + + case IOCTL_CDROM_SET_SPEED: + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, + "RequestDispatchToSequentialQueue: [%p] IOCTL_CDROM_SET_SPEED\n", Request)); + + status = RequestValidateSetSpeed(deviceExtension, Request, RequestParameters, &dataLength); + + processed = TRUE; + break; + } + + case IOCTL_DVD_END_SESSION: + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, + "RequestDispatchToSequentialQueue: [%p] IOCTL_DVD_END_SESSION\n", Request)); + + status = RequestValidateDvdEndSession(deviceExtension, Request, RequestParameters, &dataLength); + + processed = TRUE; + break; + } + + case IOCTL_AACS_END_SESSION: + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, + "RequestDispatchToSequentialQueue: [%p] IOCTL_AACS_END_SESSION\n", Request)); + + status = RequestValidateAacsEndSession(deviceExtension, Request, RequestParameters, &dataLength); + + processed = TRUE; + break; + } + + case IOCTL_AACS_READ_MEDIA_KEY_BLOCK: + { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, + "AACS: Querying full MKB with bufferSize of %x bytes\n", + (int)RequestParameters.Parameters.DeviceIoControl.OutputBufferLength + )); + + status = RequestValidateAacsReadMediaKeyBlock(deviceExtension, Request, RequestParameters, &dataLength); + + processed = TRUE; + break; + } + + case IOCTL_AACS_START_SESSION: + { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, + "AACS: Requesting AGID\n" + )); + + status = RequestValidateAacsStartSession(deviceExtension, RequestParameters, &dataLength); + + processed = TRUE; + break; + } + + case IOCTL_AACS_SEND_CERTIFICATE: + { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, + "AACS: Sending host certificate to drive\n" + )); + + status = RequestValidateAacsSendCertificate(deviceExtension, Request, RequestParameters, &dataLength); + + processed = TRUE; + break; + } + + case IOCTL_AACS_GET_CERTIFICATE: + { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, + "AACS: Querying drive certificate\n" + )); + + status = RequestValidateAacsGetCertificate(deviceExtension, Request, RequestParameters, &dataLength); + + processed = TRUE; + break; + } + + case IOCTL_AACS_GET_CHALLENGE_KEY: + { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, + "AACS: Querying drive challenge key\n" + )); + + status = RequestValidateAacsGetChallengeKey(deviceExtension, Request, RequestParameters, &dataLength); + + processed = TRUE; + break; + } + + case IOCTL_AACS_SEND_CHALLENGE_KEY: + { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, + "AACS: Sending drive challenge key\n" + )); + + status = RequestValidateAacsSendChallengeKey(deviceExtension, Request, RequestParameters, &dataLength); + + processed = TRUE; + break; + } + + case IOCTL_AACS_READ_VOLUME_ID: + { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, + "AACS: Reading volume ID\n" + )); + + status = RequestValidateAacsReadVolumeId(deviceExtension, Request, RequestParameters, &dataLength); + + processed = TRUE; + break; + } + + case IOCTL_AACS_READ_SERIAL_NUMBER: + { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, + "AACS: Reading Serial Number\n" + )); + + status = RequestValidateAacsReadSerialNumber(deviceExtension, Request, RequestParameters, &dataLength); + + processed = TRUE; + break; + } + + case IOCTL_AACS_READ_MEDIA_ID: + { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, + "AACS: Reading media ID\n" + )); + + status = RequestValidateAacsReadMediaId(deviceExtension, Request, RequestParameters, &dataLength); + + processed = TRUE; + break; + } + + case IOCTL_AACS_READ_BINDING_NONCE: + case IOCTL_AACS_GENERATE_BINDING_NONCE: + { + if (ioctlCode == IOCTL_AACS_GENERATE_BINDING_NONCE) + { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, + "AACS: Generating new binding nonce\n" + )); + } + else + { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, + "AACS: Reading existing binding nonce\n" + )); + } + + status = RequestValidateAacsBindingNonce(deviceExtension, Request, RequestParameters, &dataLength); + + processed = TRUE; + break; + } + + case IOCTL_CDROM_ENABLE_STREAMING: + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, + "RequestDispatchToSequentialQueue: [%p] IOCTL_CDROM_ENABLE_STREAMING\n", Request)); + + status = RequestValidateEnableStreaming(Request, RequestParameters, &dataLength); + + processed = TRUE; + break; + } + + case IOCTL_CDROM_SEND_OPC_INFORMATION: + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, + "RequestDispatchToSequentialQueue: [%p] IOCTL_CDROM_SEND_OPC_INFORMATION\n", Request)); + + status = RequestValidateSendOpcInformation(Request, RequestParameters, &dataLength); + + processed = TRUE; + break; + } + + case IOCTL_CDROM_GET_PERFORMANCE: + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, + "RequestDispatchToSequentialQueue: [%p] IOCTL_CDROM_GET_PERFORMANCE\n", Request)); + + status = RequestValidateGetPerformance(Request, RequestParameters, &dataLength); + + processed = TRUE; + break; + } + + case IOCTL_STORAGE_MEDIA_REMOVAL: + case IOCTL_STORAGE_EJECTION_CONTROL: + { + if(RequestParameters.Parameters.DeviceIoControl.InputBufferLength < + sizeof(PREVENT_MEDIA_REMOVAL)) + { + status = STATUS_INFO_LENGTH_MISMATCH; + } + else + { + status = STATUS_SUCCESS; + } + + processed = TRUE; + break; // complete the irp + } + + case IOCTL_STORAGE_MCN_CONTROL: + { + if(RequestParameters.Parameters.DeviceIoControl.InputBufferLength < + sizeof(PREVENT_MEDIA_REMOVAL)) + { + status = STATUS_INFO_LENGTH_MISMATCH; + } + else + { + status = STATUS_SUCCESS; + } + + processed = TRUE; + break; // complete the irp + } + + case IOCTL_STORAGE_RESERVE: + case IOCTL_STORAGE_RELEASE: + { + // there is no validate check currently. + status = STATUS_SUCCESS; + processed = TRUE; + break; + } + + case IOCTL_STORAGE_PERSISTENT_RESERVE_IN: + case IOCTL_STORAGE_PERSISTENT_RESERVE_OUT: + { + status = RequestValidatePersistentReserve(deviceExtension, Request, RequestParameters, &dataLength); + + processed = TRUE; + break; + } + + case IOCTL_STORAGE_EJECT_MEDIA: + case IOCTL_STORAGE_LOAD_MEDIA: + case IOCTL_STORAGE_LOAD_MEDIA2: + { + status = STATUS_SUCCESS; + + processed = TRUE; + break; // complete the irp + } + + case IOCTL_STORAGE_FIND_NEW_DEVICES: + { + // process it. + IoInvalidateDeviceRelations(deviceExtension->LowerPdo, BusRelations); + + status = STATUS_SUCCESS; + + processed = TRUE; + break; // complete the irp + } + + case IOCTL_STORAGE_READ_CAPACITY: + { + if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < sizeof(STORAGE_READ_CAPACITY)) + { + dataLength = sizeof(STORAGE_READ_CAPACITY); + status = STATUS_BUFFER_TOO_SMALL; + } + else if (inZeroPowerState != FALSE) + { + status = STATUS_NO_MEDIA_IN_DEVICE; + } + else + { + status = STATUS_SUCCESS; + } + + processed = TRUE; + break; // complete the irp + } + + case IOCTL_STORAGE_CHECK_PRIORITY_HINT_SUPPORT: + { + // for disk.sys only in original classpnp + status = STATUS_NOT_SUPPORTED; + + processed = TRUE; + break; // complete the irp + } + +#if (NTDDI_VERSION >= NTDDI_WIN8) + case IOCTL_DISK_ARE_VOLUMES_READY: + { + // this request doesn't access device at all, so seemingly it can be processed + // directly; however, in case volume online is not received, we will need to + // park these requests in a queue, and the only way a request can be queued is + // if the request came out of another queue. + status = STATUS_SUCCESS; + + processed = TRUE; + break; + } + + case IOCTL_VOLUME_ONLINE: + case IOCTL_VOLUME_POST_ONLINE: + { + status = STATUS_SUCCESS; + + processed = TRUE; + break; + } +#endif + + default: + { + processed = FALSE; + break; + } + } //end of switch (ioctlCode) + + if (processed) + { + UCHAR currentStackLocationFlags = 0; + currentStackLocationFlags = RequestGetCurrentStackLocationFlags(Request); + + if ((status == STATUS_VERIFY_REQUIRED) && + (currentStackLocationFlags & SL_OVERRIDE_VERIFY_VOLUME)) + { + // If the status is verified required and this request + // should bypass verify required then retry the request. + status = STATUS_IO_DEVICE_ERROR; + UNREFERENCED_PARAMETER(status); // disables prefast warning; defensive coding... + + processed = RequestDispatchToSequentialQueue(Device, Request, RequestParameters); + } + else + { + if (NT_SUCCESS(status)) + { + // Forward the request to serialized queue. + status = WdfDeviceEnqueueRequest(Device, Request); + } + + if (!NT_SUCCESS(status)) + { + // Validation failed / forward failed, complete the request. + RequestCompletion(deviceExtension, Request, status, dataLength); + } + } + } + + return processed; +} + + +BOOLEAN +RequestDispatchSyncWithSequentialQueue( + _In_ WDFDEVICE Device, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters + ) +/*++ +Routine Description: + + These requests need to stay in caller's context and be processed in serialized manner. + +Arguments: + + Device - handle to a WDF Device object + + Request - handle to the incoming WDF Request object + + RequestParameters - request parameters + +Return Value: + + BOOLEAN - TRUE (request processed); FALSE (request is not processed in this function). + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + BOOLEAN processed = FALSE; + size_t dataLength = 0; + + PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(Device); + ULONG ioctlCode = RequestParameters.Parameters.DeviceIoControl.IoControlCode; + + switch (ioctlCode) + { + + case IOCTL_CDROM_EXCLUSIVE_ACCESS: + { + //1. Validate + status = RequestValidateExclusiveAccess(Request, RequestParameters, &dataLength); + + //2. keep the request in serialized manner and stay in user's context. + if (NT_SUCCESS(status)) + { + PCDROM_EXCLUSIVE_ACCESS exclusiveAccess = NULL; + + status = WdfRequestRetrieveInputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.InputBufferLength, + &exclusiveAccess, + NULL); + + if (NT_SUCCESS(status)) + { + // do not need to check "status" as it passed validation and cannot fail in WdfRequestRetrieveInputBuffer() + switch (exclusiveAccess->RequestType) + { + + case ExclusiveAccessQueryState: + { + status = RequestSetContextFields(Request, RequestHandleExclusiveAccessQueryLockState); + break; + } + + case ExclusiveAccessLockDevice: + { + status = RequestSetContextFields(Request, RequestHandleExclusiveAccessLockDevice); + break; + } + + case ExclusiveAccessUnlockDevice: + { + status = RequestSetContextFields(Request, RequestHandleExclusiveAccessUnlockDevice); + break; + } + default: + { + // already valicated in RequestValidateExclusiveAccess() + NT_ASSERT(FALSE); + break; + } + } + } + + if (NT_SUCCESS(status)) + { + // now, put the special synchronization information into the context + status = RequestSynchronizeProcessWithSerialQueue(Device, Request); + + // "status" is used for debugging in above statement, reset to success to avoid further work in this function. + status = STATUS_SUCCESS; + } + } + + processed = TRUE; + break; // complete the irp + } + + default: + { + processed = FALSE; + break; + } + } //end of switch (ioctlCode) + + // Following process is only valid if the request is not really processed. (failed in validation) + if (processed && !NT_SUCCESS(status)) + { + UCHAR currentStackLocationFlags = 0; + currentStackLocationFlags = RequestGetCurrentStackLocationFlags(Request); + + if ((status == STATUS_VERIFY_REQUIRED) && + (currentStackLocationFlags & SL_OVERRIDE_VERIFY_VOLUME)) + { + // + // If the status is verified required and this request + // should bypass verify required then retry the request. + // + status = STATUS_IO_DEVICE_ERROR; + UNREFERENCED_PARAMETER(status); // disables prefast warning; defensive coding... + + processed = RequestDispatchSyncWithSequentialQueue(Device, Request, RequestParameters); + } + else + { + // Validation failed / forward failed, complete the request. + RequestCompletion(deviceExtension, Request, status, dataLength); + } + } + + return processed; +} + + +BOOLEAN +RequestDispatchSpecialIoctls( + _In_ WDFDEVICE Device, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters + ) +/*++ +Routine Description: + + These requests need to be processed in different manner according to input parameters + +Arguments: + + Device - handle to a WDF Device object + + Request - handle to the incoming WDF Request object + + RequestParameters - request parameters + +Return Value: + + BOOLEAN - TRUE (request processed); FALSE (request is not processed in this function). + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + BOOLEAN processed = FALSE; + size_t dataLength = 0; + BOOLEAN requestCompleted = FALSE; + + PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(Device); + PCDROM_DATA cdData = &(deviceExtension->DeviceAdditionalData); + ULONG ioctlCode = RequestParameters.Parameters.DeviceIoControl.IoControlCode; + + switch (ioctlCode) + { + case IOCTL_SCSI_PASS_THROUGH: + case IOCTL_SCSI_PASS_THROUGH_DIRECT: + case IOCTL_SCSI_PASS_THROUGH_EX: + case IOCTL_SCSI_PASS_THROUGH_DIRECT_EX: + { + // SPTI is considered special case as we need to set the MinorFunction before pass to low level. + +#if defined (_WIN64) + if (WdfRequestIsFrom32BitProcess(Request)) + { + if ((ioctlCode == IOCTL_SCSI_PASS_THROUGH) || (ioctlCode == IOCTL_SCSI_PASS_THROUGH_DIRECT)) + { + if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength < sizeof(SCSI_PASS_THROUGH32)) + { + status = STATUS_INVALID_PARAMETER; + } + } + else + { + if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength < sizeof(SCSI_PASS_THROUGH32_EX)) + { + status = STATUS_INVALID_PARAMETER; + } + } + } + else +#endif + { + if ((ioctlCode == IOCTL_SCSI_PASS_THROUGH) || (ioctlCode == IOCTL_SCSI_PASS_THROUGH_DIRECT)) + { + if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength < sizeof(SCSI_PASS_THROUGH)) + { + status = STATUS_INVALID_PARAMETER; + } + } + else + { + if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength < sizeof(SCSI_PASS_THROUGH_EX)) + { + status = STATUS_INVALID_PARAMETER; + } + } + } + + if (!NT_SUCCESS(status)) + { + // validation failed. + RequestCompletion(deviceExtension, Request, status, dataLength); + } + else + { + // keep the request in serialized manner and stay in user's context. + status = RequestSetContextFields(Request, RequestHandleScsiPassThrough); + + if (NT_SUCCESS(status)) + { + status = RequestSynchronizeProcessWithSerialQueue(Device, Request); + } + else + { + RequestCompletion(deviceExtension, Request, status, 0); + } + } + + requestCompleted = TRUE; + processed = TRUE; + break; + } + + case IOCTL_STORAGE_QUERY_PROPERTY: + { + if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength < sizeof(STORAGE_PROPERTY_QUERY)) + { + status = STATUS_INFO_LENGTH_MISMATCH; + } + else + { + PSTORAGE_PROPERTY_QUERY inputBuffer = NULL; + + status = WdfRequestRetrieveInputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.InputBufferLength, + &inputBuffer, + NULL); + + if (NT_SUCCESS(status)) + { + if (!EXCLUSIVE_MODE(cdData) || // not locked + EXCLUSIVE_OWNER(cdData, WdfRequestGetFileObject(Request)) || // request is from lock owner + (inputBuffer->QueryType == PropertyExistsQuery)) // request not access device + { + if (inputBuffer->PropertyId == StorageDeviceUniqueIdProperty) + { + // previously handled in classpnp + // keep the request in serialized manner and stay in user's context. + status = RequestSetContextFields(Request, RequestHandleQueryPropertyDeviceUniqueId); + + if (NT_SUCCESS(status)) + { + status = RequestSynchronizeProcessWithSerialQueue(Device, Request); + // remeber that the request has been completed. + requestCompleted = TRUE; + } + } + else if (inputBuffer->PropertyId == StorageDeviceWriteCacheProperty) + { + // previously handled in classpnp + // keep the request in serialized manner and stay in user's context. + status = RequestSetContextFields(Request, RequestHandleQueryPropertyWriteCache); + + if (NT_SUCCESS(status)) + { + status = RequestSynchronizeProcessWithSerialQueue(Device, Request); + // remeber that the request has been completed. + requestCompleted = TRUE; + } + } + else + { + // Pass to port driver for handling + RequestDispatchUnknownRequests(Device, Request, RequestParameters); + + // remeber that the request has been completed. + requestCompleted = TRUE; + } + } + else + { + // If cached data exists, return cached data. Otherwise, fail the request. + if ((inputBuffer->QueryType == PropertyStandardQuery) && + ((inputBuffer->PropertyId == StorageDeviceProperty) || (inputBuffer->PropertyId == StorageAdapterProperty)) ) + { + status = RequestHandleQueryPropertyRetrieveCachedData(deviceExtension, Request, RequestParameters, &dataLength); + } + else + { + status = STATUS_ACCESS_DENIED; + } + } + } + } + + processed = TRUE; + break; + } + + // this IOCTL is a fake one, used for MCN process sync-ed with serial queue. + case IOCTL_MCN_SYNC_FAKE_IOCTL: + { + PIRP irp = WdfRequestWdmGetIrp(Request); + + if ((deviceExtension->MediaChangeDetectionInfo != NULL) && + (irp == deviceExtension->MediaChangeDetectionInfo->MediaChangeSyncIrp) && + (WdfRequestGetRequestorMode(Request) == KernelMode) && + (RequestParameters.Parameters.Others.Arg1 == RequestSetupMcnSyncIrp) && + (RequestParameters.Parameters.Others.Arg2 == RequestSetupMcnSyncIrp) && + (RequestParameters.Parameters.Others.Arg4 == RequestSetupMcnSyncIrp)) + { + // This is the requset we use to sync Media Change Detection with sequential queue. + status = WdfDeviceEnqueueRequest(Device, Request); + + if (!NT_SUCCESS(status)) + { + RequestCompletion(deviceExtension, Request, status, dataLength); + } + + requestCompleted = TRUE; + processed = TRUE; + } + else + { + // process as an unknown request. + processed = FALSE; + } + break; + } + + default: + { + processed = FALSE; + break; + } + } //end of switch (ioctlCode) + + if (processed && !requestCompleted) + { + UCHAR currentStackLocationFlags = 0; + currentStackLocationFlags = RequestGetCurrentStackLocationFlags(Request); + + if ((status == STATUS_VERIFY_REQUIRED) && + (currentStackLocationFlags & SL_OVERRIDE_VERIFY_VOLUME)) + { + // If the status is verified required and this request + // should bypass verify required then retry the request. + status = STATUS_IO_DEVICE_ERROR; + UNREFERENCED_PARAMETER(status); // disables prefast warning; defensive coding... + + processed = RequestDispatchSpecialIoctls(Device, Request, RequestParameters); + } + else + { + RequestCompletion(deviceExtension, Request, status, dataLength); + } + } + + return processed; +} + + +BOOLEAN +RequestDispatchUnknownRequests( + _In_ WDFDEVICE Device, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters + ) +/*++ +Routine Description: + + All unknown requests will be pass to lower level driver. + If IRQL is PASSIVE_LEVEL, the request will be serialized; + Otherwise, it'll be sent and forget. + +Arguments: + + Device - handle to a WDF Device object + + Request - handle to the incoming WDF Request object + + RequestParameters - request parameters + +Return Value: + + BOOLEAN - TRUE (request processed); FALSE (request is not processed in this function). + +--*/ +{ + NTSTATUS status = STATUS_UNSUCCESSFUL; + PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(Device); + + ULONG baseCode = DEVICE_TYPE_FROM_CTL_CODE(RequestParameters.Parameters.DeviceIoControl.IoControlCode); + + if ((KeGetCurrentIrql() != PASSIVE_LEVEL) || + (baseCode == FILE_DEVICE_ACPI)) + { + // 1. When IRQL is higher than PASSIVE_LEVEL, + // 2. ataport sends IOCTL_ACPI_ASYNC_EVAL_METHOD before queue starts, + // send request directly to lower driver. + status = RequestHandleUnknownIoctl(Device, Request); + } + else + { + // keep the request in serialized manner and stay in user's context. + status = RequestSetContextFields(Request, RequestHandleUnknownIoctl); + + if (NT_SUCCESS(status)) + { + status = RequestSynchronizeProcessWithSerialQueue(Device, Request); + } + else + { + RequestCompletion(deviceExtension, Request, status, 0); + } + } + + UNREFERENCED_PARAMETER(status); //defensive coding, avoid PREFAST warning. + + // All unknown IOCTLs are processed in this function. + return TRUE; //processed +} + +VOID +RequestProcessInternalDeviceControl( + _In_ WDFREQUEST Request, + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension + ) +/*++ +Routine Description: + + all internal IOCTL will be send to lower driver asynchronously. + +Arguments: + + Request - handle to the incoming WDF Request object + DeviceExtension - device extension structure + +Return Value: + + None + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PIRP irp = NULL; + PIO_STACK_LOCATION irpStack = NULL; + PIO_STACK_LOCATION nextStack = NULL; + BOOLEAN requestSent = FALSE; + + irp = WdfRequestWdmGetIrp(Request); + irpStack = IoGetCurrentIrpStackLocation(irp); + nextStack = IoGetNextIrpStackLocation(irp); + + // Set the parameters in the next stack location. + nextStack->Parameters.Scsi.Srb = irpStack->Parameters.Scsi.Srb; + nextStack->MajorFunction = IRP_MJ_SCSI; + nextStack->MinorFunction = IRP_MN_SCSI_CLASS; + + WdfRequestSetCompletionRoutine(Request, RequestDummyCompletionRoutine, NULL); + + status = RequestSend(DeviceExtension, + Request, + DeviceExtension->IoTarget, + 0, + &requestSent); + + // send the request straight down (asynchronously) + if (!requestSent) + { + // fail the request + RequestCompletion(DeviceExtension, Request, status, WdfRequestGetInformation(Request)); + } + + return; +} + + + +// +// Serial I/O Queue Event callbacks +// + +VOID +SequentialQueueEvtIoReadWrite( + _In_ WDFQUEUE Queue, + _In_ WDFREQUEST Request, + _In_ size_t Length + ) +/*++ +Routine Description: + + validate and process read/write request. + +Arguments: + + Queue - parallel queue itself + + Request - handle to the incoming WDF Request object + + Length - read / write lenght + +Return Value: + + None + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + WDFDEVICE device = WdfIoQueueGetDevice(Queue); + PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(device); + WDF_REQUEST_PARAMETERS requestParameters; + PIRP wdmIrp = WdfRequestWdmGetIrp(Request); + PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(wdmIrp); + PCDROM_DATA cdData = &(deviceExtension->DeviceAdditionalData); + + // Get the request parameters + WDF_REQUEST_PARAMETERS_INIT(&requestParameters); + WdfRequestGetParameters(Request, &requestParameters); + + if (requestParameters.Type == WdfRequestTypeRead) + { + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, + "Receiving READ, Length %Ix\n", (ULONG) Length)); + } + else + { + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, + "Receiving WRITE, Length %Ix\n", (ULONG) Length)); + } + + // Check if a verify is required before a READ/WRITE + if (TEST_FLAG(deviceExtension->DeviceObject->Flags, DO_VERIFY_VOLUME) && + (requestParameters.MinorFunction != CDROM_VOLUME_VERIFY_CHECKED) && + !TEST_FLAG(currentIrpStack->Flags, SL_OVERRIDE_VERIFY_VOLUME)) + { + // DO_VERIFY_VOLUME is set for the device object, + // but this request is not itself a verify request. + // So fail this request. + RequestCompletion(deviceExtension, Request, STATUS_VERIFY_REQUIRED, 0); + } + else + { + // Since we've bypassed the verify-required tests we don't need to repeat + // them with this IRP - in particular we don't want to worry about + // hitting them at the partition 0 level if the request has come through + // a non-zero partition. + currentIrpStack->MinorFunction = CDROM_VOLUME_VERIFY_CHECKED; + + // Fail READ/WRITE requests when music is playing + if (deviceExtension->DeviceAdditionalData.PlayActive) + { + RequestCompletion(deviceExtension, Request, STATUS_DEVICE_BUSY, 0); + + return; + } + + // Fail READ/WRITE requests from non-owners if the drive is locked + if (EXCLUSIVE_MODE(cdData) && !EXCLUSIVE_OWNER(cdData, WdfRequestGetFileObject(Request))) + { + RequestCompletion(deviceExtension, Request, STATUS_ACCESS_DENIED, 0); + + return; + } + + // Succeed READ/WRITE requests of length 0 + if (Length == 0) + { + // Several parts of the code turn 0 into 0xffffffff, + // so don't process a zero-length request any further. + RequestCompletion(deviceExtension, Request, STATUS_SUCCESS, Length); + + return; + } + + // If there is an unexpected write request, we want to rediscover MMC capabilities + if (!deviceExtension->DeviceAdditionalData.Mmc.WriteAllowed && + (requestParameters.Type == WdfRequestTypeWrite)) + { + // Schedule MMC capabilities update now, but perform it later in a work item + deviceExtension->DeviceAdditionalData.Mmc.UpdateState = CdromMmcUpdateRequired; + } + + // If MMC capabilities update is required, we create a separate work item to avoid blocking + // the current thread; otherwise, we initiate an async read/write in the current thread. + if (DeviceIsMmcUpdateRequired(deviceExtension->Device)) + { + deviceExtension->ReadWriteWorkItemContext.OriginalRequest = Request; + WdfWorkItemEnqueue(deviceExtension->ReadWriteWorkItem); + + status = STATUS_SUCCESS; + } + else + { + status = RequestValidateReadWrite(deviceExtension, Request, requestParameters); + + if (NT_SUCCESS(status)) + { + status = RequestHandleReadWrite(deviceExtension, Request, requestParameters); + } + } + + if (!NT_SUCCESS(status)) + { + RequestCompletion(deviceExtension, Request, status, 0); + } + } + + return; +} + + +VOID +ReadWriteWorkItemRoutine( + _In_ WDFWORKITEM WorkItem + ) +/*++ + +Routine Description: + + Work item routine for validating and initiating read and write requests. + The reason why we do that from a work item is because we may need to update MMC + capabilities before validating a read/write request and that is a sync operation. + +Arguments: + + WorkItem - WDF work item + +Return Value: + + none + +--*/ +{ + PCDROM_DEVICE_EXTENSION deviceExtension = NULL; + WDFREQUEST readWriteRequest = NULL; + WDF_REQUEST_PARAMETERS readWriteRequestParameters; + NTSTATUS status = STATUS_SUCCESS; + + PAGED_CODE (); + + deviceExtension = WdfObjectGetTypedContext(WdfWorkItemGetParentObject(WorkItem), CDROM_DEVICE_EXTENSION); + readWriteRequest = deviceExtension->ReadWriteWorkItemContext.OriginalRequest; + deviceExtension->ReadWriteWorkItemContext.OriginalRequest = NULL; + + WDF_REQUEST_PARAMETERS_INIT(&readWriteRequestParameters); + WdfRequestGetParameters(readWriteRequest, &readWriteRequestParameters); + + if (DeviceIsMmcUpdateRequired(deviceExtension->Device)) + { + // Issue command to update the drive capabilities. + // The failure of MMC update is not considered critical, so we'll + // continue to process the request even if MMC update fails. + (VOID) DeviceUpdateMmcCapabilities(deviceExtension->Device); + } + + // Now verify and process the request + if (NT_SUCCESS(status)) + { + status = RequestValidateReadWrite(deviceExtension, readWriteRequest, readWriteRequestParameters); + } + if (NT_SUCCESS(status)) + { + status = RequestHandleReadWrite(deviceExtension, readWriteRequest, readWriteRequestParameters); + } + + // Complete the request immediately on failure + if (!NT_SUCCESS(status)) + { + RequestCompletion(deviceExtension, readWriteRequest, status, 0); + } +} + + +VOID +SequentialQueueEvtIoDeviceControl( + _In_ WDFQUEUE Queue, + _In_ WDFREQUEST Request, + _In_ size_t OutputBufferLength, + _In_ size_t InputBufferLength, + _In_ ULONG IoControlCode + ) +/*++ +Routine Description: + + validate and process IOCTL request. + +Arguments: + + Queue - sequential queue + + Request - handle to the incoming WDF Request object + +Return Value: + + None + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + WDFDEVICE device = WdfIoQueueGetDevice(Queue); + PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(device); + PCDROM_REQUEST_CONTEXT requestContext = RequestGetContext(Request); + PCDROM_DATA cdData = &(deviceExtension->DeviceAdditionalData); + WDF_REQUEST_PARAMETERS requestParameters; + + UNREFERENCED_PARAMETER(OutputBufferLength); + UNREFERENCED_PARAMETER(InputBufferLength); + UNREFERENCED_PARAMETER(IoControlCode); + + // get the request parameters + WDF_REQUEST_PARAMETERS_INIT(&requestParameters); + WdfRequestGetParameters(Request, &requestParameters); + + // If the device is in exclusive mode, check whether the request is from + // the handle that locked the device + if (EXCLUSIVE_MODE(cdData) && !EXCLUSIVE_OWNER(cdData, WdfRequestGetFileObject(Request))) + { + BOOLEAN isBlocked = FALSE; + + status = RequestIsIoctlBlockedByExclusiveAccess(Request, &isBlocked); + if (NT_SUCCESS(status) && isBlocked) + { + if (requestContext->SyncRequired) + { + // set the following event, so RequestSynchronizeProcessWithSerialQueue() can contintue run to process the real request. + // this function will wait for the request process finishes. + KeSetEvent(requestContext->SyncEvent, IO_CD_ROM_INCREMENT, FALSE); + } + else + { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, + "DeviceEvtIoInCallerContext: Access Denied! Device in exclusive mode.Failing Ioctl %lx\n", + requestParameters.Parameters.DeviceIoControl.IoControlCode)); + RequestCompletion(deviceExtension, Request, STATUS_ACCESS_DENIED, 0); + } + + return; + } + } + + if (!cdData->Mmc.WriteAllowed && + ((requestParameters.Parameters.DeviceIoControl.IoControlCode == IOCTL_DISK_IS_WRITABLE) || + (requestParameters.Parameters.DeviceIoControl.IoControlCode == IOCTL_DISK_VERIFY))) + { + cdData->Mmc.UpdateState = CdromMmcUpdateRequired; + } + + // check if this is a synchronized ioctl + if (requestContext->SyncRequired) + { + // set the following event, so RequestSynchronizeProcessWithSerialQueue() can contintue run to process the real request. + // this function will wait for the request process finishes. + KeSetEvent(requestContext->SyncEvent, IO_CD_ROM_INCREMENT, FALSE); + } + else + { + deviceExtension->IoctlWorkItemContext.OriginalRequest = Request; + + // all other IOCTL processing is currently processed via a + // work item running at PASSIVE_LEVEL. + WdfWorkItemEnqueue(deviceExtension->IoctlWorkItem); + } + + return; +} + + +VOID +IoctlWorkItemRoutine( + _In_ WDFWORKITEM WorkItem + ) +/*++ + +Routine Description: + + Work item routine for processing ioctl requests. + This is needed because event callbacks are called at DISPATCH_LEVEL and ioctl + requests are currently processed synchronously and not asynchronously. + +Arguments: + + WorkItem - WDF work item + +Return Value: + + none + +--*/ +{ + PCDROM_DEVICE_EXTENSION deviceExtension = NULL; + + PAGED_CODE (); + + deviceExtension = WdfObjectGetTypedContext(WdfWorkItemGetParentObject(WorkItem), CDROM_DEVICE_EXTENSION); + + if (DeviceIsMmcUpdateRequired(deviceExtension->Device)) + { + // Issue command to update the drive capabilities. + // The failure of MMC update is not considered critical, + // so that we'll continue to process I/O even MMC update fails. + DeviceUpdateMmcCapabilities(deviceExtension->Device); + } + + RequestProcessSerializedIoctl(deviceExtension, deviceExtension->IoctlWorkItemContext.OriginalRequest); +} + + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +RequestProcessSerializedIoctl( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request + ) +/*++ +Routine Description: + + a dispatch routine for all functions to process IOCTLs. + +Arguments: + + DeviceExtension - device context + + Request - handle to the incoming WDF Request object + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + size_t information = 0; + WDF_REQUEST_PARAMETERS requestParameters; + BOOLEAN completeRequest = TRUE; + + PAGED_CODE (); + + // Get the Request parameters + WDF_REQUEST_PARAMETERS_INIT(&requestParameters); + WdfRequestGetParameters(Request, &requestParameters); + + NormalizeIoctl(&requestParameters); + + // process IOCTLs + switch (requestParameters.Parameters.DeviceIoControl.IoControlCode) + { + case IOCTL_CDROM_READ_TOC: + case IOCTL_CDROM_GET_LAST_SESSION: + status = RequestHandleReadTOC(DeviceExtension, Request, requestParameters, &information); + break; + + case IOCTL_CDROM_READ_TOC_EX: + status = RequestHandleReadTocEx(DeviceExtension, Request, requestParameters, &information); + break; + + case IOCTL_CDROM_GET_CONFIGURATION: + status = RequestHandleGetConfiguration(DeviceExtension, Request, requestParameters, &information); + break; + + case IOCTL_CDROM_RAW_READ: + status = DeviceHandleRawRead(DeviceExtension, Request, requestParameters, &information); + break; + + case IOCTL_DISK_GET_LENGTH_INFO: + case IOCTL_DISK_GET_DRIVE_GEOMETRY: + case IOCTL_DISK_GET_DRIVE_GEOMETRY_EX: + case IOCTL_CDROM_GET_DRIVE_GEOMETRY: + case IOCTL_CDROM_GET_DRIVE_GEOMETRY_EX: + case IOCTL_STORAGE_READ_CAPACITY: + status = RequestHandleGetDriveGeometry(DeviceExtension, Request, requestParameters, &information); + break; + + case IOCTL_DISK_VERIFY: + status = RequestHandleDiskVerify(DeviceExtension, Request, requestParameters, &information); + break; + + case IOCTL_STORAGE_CHECK_VERIFY: + // IOCTL_STORAGE_CHECK_VERIFY2 was processed including send a Test Unit Read + // with srb flag SRB_CLASS_FLAGS_LOW_PRIORITY to port driver asynchronizelly. + // The original request was completed after TUR finishes. + // As CDROM.SYS serializes IOs need accessing device, it's not a big difference from above behavior to + // just process it in serialized manner. So I put it here and treat it as same as IOCTL_STORAGE_CHECK_VERIFY. + case IOCTL_STORAGE_CHECK_VERIFY2: + status = RequestHandleCheckVerify(DeviceExtension, Request, requestParameters, &information); + break; + + case IOCTL_DISK_GET_DRIVE_LAYOUT: + case IOCTL_DISK_GET_DRIVE_LAYOUT_EX: + case IOCTL_DISK_GET_PARTITION_INFO: + case IOCTL_DISK_GET_PARTITION_INFO_EX: + status = RequestHandleFakePartitionInfo(DeviceExtension, Request, requestParameters, &information); + break; + + case IOCTL_DISK_IS_WRITABLE: + // + // Even though this media is writable, the requester of this IOCTL really + // wants to know if thw media behaves like any other disk or not. This is + // so if FeatureDefectManagement and FeatureRandomWritable are current on + // the drive-represented by the FeatureDefectManagement validation schema + // + if (DeviceExtension->DeviceAdditionalData.Mmc.WriteAllowed && + (DeviceExtension->DeviceAdditionalData.Mmc.ValidationSchema == FeatureDefectManagement)) + { + status = STATUS_SUCCESS; + } + else + { + status = STATUS_MEDIA_WRITE_PROTECTED; + } + information = 0; + break; + + case IOCTL_CDROM_PLAY_AUDIO_MSF: + status = DeviceHandlePlayAudioMsf(DeviceExtension, Request, requestParameters, &information); + break; + + case IOCTL_CDROM_READ_Q_CHANNEL: + status = DeviceHandleReadQChannel(DeviceExtension, Request, requestParameters, &information); + break; + + case IOCTL_CDROM_PAUSE_AUDIO: + status = DeviceHandlePauseAudio(DeviceExtension, Request, &information); + break; + + case IOCTL_CDROM_RESUME_AUDIO: + status = DeviceHandleResumeAudio(DeviceExtension, Request, &information); + break; + + case IOCTL_CDROM_SEEK_AUDIO_MSF: + status = DeviceHandleSeekAudioMsf(DeviceExtension, Request, requestParameters, &information); + break; + + case IOCTL_CDROM_STOP_AUDIO: + status = DeviceHandleStopAudio(DeviceExtension, Request, &information); + break; + + case IOCTL_CDROM_GET_VOLUME: + case IOCTL_CDROM_SET_VOLUME: + status = DeviceHandleGetSetVolume(DeviceExtension, Request, requestParameters, &information); + break; + + case IOCTL_DVD_GET_REGION: + status = RequestHandleGetDvdRegion(DeviceExtension, Request, &information); + break; + + case IOCTL_DVD_READ_STRUCTURE: + status = DeviceHandleReadDvdStructure(DeviceExtension, Request, requestParameters, &information); + break; + + case IOCTL_DVD_END_SESSION: + status = DeviceHandleDvdEndSession(DeviceExtension, Request, requestParameters, &information); + break; + + case IOCTL_DVD_START_SESSION: + case IOCTL_DVD_READ_KEY: + status = DeviceHandleDvdStartSessionReadKey(DeviceExtension, Request, requestParameters, &information); + break; + + case IOCTL_DVD_SEND_KEY: + case IOCTL_DVD_SEND_KEY2: + status = DeviceHandleDvdSendKey(DeviceExtension, Request, requestParameters, &information); + break; + + case IOCTL_STORAGE_SET_READ_AHEAD: + status = DeviceHandleSetReadAhead(DeviceExtension, Request, requestParameters, &information); + break; + + case IOCTL_CDROM_SET_SPEED: + status = DeviceHandleSetSpeed(DeviceExtension, Request, requestParameters, &information); + break; + + case IOCTL_AACS_READ_MEDIA_KEY_BLOCK_SIZE: + case IOCTL_AACS_READ_MEDIA_KEY_BLOCK: + status = DeviceHandleAacsReadMediaKeyBlock(DeviceExtension, Request, requestParameters, &information); + break; + + case IOCTL_AACS_START_SESSION: + status = DeviceHandleAacsStartSession(DeviceExtension, Request, requestParameters, &information); + break; + + case IOCTL_AACS_END_SESSION: + status = DeviceHandleAacsEndSession(DeviceExtension, Request, requestParameters, &information); + break; + + case IOCTL_AACS_SEND_CERTIFICATE: + status = DeviceHandleAacsSendCertificate(DeviceExtension, Request, requestParameters, &information); + break; + + case IOCTL_AACS_GET_CERTIFICATE: + status = DeviceHandleAacsGetCertificate(DeviceExtension, Request, requestParameters, &information); + break; + + case IOCTL_AACS_GET_CHALLENGE_KEY: + status = DeviceHandleAacsGetChallengeKey(DeviceExtension, Request, requestParameters, &information); + break; + + case IOCTL_AACS_SEND_CHALLENGE_KEY: + status = DeviceHandleSendChallengeKey(DeviceExtension, Request, requestParameters, &information); + break; + + case IOCTL_AACS_READ_VOLUME_ID: + status = DeviceHandleReadVolumeId(DeviceExtension, Request, requestParameters, &information); + break; + + case IOCTL_AACS_READ_SERIAL_NUMBER: + status = DeviceHandleAacsReadSerialNumber(DeviceExtension, Request, requestParameters, &information); + break; + + case IOCTL_AACS_READ_MEDIA_ID: + status = DeviceHandleAacsReadMediaId(DeviceExtension, Request, requestParameters, &information); + break; + + case IOCTL_AACS_READ_BINDING_NONCE: + status = DeviceHandleAacsReadBindingNonce(DeviceExtension, Request, requestParameters, &information); + break; + + case IOCTL_AACS_GENERATE_BINDING_NONCE: + status = DeviceHandleAacsGenerateBindingNonce(DeviceExtension, Request, requestParameters, &information); + break; + + case IOCTL_CDROM_ENABLE_STREAMING: + status = RequestHandleEnableStreaming(DeviceExtension, Request, &information); + break; + + case IOCTL_CDROM_SEND_OPC_INFORMATION: + status = RequestHandleSendOpcInformation(DeviceExtension, Request, &information); + break; + + case IOCTL_CDROM_GET_PERFORMANCE: + status = RequestHandleGetPerformance(DeviceExtension, Request, requestParameters, &information); + break; + + // This IOCTL is a fake one, used for MCN process sync-ed with serial queue. + case IOCTL_MCN_SYNC_FAKE_IOCTL: + status = RequestHandleMcnSyncFakeIoctl(DeviceExtension, &information); + break; + + case IOCTL_STORAGE_MEDIA_REMOVAL: + case IOCTL_STORAGE_EJECTION_CONTROL: + { + status = RequestHandleEjectionControl(DeviceExtension, Request, requestParameters, &information); + + break; + } + + case IOCTL_STORAGE_EJECT_MEDIA: + case IOCTL_STORAGE_LOAD_MEDIA: + case IOCTL_STORAGE_LOAD_MEDIA2: + { + status = RequestHandleLoadEjectMedia(DeviceExtension, Request, requestParameters, &information); + + break; + } + + case IOCTL_STORAGE_MCN_CONTROL: + { + status = RequestHandleMcnControl(DeviceExtension, Request, &information); + + break; + } + + case IOCTL_STORAGE_RESERVE: + case IOCTL_STORAGE_RELEASE: + { + status = RequestHandleReserveRelease(DeviceExtension, Request, requestParameters, &information); + + break; + } + + case IOCTL_STORAGE_PERSISTENT_RESERVE_IN: + case IOCTL_STORAGE_PERSISTENT_RESERVE_OUT: + { + status = RequestHandlePersistentReserve(DeviceExtension, Request, requestParameters, &information); + + break; + } + +#if (NTDDI_VERSION >= NTDDI_WIN8) + case IOCTL_DISK_ARE_VOLUMES_READY: + { + status = RequestHandleAreVolumesReady(DeviceExtension, Request, requestParameters, &information); + + completeRequest = FALSE; + + break; + } + + case IOCTL_VOLUME_ONLINE: + case IOCTL_VOLUME_POST_ONLINE: + { + status = RequestHandleVolumeOnline(DeviceExtension, Request, requestParameters, &information); + + break; + } +#endif + + default: + { + status = STATUS_ACCESS_DENIED; + break; + } + } // end of switch(ioctl) + + if (completeRequest) + { + RequestCompletion(DeviceExtension, Request, status, information); + } + + return status; +} + +VOID +SequentialQueueEvtCanceledOnQueue( + _In_ WDFQUEUE Queue, + _In_ WDFREQUEST Request + ) +/*++ +Routine Description: + + Perform cancellation when request is still in queue. + + If request is sych-ed in another thread, signal the event to let that thread be able to complete the request. + Otherwise, complete the request. + +Arguments: + + Queue - serial queue + Request - handle to the incoming WDF Request object + +Return Value: + + None + +--*/ +{ + PCDROM_REQUEST_CONTEXT requestContext = RequestGetContext(Request); + + if (requestContext->SyncRequired) + { + KeSetEvent(requestContext->SyncEvent, IO_CD_ROM_INCREMENT, FALSE); + } + else + { + PCDROM_DEVICE_EXTENSION deviceExtension = NULL; + WDFDEVICE device = WdfIoQueueGetDevice(Queue); + + deviceExtension = DeviceGetExtension(device); + + RequestCompletion(deviceExtension, Request, STATUS_CANCELLED, 0); + + } + + return; +} + + +NTSTATUS +RequestSynchronizeProcessWithSerialQueue( + _In_ WDFDEVICE Device, + _In_ WDFREQUEST Request + ) +/*++ +Routine Description: + + This is the mechanism to sync a request process in original thread with serialize queue. + initialize a EVENT and put the request inot serialize queue; + waiting for serialize queue processes to this request and signal the EVENT; + call the request handler to process this request. + +Arguments: + + DeviceExtension - device context + + Request - handle to the incoming WDF Request object + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(Device); + PCDROM_REQUEST_CONTEXT requestContext = RequestGetContext(Request); + PKEVENT bufferToFree = requestContext->SyncEvent; + + if (KeGetCurrentIrql() >= DISPATCH_LEVEL) { + // cannot block at or above DISPATCH_LEVEL + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, + "RequestSynchronousProcessWithSerialQueue called at DISPATCH_LEVEL or above")); + NT_ASSERT(FALSE); + RequestCompletion(deviceExtension, Request, STATUS_INVALID_LEVEL, 0); + return STATUS_INVALID_LEVEL; + } + + // init the synchronization event + KeInitializeEvent(requestContext->SyncEvent, NotificationEvent, FALSE); + + // do we still need to do something like this? + // SET_FLAG(nextStack->Flags, SL_OVERRIDE_VERIFY_VOLUME); + + // NOTE: this mechanism relies on that KMDF will not complete request by itself. + // Doing that will cause the syncEvent not fired thus this thread will stuck. + // This should not really happen: our EvtCanceledOnQueue callbacks should be + // called even if queues are purged for some reason. The only case when these + // callbacks are not called is when a request is owned by the driver (i.e. has + // already been passed to one of the registered handlers). In this case, it is + // our responsibility to cancel such requests properly. + status = WdfDeviceEnqueueRequest(Device, Request); + + if (!NT_SUCCESS(status)) + { + // Failed to forward request! Pretend the sync event already occured, otherwise we'll hit + // an assert in RequestEvtCleanup. + KeSetEvent(requestContext->SyncEvent, IO_CD_ROM_INCREMENT, FALSE); + RequestCompletion(deviceExtension, Request, status, WdfRequestGetInformation(Request)); + } + else + { + NTSTATUS waitStatus = STATUS_UNSUCCESSFUL; + PCDROM_DATA cdData = &(deviceExtension->DeviceAdditionalData); + BOOLEAN fCallSyncCallback = FALSE; + PIRP irp = WdfRequestWdmGetIrp(Request); + + // ok, now wait on the event + while (waitStatus != STATUS_SUCCESS) + { + waitStatus = KeWaitForSingleObject(requestContext->SyncEvent, Executive, KernelMode, TRUE, NULL); + if (waitStatus == STATUS_SUCCESS) // must check equality -- STATUS_ALERTED is success code + { + // do nothing + } + else if (waitStatus != STATUS_ALERTED) + { + // do nothing + TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_IOCTL, + "Request %p on device object %p had a non-alert, non-success result from wait (%!HRESULT!)\n", + Request, Device, waitStatus)); + NT_ASSERT(FALSE); + } + else if (PsIsThreadTerminating(PsGetCurrentThread())) + { + // the thread was alerted and is terminating, so cancel the irp + // this will cause EvtIoCanceledOnQueue to be called, which will signal the event, + // so we will get out of the while loop and eventually complete the request. + if (IoCancelIrp(irp)) + { + // cancellation routine was called + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, + "Sychronize Ioctl: request %p cancelled from device %p\n", + Request, Device)); + } + else + { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, + "Sychronize Ioctl: request %p could not be cancelled from device %p\n", + Request, Device)); + } + } + else + { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, + "SPURIOUS ALERT waiting for Request %p on device %p (%!STATUS!)\n", + Request, Device, status)); + } + } // end of wait loop on the event + + // because we've waited an unknown amount of time, should check + // the cancelled flag to immediately fail the irp as appropriate + if (WdfRequestIsCanceled(Request)) + { + // the request was cancelled, thus we should always stop + // processing here if possible. + status = STATUS_CANCELLED; + RequestCompletion(deviceExtension, Request, status, 0); + } + else if (EXCLUSIVE_MODE(cdData) && !EXCLUSIVE_OWNER(cdData, WdfRequestGetFileObject(Request))) + { + WDF_REQUEST_PARAMETERS requestParameters; + BOOLEAN isBlocked = FALSE; + + // get the request parameters + WDF_REQUEST_PARAMETERS_INIT(&requestParameters); + WdfRequestGetParameters(Request, &requestParameters); + + status = RequestIsIoctlBlockedByExclusiveAccess(Request, &isBlocked); + if (isBlocked) + { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, + "Access Denied! Device in exclusive mode.Failing Ioctl %lx\n", + requestParameters.Parameters.DeviceIoControl.IoControlCode)); + RequestCompletion(deviceExtension, Request, STATUS_ACCESS_DENIED, 0); + } + else + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, + "Ioctl %lx not blocked by cdrom being in exclusive mode\n", + requestParameters.Parameters.DeviceIoControl.IoControlCode)); + fCallSyncCallback = TRUE; + } + } + else + { + fCallSyncCallback = TRUE; + } + + if (fCallSyncCallback) + { + // Synchronization completed successfully. Call the requested routine + status = requestContext->SyncCallback(Device, Request); + } + } + + // The next SequentialQueue evt routine will not be triggered until the current request is completed. + + // clean up the request context setting. + FREE_POOL(bufferToFree); + + return status; +} + +NTSTATUS +RequestIsIoctlBlockedByExclusiveAccess( + _In_ WDFREQUEST Request, + _Out_ PBOOLEAN IsBlocked + ) +/*++ +Routine Description: + + Check if the IOCTL request should be blocked or not according to + the exclusive lock stat. + +Arguments: + + Request - handle to the incoming WDF Request object + +Return Value: + + NTSTATUS + + IsBlocked - TRUE (be blocked); FALSE (not blocked) + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + ULONG ioctlCode = 0; + ULONG baseCode = 0; + WDF_REQUEST_PARAMETERS requestParameters; + + // Get the Request parameters + WDF_REQUEST_PARAMETERS_INIT(&requestParameters); + WdfRequestGetParameters(Request, &requestParameters); + + // check and initialize parameter + if (IsBlocked == NULL) + { + //This is an internal function and this parameter must be supplied. + NT_ASSERT(FALSE); + + return STATUS_INVALID_PARAMETER; + } + else + { + *IsBlocked = FALSE; + } + + // check if this is an IOCTL + if ((requestParameters.Type == WdfRequestTypeDeviceControl) || + (requestParameters.Type == WdfRequestTypeDeviceControlInternal)) + { + // + // Allow minimum set of commands that are required for the disk manager + // to show the CD device, while in exclusive mode. + // Note: These commands should not generate any requests to the device, + // and thus must be handled directly in StartIO during exclusive + // access (except for the exclusive owner, of course). + // + ioctlCode = requestParameters.Parameters.DeviceIoControl.IoControlCode; + baseCode = DEVICE_TYPE_FROM_CTL_CODE(ioctlCode); + + if (ioctlCode == IOCTL_SCSI_GET_ADDRESS || + ioctlCode == IOCTL_STORAGE_GET_HOTPLUG_INFO || + ioctlCode == IOCTL_STORAGE_GET_DEVICE_NUMBER || + ioctlCode == IOCTL_STORAGE_GET_MEDIA_TYPES_EX || + ioctlCode == IOCTL_CDROM_EXCLUSIVE_ACCESS || + ioctlCode == IOCTL_CDROM_GET_INQUIRY_DATA + ) + { + *IsBlocked = FALSE; + } + + // + // Handle IOCTL_STORAGE_QUERY_PROPERTY special because: + // (1) PropertyExistsQuery should not generate device i/o + // (2) Queries for StorageDeviceProperty and StorageAdapterDescriptor + // will return cache'd data + else if (ioctlCode == IOCTL_STORAGE_QUERY_PROPERTY) + { + PSTORAGE_PROPERTY_QUERY query = NULL; + status = WdfRequestRetrieveInputBuffer(Request, + requestParameters.Parameters.DeviceIoControl.InputBufferLength, + (PVOID*)&query, + NULL); + + if (NT_SUCCESS(status)) + { + if (query != NULL) + { + if (query->QueryType == PropertyExistsQuery) + { + *IsBlocked = FALSE; + } + else if ((query->QueryType == PropertyStandardQuery) && + ((query->PropertyId == StorageDeviceProperty) || + (query->PropertyId == StorageAdapterProperty))) + { + *IsBlocked = FALSE; + } + } + } + } + + // Return TRUE for unknown IOCTLs with STORAGE bases + else if (baseCode == IOCTL_SCSI_BASE || + baseCode == IOCTL_DISK_BASE || + baseCode == IOCTL_CDROM_BASE || + baseCode == IOCTL_STORAGE_BASE || + baseCode == IOCTL_DVD_BASE ) + { + *IsBlocked = TRUE; + } + } + else + { + // this should only be called with an IOCTL + NT_ASSERT(FALSE); + + status = STATUS_INVALID_PARAMETER; + } + + return status; +} + +BOOLEAN +DeviceIsMmcUpdateRequired( + _In_ WDFDEVICE Device + ) +/*++ +Routine Description: + + Check if the device needs to update its MMC information. + +Arguments: + + Device - device to be checked. + +Return Value: + + TRUE (require update); FALSE (not require update) + +--*/ +{ + PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(Device); + PCDROM_DATA cdData = &(deviceExtension->DeviceAdditionalData); + + if ((cdData->Mmc.IsMmc) && + (cdData->Mmc.UpdateState == CdromMmcUpdateRequired)) + { + return TRUE; + } + else + { + // no update required: just proceed + return FALSE; + } +} + +VOID +RequestEvtCleanup( + _In_ WDFOBJECT Request + ) +/*++ +Routine Description: + + Request cleanup callback. + +Arguments: + + Request - request to clean up. + +Return Value: + + None + +--*/ +{ + WDFREQUEST request = (WDFREQUEST)Request; + PCDROM_REQUEST_CONTEXT requestContext = RequestGetContext(request); + + if (requestContext->SyncRequired) + { + // the event should have been signaled, just check that + NT_ASSERT(KeReadStateEvent(requestContext->SyncEvent) != 0); + } +} + diff --git a/storage/class/cdrom/src/cdrom.h b/storage/class/cdrom/src/cdrom.h new file mode 100644 index 00000000..472e240e --- /dev/null +++ b/storage/class/cdrom/src/cdrom.h @@ -0,0 +1,1609 @@ +/*++ + +Copyright (C) Microsoft Corporation. All rights reserved. + +Module Name: + + cdrom.h + +Abstract: + + Main header file for cdrom.sys. + This contains structure and function declarations as well as constant values. + +Author: + +Environment: + + kernel mode only + +Notes: + + +Revision History: + +--*/ + +#ifndef __CDROM_H__ +#define __CDROM_H__ + +#pragma warning(push) +#pragma warning(disable:4201) // nonstandard extension used : nameless struct/union +#pragma warning(disable:4214) // nonstandard extension used : bit field types other than int +#pragma warning(disable:4152) // nonstandard extension, function/data pointer conversion in expression + +#include "wdf.h" +#include "ntddmmc.h" +#include "ntddcdvd.h" +#include "ntddcdrm.h" +#include "ntdddisk.h" +#include "ntddtape.h" +#include "ntddscsi.h" +#include "ntddvol.h" +#include "specstrings.h" +#include "cdromp.h" + +// Set component ID for DbgPrintEx calls +#ifndef DEBUG_COMP_ID + #define DEBUG_COMP_ID DPFLTR_CDROM_ID +#endif + +// Include initguid.h so GUID_CONSOLE_DISPLAY_STATE is declared +#include + +// Include header file and setup GUID for tracing +#include +#define WPP_GUID_CDROM (A4196372, C3C4, 42d5, 87BF, 7EDB2E9BCC27) +#ifndef WPP_CONTROL_GUIDS + #define WPP_CONTROL_GUIDS WPP_CONTROL_GUIDS_NORMAL_FLAGS(WPP_GUID_CDROM) +#endif + +// This prototype is needed because, although NTIFS.H is now shipping with +// the WDK, can't include both it and the other headers we already use. +_IRQL_requires_max_(DISPATCH_LEVEL) +NTKERNELAPI +BOOLEAN +PsIsThreadTerminating( + _In_ PETHREAD Thread + ); + +// +// +extern CDROM_SCAN_FOR_SPECIAL_INFO CdromHackItems[]; + +#define CDROM_HACK_DEC_RRD (0x00000001) +#define CDROM_HACK_FUJITSU_FMCD_10x (0x00000002) +//#define CDROM_HACK_HITACHI_1750 (0x00000004) -- obsolete +#define CDROM_HACK_HITACHI_GD_2000 (0x00000008) +#define CDROM_HACK_TOSHIBA_SD_W1101 (0x00000010) +//#define CDROM_HACK_TOSHIBA_XM_3xx (0x00000020) -- obsolete +//#define CDROM_HACK_NEC_CDDA (0x00000040) -- obsolete +//#define CDROM_HACK_PLEXTOR_CDDA (0x00000080) -- obsolete +#define CDROM_HACK_BAD_GET_CONFIG_SUPPORT (0x00000100) +//#define CDROM_HACK_FORCE_READ_CD_DETECTION (0x00000200) -- obsolete +//#define CDROM_HACK_READ_CD_SUPPORTED (0x00000400) -- obsolete +#define CDROM_HACK_BAD_TYPE_ONE_GET_CONFIG (0x00000800) +#define CDROM_HACK_BAD_VENDOR_PROFILES (0x00001000) +#define CDROM_HACK_MSFT_VIRTUAL_ODD (0x00002000) +#define CDROM_HACK_LOCKED_PAGES (0x80000000) // not a valid flag to save + +#define CDROM_HACK_VALID_FLAGS (0x00003fff) +#define CDROM_HACK_INVALID_FLAGS (~CDROM_HACK_VALID_FLAGS) + + +// A 64k buffer to be written takes the following amount of time: +// 1x CD == 75 sectors/sec == 0.4266667 seconds == 4266667 100ns units +// 4x CD == 300 sectors/sec == 0.1066667 seconds == 1066667 100ns units +// 10x CD == 300 sectors/sec == 0.0426667 seconds == 426667 100ns units +// 1x DVD == 676 sectors/sec == 0.0473373 seconds == 473373 100ns units +// 16x DVD == 10,816 sectors/sec == 0.0029586 seconds == 29586 100ns units +// 1x HDDVD == 2,230 sectors/sec == 0.0143498 seconds == 143498 100ns units +#define WRITE_RETRY_DELAY_CD_1x ((LONGLONG)4266667) +#define WRITE_RETRY_DELAY_CD_4x ((LONGLONG)1066667) +#define WRITE_RETRY_DELAY_CD_10x ((LONGLONG) 426667) +#define WRITE_RETRY_DELAY_DVD_1x ((LONGLONG) 473373) +#define WRITE_RETRY_DELAY_DVD_4x ((LONGLONG) 118343) +#define WRITE_RETRY_DELAY_DVD_16x ((LONGLONG) 29586) +#define WRITE_RETRY_DELAY_HDDVD_1x ((LONGLONG) 143498) + +// +#define MAXIMUM_RETRIES 4 + +#define CDROM_GET_CONFIGURATION_TIMEOUT (0x4) +#define CDROM_READ_DISC_INFORMATION_TIMEOUT (0x4) +#define CDROM_TEST_UNIT_READY_TIMEOUT (0x14) +#define CDROM_GET_PERFORMANCE_TIMEOUT (0x14) +#define CDROM_READ_CAPACITY_TIMEOUT (0x14) + +#define START_UNIT_TIMEOUT (60 * 4) + +// Used to detect the loss of the autorun irp. +#define MEDIA_CHANGE_TIMEOUT_TIME 300 + +// Indicates whether is is safe to send StartUnit commands +// to this device. It will only be off for some removeable devices. +#define DEV_SAFE_START_UNIT 0x00000004 + +// Indicates that the device is connected to a backup power supply +// and hence write-through and synch cache requests may be ignored +#define DEV_POWER_PROTECTED 0x00000010 + +// The following CDROM_SPECIAL_ flags are set in ScanForSpecialFlags +// in the Device Extension + +// Never Spin Up/Down the drive (may not handle properly) +#define CDROM_SPECIAL_DISABLE_SPIN_DOWN 0x00000001 +//#define CDROM_SPECIAL_DISABLE_SPIN_UP 0x00000002 + +// Don't bother to lock the queue when powering down +// (used mostly to send a quick stop to a cdrom to abort audio playback) +//#define CDROM_SPECIAL_NO_QUEUE_LOCK 0x00000008 + +// Disable write cache due to known bugs +#define CDROM_SPECIAL_DISABLE_WRITE_CACHE 0x00000010 + +// Used to indicate that this request shouldn't invoke any power type operations +// like spinning up the drive. + +#define SRB_CLASS_FLAGS_LOW_PRIORITY 0x10000000 + +// Used to indicate that an SRB is the result of a paging operation. +#define SRB_CLASS_FLAGS_PAGING 0x40000000 + +typedef struct _ERROR_RECOVERY_DATA { + MODE_PARAMETER_HEADER Header; + MODE_PARAMETER_BLOCK BlockDescriptor; + MODE_READ_RECOVERY_PAGE ReadRecoveryPage; +} ERROR_RECOVERY_DATA, *PERROR_RECOVERY_DATA; + +// A compile-time check of the 30,000 limit not overflowing ULONG size... +// Note that it is not expected that a release (FRE) driver will normally +// have such a large history, instead using the compression function. +#define CDROM_INTERPRET_SENSE_INFO2_MAXIMUM_HISTORY_COUNT 30000 +C_ASSERT( (MAXULONG - sizeof(SRB_HISTORY)) / 30000 >= sizeof(SRB_HISTORY_ITEM) ); + +// Intended to reuse a defined IOCTL code that not seen in Optical stack and does not require input parameter. +// This fake IOCTL is used used for MCN process sync-ed with serial queue. +#define IOCTL_MCN_SYNC_FAKE_IOCTL IOCTL_DISK_UPDATE_DRIVE_SIZE + +/*++//////////////////////////////////////////////////////////////////////////// + +PCDROM_ERROR_HANDLER() + +Routine Description: + + This routine is a callback into the driver to handle errors. The queue + shall not be unfrozen when this error handler is called, even though the + SRB flags may mark the queue as having been frozen due to this SRB. + +Irql: + + This routine will be called at KIRQL <= DISPATCH_LEVEL + +Arguments: + + DeviceObject is the device object the error occurred on. + + Srb is the Srb that was being processed when the error occurred. + + Status may be overwritten by the routine if it decides that the error + was benign, or otherwise wishes to change the returned status code + for this command + + Retry may be overwritten to specify that this command should or should + not be retried (if the callee supports retrying commands) + +Return Value: + + status + +--*/ +struct _CDROM_DEVICE_EXTENSION; // *PCDROM_DEVICE_EXTENSION; +typedef struct _CDROM_DEVICE_EXTENSION + CDROM_DEVICE_EXTENSION, + *PCDROM_DEVICE_EXTENSION; + +typedef +VOID +(*PCDROM_ERROR_HANDLER) ( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ PSCSI_REQUEST_BLOCK Srb, + _Inout_ PNTSTATUS Status, + _Inout_ PBOOLEAN Retry + ); + +// CdRom driver extension +typedef struct _CDROM_DRIVER_EXTENSION { + ULONG Version; + PDRIVER_OBJECT DriverObject; + ULONG Flags; + +} CDROM_DRIVER_EXTENSION, *PCDROM_DRIVER_EXTENSION; + +#define CDROM_FLAG_WINPE_MODE 0x00000001 + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(CDROM_DRIVER_EXTENSION, DriverGetExtension) + +#define CdromMmcUpdateComplete 0 +#define CdromMmcUpdateRequired 1 +#define CdromMmcUpdateStarted 2 + +typedef struct _CDROM_MMC_EXTENSION { + + BOOLEAN IsMmc; // mmc device + BOOLEAN IsAACS; // aacs compatible device + BOOLEAN IsWriter; // the drive is a writer or not + BOOLEAN WriteAllowed; // currently allow write request or not + + BOOLEAN IsCssDvd; // A CSS protected DVD or CPPM-protected DVDAudio media in Drive. + BOOLEAN StreamingReadSupported; // the drive supports streaming for reads + BOOLEAN StreamingWriteSupported; // the drive supports streaming for writes + + LONG UpdateState; + + // The feature number defines the level and form of + // validation that needs to be performed on Io requests + FEATURE_NUMBER ValidationSchema; + ULONG Blocking; + + SCSI_REQUEST_BLOCK CapabilitiesSrb; + PIRP CapabilitiesIrp; + WDFREQUEST CapabilitiesRequest; + SENSE_DATA CapabilitiesSenseData; + _Field_size_bytes_(CapabilitiesBufferSize) + PGET_CONFIGURATION_HEADER CapabilitiesBuffer; + ULONG CapabilitiesBufferSize; + PMDL CapabilitiesMdl; + + BOOLEAN ReadCdC2Pointers; + BOOLEAN ReadCdSubCode; + +} CDROM_MMC_EXTENSION, *PCDROM_MMC_EXTENSION; + +typedef struct _CDROM_SCRATCH_READ_WRITE_CONTEXT { + + // Information about the data that we need to read/write + ULONG PacketsCount; + ULONG TransferedBytes; + ULONG EntireXferLen; + ULONG MaxLength; + PUCHAR DataBuffer; + LARGE_INTEGER StartingOffset; + BOOLEAN IsRead; + + // A pointer to the SRB history item to be filled upon completion + PSRB_HISTORY_ITEM SrbHistoryItem; + +} CDROM_SCRATCH_READ_WRITE_CONTEXT, *PCDROM_SCRATCH_READ_WRITE_CONTEXT; + +// Many commands get double-buffered. Since the max +// transfer size is typically 64k, most of these requests +// can be handled with a single pre-allocated buffer. +typedef struct _CDROM_SCRATCH_CONTEXT { + + _Field_range_(4*1024, 64*1024) ULONG ScratchBufferSize; // 0x1000..0x10000 (4k..64k) + _Field_size_bytes_(ScratchBufferSize) PVOID ScratchBuffer; // used to get data for clients + + PMDL ScratchBufferMdl; // used to get data for clients + + WDFREQUEST ScratchRequest; + PSCSI_REQUEST_BLOCK ScratchSrb; + PSENSE_DATA ScratchSense; + PSRB_HISTORY ScratchHistory; + + // This MDL is used to performed the request whose required transfer size is bigger than adaptor's max. + PMDL PartialMdl; + BOOLEAN PartialMdlIsBuilt; + + // For debugging, set/clear this field when using the scratch buffer/request + PVOID ScratchInUse; + PCSTR ScratchInUseFileName; + ULONG ScratchInUseLineNumber; + + // Stuff for asynchronous retrying of the transfer. + ULONG NumRetries; + + // Read Write context + CDROM_SCRATCH_READ_WRITE_CONTEXT ScratchReadWriteContext; + +} CDROM_SCRATCH_CONTEXT, *PCDROM_SCRATCH_CONTEXT; + +// Context structure for the IOCTL work item +typedef struct _CDROM_IOCTL_CONTEXT { + + WDFREQUEST OriginalRequest; + +} CDROM_IOCTL_CONTEXT, *PCDROM_IOCTL_CONTEXT; + +// Context structure for the read/write work item +typedef struct _CDROM_READ_WRITE_CONTEXT { + + WDFREQUEST OriginalRequest; + +} CDROM_READ_WRITE_CONTEXT, *PCDROM_READ_WRITE_CONTEXT; + +typedef struct _CDROM_DATA { + + CDROM_MMC_EXTENSION Mmc; + + // hack flags for ScanForSpecial routines + ULONG_PTR HackFlags; + + // the error handling routines need to be per-device, not per-driver.... + PCDROM_ERROR_HANDLER ErrorHandler; + + // Indicates whether an audio play operation is currently being performed. + // Only thing this does is prevent reads and toc requests while playing audio. + BOOLEAN PlayActive; + + // indicate we need to pick a default dvd region for the user if we can + ULONG PickDvdRegion; + + // The well known name link for this device. + UNICODE_STRING WellKnownName; + + // We need to distinguish between the two... + ULONG MaxPageAlignedTransferBytes; + ULONG MaxUnalignedTransferBytes; + + // Indicates that this is a DEC RRD cdrom. + // This drive requires software to fix responses from the faulty firmware + BOOLEAN IsDecRrd; + + // Storage for the error recovery page. This is used as the method + // to switch block sizes for some drive-specific error recovery routines. + // ERROR_RECOVERY_DATA recoveryData; //obsolete along with error process for TOSHIBA_XM_3xx + + // Indicates that the device is in exclusive mode and only + // the requests from the exclusive owner will be processed. + WDFFILEOBJECT ExclusiveOwner; + + // Caller name of the owner, if the device is in exclusive mode. + UCHAR CallerName[CDROM_EXCLUSIVE_CALLER_LENGTH]; + + // Indicates that the device speed should be set to + // default value on the next media change. + BOOLEAN RestoreDefaults; + + // How long to wait between retries if a READ/WRITE irp + // gets a LWIP (2/4/7, 2/4/8)? + LONGLONG ReadWriteRetryDelay100nsUnits; + + // Cached Device Type information. Maybe FILE_DEVICE_CD_ROM or FILE_DEVICE_DVD + // CommonExtension.DevInfo->DeviceType maybe FILE_DEVICE_CD_ROM when this field is FILE_DEVICE_DVD + DEVICE_TYPE DriveDeviceType; + + _Field_size_bytes_(CachedInquiryDataByteCount) + PINQUIRYDATA CachedInquiryData; + ULONG CachedInquiryDataByteCount; + +} CDROM_DATA, *PCDROM_DATA; + + +typedef struct _CDROM_POWER_OPTIONS { + ULONG PowerDown : 1; + ULONG LockQueue : 1; + ULONG HandleSpinDown : 1; + ULONG HandleSpinUp : 1; + ULONG Reserved : 27; +} CDROM_POWER_OPTIONS, *PCDROM_POWER_OPTIONS; + +// this is a private enum, but must be kept here +// to properly compile size of CDROM_DEVICE_EXTENSION +typedef enum { + PowerDownDeviceInitial, + PowerDownDeviceLocked, + PowerDownDeviceQuiesced, + PowerDownDeviceFlushed, + PowerDownDeviceStopped, + PowerDownDeviceOff, + PowerDownDeviceUnlocked +} CDROM_POWER_DOWN_STATE; + +// this is a private enum, but must be kept here +// to properly compile size of CDROM_DEVICE_EXTENSION +typedef enum { + PowerUpDeviceInitial, + PowerUpDeviceLocked, + PowerUpDeviceOn, + PowerUpDeviceStarted, + PowerUpDeviceUnlocked +} CDROM_POWER_UP_STATE; + +// this is a private structure, but must be kept here +// to properly compile size of CDROM_DEVICE_EXTENSION +typedef struct _CDROM_POWER_CONTEXT { + + BOOLEAN InUse; + + LARGE_INTEGER StartTime; + LARGE_INTEGER Step1CompleteTime; // for SYNC CACHE in power down case + LARGE_INTEGER CompleteTime; + + union { + CDROM_POWER_DOWN_STATE PowerDown; + CDROM_POWER_UP_STATE PowerUp; // currently not used. + } PowerChangeState; + + CDROM_POWER_OPTIONS Options; + + WDFREQUEST PowerRequest; + + SCSI_REQUEST_BLOCK Srb; + SENSE_DATA SenseData; + + ULONG RetryCount; + LONGLONG RetryIntervalIn100ns; + +} CDROM_POWER_CONTEXT, *PCDROM_POWER_CONTEXT; + +// device extension structure +typedef struct _CDROM_DEVICE_EXTENSION { + + // Version control field + ULONG Version; + + // structure size + ULONG Size; + + // the structure is fully ready to use + BOOLEAN IsInitialized; + + // the device is active + BOOLEAN IsActive; + + // the device is surprise removed. + BOOLEAN SurpriseRemoved; + + // Back pointer to device object + WDFDEVICE Device; + + // Save IoTarget here, do not retrieve anytime. + WDFIOTARGET IoTarget; + + // Additional WDF queue for serial I/O processing + WDFQUEUE SerialIOQueue; + + // A separate queue for all the create file requests in sync with device + // removal + WDFQUEUE CreateQueue; + + //Main timer of driver, will do Mcn work. (once per second) + WDFTIMER MainTimer; + + // Pointer to the initialization data for this driver. This is more + // efficient than constantly getting the driver extension. + PCDROM_DRIVER_EXTENSION DriverExtension; + + // WDM device information + PDEVICE_OBJECT DeviceObject; + + // Pointer to the physical device object we attached to + PDEVICE_OBJECT LowerPdo; + + // FILE_DEVICE_CD_ROM -- 2 + DEVICE_TYPE DeviceType; + + // The name of the object + UNICODE_STRING DeviceName; + + // System device number + ULONG DeviceNumber; + + // Values for the flags are below. + USHORT DeviceFlags; + + // Flags for special behaviour required by different hardware, + // such as never spinning down or disabling advanced features such as write cache + ULONG ScanForSpecialFlags; + + // Add default Srb Flags. + ULONG SrbFlags; + + // Request timeout in seconds; + ULONG TimeOutValue; + + //The SCSI address of the device. + SCSI_ADDRESS ScsiAddress; + + // Buffer for drive parameters returned in IO device control. + DISK_GEOMETRY DiskGeometry; + + // Log2 of sector size + UCHAR SectorShift; + + // Length of partition in bytes + LARGE_INTEGER PartitionLength; + + // Number of bytes before start of partition + LARGE_INTEGER StartingOffset; + + // Interface name string returned by IoRegisterDeviceInterface. + UNICODE_STRING MountedDeviceInterfaceName; + + // Device capabilities + PSTORAGE_DEVICE_DESCRIPTOR DeviceDescriptor; + + // SCSI port driver capabilities + PSTORAGE_ADAPTER_DESCRIPTOR AdapterDescriptor; + + // Device power properties + PDEVICE_POWER_DESCRIPTOR PowerDescriptor; + + // Request Sense Buffer + PSENSE_DATA SenseData; + + // Total number of SCSI protocol errors on the device. + ULONG ErrorCount; + + // Lock count for removable media. + LONG LockCount; + LONG ProtectedLockCount; + LONG InternalLockCount; + + KEVENT EjectSynchronizationEvent; + WDFWAITLOCK EjectSynchronizationLock; + + // Indicates that the necessary data structures for media change + // detection have been initialized. + PMEDIA_CHANGE_DETECTION_INFO MediaChangeDetectionInfo; + + // Contains necessary data structures for ZPODD support. + PZERO_POWER_ODD_INFO ZeroPowerODDInfo; + + // File system context. Used for kernel-mode requests to disable autorun. + FILE_OBJECT_CONTEXT KernelModeMcnContext; + + // Count of media changes. This field is only valid for the root partition + // (ie. if PhysicalDevice == NULL). + ULONG MediaChangeCount; + + // Storage for a release queue request. + WDFSPINLOCK ReleaseQueueSpinLock; + WDFREQUEST ReleaseQueueRequest; + SCSI_REQUEST_BLOCK ReleaseQueueSrb; + WDFMEMORY ReleaseQueueInputMemory; //This is a wrapper of ReleaseQueueSrb + BOOLEAN ReleaseQueueNeeded; + BOOLEAN ReleaseQueueInProgress; + + // Context structure for power operations. Since we can only have + // one D irp at any time in the stack we don't need to worry about + // allocating multiple of these structures. + CDROM_POWER_CONTEXT PowerContext; + BOOLEAN PowerDownInProgress; + +#if (NTDDI_VERSION >= NTDDI_WIN8) + BOOLEAN IsVolumeOnlinePending; + WDFQUEUE ManualVolumeReadyQueue; +#endif + + // Lock for Shutdown/Flush operations that need to stop/start the queue + WDFWAITLOCK ShutdownFlushWaitLock; + + // device specific data area + CDROM_DATA DeviceAdditionalData; + + // scratch buffer related fields. + CDROM_SCRATCH_CONTEXT ScratchContext; + + // Hold new private data that only classpnp should modify + // in this structure. + PCDROM_PRIVATE_FDO_DATA PrivateFdoData; + + // Work item for async reads and writes and its context + WDFWORKITEM ReadWriteWorkItem; + CDROM_READ_WRITE_CONTEXT ReadWriteWorkItemContext; + + // Auxiliary WDF object for processing ioctl requests that need to go down + // to the port driver. + WDFWORKITEM IoctlWorkItem; + CDROM_IOCTL_CONTEXT IoctlWorkItemContext; + +} CDROM_DEVICE_EXTENSION, *PCDROM_DEVICE_EXTENSION; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(CDROM_DEVICE_EXTENSION, DeviceGetExtension) + +// a type definition for functions to be called after synchronization +typedef +NTSTATUS +SYNC_HANDLER ( + _In_ WDFDEVICE Device, + _In_ WDFREQUEST Request + ); + +typedef SYNC_HANDLER *PSYNC_HANDLER ; + +typedef struct _CDROM_REQUEST_CONTEXT { + PCDROM_DEVICE_EXTENSION DeviceExtension; + + WDFREQUEST OriginalRequest; + + LARGE_INTEGER TimeReceived; + LARGE_INTEGER TimeSentDownFirstTime; + LARGE_INTEGER TimeSentDownLasttTime; + + + ULONG RetriedCount; + + // Used to send down an incoming IOCTL in the original context + BOOLEAN SyncRequired; + PKEVENT SyncEvent; + PSYNC_HANDLER SyncCallback; + + // + // Used for READ/WRITE requests. + // The reason why kernel primitives are used for the spinlock and + // the timer instead of WDF object is there is a race condition + // between the cancel callback and the timer routine. + // Because of this, the timer and the spin lock need to be associated + // per request rather than using shared memory in the device extension + // and it is possible for the WDF object initialization to fail whereas + // the kernel primitives initialize provided memory. Initializing the + // kernel primitives will never fail. Since READ/WRITE is a critical + // code path, it is not desired for READs or WRITEs to fail due to + // an allocation failure that can be avoided and because it is not + // uncommon to see a failure during a READ or WRITE that may not + // occur upon a retry. + // + KSPIN_LOCK ReadWriteCancelSpinLock; + KTIMER ReadWriteTimer; + KDPC ReadWriteDpc; + BOOLEAN ReadWriteIsCompleted; + BOOLEAN ReadWriteRetryInitialized; + +} CDROM_REQUEST_CONTEXT, *PCDROM_REQUEST_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(CDROM_REQUEST_CONTEXT, RequestGetContext) + +// Define context structure for asynchronous completions. +typedef struct _COMPLETION_CONTEXT { + WDFDEVICE Device; + SCSI_REQUEST_BLOCK Srb; +} COMPLETION_CONTEXT, *PCOMPLETION_CONTEXT; + + +// +#define SCSI_CDROM_TIMEOUT 10 +#define SCSI_CHANGER_BONUS_TIMEOUT 10 + +// +// This value is used as the upper limit for all commands CDROM sends down +// to device, unless the default timeout value is overriden by registry value +// "TimeOutValue" and it is larger than this value. +// +#define SCSI_CDROM_OPC_TIMEOUT 260 + +#define HITACHI_MODE_DATA_SIZE 12 +#define MODE_DATA_SIZE 64 + +#define RAW_SECTOR_SIZE 2352 +#define COOKED_SECTOR_SIZE 2048 + +#define CDROM_SRB_LIST_SIZE 4 + +#define PLAY_ACTIVE(x) (x->DeviceAdditionalData.PlayActive) + +#define MSF_TO_LBA(Minutes,Seconds,Frames) \ + (ULONG)((60 * 75 * (Minutes)) + (75 * (Seconds)) + ((Frames) - 150)) + +// Sector types for READ_CD + +#define ANY_SECTOR 0 +#define CD_DA_SECTOR 1 +#define YELLOW_MODE1_SECTOR 2 +#define YELLOW_MODE2_SECTOR 3 +#define FORM2_MODE1_SECTOR 4 +#define FORM2_MODE2_SECTOR 5 + +#define MAX_COPY_PROTECT_AGID 4 + +#ifdef ExAllocatePool + #undef ExAllocatePool + #define ExAllocatePool #assert(FALSE) +#endif + +// memory allocation tags +// Sc?? - Mass storage driver tags +// ScC - Class driver misc allocations +// ScC? - CdRom + +#define CDROM_TAG_AUTORUN_DISABLE 'ACcS' // "ScCA" - Autorun disable functionality +#define CDROM_TAG_MEDIA_CHANGE_DETECTION 'aCcS' // "ScCa" - Media change detection + +#define CDROM_TAG_SCRATCH 'BCcS' // "ScSB" - Scratch buffer (usually 64k) +#define CDROM_TAG_GET_CONFIG 'CCcS' // "ScCC" - Ioctl GET_CONFIGURATION +#define CDROM_TAG_COMPLETION_CONTEXT 'cCcS' // "ScCc" - Context of completion routine +#define CDROM_TAG_DESCRIPTOR 'DCcS' // "ScCD" - Adaptor & Device descriptor buffer +#define CDROM_TAG_DISC_INFO 'dCcS' // "ScCd" - Disc information +#define CDROM_TAG_SYNC_EVENT 'eCcS' // "ScCe" - Request sync event +#define CDROM_TAG_FEATURE 'FCcS' // "ScCF" - Feature descriptor +#define CDROM_TAG_GESN 'GCcS' // "ScCG" - GESN buffer +#define CDROM_TAG_SENSE_INFO 'ICcS' // "ScCI" - Sense info buffers +#define CDROM_TAG_INQUIRY 'iCcS' // "ScCi" - Cached inquiry buffer +#define CDROM_TAG_MODE_DATA 'MCcS' // "ScCM" - Mode data buffer +#define CDROM_TAG_STREAM 'OCCS' // "SCCO" - Set stream buffer +#define CDROM_TAG_NOTIFICATION 'oCcS' // "ScCo" - Device Notification buffer +#define CDROM_TAG_PLAY_ACTIVE 'pCcS' // "ScCp" - Play active checks +#define CDROM_TAG_REGISTRY 'rCcS' // "ScCr" - Registry string +#define CDROM_TAG_SRB 'SCcS' // "ScCS" - Srb allocation +#define CDROM_TAG_STRINGS 'sCcS' // "ScCs" - Assorted string data +#define CDROM_TAG_UPDATE_CAP 'UCcS' // "ScCU" - Update capacity path +#define CDROM_TAG_ZERO_POWER_ODD 'ZCcS' // "ScCZ" - Zero Power ODD + +#define DVD_TAG_READ_KEY 'uCcS' // "ScCu" - Read buffer for dvd key +#define DVD_TAG_RPC2_CHECK 'VCcS' // "ScCV" - Read buffer for dvd/rpc2 check +#define DVD_TAG_DVD_REGION 'vCcS' // "ScCv" - Read buffer for rpc2 check +#define DVD_TAG_SECURITY 'XCcS' // "ScCX" - Security descriptor + + +// registry keys and data entry names. +#define CDROM_SUBKEY_NAME (L"CdRom") // store new settings here +#define CDROM_READ_CD_NAME (L"ReadCD") // READ_CD support previously detected +#define CDROM_NON_MMC_DRIVE_NAME (L"NonMmc") // MMC commands hang +#define CDROM_TYPE_ONE_GET_CONFIG_NAME (L"NoTypeOneGetConfig") // Type One Get Config commands not supported +#define CDROM_NON_MMC_VENDOR_SPECIFIC_PROFILE (L"NonMmcVendorSpecificProfile") // GET_CONFIG returns vendor specific header + // profiles that are not per spec (length divisible by 4) +#define DVD_DEFAULT_REGION (L"DefaultDvdRegion") // this is init. by the dvd class installer +#define DVD_MAX_REGION 8 + +// AACS defines +#define AACS_MKB_PACK_SIZE 0x8000 // does not include header + +//enumeration of device interfaces need to be registered. +typedef enum { + CdRomDeviceInterface = 0, // CdRomClassGuid + MountedDeviceInterface // MOUNTDEV_MOUNTED_DEVICE_GUID +} CDROM_DEVICE_INTERFACES, *PCDROM_DEVICE_INTERFACES; + + +typedef +VOID +(*PCDROM_SCAN_FOR_SPECIAL_HANDLER) ( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ ULONG_PTR Data + ); + +// Rountines Definition + +#define FREE_POOL(_PoolPtr) \ + if (_PoolPtr != NULL) { \ + ExFreePool(_PoolPtr); \ + _PoolPtr = NULL; \ + } + +#define EXCLUSIVE_MODE(_CdData) (_CdData->ExclusiveOwner != NULL) +#define EXCLUSIVE_OWNER(_CdData, _FileObject) (_CdData->ExclusiveOwner == _FileObject) + +#define IS_SCSIOP_READ(opCode) \ + ((opCode == SCSIOP_READ6) || \ + (opCode == SCSIOP_READ) || \ + (opCode == SCSIOP_READ12) || \ + (opCode == SCSIOP_READ16)) + +#define IS_SCSIOP_WRITE(opCode) \ + ((opCode == SCSIOP_WRITE6) || \ + (opCode == SCSIOP_WRITE) || \ + (opCode == SCSIOP_WRITE12) || \ + (opCode == SCSIOP_WRITE16)) + +#define IS_SCSIOP_READWRITE(opCode) (IS_SCSIOP_READ(opCode) || IS_SCSIOP_WRITE(opCode)) + +// Bit Flag Macros +#define SET_FLAG(Flags, Bit) ((Flags) |= (Bit)) +#define CLEAR_FLAG(Flags, Bit) ((Flags) &= ~(Bit)) +#define TEST_FLAG(Flags, Bit) (((Flags) & (Bit)) != 0) + +__inline +BOOLEAN +ValidChar(UCHAR Ch) +{ + if (((Ch >= '0') && (Ch <= '9')) || + (((Ch|0x20) >= 'a') && ((Ch|0x20) <= 'z')) || + (strchr(" .,:;_-", Ch) != NULL)) + { + return TRUE; + } + return FALSE; +} + +// could be #define, but this allows typechecking +__inline +BOOLEAN +PORT_ALLOCATED_SENSE( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ PSCSI_REQUEST_BLOCK Srb + ) +{ + UNREFERENCED_PARAMETER(DeviceExtension); + return (BOOLEAN)((TEST_FLAG(Srb->SrbFlags, SRB_FLAGS_PORT_DRIVER_ALLOCSENSE) && + TEST_FLAG(Srb->SrbFlags, SRB_FLAGS_FREE_SENSE_BUFFER)) + ); +} + +__inline +VOID +FREE_PORT_ALLOCATED_SENSE_BUFFER( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ PSCSI_REQUEST_BLOCK Srb + ) +{ +#ifndef DEBUG + UNREFERENCED_PARAMETER(DeviceExtension); +#endif + NT_ASSERT(TEST_FLAG(Srb->SrbFlags, SRB_FLAGS_PORT_DRIVER_ALLOCSENSE)); + NT_ASSERT(TEST_FLAG(Srb->SrbFlags, SRB_FLAGS_FREE_SENSE_BUFFER)); + NT_ASSERT(Srb->SenseInfoBuffer != DeviceExtension->SenseData); + + ExFreePool(Srb->SenseInfoBuffer); + Srb->SenseInfoBuffer = NULL; + Srb->SenseInfoBufferLength = 0; + CLEAR_FLAG(Srb->SrbFlags, SRB_FLAGS_FREE_SENSE_BUFFER); + return; +} + +// Standard driver entry function +DRIVER_INITIALIZE DriverEntry; + +// Driver Event callbacks +EVT_WDF_DRIVER_DEVICE_ADD DriverEvtDeviceAdd; + +EVT_WDF_OBJECT_CONTEXT_CLEANUP DriverEvtCleanup; + +// Device Event callbacks + +EVT_WDF_OBJECT_CONTEXT_CLEANUP DeviceEvtCleanup; + +EVT_WDF_FILE_CLOSE DeviceEvtFileClose; + +EVT_WDF_IO_IN_CALLER_CONTEXT DeviceEvtIoInCallerContext; + +EVT_WDF_DEVICE_SELF_MANAGED_IO_INIT DeviceEvtSelfManagedIoInit; + +EVT_WDF_DEVICE_SELF_MANAGED_IO_CLEANUP DeviceEvtSelfManagedIoCleanup; + +EVT_WDF_DEVICE_D0_ENTRY DeviceEvtD0Entry; + +EVT_WDF_DEVICE_D0_EXIT DeviceEvtD0Exit; + +EVT_WDF_DEVICE_SURPRISE_REMOVAL DeviceEvtSurpriseRemoval; + +// Create Queue Event callbacks + +EVT_WDF_IO_QUEUE_IO_DEFAULT CreateQueueEvtIoDefault; + +// Sequential Queue Event callbacks + +// We do not use KMDF annotation for the following function, because it handles +// both read and write requests and there is no single annotation for that. +VOID +SequentialQueueEvtIoReadWrite( + _In_ WDFQUEUE Queue, + _In_ WDFREQUEST Request, + _In_ size_t Length + ); + +EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL SequentialQueueEvtIoDeviceControl; + +EVT_WDF_IO_QUEUE_IO_CANCELED_ON_QUEUE SequentialQueueEvtCanceledOnQueue; + +// Miscellaneous request callbacks + +EVT_WDF_OBJECT_CONTEXT_CLEANUP RequestEvtCleanup; + +EVT_WDFDEVICE_WDM_IRP_PREPROCESS RequestProcessShutdownFlush; + +EVT_WDFDEVICE_WDM_IRP_PREPROCESS RequestProcessSetPower; + + +// helper functions + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +DeviceClaimRelease( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ BOOLEAN Release + ); + +_IRQL_requires_max_(APC_LEVEL) +VOID +DeviceReleaseMcnResources( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +DeviceRetrieveDescriptor( + _In_ WDFDEVICE Device, + _In_ PSTORAGE_PROPERTY_ID PropertyId, + _Outptr_ PSTORAGE_DESCRIPTOR_HEADER* Descriptor + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +VOID +DeviceRetrieveHackFlagsFromRegistry( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension + ); + +_IRQL_requires_max_(APC_LEVEL) +VOID +DeviceHackFlagsScan( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ ULONG_PTR Data + ); + +_IRQL_requires_max_(APC_LEVEL) +BOOLEAN +StringsAreMatched( + _In_opt_z_ PCHAR StringToMatch, + _In_z_ PCHAR TargetString + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +VOID +DeviceGetParameter( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_opt_ PWSTR SubkeyName, + _In_ PWSTR ParameterName, + _Inout_ PULONG ParameterValue // also default value + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +DeviceSetParameter( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_opt_z_ PWSTR SubkeyName, + _In_ PWSTR ParameterName, + _In_ ULONG ParameterValue + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +ULONG +DeviceGetTimeOutValueFromRegistry(); + +_IRQL_requires_max_(APC_LEVEL) +VOID +ScanForSpecialHandler( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ ULONG_PTR HackFlags + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +DeviceSendSrbSynchronously( + _In_ WDFDEVICE Device, + _In_ PSCSI_REQUEST_BLOCK Srb, + _In_opt_ PVOID BufferAddress, + _In_ ULONG BufferLength, + _In_ BOOLEAN WriteToDevice, + _In_opt_ WDFREQUEST OriginalRequest + ); + +BOOLEAN +RequestSenseInfoInterpret( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, // get IRP MJ code, IoControlCode from it (or attached original request) + _In_ PSCSI_REQUEST_BLOCK Srb, + _In_ ULONG RetriedCount, + _Out_ NTSTATUS* Status, + _Out_opt_ _Deref_out_range_(0, MAXIMUM_RETRY_FOR_SINGLE_IO_IN_100NS_UNITS) + LONGLONG* RetryIntervalIn100ns + ); + +VOID +RequestSetReceivedTime( + _In_ WDFREQUEST Request + ); + +VOID +RequestSetSentTime( + _In_ WDFREQUEST Request + ); + +VOID +RequestClearSendTime( + _In_ WDFREQUEST Request + ); + +BOOLEAN +RequestSenseInfoInterpretForScratchBuffer( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ ULONG RetriedCount, + _Out_ NTSTATUS* Status, + _Out_ _Deref_out_range_(0, MAXIMUM_RETRY_FOR_SINGLE_IO_IN_100NS_UNITS) + LONGLONG* RetryIntervalIn100ns + ); + + +VOID +DeviceSendNotification( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ const GUID* Guid, + _In_ ULONG ExtraDataSize, + _In_opt_ PVOID ExtraData + ); + +VOID +DeviceSendStartUnit( + _In_ WDFDEVICE Device + ); + +EVT_WDF_REQUEST_COMPLETION_ROUTINE DeviceAsynchronousCompletion; + +VOID +DeviceReleaseQueue( + _In_ WDFDEVICE Device + ); + +EVT_WDF_REQUEST_COMPLETION_ROUTINE DeviceReleaseQueueCompletion; + +VOID +DevicePerfIncrementErrorCount( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +DeviceCacheDeviceInquiryData( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension + ); + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DeviceCacheGetConfigurationData( + _In_ WDFDEVICE Device + ); + +_IRQL_requires_max_(APC_LEVEL) +PVOID +DeviceFindFeaturePage( + _In_reads_bytes_(Length) PGET_CONFIGURATION_HEADER FeatureBuffer, + _In_ ULONG const Length, + _In_ FEATURE_NUMBER const Feature + ); + +_IRQL_requires_max_(APC_LEVEL) +VOID +DevicePrintAllFeaturePages( + _In_reads_bytes_(Usable) PGET_CONFIGURATION_HEADER Buffer, + _In_ ULONG const Usable + ); + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DeviceSetRawReadInfo( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +MediaReadCapacity( + _In_ WDFDEVICE Device + ); + +_IRQL_requires_max_(APC_LEVEL) +VOID +MediaReadCapacityDataInterpret( + _In_ WDFDEVICE Device, + _In_ PREAD_CAPACITY_DATA ReadCapacityBuffer + ); + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DeviceInitReleaseQueueContext( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension + ); + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DeviceInitPowerContext( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension + ); + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DeviceCreateWellKnownName( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension + ); + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DeviceInitializeDvd( + _In_ WDFDEVICE Device + ); + +_IRQL_requires_max_(APC_LEVEL) +VOID +DevicePickDvdRegion( + _In_ WDFDEVICE Device + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +DeviceRegisterInterface( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ CDROM_DEVICE_INTERFACES InterfaceType + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +NTSTATUS +DeviceSendPowerDownProcessRequest( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_opt_ PFN_WDF_REQUEST_COMPLETION_ROUTINE CompletionRoutine, + _In_opt_ WDFCONTEXT Context + ); + +_IRQL_requires_max_(APC_LEVEL) +VOID +DeviceScanForSpecial( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ CDROM_SCAN_FOR_SPECIAL_INFO DeviceList[], + _In_ PCDROM_SCAN_FOR_SPECIAL_HANDLER Function + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +DeviceInitializeHotplugInfo( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension + ); + +NTSTATUS +DeviceErrorHandlerForMmc( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ PSCSI_REQUEST_BLOCK Srb, + _Inout_ PNTSTATUS Status, + _Inout_ PBOOLEAN Retry + ); + +NTSTATUS +DeviceErrorHandlerForHitachiGD2000( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ PSCSI_REQUEST_BLOCK Srb, + _Inout_ PNTSTATUS Status, + _Inout_ PBOOLEAN Retry + ); + +EVT_WDF_WORKITEM DeviceRestoreDefaultSpeed; + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +DeviceInitializeMediaChangeDetection( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension + ); + +VOID +DeviceSetMediaChangeStateEx( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ MEDIA_CHANGE_DETECTION_STATE NewState, + _Inout_opt_ PMEDIA_CHANGE_DETECTION_STATE OldState + ); + +_IRQL_requires_max_(APC_LEVEL) +VOID +DeviceSendDelayedMediaChangeNotifications( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension + ); + +NTSTATUS +RequestSynchronizeProcessWithSerialQueue( + _In_ WDFDEVICE Device, + _In_ WDFREQUEST Request + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +DeviceCleanupProtectedLocks( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ PFILE_OBJECT_CONTEXT FileObjectContext + ); + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DeviceCleanupDisableMcn( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ PFILE_OBJECT_CONTEXT FileObjectContext + ); + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DeviceUnlockExclusive( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFFILEOBJECT FileObject, + _In_ BOOLEAN IgnorePreviousMediaChanges + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +RequestProcessSerializedIoctl( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request + ); + +NTSTATUS +RequestIsIoctlBlockedByExclusiveAccess( + _In_ WDFREQUEST Request, + _Out_ PBOOLEAN IsBlocked + ); + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DeviceSendRequestSynchronously( + _In_ WDFDEVICE Device, + _In_ WDFREQUEST Request, + _In_ BOOLEAN RequestFormated + ); + +VOID +DeviceSendIoctlAsynchronously( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ ULONG IoControlCode, + _In_ PDEVICE_OBJECT TargetDeviceObject + ); + +IO_COMPLETION_ROUTINE RequestAsynchronousIrpCompletion; + +// MMC Update functions + +BOOLEAN +DeviceIsMmcUpdateRequired( + _In_ WDFDEVICE Device + ); + +// Helper functions + +_IRQL_requires_max_(APC_LEVEL) +VOID +DeviceEnableMediaChangeDetection( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _Inout_ PFILE_OBJECT_CONTEXT FileObjectContext, + _In_ BOOLEAN IgnorePreviousMediaChanges + ); + +_IRQL_requires_max_(APC_LEVEL) +VOID +DeviceDisableMediaChangeDetection( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _Inout_ PFILE_OBJECT_CONTEXT FileObjectContext + ); + +NTSTATUS +RequestSetContextFields( + _In_ WDFREQUEST Request, + _In_ PSYNC_HANDLER Handler + ); + +_IRQL_requires_max_(APC_LEVEL) +BOOLEAN +DeviceIsPlayActive( + _In_ WDFDEVICE Device + ); + +NTSTATUS +RequestDuidGetDeviceIdProperty( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + +NTSTATUS +RequestDuidGetDeviceProperty( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + +_IRQL_requires_max_(APC_LEVEL) +ULONG +DeviceRetrieveModeSenseUsingScratch( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_reads_bytes_(Length) PCHAR ModeSenseBuffer, + _In_ ULONG Length, + _In_ UCHAR PageCode, + _In_ UCHAR PageControl + ); + +_IRQL_requires_max_(APC_LEVEL) +PVOID +ModeSenseFindSpecificPage( + _In_reads_bytes_(Length) PCHAR ModeSenseBuffer, + _In_ size_t Length, + _In_ UCHAR PageMode, + _In_ BOOLEAN Use6Byte + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +PerformEjectionControl( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ MEDIA_LOCK_TYPE LockType, + _In_ BOOLEAN Lock + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +VOID +DeviceDisableMainTimer( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension + ); + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DeviceEnableMainTimer( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension + ); + +EVT_WDF_TIMER DeviceMainTimerTickHandler; + +VOID +RequestSetupMcnSyncIrp( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension + ); + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +RequestSetupMcnRequest( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ BOOLEAN UseGesn + ); + +_IRQL_requires_max_(APC_LEVEL) +BOOLEAN +RequestSendMcnRequest( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension + ); + +_IRQL_requires_max_(APC_LEVEL) +BOOLEAN +RequestPostWorkMcnRequest( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +NTSTATUS +PowerContextReuseRequest( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +NTSTATUS +PowerContextBeginUse( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +NTSTATUS +PowerContextEndUse( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension + ); + +POWER_SETTING_CALLBACK DevicePowerSettingCallback; + +// Zero Power ODD functions + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +DeviceInitializeZPODD( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension + ); + +_IRQL_requires_max_(APC_LEVEL) +VOID +DeviceReleaseZPODDResources( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension + ); + +NTSTATUS +DeviceZPODDGetPowerupReason( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _Out_ PSTORAGE_IDLE_POWERUP_REASON PowerupReason + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +BOOLEAN +DeviceZPODDIsInHomePosition( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +VOID +DeviceMarkActive( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ BOOLEAN IsActive, + _In_ BOOLEAN SetIdleTimeout + ); + +// common routines for specific IOCTL process + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DvdStartSessionReadKey( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ ULONG IoControlCode, + _In_opt_ WDFREQUEST OriginalRequest, + _In_opt_ PVOID InputBuffer, + _In_ size_t InputBufferLength, + _In_ PVOID OutputBuffer, + _In_ size_t OutputBufferLength, + _Out_ size_t * DataLength + ); + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +ReadDvdStructure( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_opt_ WDFREQUEST OriginalRequest, + _In_ PVOID InputBuffer, + _In_ size_t InputBufferLength, + _In_ PVOID OutputBuffer, + _In_ size_t OutputBufferLength, + _Out_ size_t * DataLength + ); + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +ReadQChannel( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_opt_ WDFREQUEST OriginalRequest, + _In_ PVOID InputBuffer, + _In_ size_t InputBufferLength, + _In_ PVOID OutputBuffer, + _In_ size_t OutputBufferLength, + _Out_ size_t * DataLength + ); + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DvdSendKey( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_opt_ WDFREQUEST OriginalRequest, + _In_ PVOID InputBuffer, + _In_ size_t InputBufferLength, + _Out_ size_t * DataLength + ); + + +#ifndef SIZEOF_ARRAY + #define SIZEOF_ARRAY(ar) (sizeof(ar)/sizeof((ar)[0])) +#endif // !defined(SIZEOF_ARRAY) + + +// 100us to seconds +#define UNIT_100NS_PER_SECOND (10*1000*1000) +#define SECONDS_TO_100NS_UNITS(x) (((LONGLONG)x) * UNIT_100NS_PER_SECOND) + +// +// Bit Flag Macros +// +#define SET_FLAG(Flags, Bit) ((Flags) |= (Bit)) +#define CLEAR_FLAG(Flags, Bit) ((Flags) &= ~(Bit)) +#define TEST_FLAG(Flags, Bit) (((Flags) & (Bit)) != 0) + +// +// neat little hacks to count number of bits set efficiently +// +__inline ULONG CountOfSetBitsUChar(UCHAR _X) + { ULONG i = 0; while (_X) { _X &= _X - 1; i++; } return i; } +__inline ULONG CountOfSetBitsULong(ULONG _X) + { ULONG i = 0; while (_X) { _X &= _X - 1; i++; } return i; } +__inline ULONG CountOfSetBitsULong32(ULONG32 _X) + { ULONG i = 0; while (_X) { _X &= _X - 1; i++; } return i; } +__inline ULONG CountOfSetBitsULong64(ULONG64 _X) + { ULONG i = 0; while (_X) { _X &= _X - 1; i++; } return i; } +__inline ULONG CountOfSetBitsUlongPtr(ULONG_PTR _X) + { ULONG i = 0; while (_X) { _X &= _X - 1; i++; } return i; } + + +__inline +BOOLEAN +IsVolumeMounted( + _In_ PDEVICE_OBJECT DeviceObject + ) +{ +#pragma prefast(push) +#pragma prefast(disable: 28175, "there is no other way to check if there is volume mounted") + return (DeviceObject->Vpb != NULL) && + ((DeviceObject->Vpb->Flags & VPB_MOUNTED) != 0); +#pragma prefast(pop) +} + + +__inline _Ret_range_(0,MAXIMUM_RETRY_FOR_SINGLE_IO_IN_100NS_UNITS) +LONGLONG +ConvertSectorsPerSecondTo100nsUnitsFor64kWrite( + _In_range_(1,0xFFFFFFFF) ULONG SectorsPerSecond // zero would cause divide-by-zero + ) +{ + // 64k write + // ---------------- == time per 64k write + // sectors/second + // + // (32 / N) == seconds + // (32 / N) * (1,000,000,000) == nanoseconds + // (32 / N) * (1,000,000,000) / 100 == 100ns increments + // (32 * 10,000,000) / N == 100ns increments + // + // 320,000,000 / N == 100ns increments + // And this is safe to run in kernel-mode (no floats) + // + + // this assert ensures that we _never_ can return a value + // larger than the maximum allowed. + C_ASSERT(320000000 < MAXIMUM_RETRY_FOR_SINGLE_IO_IN_100NS_UNITS); + + return 320000000 / SectorsPerSecond; +} + +__inline +UCHAR +RequestGetCurrentStackLocationFlags( + _In_ WDFREQUEST Request + ) +{ + PIRP irp = NULL; + PIO_STACK_LOCATION currentStack = NULL; + + irp = WdfRequestWdmGetIrp(Request); + currentStack = IoGetCurrentIrpStackLocation(irp); + + return currentStack->Flags; +} + +__inline +ULONG +TimeOutValueGetCapValue( + _In_ ULONG TimeOutValue, + _In_ ULONG Times + ) +{ + ULONG value = 0; + + if (TimeOutValue > SCSI_CDROM_OPC_TIMEOUT) + { + // if time out value is specified by user in registry, and is + // bigger than OPC time out, it should be big enough + value = TimeOutValue; + } + else + { + // otherwise, OPC time out value should be the upper limit + value = min(TimeOutValue * Times, SCSI_CDROM_OPC_TIMEOUT); + } + + return value; +} + +VOID +RequestCompletion( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ NTSTATUS Status, + _In_ ULONG_PTR Information + ); + +NTSTATUS +RequestSend( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDFIOTARGET IoTarget, + _In_ ULONG Flags, + _Out_opt_ PBOOLEAN RequestSent + ); + +EVT_WDF_REQUEST_COMPLETION_ROUTINE RequestDummyCompletionRoutine; + +VOID +RequestProcessInternalDeviceControl( + _In_ WDFREQUEST Request, + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension + ); + +EVT_WDF_WORKITEM IoctlWorkItemRoutine; + +EVT_WDF_WORKITEM ReadWriteWorkItemRoutine; + +#pragma warning(pop) // un-sets any local warning changes + +#endif // __CDROMP_H__ + + diff --git a/storage/class/cdrom/src/cdrom.htm b/storage/class/cdrom/src/cdrom.htm new file mode 100644 index 00000000..483d3c85 --- /dev/null +++ b/storage/class/cdrom/src/cdrom.htm @@ -0,0 +1,86 @@ + + + + +CD ROM + + + +

CD ROM

+ +

SUMMARY

+The CD ROM driver is used to provide access to CD, DVD and Blu-ray drives. It supports Plug and Play, Power Management, and AutoRun (media change notification). It is a 64-bit compliant driver. + +

BUILDING THE SAMPLE

+To build cdrom.sys, you must first set up the DDK/WDK environment on your host machine. The "Installation and Release Notes" in the Windows 2000/XP/Server 2003/Vista/Server 2008/Windows 7 DDK/WDK has a complete description on how to do this. +

    +
  • Click the Free Build Environment or Checked Build Environment icon under your Windows Driver Kit program group to set basic environment variables need by the build utility.
  • +
  • Change to the directory containing the driver source code, such as "cd src\storage\class\cdrom".
  • +
  • Build the driver by typing BLD.
  • +
+ +Macro BLD invokes the Microsoft make routines that produce log file called buildxxx_yyy_zzz.log, and also buildxxx_yyy_zzz.wrn and buildxxx_yyy_zzz.err if there are any warnings or errors, where xxx stands for fre or chk depending on the environment chosen, yyy stands for the OS version (W2k, WXP, Wnet or Win7), and zzz stands for platform version (x86, ia64 or amd64). + +

If the build succeeds, the driver will be placed in the binary output directory specified for the build environment. You can get the output path from the buildxxx_yyy_zzz.log file. + +

INSTALLATION

+The in-box CD ROM driver is protected by the system, and thus a normal device driver update attempt through the Device Manager will fail. Users are not encouraged to replace the in-box CD ROM driver. The following work-around is provided in case there is a need, but the users are warned that this may harm the system. +

    +
  • Click the Free Build Environment or Checked Build Environment icon under your Windows Driver Kit program group to set basic environment variables need by the build utility.
  • +
  • Change to the directory containing the driver source code, such as "cd src\storage\class\cdrom".
  • +
  • Update the "sources" file by changing the "TARGETNAME" from "cdrom" to "mycdrom".
  • +
  • Build the driver by typing BLD.
  • +
  • Locate the "cdrom.inf" file in the binary output directory, and update the file by replacing all "cdrom.sys" occurrences with "mycdrom.sys".
  • +
  • Rename the "cdrom.inf" file to "mycdrom.inf".
  • +
  • Copy "mycdrom.sys" and "mycdrom.inf" from the binary output directory to the test machine, if applicable.
  • +
  • Launch the Device Manager (by clicking on Windows Start, Run option and typing "devmgmt.msc").
  • +
  • Select the appropriate device under the "DVD/CD-ROM drives" category.
  • +
  • On the right-click menu, select "Update Driver Software...".
  • +
  • Select "Browse my computer for driver software".
  • +
  • Select "Let me pick from a list of device drivers on my computer".
  • +
  • Click "Have Disk...", and point to the directory that contains "mycdrom.inf" and "mycdrom.sys".
  • +
  • Click "Next". If you get a warning dialog about installing unsigned driver, click "Yes".
  • +
  • Click "Next" to complete the driver upgrade.
  • +
+ +NOTE: After installation completes successfully, "mycdrom.sys" will be the effective driver for the device, "cdrom.sys" will no longer be used. + +

CODE TOUR

+

File Manifest

+
File			Description
+
+
+aacs.c			The CDROM class driver implementation of handling AACS IOCTLs
+autorun.c		Code for supporting media change detection in the cd/dvd driver
+cdrom.c			Main code base
+cdrom.h			Main header file for cdrom.sys
+cdrom.htm		This file
+cdrom.inf		The CDROM class driver configuration file
+cdrom.rc		Resource file
+cdromp.h		Private header file for cdrom.sys modules
+common.c		Shared private routines for cdrom.sys
+data.c			Global data definitions
+guid.c			GUIDs needed for cdrom.sys
+init.c			Initialization routines for cdrom.sys
+ioctl.c			Ioctl dispatch handlers
+ioctl.h			Ioctl dispatch handlers - header file
+makefile		Makefile
+makefile.inc		Makefile used to generate custom targets required by the module
+mmc.c			All functions related to MMC
+mmc.h			All functions related to MMC - header file
+pnppower.c		Functions to handle PnP and Power IRPs
+scratch.c		Functions for using common scratch buffer
+scratch.h		Functions for using common scratch buffer - header file
+sense.c			Functions needed to accurately determine how to retry requests on CDROM device types
+sources			Macro definitions that are recognized by the Build utility
+
+
+

Top of page

+ + + +
+

+ +

© 2008 Microsoft Corporation

+ diff --git a/storage/class/cdrom/src/cdrom.inf b/storage/class/cdrom/src/cdrom.inf new file mode 100644 index 00000000..a1ba9f7f Binary files /dev/null and b/storage/class/cdrom/src/cdrom.inf differ diff --git a/storage/class/cdrom/src/cdrom.rc b/storage/class/cdrom/src/cdrom.rc new file mode 100644 index 00000000..688f9142 --- /dev/null +++ b/storage/class/cdrom/src/cdrom.rc @@ -0,0 +1,23 @@ +//+------------------------------------------------------------------------- +// +// Microsoft Windows +// +// Copyright (C) Microsoft Corporation, 1996 - 1999 +// +// File: scsicdrm.rc +// +//-------------------------------------------------------------------------- + +#include + +#include + +#define VER_FILETYPE VFT_DRV +#define VER_FILESUBTYPE VFT2_DRV_SYSTEM +#define VER_FILEDESCRIPTION_STR "SCSI CD-ROM Driver" +#define VER_INTERNALNAME_STR "cdrom.sys" +#define VER_ORIGINALFILENAME_STR "cdrom.sys" +#define VER_LANGNEUTRAL + +#include "common.ver" + diff --git a/storage/class/cdrom/src/cdrom.vcxproj b/storage/class/cdrom/src/cdrom.vcxproj new file mode 100644 index 00000000..eb8a7163 --- /dev/null +++ b/storage/class/cdrom/src/cdrom.vcxproj @@ -0,0 +1,169 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {1683D068-B3E1-4216-8BA9-A8ADC10DBAC6} + $(MSBuildProjectName) + 1 + false + Debug + Win32 + {E200755F-0634-4431-B800-411C41E79190} + + + + Windows10 + False + Universal + KMDF + WindowsKernelModeDriver10.0 + Driver + + + Windows10 + True + Universal + KMDF + WindowsKernelModeDriver10.0 + Driver + + + Windows10 + False + Universal + KMDF + WindowsKernelModeDriver10.0 + Driver + + + Windows10 + True + Universal + KMDF + WindowsKernelModeDriver10.0 + Driver + + + + $(IntDir) + + + + + + + + + + + + + + + + true + true + TracePrint((LEVEL,FLAGS,MSG,...)) + + + $(InfArch) + true + .\$(IntDir)\cdrom.inf + + + true + true + TracePrint((LEVEL,FLAGS,MSG,...)) + + + + cdrom + + + cdrom + + + cdrom + + + cdrom + + + + true + Level4 + + + + + %(AdditionalDependencies);$(DDK_LIB_PATH)\ntoskrnl.lib + + + + + true + Level4 + + + + + %(AdditionalDependencies);$(DDK_LIB_PATH)\ntoskrnl.lib + + + + + true + Level4 + + + + + %(AdditionalDependencies);$(DDK_LIB_PATH)\ntoskrnl.lib + + + + + true + Level4 + + + + + %(AdditionalDependencies);$(DDK_LIB_PATH)\ntoskrnl.lib + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/storage/class/cdrom/src/cdrom.vcxproj.Filters b/storage/class/cdrom/src/cdrom.vcxproj.Filters new file mode 100644 index 00000000..35fd8b4c --- /dev/null +++ b/storage/class/cdrom/src/cdrom.vcxproj.Filters @@ -0,0 +1,75 @@ + + + + + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* + {00DD8EE3-FDCD-4456-BC4F-E74036AB1AC1} + + + h;hpp;hxx;hm;inl;inc;xsd + {ED90C8BD-839B-498E-801C-9D36D5AE7AA7} + + + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml + {4FF8F695-EF19-47F0-B961-AA636092E365} + + + inf;inv;inx;mof;mc; + {AB325463-69C0-4899-82FF-C8D632CBE6C9} + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Driver Files + + + Driver Files + + + + + Resource Files + + + \ No newline at end of file diff --git a/storage/class/cdrom/src/cdromp.h b/storage/class/cdrom/src/cdromp.h new file mode 100644 index 00000000..2fdf7118 --- /dev/null +++ b/storage/class/cdrom/src/cdromp.h @@ -0,0 +1,383 @@ +/*++ + +Copyright (C) Microsoft Corporation. All rights reserved. + +Module Name: + + cdromp.h + +Abstract: + + Private header file for cdrom.sys modules. This contains private + structure and function declarations as well as constant values which do + not need to be exported. + +Author: + +Environment: + + kernel mode only + +Notes: + + +Revision History: + +--*/ + +#ifndef __CDROMP_H__ +#define __CDROMP_H__ + + +#include +#include +#include +#include +#include + +/* + * IA64 requires 8-byte alignment for pointers, but the IA64 NT kernel expects 16-byte alignment + */ +#ifdef _WIN64 + #define PTRALIGN DECLSPEC_ALIGN(16) +#else + #define PTRALIGN +#endif + +// NOTE: Start with a smaller 100 second maximum, due to current assert in CLASSPNP +// 0x0000 00C9'2A69 C000 (864,000,000,000) is 24 hours in 100ns units +// 0x0000 0000'3B9A CA00 ( 1,000,000,000) is 100 seconds in 100ns units +#define MAXIMUM_RETRY_FOR_SINGLE_IO_IN_100NS_UNITS (0x3B9ACA00) + +// structures to simplify matching devices, ids, and hacks required for +// these ids. +typedef struct _CDROM_SCAN_FOR_SPECIAL_INFO { + // + // * NULL pointers indicates that no match is required. + // * empty string will only match an empty string. non-existant strings + // in the device descriptor are considered empty strings for this match. + // (ie. "" will only match "") + // * all other strings will do partial matches, based upon + // string provided (ie. "hi" will match "hitazen" and "higazui") + // * array must end with all three PCHARs being set to NULL. + // + + PCHAR VendorId; + PCHAR ProductId; + PCHAR ProductRevision; + + // + // marked as a ULONG_PTR to allow use as either a ptr to a data block + // or 32 bits worth of flags. (64 bits on 64 bit systems) no longer a + // const so that it may be dynamically built. + // + + ULONG_PTR Data; + +} CDROM_SCAN_FOR_SPECIAL_INFO, *PCDROM_SCAN_FOR_SPECIAL_INFO; + +// Define the various states that media can be in for autorun. +typedef enum _MEDIA_CHANGE_DETECTION_STATE { + MediaUnknown, + MediaPresent, + MediaNotPresent, + MediaUnavailable // e.g. cd-r media undergoing burn +} MEDIA_CHANGE_DETECTION_STATE, *PMEDIA_CHANGE_DETECTION_STATE; + + +/*++//////////////////////////////////////////////////////////////////////////// + + This structure defines the history kept for a given transfer packet. + It includes a srb status/sense data structure that is always either valid + or zero-filled for the full 18 bytes, time sent/completed, and how long + the retry delay was requested to be. + +--*/ +typedef struct _SRB_HISTORY_ITEM { + LARGE_INTEGER TickCountSent; // 0x00..0x07 + LARGE_INTEGER TickCountCompleted; // 0x08..0x0F + ULONG MillisecondsDelayOnRetry; // 0x10..0x13 + SENSE_DATA NormalizedSenseData; // 0x14..0x25 (0x12 bytes) + UCHAR SrbStatus; // 0x26 + UCHAR ClassDriverUse; // 0x27 -- one byte free (alignment) +} SRB_HISTORY_ITEM, *PSRB_HISTORY_ITEM; + +typedef struct _SRB_HISTORY { + ULONG_PTR ClassDriverUse[4]; // for the class driver to use as they please + _Field_range_(1,30000) + ULONG TotalHistoryCount; + _Field_range_(0,TotalHistoryCount) + ULONG UsedHistoryCount; + _Field_size_part_(TotalHistoryCount, UsedHistoryCount) + SRB_HISTORY_ITEM History[1]; +} SRB_HISTORY, *PSRB_HISTORY; + +extern CDROM_SCAN_FOR_SPECIAL_INFO CdRomBadItems[]; + +/*++////////////////////////////////////////////////////////////////////////////*/ + +// legacy registry key and values. +#define CLASSP_REG_SUBKEY_NAME (L"Classpnp") + +#define CLASSP_REG_HACK_VALUE_NAME (L"HackMask") +#define CLASSP_REG_MMC_DETECTION_VALUE_NAME (L"MMCDetectionState") +#define CLASSP_REG_WRITE_CACHE_VALUE_NAME (L"WriteCacheEnableOverride") +#define CLASSP_REG_PERF_RESTORE_VALUE_NAME (L"RestorePerfAtCount") +#define CLASSP_REG_REMOVAL_POLICY_VALUE_NAME (L"UserRemovalPolicy") +#define WINPE_REG_KEY_NAME (L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\MiniNT") + +#define CLASS_PERF_RESTORE_MINIMUM (0x10) +#define CLASS_ERROR_LEVEL_1 (0x4) +#define CLASS_ERROR_LEVEL_2 (0x8) + +#define FDO_HACK_CANNOT_LOCK_MEDIA (0x00000001) +#define FDO_HACK_GESN_IS_BAD (0x00000002) +#define FDO_HACK_NO_RESERVE6 (0x00000008) +#define FDO_HACK_GESN_IGNORE_OPCHANGE (0x00000010) +#define FDO_HACK_NO_STREAMING (0x00000020) +#define FDO_HACK_NO_ASYNCHRONOUS_NOTIFICATION (0x00000040) + +#define FDO_HACK_VALID_FLAGS (0x0000007F) +#define FDO_HACK_INVALID_FLAGS (~FDO_HACK_VALID_FLAGS) + +/* + * Lots of retries of synchronized SCSI commands that devices may not + * even support really slows down the system (especially while booting). + * (Even GetDriveCapacity may be failed on purpose if an external disk is powered off). + * If a disk cannot return a small initialization buffer at startup + * in two attempts (with delay interval) then we cannot expect it to return + * data consistently with four retries. + * So don't set the retry counts as high here as for data SRBs. + * + * If we find that these requests are failing consecutively, + * despite the retry interval, on otherwise reliable media, + * then we should either increase the retry interval for + * that failure or (by all means) increase these retry counts as appropriate. + */ +//#define NUM_LOCKMEDIAREMOVAL_RETRIES 1 +//#define NUM_MODESENSE_RETRIES 1 +//#define NUM_DRIVECAPACITY_RETRIES 1 + +/* + * We retry failed I/O requests at 1-second intervals. + * In the case of a failure due to bus reset, we want to make sure that we retry after the allowable + * reset time. For SCSI, the allowable reset time is 5 seconds. ScsiPort queues requests during + * a bus reset, which should cause us to retry after the reset is over; but the requests queued in + * the miniport are failed all the way back to us immediately. In any event, in order to make + * extra sure that our retries span the allowable reset time, we should retry more than 5 times. + */ +//#define NUM_IO_RETRIES 8 + +#define CDROM_VOLUME_VERIFY_CHECKED 0x34 + +#define CDROM_TAG_PRIVATE_DATA 'CPcS' + +typedef struct _MEDIA_CHANGE_DETECTION_INFO { + + // Use AN if supported so that we don't need to poll for media change notifications. + BOOLEAN AsynchronousNotificationSupported; + + // If AN is turned on and we received an AN signal when the device is exclusively locked, + // we should take a note and send down a GESN when the lock is lifted, since otherwise + // we will lose the signal. Even worse, some ODD models will signal the event again next + // time a SYNC CACHE is sent down, and processing the event in that arbitrary timing may + // cause unexpected behaviors. + BOOLEAN ANSignalPendingDueToExclusiveLock; + + // Mutex to synchronize enable/disable requests and media state changes + KMUTEX MediaChangeMutex; + + // For request erialization use. + // This irp is used in timer callback routine, will be sent to the device itself. + // so that the sequentail queue will get request wrapped on this irp. After doing + // the real work, this irp will be completed to indicate it's ok to send the next + // MCN request. + PIRP MediaChangeSyncIrp; + + // The last known state of the media (present, not present, unknown). + // Protected by MediaChangeMutex. + MEDIA_CHANGE_DETECTION_STATE LastKnownMediaDetectionState; + + // The last state of the media (present, not present, unknown) reported to apps + // via notifications. Protected by MediaChangeMutex + MEDIA_CHANGE_DETECTION_STATE LastReportedMediaDetectionState; + + // This is a count of how many time MCD has been disabled. if it is + // set to zero, then we'll poll the device for MCN events with the + // then-current method (ie. TEST UNIT READY or GESN). this is + // protected by MediaChangeMutex + LONG MediaChangeDetectionDisableCount; + + // recent changes allowed instant retries of the MCN REQUEST. Since this + // could cause an infinite loop, keep a count of how many times we've + // retried immediately so that we can catch if the count exceeds an + // arbitrary limit. + LONG MediaChangeRetryCount; + + // use GESN if it's available + struct { + BOOLEAN Supported; + BOOLEAN HackEventMask; + UCHAR EventMask; + UCHAR NoChangeEventMask; + PUCHAR Buffer; + PMDL Mdl; + ULONG BufferSize; + } Gesn; + + // If this value is one, then the REQUEST is currently in use. + // If this value is zero, then the REQUEST is available. + // Use InterlockedCompareExchange() to set from "available" to "in use". + // ASSERT that InterlockedCompareExchange() showed previous value of + // "in use" when changing back to "available" state. + // This also implicitly protects the MediaChangeSrb and SenseBuffer + // + // This protect is needed in the polling case since the timer is fired asynchronous + // to our sequential I/O queues, and when the timer is fired, our Sync Irp could be + // still using the MediaChangeRequest. However, if AN is used, then each interrupt + // will cause us to queue a request, so interrupts are serialized, and within the + // handling of each request, we already sequentially use the MediaChangeRequest if + // we need retries. We still use it in case of AN to be consistent with polling, but + // if in the future we remove polling altogether, then we don't need this field anymore. + LONG MediaChangeRequestInUse; + + // Pointer to the REQUEST to be used for media change detection. + // protected by Interlocked MediaChangeRequestInUse + WDFREQUEST MediaChangeRequest; + + // The srb for the media change detection. + // protected by Interlocked MediaChangeIrpInUse + SCSI_REQUEST_BLOCK MediaChangeSrb; + PUCHAR SenseBuffer; + ULONG SrbFlags; + + // Handle to the display state notification registration. + PVOID DisplayStateCallbackHandle; + +} MEDIA_CHANGE_DETECTION_INFO, *PMEDIA_CHANGE_DETECTION_INFO; + +#define DELAY_TIME_TO_ENTER_ZERO_POWER_IN_MS (60 * 1000) +#define DELAY_TIME_TO_ENTER_AOAC_IDLE_POWER_IN_MS (10 * 1000) +#define BECOMING_READY_RETRY_COUNT (15) +#define BECOMING_READY_RETRY_INTERNVAL_IN_100NS (2 * 1000 * 1000) + +typedef struct _ZERO_POWER_ODD_INFO { + + UCHAR LoadingMechanism; // From Removable Medium Feature Descriptor + UCHAR Load; // From Removable Medium Feature Descriptor + + D3COLD_SUPPORT_INTERFACE D3ColdInterface; // D3Cold interface from ACPI + + BOOLEAN Reserved; // Reserved + BOOLEAN InZeroPowerState; // Is device currently in Zero Power State + BOOLEAN RetryFirstCommand; // First command after power resume should be retried + BOOLEAN MonitorStartStopUnit; // If 1. drawer 2. soft eject 3. no media 4. Immed=0, + // we will not receive any GESN events, and so we should + // monitor the command to get notified + ULONG BecomingReadyRetryCount; // How many times we should retry for becoming ready + + UCHAR SenseKey; // sense code from TUR to check media & tray status + UCHAR AdditionalSenseCode; // sense code from TUR to check media & tray status + UCHAR AdditionalSenseCodeQualifier; // sense code from TUR to check media & tray status + + PGET_CONFIGURATION_HEADER GetConfigurationBuffer; // Cached Get Configuration response from device + ULONG GetConfigurationBufferSize; // Size of the above buffer + +} ZERO_POWER_ODD_INFO, *PZERO_POWER_ODD_INFO; + +typedef enum { + SimpleMediaLock, + SecureMediaLock, + InternalMediaLock +} MEDIA_LOCK_TYPE, *PMEDIA_LOCK_TYPE; + + +typedef enum _CDROM_DETECTION_STATE { + CdromDetectionUnknown = 0, + CdromDetectionUnsupported = 1, + CdromDetectionSupported = 2 +} CDROM_DETECTION_STATE, *PCDROM_DETECTION_STATE; + + +typedef struct _CDROM_ERROR_LOG_DATA { + LARGE_INTEGER TickCount; // Offset 0x00 + ULONG PortNumber; // Offset 0x08 + + UCHAR ErrorPaging : 1; // Offset 0x0c + UCHAR ErrorRetried : 1; + UCHAR ErrorUnhandled : 1; + UCHAR ErrorReserved : 5; + + UCHAR Reserved[3]; + + SCSI_REQUEST_BLOCK Srb; // Offset 0x10 + + // We define the SenseData as the default length. + // Since the sense data returned by the port driver may be longer, + // SenseData must be at the end of this structure. + // For our internal error log, we only log the default length. + SENSE_DATA SenseData; // Offset 0x50 for x86 (or 0x68 for ia64) (ULONG32 Alignment required!) +} CDROM_ERROR_LOG_DATA, *PCDROM_ERROR_LOG_DATA; + + +#define NUM_ERROR_LOG_ENTRIES 16 + +// +// add to the front of this structure to help prevent illegal +// snooping by other utilities. +// +typedef struct _CDROM_PRIVATE_FDO_DATA { + + // this private structure allows us to + // dynamically re-enable the perf benefits + // lost due to transient error conditions. + // in w2k, a reboot was required. :( + struct { + ULONG OriginalSrbFlags; + ULONG SuccessfulIO; + ULONG ReEnableThreshhold; // 0 means never + } Perf; + + ULONG_PTR HackFlags; + + STORAGE_HOTPLUG_INFO HotplugInfo; + + BOOLEAN TimerStarted; + BOOLEAN LoggedTURFailureSinceLastIO; + BOOLEAN LoggedSYNCFailure; + + // not use WDFSPINLOCK to avoid exposing private object creation + // in initialization code. (cdrom.sys was in WDK example) + KSPIN_LOCK SpinLock; + + // Circular array of timestamped logs of errors that occurred on this device. + ULONG ErrorLogNextIndex; + CDROM_ERROR_LOG_DATA ErrorLogs[NUM_ERROR_LOG_ENTRIES]; + +}CDROM_PRIVATE_FDO_DATA, *PCDROM_PRIVATE_FDO_DATA; + +// +// this is a private structure, but must be kept here +// to properly compile size of FUNCTIONAL_DEVICE_EXTENSION +// +typedef struct _FILE_OBJECT_CONTEXT { + WDFFILEOBJECT FileObject; + WDFDEVICE DeviceObject; + ULONG LockCount; + ULONG McnDisableCount; + BOOLEAN EnforceStreamingRead; + BOOLEAN EnforceStreamingWrite; +} FILE_OBJECT_CONTEXT, *PFILE_OBJECT_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(FILE_OBJECT_CONTEXT, FileObjectGetContext) + + +#define NOT_READY_RETRY_INTERVAL 10 +#define MODE_PAGE_DATA_SIZE 192 + +// +// per session device +// +#define INVALID_SESSION ((ULONG)-1) + +#endif // __CDROMP_H__ diff --git a/storage/class/cdrom/src/common.c b/storage/class/cdrom/src/common.c new file mode 100644 index 00000000..b1ab41ec --- /dev/null +++ b/storage/class/cdrom/src/common.c @@ -0,0 +1,3872 @@ +/*++ + +Copyright (C) Microsoft Corporation. All rights reserved. + +Module Name: + + common.c + +Abstract: + + shared private routines for cdrom.sys + +Environment: + + kernel mode only + +Notes: + + +Revision History: + +--*/ + + +#include "ntddk.h" +#include "ntddstor.h" +#include "ntstrsafe.h" + +#include "cdrom.h" +#include "scratch.h" + + +#ifdef DEBUG_USE_WPP +#include "common.tmh" +#endif + +#ifdef ALLOC_PRAGMA + +#pragma alloc_text(PAGE, DeviceGetParameter) +#pragma alloc_text(PAGE, DeviceSetParameter) +#pragma alloc_text(PAGE, DeviceSendSrbSynchronously) +#pragma alloc_text(PAGE, DevicePickDvdRegion) +#pragma alloc_text(PAGE, StringsAreMatched) +#pragma alloc_text(PAGE, PerformEjectionControl) +#pragma alloc_text(PAGE, DeviceFindFeaturePage) +#pragma alloc_text(PAGE, DevicePrintAllFeaturePages) +#pragma alloc_text(PAGE, DeviceRegisterInterface) +#pragma alloc_text(PAGE, DeviceRestoreDefaultSpeed) +#pragma alloc_text(PAGE, DeviceSendRequestSynchronously) +#pragma alloc_text(PAGE, MediaReadCapacity) +#pragma alloc_text(PAGE, MediaReadCapacityDataInterpret) +#pragma alloc_text(PAGE, DeviceRetrieveModeSenseUsingScratch) +#pragma alloc_text(PAGE, ModeSenseFindSpecificPage) +#pragma alloc_text(PAGE, DeviceUnlockExclusive) + +#endif + +LPCSTR LockTypeStrings[] = {"Simple", + "Secure", + "Internal" + }; + +VOID +RequestSetReceivedTime( + _In_ WDFREQUEST Request + ) +{ + PCDROM_REQUEST_CONTEXT requestContext = RequestGetContext(Request); + LARGE_INTEGER temp; + + KeQueryTickCount(&temp); + + requestContext->TimeReceived = temp; + + return; +} + +VOID +RequestSetSentTime( + _In_ WDFREQUEST Request + ) +{ + PCDROM_REQUEST_CONTEXT requestContext = RequestGetContext(Request); + LARGE_INTEGER temp; + + KeQueryTickCount(&temp); + + if (requestContext->TimeSentDownFirstTime.QuadPart == 0) + { + requestContext->TimeSentDownFirstTime = temp; + } + + requestContext->TimeSentDownLasttTime = temp; + + if (requestContext->OriginalRequest != NULL) + { + PCDROM_REQUEST_CONTEXT originalRequestContext = RequestGetContext(requestContext->OriginalRequest); + + if (originalRequestContext->TimeSentDownFirstTime.QuadPart == 0) + { + originalRequestContext->TimeSentDownFirstTime = temp; + } + + originalRequestContext->TimeSentDownLasttTime = temp; + } + + return; +} + +VOID +RequestClearSendTime( + _In_ WDFREQUEST Request + ) +/* +Routine Description: + + This function is used to clean SentTime fields in reusable request context. + +Arguments: + Request - + +Return Value: + N/A + +*/ +{ + PCDROM_REQUEST_CONTEXT requestContext = RequestGetContext(Request); + + requestContext->TimeSentDownFirstTime.QuadPart = 0; + requestContext->TimeSentDownLasttTime.QuadPart = 0; + + return; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +VOID +DeviceGetParameter( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_opt_ PWSTR SubkeyName, + _In_ PWSTR ParameterName, + _Inout_ PULONG ParameterValue // also default value + ) +/*++ +Routine Description: + + retrieve device parameter from registry. + +Arguments: + + DeviceExtension - device context. + + SubkeyName - name of subkey + + ParameterName - the registry parameter to be retrieved + +Return Value: + + ParameterValue - registry value retrieved + +--*/ +{ + NTSTATUS status; + WDFKEY rootKey = NULL; + WDFKEY subKey = NULL; + UNICODE_STRING registrySubKeyName; + UNICODE_STRING registryValueName; + ULONG defaultParameterValue; + + PAGED_CODE(); + + RtlInitUnicodeString(®istryValueName, ParameterName); + + if (SubkeyName != NULL) + { + RtlInitUnicodeString(®istrySubKeyName, SubkeyName); + } + + // open the hardware key + status = WdfDeviceOpenRegistryKey(DeviceExtension->Device, + PLUGPLAY_REGKEY_DEVICE, + KEY_READ, + WDF_NO_OBJECT_ATTRIBUTES, + &rootKey); + + // open the sub key + if (NT_SUCCESS(status) && (SubkeyName != NULL)) + { + status = WdfRegistryOpenKey(rootKey, + ®istrySubKeyName, + KEY_READ, + WDF_NO_OBJECT_ATTRIBUTES, + &subKey); + + if (!NT_SUCCESS(status)) + { + WdfRegistryClose(rootKey); + rootKey = NULL; + } + } + + if (NT_SUCCESS(status) && (rootKey != NULL)) + { + defaultParameterValue = *ParameterValue; + + status = WdfRegistryQueryULong((subKey != NULL) ? subKey : rootKey, + ®istryValueName, + ParameterValue); + + if (!NT_SUCCESS(status)) + { + *ParameterValue = defaultParameterValue; // use default value + } + } + + // close what we open + if (subKey != NULL) + { + WdfRegistryClose(subKey); + subKey = NULL; + } + + if (rootKey != NULL) + { + WdfRegistryClose(rootKey); + rootKey = NULL; + } + + // Windows 2000 SP3 uses the driver-specific key, so look in there + if (!NT_SUCCESS(status)) + { + // open the software key + status = WdfDeviceOpenRegistryKey(DeviceExtension->Device, + PLUGPLAY_REGKEY_DRIVER, + KEY_READ, + WDF_NO_OBJECT_ATTRIBUTES, + &rootKey); + + // open the sub key + if (NT_SUCCESS(status) && (SubkeyName != NULL)) + { + status = WdfRegistryOpenKey(rootKey, + ®istrySubKeyName, + KEY_READ, + WDF_NO_OBJECT_ATTRIBUTES, + &subKey); + + if (!NT_SUCCESS(status)) + { + WdfRegistryClose(rootKey); + rootKey = NULL; + } + } + + if (NT_SUCCESS(status) && (rootKey != NULL)) + { + defaultParameterValue = *ParameterValue; + + status = WdfRegistryQueryULong((subKey != NULL) ? subKey : rootKey, + ®istryValueName, + ParameterValue); + + if (!NT_SUCCESS(status)) + { + *ParameterValue = defaultParameterValue; // use default value + } + else + { + // Migrate the value over to the device-specific key + DeviceSetParameter(DeviceExtension, SubkeyName, ParameterName, *ParameterValue); + } + } + + // close what we open + if (subKey != NULL) + { + WdfRegistryClose(subKey); + subKey = NULL; + } + + if (rootKey != NULL) + { + WdfRegistryClose(rootKey); + rootKey = NULL; + } + } + + return; + +} // end DeviceetParameter() + + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +DeviceSetParameter( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_opt_z_ PWSTR SubkeyName, + _In_ PWSTR ParameterName, + _In_ ULONG ParameterValue + ) +/*++ +Routine Description: + + set parameter to registry. + +Arguments: + + DeviceExtension - device context. + + SubkeyName - name of subkey + + ParameterName - the registry parameter to be retrieved + + ParameterValue - registry value to be set + +Return Value: + NTSTATUS + +--*/ +{ + NTSTATUS status; + WDFKEY rootKey = NULL; + WDFKEY subKey = NULL; + UNICODE_STRING registrySubKeyName; + UNICODE_STRING registryValueName; + + PAGED_CODE(); + + RtlInitUnicodeString(®istryValueName, ParameterName); + + if (SubkeyName != NULL) + { + RtlInitUnicodeString(®istrySubKeyName, SubkeyName); + } + + // open the hardware key + status = WdfDeviceOpenRegistryKey(DeviceExtension->Device, + PLUGPLAY_REGKEY_DEVICE, + KEY_READ | KEY_WRITE, + WDF_NO_OBJECT_ATTRIBUTES, + &rootKey); + + // open the sub key + if (NT_SUCCESS(status) && (SubkeyName != NULL)) + { + status = WdfRegistryOpenKey(rootKey, + ®istrySubKeyName, + KEY_READ | KEY_WRITE, + WDF_NO_OBJECT_ATTRIBUTES, + &subKey); + + if (!NT_SUCCESS(status)) + { + WdfRegistryClose(rootKey); + rootKey = NULL; + } + } + + if (NT_SUCCESS(status) && (rootKey != NULL)) + { + status = WdfRegistryAssignULong((subKey != NULL) ? subKey : rootKey, + ®istryValueName, + ParameterValue); + } + + // close what we open + if (subKey != NULL) + { + WdfRegistryClose(subKey); + subKey = NULL; + } + + if (rootKey != NULL) + { + WdfRegistryClose(rootKey); + rootKey = NULL; + } + + return status; + +} // end DeviceSetParameter() + + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DeviceSendRequestSynchronously( + _In_ WDFDEVICE Device, + _In_ WDFREQUEST Request, + _In_ BOOLEAN RequestFormated + ) +/*++ +Routine Description: + + send a request to lower driver synchronously. + +Arguments: + + Device - device object. + + Request - request object + + RequestFormated - if the request is already formatted, will no do it in this function + +Return Value: + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(Device); + BOOLEAN requestCancelled = FALSE; + PCDROM_REQUEST_CONTEXT requestContext = RequestGetContext(Request); + + PAGED_CODE(); + + if (!RequestFormated) + { + // set request up for sending down + WdfRequestFormatRequestUsingCurrentType(Request); + } + + // get cancellation status for the original request + if (requestContext->OriginalRequest != NULL) + { + requestCancelled = WdfRequestIsCanceled(requestContext->OriginalRequest); + } + + if (!requestCancelled) + { + status = RequestSend(deviceExtension, + Request, + deviceExtension->IoTarget, + WDF_REQUEST_SEND_OPTION_SYNCHRONOUS, + NULL); + } + else + { + status = STATUS_CANCELLED; + } + + return status; +} + + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +DeviceSendSrbSynchronously( + _In_ WDFDEVICE Device, + _In_ PSCSI_REQUEST_BLOCK Srb, + _In_opt_ PVOID BufferAddress, + _In_ ULONG BufferLength, + _In_ BOOLEAN WriteToDevice, + _In_opt_ WDFREQUEST OriginalRequest + ) +/*++ +Routine Description: + + Send a SRB structure to lower driver synchronously. + + Process of this function: + 1. Allocate SenseBuffer; Create Request; Allocate MDL + 2. Do following loop if necessary + 2.1 Reuse Request + 2.2 Format Srb, Irp + 2.3 Send Request + 2.4 Error Intepret and retry decision making. + 3. Release all allocated resosurces. + +Arguments: + + Device - device object. + + Request - request object + + RequestFormated - if the request is already formatted, will no do it in this function + +Return Value: + NTSTATUS + +NOTE: +The caller needs to setup following fields before calling this routine. + srb.CdbLength + srb.TimeOutValue + cdb + +BufferLength and WriteToDevice to control the data direction of the device + BufferLength = 0: No data transfer + BufferLenth != 0 && !WriteToDevice: get data from device + BufferLenth != 0 && WriteToDevice: send data to device +--*/ +{ + NTSTATUS status; + PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(Device); + PCDROM_PRIVATE_FDO_DATA fdoData = deviceExtension->PrivateFdoData; + PUCHAR senseInfoBuffer = NULL; + ULONG retryCount = 0; + BOOLEAN retry = FALSE; + ULONG ioctlCode = 0; + WDFREQUEST request = NULL; + PIRP irp = NULL; + PIO_STACK_LOCATION nextStack = NULL; + PMDL mdlAddress = NULL; + BOOLEAN memoryLocked = FALSE; + WDF_OBJECT_ATTRIBUTES attributes; + PZERO_POWER_ODD_INFO zpoddInfo = deviceExtension->ZeroPowerODDInfo; + + PAGED_CODE(); + + // NOTE: This code is only pagable because we are not freezing + // the queue. Allowing the queue to be frozen from a pagable + // routine could leave the queue frozen as we try to page in + // the code to unfreeze the queue. The result would be a nice + // case of deadlock. Therefore, since we are unfreezing the + // queue regardless of the result, just set the NO_FREEZE_QUEUE + // flag in the SRB. + NT_ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL); + + //1. allocate SenseBuffer and initiate Srb common fields + // these fields will not be changed by lower driver. + { + // Write length to SRB. + Srb->Length = sizeof(SCSI_REQUEST_BLOCK); + Srb->Function = SRB_FUNCTION_EXECUTE_SCSI; + Srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE; + + // Sense buffer is in aligned nonpaged pool. + senseInfoBuffer = ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned, + SENSE_BUFFER_SIZE, + CDROM_TAG_SENSE_INFO); + + if (senseInfoBuffer == NULL) + { + status = STATUS_INSUFFICIENT_RESOURCES; + + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, + "DeviceSendSrbSynchronously: Can't allocate MDL\n")); + + goto Exit; + } + + Srb->SenseInfoBuffer = senseInfoBuffer; + Srb->DataBuffer = BufferAddress; + + // set timeout value to default value if it's not specifically set by caller. + if (Srb->TimeOutValue == 0) + { + Srb->TimeOutValue = deviceExtension->TimeOutValue; + } + } + + //2. Create Request object + { + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, + CDROM_REQUEST_CONTEXT); + + status = WdfRequestCreate(&attributes, + deviceExtension->IoTarget, + &request); + + if (!NT_SUCCESS(status)) + { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, + "DeviceSendSrbSynchronously: Can't create request: %lx\n", + status)); + + goto Exit; + } + + irp = WdfRequestWdmGetIrp(request); + } + + // 3. Build an MDL for the data buffer and stick it into the irp. + if (BufferAddress != NULL) + { + mdlAddress = IoAllocateMdl( BufferAddress, + BufferLength, + FALSE, + FALSE, + irp ); + if (mdlAddress == NULL) + { + status = STATUS_INSUFFICIENT_RESOURCES; + + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, + "DeviceSendSrbSynchronously: Can't allocate MDL\n")); + + goto Exit; + } + + try + { + MmProbeAndLockPages(mdlAddress, + KernelMode, + (WriteToDevice ? IoReadAccess : IoWriteAccess)); + } + except(EXCEPTION_EXECUTE_HANDLER) + { + status = GetExceptionCode(); + + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, + "DeviceSendSrbSynchronously: Exception %lx locking buffer\n", status)); + + goto Exit; + } + + memoryLocked = TRUE; + } + + // 4. Format Srb, Irp; Send request and retry when necessary + do + { + // clear the control variable. + retry = FALSE; + + // 4.1 reuse the request object; set originalRequest field. + { + WDF_REQUEST_REUSE_PARAMS params; + PCDROM_REQUEST_CONTEXT requestContext = NULL; + + // deassign the MdlAddress, this is the value we assign explicitly. + // doing this can prevent WdfRequestReuse to release the Mdl unexpectly. + if (irp->MdlAddress) + { + irp->MdlAddress = NULL; + } + + WDF_REQUEST_REUSE_PARAMS_INIT(¶ms, + WDF_REQUEST_REUSE_NO_FLAGS, + STATUS_SUCCESS); + + status = WdfRequestReuse(request, ¶ms); + + if (!NT_SUCCESS(status)) + { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, + "DeviceSendSrbSynchronously: WdfRequestReuse failed, %!STATUS!\n", + status)); + // exit the loop. + break; + } + + // WDF requests to format the request befor sending it + status = WdfIoTargetFormatRequestForInternalIoctlOthers(deviceExtension->IoTarget, + request, + ioctlCode, + NULL, NULL, + NULL, NULL, + NULL, NULL); + + if (!NT_SUCCESS(status)) + { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, + "DeviceSendSrbSynchronously: WdfIoTargetFormatRequestForInternalIoctlOthers failed, %!STATUS!\n", + status)); + // exit the loop. + break; + } + + requestContext = RequestGetContext(request); + requestContext->OriginalRequest = OriginalRequest; + } + + // 4.2 Format Srb and Irp + { + Srb->OriginalRequest = irp; + Srb->QueueAction = SRB_SIMPLE_TAG_REQUEST; + Srb->DataTransferLength = BufferLength; + Srb->SrbFlags = deviceExtension->SrbFlags; + + // Disable synchronous transfer for these requests. + SET_FLAG(Srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER); + SET_FLAG(Srb->SrbFlags, SRB_FLAGS_NO_QUEUE_FREEZE); + + if (BufferAddress != NULL) + { + if (WriteToDevice) + { + SET_FLAG(Srb->SrbFlags, SRB_FLAGS_DATA_OUT); + ioctlCode = IOCTL_SCSI_EXECUTE_OUT; + } + else + { + SET_FLAG(Srb->SrbFlags, SRB_FLAGS_DATA_IN); + ioctlCode = IOCTL_SCSI_EXECUTE_IN; + } + } + else + { + ioctlCode = IOCTL_SCSI_EXECUTE_NONE; + } + + + // Zero out status. + Srb->ScsiStatus = 0; + Srb->SrbStatus = 0; + Srb->NextSrb = NULL; + + // irp related fields + irp->MdlAddress = mdlAddress; + + nextStack = IoGetNextIrpStackLocation(irp); + + nextStack->MajorFunction = IRP_MJ_SCSI; + nextStack->Parameters.DeviceIoControl.IoControlCode = ioctlCode; + nextStack->Parameters.Scsi.Srb = Srb; + } + + // 4.3 send Request to lower driver. + status = DeviceSendRequestSynchronously(Device, request, TRUE); + + if (status != STATUS_CANCELLED) + { + NT_ASSERT(SRB_STATUS(Srb->SrbStatus) != SRB_STATUS_PENDING); + NT_ASSERT(status != STATUS_PENDING); + NT_ASSERT(!(Srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN)); + + // 4.4 error process. + if (SRB_STATUS(Srb->SrbStatus) != SRB_STATUS_SUCCESS) + { + LONGLONG retryIntervalIn100ns = 0; + + // Update status and determine if request should be retried. + retry = RequestSenseInfoInterpret(deviceExtension, + request, + Srb, + retryCount, + &status, + &retryIntervalIn100ns); + + if (retry) + { + LARGE_INTEGER t; + t.QuadPart = -retryIntervalIn100ns; + retryCount++; + KeDelayExecutionThread(KernelMode, FALSE, &t); + } + } + else + { + // Request succeeded. + fdoData->LoggedTURFailureSinceLastIO = FALSE; + status = STATUS_SUCCESS; + retry = FALSE; + } + } + } while(retry); + + if ((zpoddInfo != NULL) && + (zpoddInfo->MonitorStartStopUnit != FALSE) && + (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SUCCESS)) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, + "DeviceSendSrbSynchronously: soft eject detected, device marked as active\n")); + + DeviceMarkActive(deviceExtension, TRUE, FALSE); + } + + // 5. Release all allocated resources. + + // required even though we allocated our own, since the port driver may + // have allocated one also + if (PORT_ALLOCATED_SENSE(deviceExtension, Srb)) + { + FREE_PORT_ALLOCATED_SENSE_BUFFER(deviceExtension, Srb); + } + +Exit: + + if (senseInfoBuffer != NULL) + { + FREE_POOL(senseInfoBuffer); + } + + Srb->SenseInfoBuffer = NULL; + Srb->SenseInfoBufferLength = 0; + + if (mdlAddress) + { + if (memoryLocked) + { + MmUnlockPages(mdlAddress); + memoryLocked = FALSE; + } + + IoFreeMdl(mdlAddress); + irp->MdlAddress = NULL; + } + + if (request) + { + WdfObjectDelete(request); + } + + return status; +} + + +VOID +DeviceSendNotification( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ const GUID* Guid, + _In_ ULONG ExtraDataSize, + _In_opt_ PVOID ExtraData + ) +/*++ +Routine Description: + + send notification to other components + +Arguments: + + DeviceExtension - device context. + + Guid - GUID for the notification + + ExtraDataSize - data size along with notification + + ExtraData - data buffer send with notification + +Return Value: + None + +--*/ +{ + PTARGET_DEVICE_CUSTOM_NOTIFICATION notification; + ULONG requiredSize; + NTSTATUS status; + + status = RtlULongAdd((sizeof(TARGET_DEVICE_CUSTOM_NOTIFICATION) - sizeof(UCHAR)), + ExtraDataSize, + &requiredSize); + + if (!(NT_SUCCESS(status)) || (requiredSize > 0x0000ffff)) + { + // MAX_USHORT, max total size for these events! + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_MCN, + "Error sending event: size too large! (%x)\n", + requiredSize)); + return; + } + + notification = ExAllocatePoolWithTag(NonPagedPoolNx, + requiredSize, + CDROM_TAG_NOTIFICATION); + + // if none allocated, exit + if (notification == NULL) + { + return; + } + + // Prepare and send the request! + RtlZeroMemory(notification, requiredSize); + notification->Version = 1; + notification->Size = (USHORT)(requiredSize); + notification->FileObject = NULL; + notification->NameBufferOffset = -1; + notification->Event = *Guid; + + if (ExtraData != NULL) + { + RtlCopyMemory(notification->CustomDataBuffer, ExtraData, ExtraDataSize); + } + + IoReportTargetDeviceChangeAsynchronous(DeviceExtension->LowerPdo, + notification, + NULL, + NULL); + + FREE_POOL(notification); + + return; +} + + +VOID +DeviceSendStartUnit( + _In_ WDFDEVICE Device + ) +/*++ + +Routine Description: + + Send command to SCSI unit to start or power up. + Because this command is issued asynchronounsly, that is, without + waiting on it to complete, the IMMEDIATE flag is not set. This + means that the CDB will not return until the drive has powered up. + This should keep subsequent requests from being submitted to the + device before it has completely spun up. + + This routine is called from the InterpretSense routine, when a + request sense returns data indicating that a drive must be + powered up. + + This routine may also be called from a class driver's error handler, + or anytime a non-critical start device should be sent to the device. + +Arguments: + + Device - The device object. + +Return Value: + + None. + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PCDROM_DEVICE_EXTENSION deviceExtension = NULL; + WDF_OBJECT_ATTRIBUTES attributes; + WDFREQUEST startUnitRequest = NULL; + WDFMEMORY inputMemory = NULL; + + PCOMPLETION_CONTEXT context = NULL; + PSCSI_REQUEST_BLOCK srb = NULL; + PCDB cdb = NULL; + + deviceExtension = DeviceGetExtension(Device); + + if (NT_SUCCESS(status)) + { + // Allocate Srb from nonpaged pool. + context = ExAllocatePoolWithTag(NonPagedPoolNx, + sizeof(COMPLETION_CONTEXT), + CDROM_TAG_COMPLETION_CONTEXT); + + if (context == NULL) + { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, + "DeviceSendStartUnit: Failed to allocate completion context\n")); + + status = STATUS_INTERNAL_ERROR; + } + } + + if (NT_SUCCESS(status)) + { + // Save the device object in the context for use by the completion + // routine. + context->Device = Device; + srb = &context->Srb; + + // Zero out srb. + RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK)); + + // setup SRB structure. + srb->Length = sizeof(SCSI_REQUEST_BLOCK); + srb->Function = SRB_FUNCTION_EXECUTE_SCSI; + srb->TimeOutValue = START_UNIT_TIMEOUT; + + srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER | + SRB_FLAGS_DISABLE_SYNCH_TRANSFER; + + // setup CDB + srb->CdbLength = 6; + cdb = (PCDB)srb->Cdb; + + cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT; + cdb->START_STOP.Start = 1; + cdb->START_STOP.Immediate = 0; + cdb->START_STOP.LogicalUnitNumber = srb->Lun; + + //Create Request for sending down to port driver + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, + CDROM_REQUEST_CONTEXT); + attributes.ParentObject = deviceExtension->IoTarget; + + status = WdfRequestCreate(&attributes, + deviceExtension->IoTarget, + &startUnitRequest); + } + + if (NT_SUCCESS(status)) + { + srb->OriginalRequest = WdfRequestWdmGetIrp(startUnitRequest); + NT_ASSERT(srb->OriginalRequest != NULL); + + //Prepare the request + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + attributes.ParentObject = startUnitRequest; + + status = WdfMemoryCreatePreallocated(&attributes, + (PVOID)srb, + sizeof(SCSI_REQUEST_BLOCK), + &inputMemory); + } + + if (NT_SUCCESS(status)) + { + status = WdfIoTargetFormatRequestForInternalIoctlOthers(deviceExtension->IoTarget, + startUnitRequest, + IOCTL_SCSI_EXECUTE_NONE, + inputMemory, + NULL, + NULL, + NULL, + NULL, + NULL); + } + + if (NT_SUCCESS(status)) + { + // Set a CompletionRoutine callback function. + WdfRequestSetCompletionRoutine(startUnitRequest, + DeviceAsynchronousCompletion, + context); + + status = RequestSend(deviceExtension, + startUnitRequest, + deviceExtension->IoTarget, + 0, + NULL); + } + + // release resources when failed. + if (!NT_SUCCESS(status)) + { + FREE_POOL(context); + if (startUnitRequest != NULL) + { + WdfObjectDelete(startUnitRequest); + } + } + + return; +} // end StartUnit() + + +VOID +DeviceSendIoctlAsynchronously( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ ULONG IoControlCode, + _In_ PDEVICE_OBJECT TargetDeviceObject + ) +/*++ + +Routine Description: + + Send an IOCTL asynchronously + +Arguments: + + DeviceExtension - device context. + IoControlCode - IOCTL code. + TargetDeviceObject - target device object. + +Return Value: + + None. + +--*/ +{ + PIRP irp = NULL; + PIO_STACK_LOCATION nextIrpStack = NULL; + + irp = IoAllocateIrp(DeviceExtension->DeviceObject->StackSize, FALSE); + + if (irp != NULL) + { + nextIrpStack = IoGetNextIrpStackLocation(irp); + + nextIrpStack->MajorFunction = IRP_MJ_DEVICE_CONTROL; + + nextIrpStack->Parameters.DeviceIoControl.OutputBufferLength = 0; + nextIrpStack->Parameters.DeviceIoControl.InputBufferLength = 0; + nextIrpStack->Parameters.DeviceIoControl.IoControlCode = IoControlCode; + nextIrpStack->Parameters.DeviceIoControl.Type3InputBuffer = NULL; + + IoSetCompletionRoutine(irp, + RequestAsynchronousIrpCompletion, + DeviceExtension, + TRUE, + TRUE, + TRUE); + + (VOID) IoCallDriver(TargetDeviceObject, irp); + } +} + +NTSTATUS +RequestAsynchronousIrpCompletion( + _In_ PDEVICE_OBJECT DeviceObject, + _In_ PIRP Irp, + _In_reads_opt_(_Inexpressible_("varies")) PVOID Context + ) +/*++ + +Routine Description: + + Free the Irp. + +Arguments: + + DeviceObject - device that the completion routine fires on. + + Irp - The irp to be completed. + + Context - IRP context + +Return Value: + NTSTATUS + +--*/ +{ + UNREFERENCED_PARAMETER(DeviceObject); + UNREFERENCED_PARAMETER(Context); + + IoFreeIrp(Irp); + + return STATUS_MORE_PROCESSING_REQUIRED; +} + +VOID +DeviceAsynchronousCompletion( + _In_ WDFREQUEST Request, + _In_ WDFIOTARGET Target, + _In_ PWDF_REQUEST_COMPLETION_PARAMS Params, + _In_ WDFCONTEXT Context + ) +/*++ + +Routine Description: + + This routine is called when an asynchronous I/O request + which was issused by the class driver completes. Examples of such requests + are release queue or START UNIT. This routine releases the queue if + necessary. It then frees the context and the IRP. + +Arguments: + + DeviceObject - The device object for the logical unit; however since this + is the top stack location the value is NULL. + + Irp - Supplies a pointer to the Irp to be processed. + + Context - Supplies the context to be used to process this request. + +Return Value: + + None. + +--*/ +{ + PCOMPLETION_CONTEXT context = (PCOMPLETION_CONTEXT)Context; + PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(context->Device); + + UNREFERENCED_PARAMETER(Target); + UNREFERENCED_PARAMETER(Params); + + // If this is an execute srb, then check the return status and make sure. + // the queue is not frozen. + if (context->Srb.Function == SRB_FUNCTION_EXECUTE_SCSI) + { + // Check for a frozen queue. + if (context->Srb.SrbStatus & SRB_STATUS_QUEUE_FROZEN) + { + // Unfreeze the queue getting the device object from the context. + DeviceReleaseQueue(context->Device); + } + } + + // free port-allocated sense buffer if we can detect + // + if (PORT_ALLOCATED_SENSE(deviceExtension, &context->Srb)) + { + FREE_PORT_ALLOCATED_SENSE_BUFFER(deviceExtension, &context->Srb); + } + + FREE_POOL(context); + + WdfObjectDelete(Request); + +} // end DeviceAsynchronousCompletion() + + +VOID +DeviceReleaseQueue( + _In_ WDFDEVICE Device + ) +/*++ + +Routine Description: + + This routine issues an internal device control command + to the port driver to release a frozen queue. The call + is issued asynchronously as DeviceReleaseQueue will be invoked + from the IO completion DPC (and will have no context to + wait for a synchronous call to complete). + + This routine must be called with the remove lock held. + +Arguments: + + Device - The functional device object for the device with the frozen queue. + +Return Value: + + None. + +--*/ +{ + PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(Device); + PSCSI_REQUEST_BLOCK srb = NULL; + KIRQL currentIrql; + + // we raise irql seperately so we're not swapped out or suspended + // while holding the release queue irp in this routine. this lets + // us release the spin lock before lowering irql. + KeRaiseIrql(DISPATCH_LEVEL, ¤tIrql); + + WdfSpinLockAcquire(deviceExtension->ReleaseQueueSpinLock); + + if (deviceExtension->ReleaseQueueInProgress) + { + // Someone is already doing this work - just set the flag to indicate that + // we need to release the queue again. + deviceExtension->ReleaseQueueNeeded = TRUE; + WdfSpinLockRelease(deviceExtension->ReleaseQueueSpinLock); + KeLowerIrql(currentIrql); + + return; + } + + // Mark that there is a release queue in progress and drop the spinlock. + deviceExtension->ReleaseQueueInProgress = TRUE; + + WdfSpinLockRelease(deviceExtension->ReleaseQueueSpinLock); + + srb = &(deviceExtension->ReleaseQueueSrb); + + // Optical media are removable, so we just flush the queue. This will also release it. + srb->Function = SRB_FUNCTION_FLUSH_QUEUE; + + srb->OriginalRequest = WdfRequestWdmGetIrp(deviceExtension->ReleaseQueueRequest); + + // Set a CompletionRoutine callback function. + WdfRequestSetCompletionRoutine(deviceExtension->ReleaseQueueRequest, + DeviceReleaseQueueCompletion, + Device); + // Send the request. If an error occurs, complete the request. + RequestSend(deviceExtension, + deviceExtension->ReleaseQueueRequest, + deviceExtension->IoTarget, + WDF_REQUEST_SEND_OPTION_IGNORE_TARGET_STATE, + NULL); + + KeLowerIrql(currentIrql); + + return; + +} // end DeviceReleaseQueue() + +VOID +DeviceReleaseQueueCompletion( + _In_ WDFREQUEST Request, + _In_ WDFIOTARGET Target, + _In_ PWDF_REQUEST_COMPLETION_PARAMS Params, + _In_ WDFCONTEXT Context + ) +/*++ + +Routine Description: + + This routine is called when an asynchronous release queue request which + was issused in DeviceReleaseQueue completes. This routine prepares for + the next release queue request and resends it if necessary. + +Arguments: + + Request - The completed request. + + Target - IoTarget object + + Params - Completion parameters + + Context - WDFDEVICE object handle. + +Return Value: + + None. + +--*/ +{ + NTSTATUS status; + WDFDEVICE device = Context; + PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(device); + + BOOLEAN releaseQueueNeeded = FALSE; + WDF_REQUEST_REUSE_PARAMS params = {0}; + + UNREFERENCED_PARAMETER(Target); + UNREFERENCED_PARAMETER(Params); + + WDF_REQUEST_REUSE_PARAMS_INIT(¶ms, + WDF_REQUEST_REUSE_NO_FLAGS, + STATUS_SUCCESS); + + // Grab the spinlock and clear the release queue in progress flag so others + // can run. Save (and clear) the state of the release queue needed flag + // so that we can issue a new release queue outside the spinlock. + WdfSpinLockAcquire(deviceExtension->ReleaseQueueSpinLock); + + releaseQueueNeeded = deviceExtension->ReleaseQueueNeeded; + + deviceExtension->ReleaseQueueNeeded = FALSE; + deviceExtension->ReleaseQueueInProgress = FALSE; + + // Reuse the ReleaseQueueRequest for the next time. + status = WdfRequestReuse(Request,¶ms); + + if (NT_SUCCESS(status)) + { + // Preformat the ReleaseQueueRequest for the next time. + // This should always succeed because it was already preformatted once during device initialization + status = WdfIoTargetFormatRequestForInternalIoctlOthers(deviceExtension->IoTarget, + Request, + IOCTL_SCSI_EXECUTE_NONE, + deviceExtension->ReleaseQueueInputMemory, + NULL, + NULL, + NULL, + NULL, + NULL); + } + + if (!NT_SUCCESS(status)) + { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, + "DeviceReleaseQueueCompletion: WdfIoTargetFormatRequestForInternalIoctlOthers failed, %!STATUS!\n", + status)); + } + + RequestClearSendTime(Request); + + WdfSpinLockRelease(deviceExtension->ReleaseQueueSpinLock); + + // If we need a release queue then issue one now. Another processor may + // have already started one in which case we'll try to issue this one after + // it is done - but we should never recurse more than one deep. + if (releaseQueueNeeded) + { + DeviceReleaseQueue(device); + } + + return; + +} // DeviceReleaseQueueCompletion() + + +// +// In order to provide better performance without the need to reboot, +// we need to implement a self-adjusting method to set and clear the +// srb flags based upon current performance. +// +// whenever there is an error, immediately grab the spin lock. the +// MP perf hit here is acceptable, since we're in an error path. this +// is also neccessary because we are guaranteed to be modifying the +// SRB flags here, setting SuccessfulIO to zero, and incrementing the +// actual error count (which is always done within this spinlock). +// +// whenever there is no error, increment a counter. if there have been +// errors on the device, and we've enabled dynamic perf, *and* we've +// just crossed the perf threshhold, then grab the spin lock and +// double check that the threshhold has, indeed been hit(*). then +// decrement the error count, and if it's dropped sufficiently, undo +// some of the safety changes made in the SRB flags due to the errors. +// +// * this works in all cases. even if lots of ios occur after the +// previous guy went in and cleared the successfulio counter, that +// just means that we've hit the threshhold again, and so it's proper +// to run the inner loop again. +// + +VOID +DevicePerfIncrementErrorCount( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension + ) +{ + PCDROM_PRIVATE_FDO_DATA fdoData = DeviceExtension->PrivateFdoData; + KIRQL oldIrql; + ULONG errors; + + KeAcquireSpinLock(&fdoData->SpinLock, &oldIrql); + + fdoData->Perf.SuccessfulIO = 0; // implicit interlock + errors = InterlockedIncrement((PLONG)&DeviceExtension->ErrorCount); + + if (errors >= CLASS_ERROR_LEVEL_1) + { + // If the error count has exceeded the error limit, then disable + // any tagged queuing, multiple requests per lu queueing + // and sychronous data transfers. + // + // Clearing the no queue freeze flag prevents the port driver + // from sending multiple requests per logical unit. + CLEAR_FLAG(DeviceExtension->SrbFlags, SRB_FLAGS_NO_QUEUE_FREEZE); + CLEAR_FLAG(DeviceExtension->SrbFlags, SRB_FLAGS_QUEUE_ACTION_ENABLE); + + SET_FLAG(DeviceExtension->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER); + + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, + "PerfIncrementErrorCount: Too many errors; disabling tagged queuing and " + "synchronous data tranfers.\n")); + } + + if (errors >= CLASS_ERROR_LEVEL_2) + { + // If a second threshold is reached, disable disconnects. + SET_FLAG(DeviceExtension->SrbFlags, SRB_FLAGS_DISABLE_DISCONNECT); + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, + "PerfIncrementErrorCount: Too many errors; disabling disconnects.\n")); + } + + KeReleaseSpinLock(&fdoData->SpinLock, oldIrql); + return; +} + + +_IRQL_requires_max_(APC_LEVEL) +PVOID +DeviceFindFeaturePage( + _In_reads_bytes_(Length) PGET_CONFIGURATION_HEADER FeatureBuffer, + _In_ ULONG const Length, + _In_ FEATURE_NUMBER const Feature + ) +/*++ +Routine Description: + + find the specific feature page in the buffer + +Arguments: + + FeatureBuffer - buffer contains the device feature set. + + Length - buffer length + + Feature - the feature number looking for. + +Return Value: + + PVOID - pointer to the starting location of the specific feature in buffer. + +--*/ +{ + PUCHAR buffer; + PUCHAR limit; + ULONG validLength; + + PAGED_CODE(); + + if (Length < sizeof(GET_CONFIGURATION_HEADER) + sizeof(FEATURE_HEADER)) + { + return NULL; + } + + // Calculate the length of valid data available in the + // capabilities buffer from the DataLength field + REVERSE_BYTES(&validLength, FeatureBuffer->DataLength); + + validLength += RTL_SIZEOF_THROUGH_FIELD(GET_CONFIGURATION_HEADER, DataLength); + + // set limit to point to first illegal address + limit = (PUCHAR)FeatureBuffer; + limit += min(Length, validLength); + + // set buffer to point to first page + buffer = FeatureBuffer->Data; + + // loop through each page until we find the requested one, or + // until it's not safe to access the entire feature header + // (if equal, have exactly enough for the feature header) + while (buffer + sizeof(FEATURE_HEADER) <= limit) + { + PFEATURE_HEADER header = (PFEATURE_HEADER)buffer; + FEATURE_NUMBER thisFeature; + + thisFeature = (header->FeatureCode[0] << 8) | + (header->FeatureCode[1]); + + if (thisFeature == Feature) + { + PUCHAR temp; + + // if don't have enough memory to safely access all the feature + // information, return NULL + temp = buffer; + temp += sizeof(FEATURE_HEADER); + temp += header->AdditionalLength; + + if (temp > limit) + { + // this means the transfer was cut-off, an insufficiently + // small buffer was given, or other arbitrary error. since + // it's not safe to view the amount of data (even though + // the header is safe) in this feature, pretend it wasn't + // transferred at all... + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, + "Feature %x exists, but not safe to access all its data. returning NULL\n", + Feature)); + return NULL; + } + else + { + return buffer; + } + } + + if ((header->AdditionalLength % 4) && + !(Feature >= 0xff00 && Feature <= 0xffff)) + { + return NULL; + } + + buffer += sizeof(FEATURE_HEADER); + buffer += header->AdditionalLength; + } + + return NULL; +} + + +_IRQL_requires_max_(APC_LEVEL) +VOID +DevicePrintAllFeaturePages( + _In_reads_bytes_(Usable) PGET_CONFIGURATION_HEADER Buffer, + _In_ ULONG const Usable + ) +/*++ +Routine Description: + + print out all feature pages in the buffer + +Arguments: + + Buffer - buffer contains the device feature set. + + Usable - + +Return Value: + + none + +--*/ +{ +#if DBG + PFEATURE_HEADER header; + + PAGED_CODE(); + + //////////////////////////////////////////////////////////////////////////////// + // items expected to ALWAYS be current if they exist + //////////////////////////////////////////////////////////////////////////////// + + header = DeviceFindFeaturePage(Buffer, Usable, FeatureProfileList); + if (header != NULL) { + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT, + "CdromGetConfiguration: CurrentProfile %x " + "with %x bytes of data at %p\n", + Buffer->CurrentProfile[0] << 8 | + Buffer->CurrentProfile[1], + Usable, Buffer)); + } + + header = DeviceFindFeaturePage(Buffer, Usable, FeatureCore); + if (header) { + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT, + "CdromGetConfiguration: %s %s\n", + (header->Current ? + "Currently supports" : "Is able to support"), + "CORE Features" + )); + } + + header = DeviceFindFeaturePage(Buffer, Usable, FeatureMorphing); + if (header) { + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT, + "CdromGetConfiguration: %s %s\n", + (header->Current ? + "Currently supports" : "Is able to support"), + "Morphing" + )); + } + + header = DeviceFindFeaturePage(Buffer, Usable, FeatureRemovableMedium); + if (header) { + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT, + "CdromGetConfiguration: %s %s\n", + (header->Current ? + "Currently supports" : "Is able to support"), + "Removable Medium" + )); + } + + header = DeviceFindFeaturePage(Buffer, Usable, FeaturePowerManagement); + if (header) { + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT, + "CdromGetConfiguration: %s %s\n", + (header->Current ? + "Currently supports" : "Is able to support"), + "Power Management" + )); + } + + header = DeviceFindFeaturePage(Buffer, Usable, FeatureEmbeddedChanger); + if (header) { + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT, + "CdromGetConfiguration: %s %s\n", + (header->Current ? + "Currently supports" : "Is able to support"), + "Embedded Changer" + )); + } + + header = DeviceFindFeaturePage(Buffer, Usable, FeatureMicrocodeUpgrade); + if (header) { + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT, + "CdromGetConfiguration: %s %s\n", + (header->Current ? + "Currently supports" : "Is able to support"), + "Microcode Update" + )); + } + + header = DeviceFindFeaturePage(Buffer, Usable, FeatureTimeout); + if (header) { + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT, + "CdromGetConfiguration: %s %s\n", + (header->Current ? + "Currently supports" : "Is able to support"), + "Timeouts" + )); + } + + header = DeviceFindFeaturePage(Buffer, Usable, FeatureLogicalUnitSerialNumber); + if (header) { + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT, + "CdromGetConfiguration: %s %s\n", + (header->Current ? + "Currently supports" : "Is able to support"), + "LUN Serial Number" + )); + } + + header = DeviceFindFeaturePage(Buffer, Usable, FeatureFirmwareDate); + if (header) { + + ULONG featureSize = header->AdditionalLength; + featureSize += RTL_SIZEOF_THROUGH_FIELD(FEATURE_HEADER, AdditionalLength); + + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT, + "CdromGetConfiguration: %s %s\n", + (header->Current ? + "Currently supports" : "Is able to support"), + "Firmware Date" + )); + + if (featureSize >= RTL_SIZEOF_THROUGH_FIELD(FEATURE_DATA_FIRMWARE_DATE, Minute)) + { + PFEATURE_DATA_FIRMWARE_DATE date = (PFEATURE_DATA_FIRMWARE_DATE)header; + // show date as "YYYY/MM/DD hh:mm", which is 18 chars (17+NULL) + UCHAR dateString[18] = { 0 }; + dateString[ 0] = date->Year[0]; + dateString[ 1] = date->Year[1]; + dateString[ 2] = date->Year[2]; + dateString[ 3] = date->Year[3]; + dateString[ 4] = '/'; + dateString[ 5] = date->Month[0]; + dateString[ 6] = date->Month[1]; + dateString[ 7] = '/'; + dateString[ 8] = date->Day[0]; + dateString[ 9] = date->Day[1]; + dateString[10] = ' '; + dateString[11] = ' '; + dateString[12] = date->Hour[0]; + dateString[13] = date->Hour[1]; + dateString[14] = ':'; + dateString[15] = date->Minute[0]; + dateString[16] = date->Minute[1]; + dateString[17] = 0; + // SECONDS IS NOT AVAILABLE ON EARLY IMPLEMENTATIONS -- ignore it + //dateString[17] = ':'; + //dateString[18] = date->Seconds[0]; + //dateString[19] = date->Seconds[1]; + //dateString[20] = 0; + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT, + "CdromGetConfiguration: Firmware Date/Time %s (UTC)\n", + (PCSTR)dateString + )); + } + } + +//////////////////////////////////////////////////////////////////////////////// +// items expected not to always be current +//////////////////////////////////////////////////////////////////////////////// + + + header = DeviceFindFeaturePage(Buffer, Usable, FeatureWriteProtect); + if (header) { + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, + "CdromGetConfiguration: %s %s\n", + (header->Current ? + "Currently supports" : "Is able to support"), + "Software Write Protect" + )); + } + + header = DeviceFindFeaturePage(Buffer, Usable, FeatureRandomReadable); + if (header) { + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT, + "CdromGetConfiguration: %s %s\n", + (header->Current ? + "Currently supports" : "Is able to support"), + "Random Reads" + )); + } + + header = DeviceFindFeaturePage(Buffer, Usable, FeatureMultiRead); + if (header) { + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT, + "CdromGetConfiguration: %s %s\n", + (header->Current ? + "Currently supports" : "Is able to support"), + "Multi-Read" + )); + } + + header = DeviceFindFeaturePage(Buffer, Usable, FeatureCdRead); + if (header) { + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT, + "CdromGetConfiguration: %s %s\n", + (header->Current ? + "Currently supports" : "Is able to support"), + "reading from CD-ROM/R/RW" + )); + } + + header = DeviceFindFeaturePage(Buffer, Usable, FeatureDvdRead); + if (header) { + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT, + "CdromGetConfiguration: %s %s\n", + (header->Current ? + "Currently supports" : "Is able to support"), + "DVD Structure Reads" + )); + } + + header = DeviceFindFeaturePage(Buffer, Usable, FeatureRandomWritable); + if (header) { + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT, + "CdromGetConfiguration: %s %s\n", + (header->Current ? + "Currently supports" : "Is able to support"), + "Random Writes" + )); + } + + header = DeviceFindFeaturePage(Buffer, Usable, FeatureIncrementalStreamingWritable); + if (header) { + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT, + "CdromGetConfiguration: %s %s\n", + (header->Current ? + "Currently supports" : "Is able to support"), + "Incremental Streaming Writing" + )); + } + + header = DeviceFindFeaturePage(Buffer, Usable, FeatureSectorErasable); + if (header) { + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT, + "CdromGetConfiguration: %s %s\n", + (header->Current ? + "Currently supports" : "Is able to support"), + "Sector Erasable Media" + )); + } + + header = DeviceFindFeaturePage(Buffer, Usable, FeatureFormattable); + if (header) { + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT, + "CdromGetConfiguration: %s %s\n", + (header->Current ? + "Currently supports" : "Is able to support"), + "Formatting" + )); + } + + header = DeviceFindFeaturePage(Buffer, Usable, FeatureDefectManagement); + if (header) { + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT, + "CdromGetConfiguration: %s %s\n", + (header->Current ? + "Currently supports" : "Is able to support"), + "defect management" + )); + } + + header = DeviceFindFeaturePage(Buffer, Usable, FeatureWriteOnce); + if (header) { + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT, + "CdromGetConfiguration: %s %s\n", + (header->Current ? + "Currently supports" : "Is able to support"), + "Write Once Media" + )); + } + + header = DeviceFindFeaturePage(Buffer, Usable, FeatureRestrictedOverwrite); + if (header) { + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT, + "CdromGetConfiguration: %s %s\n", + (header->Current ? + "Currently supports" : "Is able to support"), + "Restricted Overwrites" + )); + } + + header = DeviceFindFeaturePage(Buffer, Usable, FeatureCdrwCAVWrite); + if (header) { + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT, + "CdromGetConfiguration: %s %s\n", + (header->Current ? + "Currently supports" : "Is able to support"), + "CD-RW CAV recording" + )); + } + + header = DeviceFindFeaturePage(Buffer, Usable, FeatureMrw); + if (header) { + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT, + "CdromGetConfiguration: %s %s\n", + (header->Current ? + "Currently supports" : "Is able to support"), + "Mount Rainier media" + )); + } + + header = DeviceFindFeaturePage(Buffer, Usable, FeatureEnhancedDefectReporting); + if (header) { + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT, + "CdromGetConfiguration: %s %s\n", + (header->Current ? + "Currently supports" : "Is able to support"), + "Enhanced Defect Reporting" + )); + } + + header = DeviceFindFeaturePage(Buffer, Usable, FeatureDvdPlusRW); + if (header) { + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT, + "CdromGetConfiguration: %s %s\n", + (header->Current ? + "Currently supports" : "Is able to support"), + "DVD+RW media" + )); + } + + header = DeviceFindFeaturePage(Buffer, Usable, FeatureRigidRestrictedOverwrite); + if (header) { + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT, + "CdromGetConfiguration: %s %s\n", + (header->Current ? + "Currently supports" : "Is able to support"), + "Rigid Restricted Overwrite" + )); + } + + header = DeviceFindFeaturePage(Buffer, Usable, FeatureCdTrackAtOnce); + if (header) { + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT, + "CdromGetConfiguration: %s %s\n", + (header->Current ? + "Currently supports" : "Is able to support"), + "CD Recording (Track At Once)" + )); + } + + header = DeviceFindFeaturePage(Buffer, Usable, FeatureCdMastering); + if (header) { + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT, + "CdromGetConfiguration: %s %s\n", + (header->Current ? + "Currently supports" : "Is able to support"), + "CD Recording (Mastering)" + )); + } + + header = DeviceFindFeaturePage(Buffer, Usable, FeatureDvdRecordableWrite); + if (header) { + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT, + "CdromGetConfiguration: %s %s\n", + (header->Current ? + "Currently supports" : "Is able to support"), + "DVD Recording (Mastering)" + )); + } + + header = DeviceFindFeaturePage(Buffer, Usable, FeatureDDCDRead); + if (header) { + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT, + "CdromGetConfiguration: %s %s\n", + (header->Current ? + "Currently supports" : "Is able to support"), + "DD CD Reading" + )); + } + + header = DeviceFindFeaturePage(Buffer, Usable, FeatureDDCDRWrite); + if (header) { + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT, + "CdromGetConfiguration: %s %s\n", + (header->Current ? + "Currently supports" : "Is able to support"), + "DD CD-R Writing" + )); + } + + header = DeviceFindFeaturePage(Buffer, Usable, FeatureDDCDRWWrite); + if (header) { + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT, + "CdromGetConfiguration: %s %s\n", + (header->Current ? + "Currently supports" : "Is able to support"), + "DD CD-RW Writing" + )); + } + + header = DeviceFindFeaturePage(Buffer, Usable, FeatureLayerJumpRecording); + if (header) { + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT, + "CdromGetConfiguration: %s %s\n", + (header->Current ? + "Currently supports" : "Is able to support"), + "Layer Jump Recording" + )); + } + + header = DeviceFindFeaturePage(Buffer, Usable, FeatureHDDVDRead); + if (header) { + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT, + "CdromGetConfiguration: %s %s\n", + (header->Current ? + "Currently supports" : "Is able to support"), + "HD-DVD Reading" + )); + } + + header = DeviceFindFeaturePage(Buffer, Usable, FeatureHDDVDWrite); + if (header) { + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT, + "CdromGetConfiguration: %s %s\n", + (header->Current ? + "Currently supports" : "Is able to support"), + "HD-DVD Writing" + )); + } + + + header = DeviceFindFeaturePage(Buffer, Usable, FeatureSMART); + if (header) { + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT, + "CdromGetConfiguration: %s %s\n", + (header->Current ? + "Currently supports" : "Is able to support"), + "S.M.A.R.T." + )); + } + + header = DeviceFindFeaturePage(Buffer, Usable, FeatureCDAudioAnalogPlay); + if (header) { + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT, + "CdromGetConfiguration: %s %s\n", + (header->Current ? + "Currently supports" : "Is able to support"), + "Analogue CD Audio Operations" + )); + } + + header = DeviceFindFeaturePage(Buffer, Usable, FeatureDvdCSS); + if (header) { + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT, + "CdromGetConfiguration: %s %s\n", + (header->Current ? + "Currently supports" : "Is able to support"), + "DVD CSS" + )); + } + + header = DeviceFindFeaturePage(Buffer, Usable, FeatureRealTimeStreaming); + if (header) { + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT, + "CdromGetConfiguration: %s %s\n", + (header->Current ? + "Currently supports" : "Is able to support"), + "Real-time Streaming Reads" + )); + } + + header = DeviceFindFeaturePage(Buffer, Usable, FeatureDiscControlBlocks); + if (header) { + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT, + "CdromGetConfiguration: %s %s\n", + (header->Current ? + "Currently supports" : "Is able to support"), + "DVD Disc Control Blocks" + )); + } + + header = DeviceFindFeaturePage(Buffer, Usable, FeatureDvdCPRM); + if (header) { + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT, + "CdromGetConfiguration: %s %s\n", + (header->Current ? + "Currently supports" : "Is able to support"), + "DVD CPRM" + )); + } + + header = DeviceFindFeaturePage(Buffer, Usable, FeatureAACS); + if (header) { + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT, + "CdromGetConfiguration: %s %s\n", + (header->Current ? + "Currently supports" : "Is able to support"), + "AACS" + )); + } + +#else + PAGED_CODE(); + + UNREFERENCED_PARAMETER(Usable); + UNREFERENCED_PARAMETER(Buffer); + +#endif // DBG + return; +} + + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +MediaReadCapacity( + _In_ WDFDEVICE Device + ) +/*++ +Routine Description: + + Get media capacity + +Arguments: + + Device - the device that owns the media + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status; + SCSI_REQUEST_BLOCK srb; + PCDB cdb = NULL; + READ_CAPACITY_DATA capacityData; + + PAGED_CODE(); + + RtlZeroMemory(&srb, sizeof(srb)); + RtlZeroMemory(&capacityData, sizeof(capacityData)); + + cdb = (PCDB)(&srb.Cdb); + + //Prepare SCSI command fields + srb.CdbLength = 10; + srb.TimeOutValue = CDROM_READ_CAPACITY_TIMEOUT; + cdb->CDB10.OperationCode = SCSIOP_READ_CAPACITY; + + status = DeviceSendSrbSynchronously(Device, + &srb, + &capacityData, + sizeof(READ_CAPACITY_DATA), + FALSE, + NULL); + + //Remember the result + if (!NT_SUCCESS(status)) + { + //Set the BytesPerBlock to zero, this is for safe as if error happens this field should stay zero (no change). + //it will be treated as error case in MediaReadCapacityDataInterpret() + capacityData.BytesPerBlock = 0; + } + + MediaReadCapacityDataInterpret(Device, &capacityData); + + return status; +} + + +_IRQL_requires_max_(APC_LEVEL) +VOID +MediaReadCapacityDataInterpret( + _In_ WDFDEVICE Device, + _In_ PREAD_CAPACITY_DATA ReadCapacityBuffer + ) +/*++ +Routine Description: + + Interpret media capacity and set corresponding fields in device context + +Arguments: + + Device - the device that owns the media + + ReadCapacityBuffer - data buffer of capacity + +Return Value: + + none + +--*/ +{ + PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(Device); + ULONG lastSector = 0; + ULONG bps = 0; + ULONG lastBit = 0; + ULONG bytesPerBlock = 0; + BOOLEAN errorHappened = FALSE; + + PAGED_CODE(); + + NT_ASSERT(ReadCapacityBuffer); + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, + "MediaReadCapacityDataInterpret: Entering\n")); + + // Swizzle bytes from Read Capacity and translate into + // the necessary geometry information in the device extension. + bytesPerBlock = ReadCapacityBuffer->BytesPerBlock; + + ((PFOUR_BYTE)&bps)->Byte0 = ((PFOUR_BYTE)&bytesPerBlock)->Byte3; + ((PFOUR_BYTE)&bps)->Byte1 = ((PFOUR_BYTE)&bytesPerBlock)->Byte2; + ((PFOUR_BYTE)&bps)->Byte2 = ((PFOUR_BYTE)&bytesPerBlock)->Byte1; + ((PFOUR_BYTE)&bps)->Byte3 = ((PFOUR_BYTE)&bytesPerBlock)->Byte0; + + // Insure that bps is a power of 2. + // This corrects a problem with the HP 4020i CDR where it + // returns an incorrect number for bytes per sector. + if (!bps) + { + // Set disk geometry to default values (per ISO 9660). + bps = 2048; + errorHappened = TRUE; + } + else + { + lastBit = (ULONG)(-1); + while (bps) + { + lastBit++; + bps = (bps >> 1); + } + bps = (1 << lastBit); + } + + deviceExtension->DiskGeometry.BytesPerSector = bps; + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, + "MediaReadCapacityDataInterpret: Calculated bps %#x\n", + deviceExtension->DiskGeometry.BytesPerSector)); + + // Copy last sector in reverse byte order. + bytesPerBlock = ReadCapacityBuffer->LogicalBlockAddress; + + ((PFOUR_BYTE)&lastSector)->Byte0 = ((PFOUR_BYTE)&bytesPerBlock)->Byte3; + ((PFOUR_BYTE)&lastSector)->Byte1 = ((PFOUR_BYTE)&bytesPerBlock)->Byte2; + ((PFOUR_BYTE)&lastSector)->Byte2 = ((PFOUR_BYTE)&bytesPerBlock)->Byte1; + ((PFOUR_BYTE)&lastSector)->Byte3 = ((PFOUR_BYTE)&bytesPerBlock)->Byte0; + + // Calculate sector to byte shift. + WHICH_BIT(bps, deviceExtension->SectorShift); + + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, + "MediaReadCapacityDataInterpret: Sector size is %d\n", + deviceExtension->DiskGeometry.BytesPerSector)); + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, + "MediaReadCapacityDataInterpret: Number of Sectors is %d\n", + lastSector + 1)); + + // Calculate media capacity in bytes. + if (errorHappened) + { + // Set disk geometry to default values (per ISO 9660). + deviceExtension->PartitionLength.QuadPart = (LONGLONG)(0x7fffffff); + } + else + { + deviceExtension->PartitionLength.QuadPart = (LONGLONG)(lastSector + 1); + deviceExtension->PartitionLength.QuadPart = + (deviceExtension->PartitionLength.QuadPart << deviceExtension->SectorShift); + } + + // we've defaulted to 32/64 forever. don't want to change this now... + deviceExtension->DiskGeometry.TracksPerCylinder = 0x40; + deviceExtension->DiskGeometry.SectorsPerTrack = 0x20; + + // Calculate number of cylinders. + deviceExtension->DiskGeometry.Cylinders.QuadPart = (LONGLONG)((lastSector + 1) / (32 * 64)); + + deviceExtension->DiskGeometry.MediaType = RemovableMedia; + + return; +} + + +_IRQL_requires_max_(APC_LEVEL) +VOID +DevicePickDvdRegion( + _In_ WDFDEVICE Device + ) +/*++ + +Routine Description: + + pick a default dvd region + +Arguments: + + Device - Device Object + +Return Value: + + none + +--*/ +{ + NTSTATUS status; + PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(Device); + + // these five pointers all point to dvdReadStructure or part of + // its data, so don't deallocate them more than once! + PDVD_READ_STRUCTURE dvdReadStructure; + PDVD_COPY_PROTECT_KEY copyProtectKey; + PDVD_COPYRIGHT_DESCRIPTOR dvdCopyRight; + PDVD_RPC_KEY rpcKey; + PDVD_SET_RPC_KEY dvdRpcKey; + + size_t bytesReturned = 0; + ULONG bufferLen = 0; + UCHAR mediaRegion = 0; + ULONG pickDvdRegion = 0; + ULONG defaultDvdRegion = 0; + ULONG dvdRegion = 0; + WDFKEY registryKey = NULL; + + DECLARE_CONST_UNICODE_STRING(registryValueName, DVD_DEFAULT_REGION); + + PAGED_CODE(); + + if ((pickDvdRegion = InterlockedExchange((PLONG)&deviceExtension->DeviceAdditionalData.PickDvdRegion, 0)) == 0) + { + // it was non-zero, so either another thread will do this, or + // we no longer need to pick a region + return; + } + + bufferLen = max( + max(sizeof(DVD_DESCRIPTOR_HEADER) + + sizeof(DVD_COPYRIGHT_DESCRIPTOR), + sizeof(DVD_READ_STRUCTURE) + ), + max(DVD_RPC_KEY_LENGTH, + DVD_SET_RPC_KEY_LENGTH + ) + ); + + dvdReadStructure = (PDVD_READ_STRUCTURE) + ExAllocatePoolWithTag(PagedPool, bufferLen, DVD_TAG_DVD_REGION); + + if (dvdReadStructure == NULL) + { + InterlockedExchange((PLONG)&deviceExtension->DeviceAdditionalData.PickDvdRegion, pickDvdRegion); + return; + } + + copyProtectKey = (PDVD_COPY_PROTECT_KEY)dvdReadStructure; + + dvdCopyRight = (PDVD_COPYRIGHT_DESCRIPTOR) + ((PDVD_DESCRIPTOR_HEADER)dvdReadStructure)->Data; + + // get the media region + RtlZeroMemory (dvdReadStructure, bufferLen); + dvdReadStructure->Format = DvdCopyrightDescriptor; + + // Build and send a request for READ_KEY + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL, + "DevicePickDvdRegion (%p): Getting Copyright Descriptor\n", + Device)); + + status = ReadDvdStructure(deviceExtension, + NULL, + dvdReadStructure, + sizeof(DVD_READ_STRUCTURE), + dvdReadStructure, + sizeof(DVD_DESCRIPTOR_HEADER) + sizeof(DVD_COPYRIGHT_DESCRIPTOR), + &bytesReturned); + + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL, + "DevicePickDvdRegion (%p): Got Copyright Descriptor %x\n", + Device, status)); + + if ((NT_SUCCESS(status)) && + (dvdCopyRight->CopyrightProtectionType == 0x01)) + { + // keep the media region bitmap around + // a 1 means ok to play + if (dvdCopyRight->RegionManagementInformation == 0xff) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, + "DevicePickDvdRegion (%p): RegionManagementInformation " + "is set to dis-allow playback for all regions. This is " + "most likely a poorly authored disc. defaulting to all " + "region disc for purpose of choosing initial region\n", + Device)); + dvdCopyRight->RegionManagementInformation = 0; + } + + mediaRegion = ~dvdCopyRight->RegionManagementInformation; + } + else + { + // can't automatically pick a default region on a drive without media, so just exit + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, + "DevicePickDvdRegion (%p): failed to auto-choose a region due to status %x getting copyright descriptor\n", + Device, status)); + goto getout; + } + + // get the device region + RtlZeroMemory (copyProtectKey, bufferLen); + copyProtectKey->KeyLength = DVD_RPC_KEY_LENGTH; + copyProtectKey->KeyType = DvdGetRpcKey; + + // Build and send a request for READ_KEY for RPC key + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL, + "DevicePickDvdRegion (%p): Getting RpcKey\n", + Device)); + status = DvdStartSessionReadKey(deviceExtension, + IOCTL_DVD_READ_KEY, + NULL, + copyProtectKey, + DVD_RPC_KEY_LENGTH, + copyProtectKey, + DVD_RPC_KEY_LENGTH, + &bytesReturned); + + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL, + "DevicePickDvdRegion (%p): Got RpcKey %x\n", + Device, status)); + + if (!NT_SUCCESS(status)) + { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, + "DevicePickDvdRegion (%p): failed to get RpcKey from " + "a DVD Device\n", Device)); + goto getout; + } + + // so we now have what we can get for the media region and the + // drive region. we will not set a region if the drive has one + // set already (mask is not all 1's), nor will we set a region + // if there are no more user resets available. + rpcKey = (PDVD_RPC_KEY)copyProtectKey->KeyData; + + if (rpcKey->RegionMask != 0xff) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, + "DevicePickDvdRegion (%p): not picking a region since " + "it is already chosen\n", Device)); + goto getout; + } + + if (rpcKey->UserResetsAvailable <= 1) + { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, + "DevicePickDvdRegion (%p): not picking a region since " + "only one change remains\n", Device)); + goto getout; + } + + // OOBE sets this key based upon the system locale + status = WdfDriverOpenParametersRegistryKey(WdfGetDriver(), + KEY_READ, + WDF_NO_OBJECT_ATTRIBUTES, + ®istryKey); + + if (NT_SUCCESS(status)) + { + status = WdfRegistryQueryULong(registryKey, + ®istryValueName, + &defaultDvdRegion); + + WdfRegistryClose(registryKey); + } + + if (!NT_SUCCESS(status)) + { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, + "DevicePickDvdRegion (%p): failed to read registry value due to status %x\n", + Device, status)); + + // by default the default Dvd region is 0 + defaultDvdRegion = 0; + status = STATUS_SUCCESS; + } + + if (defaultDvdRegion > DVD_MAX_REGION) + { + // the registry has a bogus default + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, + "DevicePickDvdRegion (%p): registry has a bogus default " + "region value of %x\n", Device, defaultDvdRegion)); + + defaultDvdRegion = 0; + } + + // if defaultDvdRegion == 0, it means no default. + + // we will select the initial dvd region for the user + + if ((defaultDvdRegion != 0) && + (mediaRegion & (1 << (defaultDvdRegion - 1)))) + { + // first choice: + // the media has region that matches + // the default dvd region. + dvdRegion = (1 << (defaultDvdRegion - 1)); + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, + "DevicePickDvdRegion (%p): Choice #1: media matches " + "drive's default, chose region %x\n", Device, dvdRegion)); + } + else if (mediaRegion) + { + // second choice: + // pick the lowest region number from the media + UCHAR mask = 1; + dvdRegion = 0; + + while (mediaRegion && !dvdRegion) + { + // pick the lowest bit + dvdRegion = mediaRegion & mask; + mask <<= 1; + } + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, + "DevicePickDvdRegion (%p): Choice #2: choosing lowest " + "media region %x\n", Device, dvdRegion)); + } + else if (defaultDvdRegion) + { + // third choice: + // default dvd region from the dvd class installer + dvdRegion = (1 << (defaultDvdRegion - 1)); + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, + "DevicePickDvdRegion (%p): Choice #3: using default " + "region for this install %x\n", Device, dvdRegion)); + } + else + { + // unable to pick one for the user -- this should rarely + // happen, since the proppage dvd class installer sets + // the key based upon the system locale + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, + "DevicePickDvdRegion (%p): Choice #4: failed to choose " + "a media region\n", Device)); + goto getout; + } + + // now that we've chosen a region, set the region by sending the + // appropriate request to the drive + RtlZeroMemory (copyProtectKey, bufferLen); + copyProtectKey->KeyLength = DVD_SET_RPC_KEY_LENGTH; + copyProtectKey->KeyType = DvdSetRpcKey; + dvdRpcKey = (PDVD_SET_RPC_KEY)copyProtectKey->KeyData; + dvdRpcKey->PreferredDriveRegionCode = (UCHAR)~dvdRegion; + + // Build and send request for SEND_KEY + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL, + "DevicePickDvdRegion (%p): Sending new Rpc Key to region %x\n", + Device, dvdRegion)); + + status = DvdSendKey(deviceExtension, + NULL, + copyProtectKey, + DVD_SET_RPC_KEY_LENGTH, + &bytesReturned); + + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL, + "DevicePickDvdRegion (%p): Sent new Rpc Key %x\n", + Device, status)); + + if (!NT_SUCCESS(status)) + { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, "DevicePickDvdRegion (%p): unable to set dvd initial " + " region code (%x)\n", Device, status)); + } + else + { + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL, "DevicePickDvdRegion (%p): Successfully set dvd " + "initial region\n", Device)); + + pickDvdRegion = 0; + } + +getout: + if (dvdReadStructure) + { + FREE_POOL(dvdReadStructure); + } + + // update the new PickDvdRegion value + InterlockedExchange((PLONG)&deviceExtension->DeviceAdditionalData.PickDvdRegion, pickDvdRegion); + + return; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +DeviceRegisterInterface( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ CDROM_DEVICE_INTERFACES InterfaceType + ) +/*++ +Routine Description: + + used to register device class interface or mount device interface + +Arguments: + + DeviceExtension - device context + + InterfaceType - interface type to be registered. + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status; + WDFSTRING string = NULL; + GUID* interfaceGuid = NULL; + PUNICODE_STRING savingString = NULL; + BOOLEAN setRestricted = FALSE; + UNICODE_STRING localString; + + PAGED_CODE(); + + //Get parameters + switch(InterfaceType) + { + case CdRomDeviceInterface: + interfaceGuid = (LPGUID)&GUID_DEVINTERFACE_CDROM; + setRestricted = TRUE; + savingString = &localString; + break; + case MountedDeviceInterface: + interfaceGuid = (LPGUID)&MOUNTDEV_MOUNTED_DEVICE_GUID; + savingString = &(DeviceExtension->MountedDeviceInterfaceName); + break; + default: + return STATUS_INVALID_PARAMETER; + } + + status = WdfDeviceCreateDeviceInterface(DeviceExtension->Device, + interfaceGuid, + NULL); + + if (!NT_SUCCESS(status)) + { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT, + "DeviceRegisterInterface: Unable to register cdrom " + "DCA for fdo %p type: %s [%lx]\n", + DeviceExtension->Device, + (InterfaceType == CdRomDeviceInterface)? "CdRom Interface" : "Mounted Device Interface", + status)); + } + + // Retrieve interface string + if (NT_SUCCESS(status)) + { + // The string object will be released when its parent object is released. + WDF_OBJECT_ATTRIBUTES attributes; + + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + attributes.ParentObject = DeviceExtension->Device; + + status = WdfStringCreate(WDF_NO_OBJECT_ATTRIBUTES, + NULL, + &string); + } + + if (NT_SUCCESS(status)) + { + status = WdfDeviceRetrieveDeviceInterfaceString(DeviceExtension->Device, + interfaceGuid, + NULL, + string); + } + + if (NT_SUCCESS(status)) + { + WdfStringGetUnicodeString(string, savingString); + + if (setRestricted) { + + + WdfObjectDelete(string); + } + } + + return status; +} // end DeviceRegisterInterface() + + +VOID +DeviceRestoreDefaultSpeed( + _In_ WDFWORKITEM WorkItem + ) +/*++ + +Routine Description: + + This workitem is called on a media change when the CDROM device + speed should be restored to the default value. + +Arguments: + + Fdo - Supplies the device object for the CDROM device. + WorkItem - Supplies the pointer to the workitem. + +Return Value: + + None + +--*/ +{ + NTSTATUS status; + WDFDEVICE device = WdfWorkItemGetParentObject(WorkItem); + PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(device); + PPERFORMANCE_DESCRIPTOR perfDescriptor; + ULONG transferLength = sizeof(PERFORMANCE_DESCRIPTOR); + SCSI_REQUEST_BLOCK srb = {0}; + PCDB cdb = (PCDB)srb.Cdb; + + PAGED_CODE(); + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DeviceRestoreDefaultSpeed: Restore device speed for %p\n", device)); + + perfDescriptor = ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned, + transferLength, + CDROM_TAG_STREAM); + if (perfDescriptor == NULL) + { + return; + } + + RtlZeroMemory(perfDescriptor, transferLength); + + perfDescriptor->RestoreDefaults = TRUE; + + srb.TimeOutValue = deviceExtension->TimeOutValue; + + srb.CdbLength = 12; + cdb->SET_STREAMING.OperationCode = SCSIOP_SET_STREAMING; + REVERSE_BYTES_SHORT(&cdb->SET_STREAMING.ParameterListLength, &transferLength); + + status = DeviceSendSrbSynchronously(device, + &srb, + perfDescriptor, + transferLength, + TRUE, + NULL); + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, + "DeviceRestoreDefaultSpeed: Set Streaming command completed with status: 0x%X\n", status)); + + FREE_POOL(perfDescriptor); + WdfObjectDelete(WorkItem); + + return; +} + +// custom string match -- careful! +_IRQL_requires_max_(APC_LEVEL) +BOOLEAN +StringsAreMatched( + _In_opt_z_ PCHAR StringToMatch, + _In_z_ PCHAR TargetString + ) +/*++ + +Routine Description: + + compares if two strings are identical + +Arguments: + + StringToMatch - source string. + TargetString - target string. + +Return Value: + + BOOLEAN - TRUE (identical); FALSE (not match) + +--*/ +{ + size_t length; + + PAGED_CODE(); + + NT_ASSERT(TargetString); + + // if no match requested, return TRUE + if (StringToMatch == NULL) + { + return TRUE; + } + + // cache the string length for efficiency + length = strlen(StringToMatch); + + // ZERO-length strings may only match zero-length strings + if (length == 0) + { + return (strlen(TargetString) == 0); + } + + // strncmp returns zero if the strings match + return (strncmp(StringToMatch, TargetString, length) == 0); +} + + +NTSTATUS +RequestSetContextFields( + _In_ WDFREQUEST Request, + _In_ PSYNC_HANDLER Handler + ) +/*++ + +Routine Description: + + set the request object context fields + +Arguments: + + Request - request object. + Handler - the function that finally handles this request. + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PCDROM_REQUEST_CONTEXT requestContext = RequestGetContext(Request); + PKEVENT syncEvent = NULL; + + syncEvent = ExAllocatePoolWithTag(NonPagedPoolNx, + sizeof(KEVENT), + CDROM_TAG_SYNC_EVENT); + + if (syncEvent == NULL) + { + // memory allocation failed. + status = STATUS_INSUFFICIENT_RESOURCES; + } + else + { + // now, put the special synchronization information into the context + requestContext->SyncRequired = TRUE; + requestContext->SyncEvent = syncEvent; + requestContext->SyncCallback = Handler; + + status = STATUS_SUCCESS; + } + + return status; +} + + +NTSTATUS +RequestDuidGetDeviceIdProperty( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + + +Arguments: + + DeviceExtension - device context + Request - request object. + RequestParameters - request parameter + DataLength - transferred data length. + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PSTORAGE_DEVICE_ID_DESCRIPTOR deviceIdDescriptor = NULL; + PSTORAGE_DESCRIPTOR_HEADER descHeader = NULL; + STORAGE_PROPERTY_ID propertyId = StorageDeviceIdProperty; + + *DataLength = 0; + + // Get the VPD page 83h data. + status = DeviceRetrieveDescriptor(DeviceExtension->Device, + &propertyId, + (PSTORAGE_DESCRIPTOR_HEADER*)&deviceIdDescriptor); + + if (NT_SUCCESS(status) && (deviceIdDescriptor == NULL)) + { + status = STATUS_NOT_FOUND; + } + + if (NT_SUCCESS(status)) + { + status = WdfRequestRetrieveOutputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, + &descHeader, + NULL); + } + + if (NT_SUCCESS(status)) + { + PSTORAGE_DEVICE_UNIQUE_IDENTIFIER storageDuid = NULL; + ULONG offset = descHeader->Size; + PUCHAR dest = (PUCHAR)descHeader + offset; + size_t outputBufferSize; + + outputBufferSize = RequestParameters.Parameters.DeviceIoControl.OutputBufferLength; + + // Adjust required size and potential destination location. + status = RtlULongAdd(descHeader->Size, deviceIdDescriptor->Size, &descHeader->Size); + + if (NT_SUCCESS(status) && + (outputBufferSize < descHeader->Size)) + { + // Output buffer is too small. Return error and make sure + // the caller gets info about required buffer size. + *DataLength = descHeader->Size; + status = STATUS_BUFFER_OVERFLOW; + } + + if (NT_SUCCESS(status)) + { + storageDuid = (PSTORAGE_DEVICE_UNIQUE_IDENTIFIER)descHeader; + storageDuid->StorageDeviceIdOffset = offset; + + RtlCopyMemory(dest, + deviceIdDescriptor, + deviceIdDescriptor->Size); + + *DataLength = storageDuid->Size; + status = STATUS_SUCCESS; + } + + FREE_POOL(deviceIdDescriptor); + } + + return status; +} + +NTSTATUS +RequestDuidGetDeviceProperty( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + + +Arguments: + + DeviceExtension - device context + Request - request object. + RequestParameters - request parameter + DataLength - transferred data length. + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PSTORAGE_DEVICE_DESCRIPTOR deviceDescriptor = DeviceExtension->DeviceDescriptor; + PSTORAGE_DESCRIPTOR_HEADER descHeader = NULL; + PSTORAGE_DEVICE_UNIQUE_IDENTIFIER storageDuid; + PUCHAR dest = NULL; + + if (deviceDescriptor == NULL) + { + status = STATUS_NOT_FOUND; + } + + if (NT_SUCCESS(status)) + { + status = WdfRequestRetrieveOutputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, + &descHeader, + NULL); + } + + if (NT_SUCCESS(status) && + (deviceDescriptor->SerialNumberOffset == 0)) + { + status = STATUS_NOT_FOUND; + } + + // Use this info only if serial number is available. + if (NT_SUCCESS(status)) + { + ULONG offset = descHeader->Size; + size_t outputBufferSize = RequestParameters.Parameters.DeviceIoControl.OutputBufferLength; + + // Adjust required size and potential destination location. + dest = (PUCHAR)descHeader + offset; + + status = RtlULongAdd(descHeader->Size, deviceDescriptor->Size, &descHeader->Size); + + if (NT_SUCCESS(status) && + (outputBufferSize < descHeader->Size)) + { + // Output buffer is too small. Return error and make sure + // the caller get info about required buffer size. + *DataLength = descHeader->Size; + status = STATUS_BUFFER_OVERFLOW; + } + + if (NT_SUCCESS(status)) + { + storageDuid = (PSTORAGE_DEVICE_UNIQUE_IDENTIFIER)descHeader; + storageDuid->StorageDeviceOffset = offset; + + RtlCopyMemory(dest, + deviceDescriptor, + deviceDescriptor->Size); + + *DataLength = storageDuid->Size; + status = STATUS_SUCCESS; + } + } + + return status; +} + +_IRQL_requires_max_(APC_LEVEL) +ULONG +DeviceRetrieveModeSenseUsingScratch( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_reads_bytes_(Length) PCHAR ModeSenseBuffer, + _In_ ULONG Length, + _In_ UCHAR PageCode, + _In_ UCHAR PageControl + ) +/*++ + +Routine Description: + + retrieve mode sense informaiton of the device + +Arguments: + + DeviceExtension - device context + ModeSenseBuffer - buffer to savee the mode sense info. + Length - buffer length + PageCode - . + PageControl - + +Return Value: + + ULONG - transferred data length + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + ULONG transferSize = min(Length, DeviceExtension->ScratchContext.ScratchBufferSize); + CDB cdb; + + PAGED_CODE(); + + ScratchBuffer_BeginUse(DeviceExtension); + + RtlZeroMemory(&cdb, sizeof(CDB)); + // Set up the CDB + cdb.MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE; + cdb.MODE_SENSE.PageCode = PageCode; + cdb.MODE_SENSE.Pc = PageControl; + cdb.MODE_SENSE.AllocationLength = (UCHAR)transferSize; + + status = ScratchBuffer_ExecuteCdb(DeviceExtension, NULL, transferSize, TRUE, &cdb, 6); + + if (NT_SUCCESS(status)) + { + transferSize = min(Length, DeviceExtension->ScratchContext.ScratchSrb->DataTransferLength); + RtlCopyMemory(ModeSenseBuffer, + DeviceExtension->ScratchContext.ScratchBuffer, + transferSize); + } + + ScratchBuffer_EndUse(DeviceExtension); + + return transferSize; +} + +_IRQL_requires_max_(APC_LEVEL) +PVOID +ModeSenseFindSpecificPage( + _In_reads_bytes_(Length) PCHAR ModeSenseBuffer, + _In_ size_t Length, + _In_ UCHAR PageMode, + _In_ BOOLEAN Use6BytesCdb + ) +/*++ + +Routine Description: + + This routine scans through the mode sense data and finds the requested + mode sense page code. + +Arguments: + ModeSenseBuffer - Supplies a pointer to the mode sense data. + + Length - Indicates the length of valid data. + + PageMode - Supplies the page mode to be searched for. + + Use6BytesCdb - Indicates whether 6 or 10 byte mode sense was used. + +Return Value: + + A pointer to the the requested mode page. If the mode page was not found + then NULL is return. + +--*/ +{ + PCHAR limit; + ULONG parameterHeaderLength; + PVOID result = NULL; + + PAGED_CODE(); + + limit = ModeSenseBuffer + Length; + parameterHeaderLength = (Use6BytesCdb) + ? sizeof(MODE_PARAMETER_HEADER) + : sizeof(MODE_PARAMETER_HEADER10); + + if (Length >= parameterHeaderLength) + { + PMODE_PARAMETER_HEADER10 modeParam10; + ULONG blockDescriptorLength; + + // Skip the mode select header and block descriptors. + if (Use6BytesCdb) + { + blockDescriptorLength = ((PMODE_PARAMETER_HEADER)ModeSenseBuffer)->BlockDescriptorLength; + } + else + { + modeParam10 = (PMODE_PARAMETER_HEADER10) ModeSenseBuffer; + blockDescriptorLength = modeParam10->BlockDescriptorLength[1]; + } + + ModeSenseBuffer += parameterHeaderLength + blockDescriptorLength; + + // ModeSenseBuffer now points at pages. Walk the pages looking for the + // requested page until the limit is reached. + while (ModeSenseBuffer + + RTL_SIZEOF_THROUGH_FIELD(MODE_DISCONNECT_PAGE, PageLength) < limit) + { + if (((PMODE_DISCONNECT_PAGE) ModeSenseBuffer)->PageCode == PageMode) + { + // found the mode page. make sure it's safe to touch it all + // before returning the pointer to caller + if (ModeSenseBuffer + ((PMODE_DISCONNECT_PAGE)ModeSenseBuffer)->PageLength > limit) + { + // Return NULL since the page is not safe to access in full + result = NULL; + } + else + { + result = ModeSenseBuffer; + } + break; + } + + // Advance to the next page which is 4-byte-aligned offset after this page. + ModeSenseBuffer += ((PMODE_DISCONNECT_PAGE) ModeSenseBuffer)->PageLength + + RTL_SIZEOF_THROUGH_FIELD(MODE_DISCONNECT_PAGE, PageLength); + } + } + + return result; +} // end ModeSenseFindSpecificPage() + + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +PerformEjectionControl( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ MEDIA_LOCK_TYPE LockType, + _In_ BOOLEAN Lock + ) +/*++ + +Routine Description: + + ejection control process + +Arguments: + + DeviceExtension - device extension + Request - WDF request to be used for communication with the device + LockType - the type of lock + Lock - if TRUE, lock the device; if FALSE, unlock it + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status; + PFILE_OBJECT_CONTEXT fileObjectContext = NULL; + SCSI_REQUEST_BLOCK srb; + PCDB cdb = NULL; + + LONG newLockCount = 0; + LONG newProtectedLockCount = 0; + LONG newInternalLockCount = 0; + LONG newFileLockCount = 0; + BOOLEAN countChanged = FALSE; + BOOLEAN previouslyLocked = FALSE; + BOOLEAN nowLocked = FALSE; + + PAGED_CODE(); + + // Prevent race conditions while working with lock counts + status = WdfWaitLockAcquire(DeviceExtension->EjectSynchronizationLock, NULL); + if (!NT_SUCCESS(status)) + { + NT_ASSERT(FALSE); + } + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, + "PerformEjectionControl: " + "Received request for %s lock type\n", + LockTypeStrings[LockType] + )); + + + // If this is a "secured" request, retrieve the file object context + if (LockType == SecureMediaLock) + { + WDFFILEOBJECT fileObject = NULL; + + fileObject = WdfRequestGetFileObject(Request); + + if (fileObject == NULL) + { + status = STATUS_INVALID_HANDLE; + + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, + "FileObject does not match to the one in IRP_MJ_CREATE, KMDF returns NULL\n")); + goto Exit; + } + + fileObjectContext = FileObjectGetContext(fileObject); + NT_ASSERT(fileObjectContext != NULL); + } + + // Lock counts should never fall below 0 + NT_ASSERT(DeviceExtension->LockCount >= 0); + NT_ASSERT(DeviceExtension->ProtectedLockCount >= 0); + NT_ASSERT(DeviceExtension->InternalLockCount >= 0); + + // Get the current lock counts + newLockCount = DeviceExtension->LockCount; + newProtectedLockCount = DeviceExtension->ProtectedLockCount; + newInternalLockCount = DeviceExtension->InternalLockCount; + if (fileObjectContext) + { + // fileObjectContext->LockCount is ULONG and should always >= 0 + newFileLockCount = fileObjectContext->LockCount; + } + + // Determine which lock counts need to be changed and how + if (Lock && LockType == SimpleMediaLock) + { + newLockCount++; + countChanged = TRUE; + } + else if (Lock && LockType == SecureMediaLock) + { + newFileLockCount++; + newProtectedLockCount++; + countChanged = TRUE; + } + else if (Lock && LockType == InternalMediaLock) + { + newInternalLockCount++; + countChanged = TRUE; + } + else if (!Lock && LockType == SimpleMediaLock) + { + if (newLockCount != 0) + { + newLockCount--; + countChanged = TRUE; + } + } + else if (!Lock && LockType == SecureMediaLock) + { + if ( (newFileLockCount == 0) || (newProtectedLockCount == 0) ) + { + status = STATUS_INVALID_DEVICE_STATE; + goto Exit; + } + newFileLockCount--; + newProtectedLockCount--; + countChanged = TRUE; + } + else if (!Lock && LockType == InternalMediaLock) + { + NT_ASSERT(newInternalLockCount != 0); + newInternalLockCount--; + countChanged = TRUE; + } + + if ( (DeviceExtension->LockCount != 0) || + (DeviceExtension->ProtectedLockCount != 0) || + (DeviceExtension->InternalLockCount != 0) ) + { + previouslyLocked = TRUE; + } + if ( (newLockCount != 0) || + (newProtectedLockCount != 0) || + (newInternalLockCount != 0) ) + { + nowLocked = TRUE; + } + + // Only send command down to device when necessary + if (previouslyLocked != nowLocked) + { + // Compose and send the PREVENT ALLOW MEDIA REMOVAL command. + RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK)); + + srb.CdbLength = 6; + srb.TimeOutValue = DeviceExtension->TimeOutValue; + + cdb = (PCDB)&srb.Cdb; + cdb->MEDIA_REMOVAL.OperationCode = SCSIOP_MEDIUM_REMOVAL; + cdb->MEDIA_REMOVAL.Prevent = Lock; + + status = DeviceSendSrbSynchronously(DeviceExtension->Device, + &srb, + NULL, + 0, + FALSE, + Request); + } + +Exit: + + // Store the updated lock counts on success + if (countChanged && NT_SUCCESS(status)) + { + DeviceExtension->LockCount = newLockCount; + DeviceExtension->ProtectedLockCount = newProtectedLockCount; + DeviceExtension->InternalLockCount = newInternalLockCount; + if (fileObjectContext) + { + fileObjectContext->LockCount = newFileLockCount; + } + } + + WdfWaitLockRelease(DeviceExtension->EjectSynchronizationLock); + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, + "PerformEjectionControl: %!STATUS!, " + "Count Changed: %d, Command Sent: %d, " + "Current Counts: Internal: %x Secure: %x Simple: %x\n", + status, + countChanged, + previouslyLocked != nowLocked, + DeviceExtension->InternalLockCount, + DeviceExtension->ProtectedLockCount, + DeviceExtension->LockCount + )); + + return status; +} + + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DeviceUnlockExclusive( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFFILEOBJECT FileObject, + _In_ BOOLEAN IgnorePreviousMediaChanges + ) +/*++ + +Routine Description: + + to unlock the exclusive lock + +Arguments: + + DeviceExtension - device context + FileObject - file object that currently holds the lock + IgnorePreviousMediaChanges - if TRUE, ignore previously accumulated media changes + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PCDROM_DATA cdData = &DeviceExtension->DeviceAdditionalData; + PMEDIA_CHANGE_DETECTION_INFO info = DeviceExtension->MediaChangeDetectionInfo; + BOOLEAN ANPending = 0; + LONG requestInUse = 0; + + PAGED_CODE(); + + if (!EXCLUSIVE_MODE(cdData)) + { + // Device is not locked for exclusive access. + // Can not process unlock request. + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, + "RequestHandleExclusiveAccessUnlockDevice: Device not locked for exclusive access, can't unlock device.\n")); + status = STATUS_INVALID_DEVICE_REQUEST; + } + else if (!EXCLUSIVE_OWNER(cdData, FileObject)) + { + // Request not from the exclusive owner, can't unlock the device. + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, + "RequestHandleExclusiveAccessUnlockDevice: Unable to unlock device, invalid file object\n")); + + status = STATUS_INVALID_HANDLE; + } + + if (NT_SUCCESS(status)) + { + // Unless we were explicitly requested not to do so, generate a media removal notification + // followed by a media arrival notification similar to volume lock/unlock file system events. + if (!IgnorePreviousMediaChanges) + { + MEDIA_CHANGE_DETECTION_STATE previousMediaState = MediaUnknown; + + // Change the media state to "unavailable", which will cause a removal notification if the media + // was previously present. At the same time, store the previous state in previousMediaState. + DeviceSetMediaChangeStateEx(DeviceExtension, MediaUnavailable, &previousMediaState); + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, + "DeviceUnlockExclusive: Changing the media state to MediaUnavailable\n")); + + // Restore the previous media state, which will cause a media arrival notification if the media + // was originally present. + DeviceSetMediaChangeStateEx(DeviceExtension, previousMediaState, NULL); + } + + // Set DO_VERIFY_VOLUME so that the file system will remount on it. + if (IsVolumeMounted(DeviceExtension->DeviceObject)) + { + SET_FLAG(DeviceExtension->DeviceObject->Flags, DO_VERIFY_VOLUME); + } + + // Set MMC state to update required + cdData->Mmc.WriteAllowed = FALSE; + cdData->Mmc.UpdateState = CdromMmcUpdateRequired; + + // Send unlock notification + DeviceSendNotification(DeviceExtension, + &GUID_IO_CDROM_EXCLUSIVE_UNLOCK, + 0, + NULL); + + InterlockedExchangePointer((PVOID)&cdData->ExclusiveOwner, NULL); + + if ((info != NULL) && (info->AsynchronousNotificationSupported != FALSE)) + { + ANPending = info->ANSignalPendingDueToExclusiveLock; + info->ANSignalPendingDueToExclusiveLock = FALSE; + + if ((ANPending != FALSE) && (info->MediaChangeDetectionDisableCount == 0)) + { + // if the request is not in use, mark it as such. + requestInUse = InterlockedCompareExchange((PLONG)&info->MediaChangeRequestInUse, 1, 0); + + if (requestInUse == 0) + { + // The last MCN finished. ok to issue the new one. + RequestSetupMcnSyncIrp(DeviceExtension); + + // The irp will go into KMDF framework and a request will be created there to represent it. + IoCallDriver(DeviceExtension->DeviceObject, info->MediaChangeSyncIrp); + } + } + } + } + + return status; +} + + +VOID +RequestCompletion( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ NTSTATUS Status, + _In_ ULONG_PTR Information + ) +{ +#ifdef DBG + ULONG ioctlCode = 0; + WDF_REQUEST_PARAMETERS requestParameters; + + // Get the Request parameters + WDF_REQUEST_PARAMETERS_INIT(&requestParameters); + WdfRequestGetParameters(Request, &requestParameters); + + if (requestParameters.Type == WdfRequestTypeDeviceControl) + { + ioctlCode = requestParameters.Parameters.DeviceIoControl.IoControlCode; + + if (requestParameters.Parameters.DeviceIoControl.IoControlCode != IOCTL_MCN_SYNC_FAKE_IOCTL) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, + "Request complete - IOCTL - code: %X; Status: %X; Information: %X\n", + ioctlCode, + Status, + (ULONG)Information)); + } + else + { + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, + "Request complete - IOCTL - code: %X; Status: %X; Information: %X\n", + ioctlCode, + Status, + (ULONG)Information)); + } + } + else if (requestParameters.Type == WdfRequestTypeRead) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, + "Request complete - READ - Starting Offset: %X; Length: %X; Transferred Length: %X; Status: %X\n", + (ULONG)requestParameters.Parameters.Read.DeviceOffset, + (ULONG)requestParameters.Parameters.Read.Length, + (ULONG)Information, + Status)); + } + else if (requestParameters.Type == WdfRequestTypeWrite) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, + "Request complete - WRITE - Starting Offset: %X; Length: %X; Transferred Length: %X; Status: %X\n", + (ULONG)requestParameters.Parameters.Write.DeviceOffset, + (ULONG)requestParameters.Parameters.Write.Length, + (ULONG)Information, + Status)); + } +#endif + + if (IoIsErrorUserInduced(Status)) + { + PIRP irp = WdfRequestWdmGetIrp(Request); + if (irp->Tail.Overlay.Thread) + { + IoSetHardErrorOrVerifyDevice(irp, DeviceExtension->DeviceObject); + } + } + + if (!NT_SUCCESS(Status) && DeviceExtension->SurpriseRemoved == TRUE) + { + // IMAPI expects ERROR_DEV_NOT_EXISTS if recorder has been surprised removed, + // or it will retry WRITE commands for up to 3 minutes + // CDROM behavior should be consistent for all requests, including SCSI pass-through + Status = STATUS_DEVICE_DOES_NOT_EXIST; + } + + WdfRequestCompleteWithInformation(Request, Status, Information); + + return; +} + + +VOID +RequestDummyCompletionRoutine( + _In_ WDFREQUEST Request, + _In_ WDFIOTARGET Target, + _In_ PWDF_REQUEST_COMPLETION_PARAMS Params, + _In_ WDFCONTEXT Context + ) +/*++ + +Routine Description: + + This is a dummy competion routine that simply calls WdfRequestComplete. We have to use + this dummy competion routine instead of WDF_REQUEST_SEND_OPTION_SEND_AND_FORGET, because + the latter causes the framework to not check if the I/O target is closed or not. + +Arguments: + + Request - completed request + Target - the I/O target that completed the request + Params - request parameters + Context - not used + +Return Value: + + none + +--*/ +{ + UNREFERENCED_PARAMETER(Target); + UNREFERENCED_PARAMETER(Params); + UNREFERENCED_PARAMETER(Context); + + WdfRequestCompleteWithInformation(Request, + WdfRequestGetStatus(Request), + WdfRequestGetInformation(Request)); +} + + +_IRQL_requires_max_(DISPATCH_LEVEL) +NTSTATUS +DeviceSendPowerDownProcessRequest( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_opt_ PFN_WDF_REQUEST_COMPLETION_ROUTINE CompletionRoutine, + _In_opt_ PVOID Context + ) +/*++ + +Routine Description: + + This function is called during processing power down request. + It is used to send either SYNC CACHE command or STOP UNIT command. + + Caller should set proper value in deviceExtension->PowerContext.PowerChangeState.PowerDown + to trigger the correct command be sent. + +Arguments: + + DeviceExtension - + + CompletionRoutine - Completion routine that needs to be set for the request + + Context - Completion context associated with the completion routine + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status; + BOOLEAN requestSent = FALSE; + + BOOLEAN shouldRetry = TRUE; + PCDB cdb = (PCDB)DeviceExtension->PowerContext.Srb.Cdb; + ULONG timeoutValue = DeviceExtension->TimeOutValue; + ULONG retryCount = 1; + + // reset some fields. + DeviceExtension->PowerContext.RetryIntervalIn100ns = 0; + status = PowerContextReuseRequest(DeviceExtension); + RequestClearSendTime(DeviceExtension->PowerContext.PowerRequest); + + if (!NT_SUCCESS(status)) + { + return status; + } + + // set proper timeout value and max retry count. + switch(DeviceExtension->PowerContext.PowerChangeState.PowerDown) + { + case PowerDownDeviceInitial: + case PowerDownDeviceQuiesced: + case PowerDownDeviceStopped: + break; + + case PowerDownDeviceLocked: + // Case of issuing SYNC CACHE command. Do not use power irp timeout remaining time in this case + // as we want to give best try on SYNC CACHE command. + retryCount = MAXIMUM_RETRIES; + timeoutValue = DeviceExtension->TimeOutValue; + break; + + case PowerDownDeviceFlushed: + { + // Case of issuing STOP UNIT command + // As "Imme" bit is set to '1', this command should be completed in short time. + // This command is at low importance, failure of this command has very small impact. + ULONG secondsRemaining = 0; + +#if (WINVER >= 0x0601) + // this API is introduced in Windows7 + PoQueryWatchdogTime(DeviceExtension->LowerPdo, &secondsRemaining); +#endif + + if (secondsRemaining == 0) + { + // not able to retrieve remaining time from PoQueryWatchdogTime API, use default values. + retryCount = MAXIMUM_RETRIES; + timeoutValue = SCSI_CDROM_TIMEOUT; + } + else + { + // plan to leave about 30 seconds to lower level drivers if possible. + if (secondsRemaining >= 32) + { + retryCount = (secondsRemaining - 30)/SCSI_CDROM_TIMEOUT + 1; + timeoutValue = SCSI_CDROM_TIMEOUT; + + if (retryCount > MAXIMUM_RETRIES) + { + retryCount = MAXIMUM_RETRIES; + } + + if (retryCount == 1) + { + timeoutValue = secondsRemaining - 30; + } + } + else + { + // issue the command with minimal timeout value and do not retry on it. + retryCount = 1; + timeoutValue = 2; + } + } + } + break; + default: + NT_ASSERT( FALSE ); + status = STATUS_NOT_IMPLEMENTED; + return status; + } + + DeviceExtension->PowerContext.RetryCount = retryCount; + + // issue command. + while (shouldRetry) + { + + // set SRB fields. + DeviceExtension->PowerContext.Srb.SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER | + SRB_FLAGS_DISABLE_SYNCH_TRANSFER | + SRB_FLAGS_NO_QUEUE_FREEZE | + SRB_FLAGS_BYPASS_LOCKED_QUEUE | + SRB_FLAGS_D3_PROCESSING; + + DeviceExtension->PowerContext.Srb.Function = SRB_FUNCTION_EXECUTE_SCSI; + DeviceExtension->PowerContext.Srb.TimeOutValue = timeoutValue; + + if (DeviceExtension->PowerContext.PowerChangeState.PowerDown == PowerDownDeviceInitial) + { + DeviceExtension->PowerContext.Srb.Function = SRB_FUNCTION_LOCK_QUEUE; + } + else if (DeviceExtension->PowerContext.PowerChangeState.PowerDown == PowerDownDeviceLocked) + { + DeviceExtension->PowerContext.Srb.Function = SRB_FUNCTION_QUIESCE_DEVICE; + } + else if (DeviceExtension->PowerContext.PowerChangeState.PowerDown == PowerDownDeviceQuiesced) + { + // Case of issuing SYNC CACHE command. + DeviceExtension->PowerContext.Srb.CdbLength = 10; + cdb->SYNCHRONIZE_CACHE10.OperationCode = SCSIOP_SYNCHRONIZE_CACHE; + } + else if (DeviceExtension->PowerContext.PowerChangeState.PowerDown == PowerDownDeviceFlushed) + { + // Case of issuing STOP UNIT command. + DeviceExtension->PowerContext.Srb.CdbLength = 6; + cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT; + cdb->START_STOP.Start = 0; + cdb->START_STOP.Immediate = 1; + } + else if (DeviceExtension->PowerContext.PowerChangeState.PowerDown == PowerDownDeviceStopped) + { + DeviceExtension->PowerContext.Srb.Function = SRB_FUNCTION_UNLOCK_QUEUE; + } + + // Set up completion routine and context if requested + if (CompletionRoutine) + { + WdfRequestSetCompletionRoutine(DeviceExtension->PowerContext.PowerRequest, + CompletionRoutine, + Context); + } + + status = RequestSend(DeviceExtension, + DeviceExtension->PowerContext.PowerRequest, + DeviceExtension->IoTarget, + CompletionRoutine ? 0 : WDF_REQUEST_SEND_OPTION_SYNCHRONOUS, + &requestSent); + + if (requestSent) + { + if ((CompletionRoutine == NULL) && + (SRB_STATUS(DeviceExtension->PowerContext.Srb.SrbStatus) != SRB_STATUS_SUCCESS)) + { + TracePrint((TRACE_LEVEL_ERROR, + TRACE_FLAG_POWER, + "%p\tError occured when issuing %s command to device. Srb %p, Status %x\n", + DeviceExtension->PowerContext.PowerRequest, + (DeviceExtension->PowerContext.PowerChangeState.PowerDown == PowerDownDeviceQuiesced) ? "SYNC CACHE" : "STOP UNIT", + &DeviceExtension->PowerContext.Srb, + DeviceExtension->PowerContext.Srb.SrbStatus)); + + NT_ASSERT(!(TEST_FLAG(DeviceExtension->PowerContext.Srb.SrbStatus, SRB_STATUS_QUEUE_FROZEN))); + + shouldRetry = RequestSenseInfoInterpret(DeviceExtension, + DeviceExtension->PowerContext.PowerRequest, + &(DeviceExtension->PowerContext.Srb), + retryCount - DeviceExtension->PowerContext.RetryCount, + &status, + &(DeviceExtension->PowerContext.RetryIntervalIn100ns)); + + if (shouldRetry && (DeviceExtension->PowerContext.RetryCount-- == 0)) + { + shouldRetry = FALSE; + } + } + else + { + // succeeded, do not need to retry. + shouldRetry = FALSE; + } + + } + else + { + // request failed to be sent + shouldRetry = FALSE; + } + + if (shouldRetry) + { + LARGE_INTEGER t; + t.QuadPart = -DeviceExtension->PowerContext.RetryIntervalIn100ns; + KeDelayExecutionThread(KernelMode, FALSE, &t); + + status = PowerContextReuseRequest(DeviceExtension); + if (!NT_SUCCESS(status)) + { + shouldRetry = FALSE; + } + } + } + + if (DeviceExtension->PowerContext.PowerChangeState.PowerDown == PowerDownDeviceQuiesced) + { + // record SYNC CACHE command completion time stamp. + KeQueryTickCount(&DeviceExtension->PowerContext.Step1CompleteTime); + } + + return status; +} + +NTSTATUS +RequestSend( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDFIOTARGET IoTarget, + _In_ ULONG Flags, + _Out_opt_ PBOOLEAN RequestSent + ) +/*++ + +Routine Description: + + Send the request to the target, wake up the device from Zero Power state if necessary. + +Arguments: + + DeviceExtension - device extension + Request - the request to be sent + IoTarget - target of the above request + Flags - flags for the operation + RequestSent - optional, if the request was sent + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + BOOLEAN requestSent = FALSE; + WDF_REQUEST_SEND_OPTIONS options; + + UNREFERENCED_PARAMETER(DeviceExtension); + + if ((DeviceExtension->ZeroPowerODDInfo != NULL) && + (DeviceExtension->ZeroPowerODDInfo->InZeroPowerState != FALSE)) + { + } + + // Now send down the request + if (NT_SUCCESS(status)) + { + WDF_REQUEST_SEND_OPTIONS_INIT(&options, Flags); + + RequestSetSentTime(Request); + + // send request and check status + + // Disable SDV warning about infinitely waiting in caller's context: + // 1. Some requests (such as SCSI_PASS_THROUGH, contains buffer from user space) need to be sent down in caller’s context. + // Consequently, these requests wait in caller’s context until they are allowed to be sent down. + // 2. Considering the situation that during sleep, a request can be hold by storage port driver. When system resumes, any time out value (if we set using KMDF time out value) might be expires. + // This will cause the waiting request being failed (behavior change). We’d rather not set time out value. + + _Analysis_assume_(options.Timeout != 0); + requestSent = WdfRequestSend(Request, IoTarget, &options); + _Analysis_assume_(options.Timeout == 0); + + // If WdfRequestSend fails, or if the WDF_REQUEST_SEND_OPTION_SYNCHRONOUS flag is set, + // the driver can call WdfRequestGetStatus immediately after calling WdfRequestSend. + if ((requestSent == FALSE) || + (Flags & WDF_REQUEST_SEND_OPTION_SYNCHRONOUS)) + { + status = WdfRequestGetStatus(Request); + + if (requestSent == FALSE) + { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, + "WdfRequestSend failed: %lx\n", + status + )); + } + } + else + { + status = STATUS_SUCCESS; + } + + if (RequestSent != NULL) + { + *RequestSent = requestSent; + } + } + + return status; +} + diff --git a/storage/class/cdrom/src/data.c b/storage/class/cdrom/src/data.c new file mode 100644 index 00000000..72ec53b8 --- /dev/null +++ b/storage/class/cdrom/src/data.c @@ -0,0 +1,283 @@ +/*++ + +Copyright (C) Microsoft Corporation. All rights reserved. + +Module Name: + + +Abstract: + + +Environment: + + +Notes: + +Revision History: + +--*/ + +#include "ntddk.h" +#include "cdrom.h" + + +#ifdef ALLOC_DATA_PRAGMA +#pragma data_seg("PAGEDATA") +#endif + +/* + +#define CDROM_HACK_DEC_RRD (0x00000001) +#define CDROM_HACK_FUJITSU_FMCD_10x (0x00000002) + #define CDROM_HACK_HITACHI_1750 (0x00000004) - obsolete. +#define CDROM_HACK_HITACHI_GD_2000 (0x00000008) +#define CDROM_HACK_TOSHIBA_SD_W1101 (0x00000010) + #define CDROM_HACK_TOSHIBA_XM_3xx (0x00000020) - obsolete. +#define CDROM_HACK_NEC_CDDA (0x00000040) +#define CDROM_HACK_PLEXTOR_CDDA (0x00000080) +#define CDROM_HACK_BAD_GET_CONFIG_SUPPORT (0x00000100) +#define CDROM_HACK_FORCE_READ_CD_DETECTION (0x00000200) +#define CDROM_HACK_READ_CD_SUPPORTED (0x00000400) + +*/ + +CDROM_SCAN_FOR_SPECIAL_INFO CdromHackItems[] = { + // digital put out drives using 512 byte block sizes, + // and needed us to send a mode page to set the sector + // size back to 2048. + { "DEC" , "RRD" , NULL, 0x0001 }, + // these fujitsu drives take longer than ten seconds to + // timeout commands when audio discs are placed in them + { "FUJITSU" , "FMCD-101" , NULL, 0x0002 }, + { "FUJITSU" , "FMCD-102" , NULL, 0x0002 }, + // these hitachi drives don't work properly in PIO mode + //{ "HITACHI ", "CDR-1750S" , NULL, 0x0004 }, + //{ "HITACHI ", "CDR-3650/1650S" , NULL, 0x0004 }, + // this particular gem doesn't automatcially spin up + // on some media access commands. + { "" , "HITACHI GD-2000" , NULL, 0x0008 }, + { "" , "HITACHI DVD-ROM GD-2000" , NULL, 0x0008 }, + // this particular drive doesn't support DVD playback. + // just print an error message in CHK builds. + { "TOSHIBA ", "SD-W1101 DVD-RAM" , NULL, 0x0010 }, + // not sure what this device's issue was. seems to + // require mode selects at various times. + //{ "TOSHIBA ", "CD-ROM XM-3" , NULL, 0x0020 }, + // NEC defined a "READ_CD" type command before there was + // a standard, so fall back on this as an option. + { "NEC" , NULL , NULL, 0x0040 }, + // plextor defined a "READ_CD" type command before there was + // a standard, so fall back on this as an option. + { "PLEXTOR ", NULL , NULL, 0x0080 }, + // this drive times out and sometimes disappears from the bus + // when send GET_CONFIGURATION commands. don't send them. + { "" , "LG DVD-ROM DRD-840B" , NULL, 0x0100 }, + { "" , "SAMSUNG DVD-ROM SD-608" , NULL, 0x0300 }, + // these drives should have supported READ_CD, but at least + // some firmware revisions did not. force READ_CD detection. + { "" , "SAMSUNG DVD-ROM SD-" , NULL, 0x0200 }, + // the mitsumi drive below doesn't follow the block-only spec, + // and we end up hanging when sending it commands it doesn't + // understand. this causes complications later, also. + { "MITSUMI ", "CR-4802TE " , NULL, 0x0100 }, + // some drives return various funky errors (such as 3/2/0 NO_SEEK_COMPLETE) + // during the detection of READ_CD support, resulting in iffy detection. + // since they probably don't support mode switching, which is really old + // legacy stuff anyways, the ability to read digitally is lost when + // these drives return unexpected error codes. note: MMC compliant drives + // are presumed to support READ_CD, as are DVD drives, and anything + // connected to a bus type other than IDE or SCSI, and therefore don't + // need to be here. + { "YAMAHA ", "CRW8424S " , NULL, 0x0400 }, + // Polling frequently on virtual optical devices created by Hyper-V will + // cause a significant perf / power hit. These devices need to be polled + // less frequently for device state changes. + { "MSFT ", NULL , NULL, 0x2000 }, + // and finally, a place to finish the list. :) + { NULL , NULL , NULL, 0x0000 } +}; + +CDROM_SCAN_FOR_SPECIAL_INFO CdRomBadItems[] = { // Type (HH, slim) + WHQL Date, if known + { "" , "MITSUMI CD-ROM FX240" , NULL , 0x02 }, + { "" , "MITSUMI CD-ROM FX320" , NULL , 0x02 }, + { "" , "MITSUMI CD-ROM FX322" , NULL , 0x02 }, + { "" , "TEAC DV-28E-A" , "2.0A", 0x02 }, + { "" , "HP CD-Writer cd16h" , "Q000", 0x02 }, + { "" , "_NEC NR-7800A" , "1.33", 0x02 }, + { "" , "COMPAQ CRD-8481B" , NULL , 0x04 }, + // The following is a list of device that report too many OpChange/Add events. + // They require ignoring (or not sending) the OpChange flag in the GESN command. + // This list contains vendor ID and product ID as separate strings for USB/1394 interface. + { "HL-DT-ST", "DVDRAM GMA-4020B" , NULL , 0x10 }, // hh , 2002/04/22 + { "HL-DT-ST", "DVD-RW GCA-4020B" , NULL , 0x10 }, // hh , 2002/05/14 + { "HL-DT-ST", "DVDRAM GSA-4040B" , NULL , 0x10 }, // hh , 2003/05/06 + { "HL-DT-ST", "DVDRAM GMA-4040B" , NULL , 0x10 }, // hh , 2003/07/27 + { "HL-DT-ST", "DVD-RW GWA-4040B" , NULL , 0x10 }, // hh , 2003/11/18 + { "HL-DT-ST", "DVDRAM GSA-4081B" , NULL , 0x10 }, // hh , 2003/11/06 + { "HL-DT-ST", "DVDRAM GSA-4082B" , NULL , 0x10 }, // hh , 2004/01/27 + { "HL-DT-ST", "DVD-RW GWA-4082B" , NULL , 0x10 }, // hh , 2004/03/11 + { "HL-DT-ST", "DVDRAM GSA-4120B" , NULL , 0x10 }, // hh , 2004/05/16 + { "HL-DT-ST", "DVD+RW GRA-4120B" , NULL , 0x10 }, // hh , 2004/04/28 + { "HL-DT-ST", "DVDRAM GSA-4160B" , NULL , 0x10 }, // hh , 2004/08/12 + { "HL-DT-ST", "DVD-RW GWA-4160B" , NULL , 0x10 }, // hh , 2004/08/24 + { "HL-DT-ST", "DVDRAM GSA-4163B" , NULL , 0x10 }, // hh , 2004/11/09 + { "HL-DT-ST", "DVD-RW GWA-4163B" , NULL , 0x10 }, // hh , 2004/12/29 + { "HL-DT-ST", "DVDRAM GSA-4165B" , NULL , 0x10 }, // hh , 2005/06/09 + { "HL-DT-ST", "DVDRAM_GSA-4165B" , NULL , 0x10 }, // hh , 2005/06/28 + { "HL-DT-ST", "DVD-RW GWA-4165B" , NULL , 0x10 }, // hh , 2005/08/23 + { "HL-DT-ST", "DVDRAM GSA-4167B" , NULL , 0x10 }, // hh , 2005/07/01 + { "HL-DT-ST", "DVDRAM GSA-H10N" , NULL , 0x10 }, // hh , 2006/02/16 + { "HL-DT-ST", "DVDRAM_GSA-H10N" , NULL , 0x10 }, // hh , 2006/02/16 + { "HL-DT-ST", "DVDRAM GSA-H10L" , NULL , 0x10 }, // hh , 2006/02/27 + { "HL-DT-ST", "DVDRAM_GSA-H10L" , NULL , 0x10 }, // hh , 2006/04/21 + { "HL-DT-ST", "DVDRAM GSA-H10A" , NULL , 0x10 }, // hh , 2006/01/03 + { "HL-DT-ST", "DVDRAM_GSA-H10A" , NULL , 0x10 }, // hh , 2006/05/14 + { "HL-DT-ST", "DVD-RW GSA-H11N" , NULL , 0x10 }, // hh , 2006/04/28 + { "HL-DT-ST", "DVD-RW_GSA-H11N" , NULL , 0x10 }, // hh , 2006/02/22 + + { "HL-DT-ST", "DVDRAM GSA-4080N" , NULL , 0x10 }, // slim, 2004/08/08 + { "HL-DT-ST", "DVDRAM GMA-4080N" , NULL , 0x10 }, // slim, 2004/11/09 + { "HL-DT-ST", "DVD-RW GCA-4080N" , NULL , 0x10 }, // slim, 2004/11/22 + { "HL-DT-ST", "DVD-RW GWA-4080N" , NULL , 0x10 }, // slim, 2004/08/17 + { "HL-DT-ST", "DVDRAM GSA-4082N" , NULL , 0x10 }, // slim, 2005/07/12 + { "HL-DT-ST", "DVDRAM_GSA-4082N" , NULL , 0x10 }, // slim, 2005/09/21 + { "HL-DT-ST", "DVDRAM GMA-4082N" , NULL , 0x10 }, // slim, 2005/10/20 + { "HL-DT-ST", "DVD-RW GRA-4082N" , NULL , 0x10 }, // slim, 2006/06/07 + { "HL-DT-ST", "DVD-RW GWA-4082N" , NULL , 0x10 }, // slim, 2005/05/24 + { "HL-DT-ST", "DVDRAM GMA4082Nf" , NULL , 0x10 }, // slim, 2006/02/28 + { "HL-DT-ST", "DVDRAM GMA4082Nj" , NULL , 0x10 }, // slim, 2006/01/26 + + { "HL-DT-ST", "DVDRAM GSA-4084N" , NULL , 0x10 }, // slim, 2005/12/21 + { "HL-DT-ST", "DVDRAM GMA-4084N" , NULL , 0x10 }, // slim, 2006/02/15 + { "HP" , "DVD Writer 550s" , NULL , 0x10 }, // slim, 2006/05/08 + { "HL-DT-ST", "DVDRAM GSA-T10N" , NULL , 0x10 }, // slim, 2006/07/26 + { "HL-DT-ST", "DVDRAM_GSA-T10N" , NULL , 0x10 }, // slim, 2006/07/26 + { "HL-DT-ST", "DVD+-RW GSA-T11N" , NULL , 0x10 }, // slim, 2006/07/25 + + { "HL-DT-ST", "DVD-ROM GDR8160B" , NULL , 0x10 }, // hh , 2001/10/12 + { "COMPAQ" , "DVD-ROM GDR8160B" , NULL , 0x10 }, // hh , 2001/11/08 + { "HL-DT-ST", "DVD-ROM GDR8161B" , NULL , 0x10 }, // hh , 2002/07/19 + { "HL-DT-ST", "DVD-ROM GDR8162B" , NULL , 0x10 }, // hh , 2003/04/22 + { "HL-DT-ST", "DVD-ROM GDR8163B" , NULL , 0x10 }, // hh , 2004/05/19 + { "HL-DT-ST", "DVD-ROM GDR8164B" , NULL , 0x10 }, // hh , 2005/06/29 + { "HL-DT-ST", "DVD-ROM GDRH10N" , NULL , 0x10 }, // hh , 2006/03/07 + + { "HL-DT-ST", "DVD-ROM GDR8081N" , NULL , 0x10 }, // slim, 2001/08/27 + { "HL-DT-ST", "DVD-ROM GDR8082N" , NULL , 0x10 }, // slim, 2003/02/02 + { "HL-DT-ST", "DVD-ROM GDR8083N" , NULL , 0x10 }, // slim, 2003/02/02 + { "HL-DT-ST", "DVD-ROM GDR8085N" , NULL , 0x10 }, // slim, 2005/11/10 + + { "HL-DT-ST", "RW/DVD GCC-4080N" , NULL , 0x10 }, // slim, 2001/08/21 + { "HL-DT-ST", "RW/DVD_GCC-4080N" , NULL , 0x10 }, // slim, + { "HL-DT-ST", "RW/DVD GCC-4160N" , NULL , 0x10 }, // slim, 2002/04/08 + { "HL-DT-ST", "RW/DVD GCC-4240N" , NULL , 0x10 }, // slim, 2002/04/26 + { "HL-DT-ST", "RW/DVD GCC-4241N" , NULL , 0x10 }, // slim, 2003/04/07 + { "HL-DT-ST", "RW/DVD_GCC-4241N" , NULL , 0x10 }, // slim, 2004/03/07 + { "HL-DT-ST", "RW/DVD GCC-4242N" , NULL , 0x10 }, // slim, 2003/12/21 + { "HL-DT-ST", "RW/DVD GCC-4246N" , NULL , 0x10 }, // slim, 2005/05/23 + { "HL-DT-ST", "BD-RE GBW-H10N" , NULL , 0x10 }, // hh , 2006/06/27 + + { "HL-DT-ST", "DVDRAM GSA-4083N" , NULL , 0x10 }, // hh , 2006/05/17 + { "HL-DT-ST", "DVD+-RW GWA4083N" , NULL , 0x10 }, // hh , 2006/06/05 + + { "PIONEER", "DVD-RW DVR-106D" , NULL , 0x10 }, // hh , ? + { "ASUS", "DVD-RW DRW-0402P" , NULL , 0x10 }, // hh , ? + + // + // This list contains devices that claims to support asynchronous notification, but + // doesn't handle it well (e.g., some TSST devices will not report media removal if + // the GESN command is sent down immediately after the AN interrupt, they need some + // time in between to be able to correctly report media removal). + // + + { "TSSTcorp", "CDDVDW SN-S083A" , "SB00", 0x40 }, // slim, ? + + // + // This list contains vendor ID and product ID as a single string for ATAPI interface. + // + + { "", "HL-DT-ST DVDRAM GMA-4020B" , NULL , 0x10 }, // hh , 2002/04/22 + { "", "HL-DT-ST DVD-RW GCA-4020B" , NULL , 0x10 }, // hh , 2002/05/14 + { "", "HL-DT-ST DVDRAM GSA-4040B" , NULL , 0x10 }, // hh , 2003/05/06 + { "", "HL-DT-ST DVDRAM GMA-4040B" , NULL , 0x10 }, // hh , 2003/07/27 + { "", "HL-DT-ST DVD-RW GWA-4040B" , NULL , 0x10 }, // hh , 2003/11/18 + { "", "HL-DT-ST DVDRAM GSA-4081B" , NULL , 0x10 }, // hh , 2003/11/06 + { "", "HL-DT-ST DVDRAM GSA-4082B" , NULL , 0x10 }, // hh , 2004/01/27 + { "", "HL-DT-ST DVD-RW GWA-4082B" , NULL , 0x10 }, // hh , 2004/03/11 + { "", "HL-DT-ST DVDRAM GSA-4120B" , NULL , 0x10 }, // hh , 2004/05/16 + { "", "HL-DT-ST DVD+RW GRA-4120B" , NULL , 0x10 }, // hh , 2004/04/28 + { "", "HL-DT-ST DVDRAM GSA-4160B" , NULL , 0x10 }, // hh , 2004/08/12 + { "", "HL-DT-ST DVD-RW GWA-4160B" , NULL , 0x10 }, // hh , 2004/08/24 + { "", "HL-DT-ST DVDRAM GSA-4163B" , NULL , 0x10 }, // hh , 2004/11/09 + { "", "HL-DT-ST DVD-RW GWA-4163B" , NULL , 0x10 }, // hh , 2004/12/29 + { "", "HL-DT-ST DVDRAM GSA-4165B" , NULL , 0x10 }, // hh , 2005/06/09 + { "", "HL-DT-ST DVDRAM_GSA-4165B" , NULL , 0x10 }, // hh , 2005/06/28 + { "", "HL-DT-ST DVD-RW GWA-4165B" , NULL , 0x10 }, // hh , 2005/08/23 + { "", "HL-DT-ST DVDRAM GSA-4167B" , NULL , 0x10 }, // hh , 2005/07/01 + { "", "HL-DT-ST DVDRAM GSA-H10N" , NULL , 0x10 }, // hh , 2006/02/16 + { "", "HL-DT-ST DVDRAM_GSA-H10N" , NULL , 0x10 }, // hh , 2006/02/16 + { "", "HL-DT-ST DVDRAM GSA-H10L" , NULL , 0x10 }, // hh , 2006/02/27 + { "", "HL-DT-ST DVDRAM_GSA-H10L" , NULL , 0x10 }, // hh , 2006/04/21 + { "", "HL-DT-ST DVDRAM GSA-H10A" , NULL , 0x10 }, // hh , 2006/01/03 + { "", "HL-DT-ST DVDRAM_GSA-H10A" , NULL , 0x10 }, // hh , 2006/05/14 + { "", "HL-DT-ST DVD-RW GSA-H11N" , NULL , 0x10 }, // hh , 2006/04/28 + { "", "HL-DT-ST DVD-RW_GSA-H11N" , NULL , 0x10 }, // hh , 2006/02/22 + + { "", "HL-DT-ST DVDRAM GSA-4080N" , NULL , 0x10 }, // slim, 2004/08/08 + { "", "HL-DT-ST DVDRAM GMA-4080N" , NULL , 0x10 }, // slim, 2004/11/09 + { "", "HL-DT-ST DVD-RW GCA-4080N" , NULL , 0x10 }, // slim, 2004/11/22 + { "", "HL-DT-ST DVD-RW GWA-4080N" , NULL , 0x10 }, // slim, 2004/08/17 + { "", "HL-DT-ST DVDRAM GSA-4082N" , NULL , 0x10 }, // slim, 2005/07/12 + { "", "HL-DT-ST DVDRAM_GSA-4082N" , NULL , 0x10 }, // slim, 2005/09/21 + { "", "HL-DT-ST DVDRAM GMA-4082N" , NULL , 0x10 }, // slim, 2005/10/20 + { "", "HL-DT-ST DVD-RW GRA-4082N" , NULL , 0x10 }, // slim, 2006/06/07 + { "", "HL-DT-ST DVD-RW GWA-4082N" , NULL , 0x10 }, // slim, 2005/05/24 + { "", "HL-DT-ST DVDRAM GMA4082Nf" , NULL , 0x10 }, // slim, 2006/02/28 + { "", "HL-DT-ST DVDRAM GMA4082Nj" , NULL , 0x10 }, // slim, 2006/01/26 + + { "", "HL-DT-ST DVDRAM GSA-4084N" , NULL , 0x10 }, // slim, 2005/12/21 + { "", "HL-DT-ST DVDRAM GMA-4084N" , NULL , 0x10 }, // slim, 2006/02/15 + { "", "HP DVD Writer 550s" , NULL , 0x10 }, // slim, 2006/05/08 + { "", "HL-DT-ST DVDRAM GSA-T10N" , NULL , 0x10 }, // slim, 2006/07/26 + { "", "HL-DT-ST DVDRAM_GSA-T10N" , NULL , 0x10 }, // slim, 2006/07/26 + { "", "HL-DT-ST DVD+-RW GSA-T11N" , NULL , 0x10 }, // slim, 2006/07/25 + + { "", "HL-DT-ST DVD-ROM GDR8160B" , NULL , 0x10 }, // hh , 2001/10/12 + { "", "COMPAQ DVD-ROM GDR8160B" , NULL , 0x10 }, // hh , 2001/11/08 + { "", "HL-DT-ST DVD-ROM GDR8161B" , NULL , 0x10 }, // hh , 2002/07/19 + { "", "HL-DT-ST DVD-ROM GDR8162B" , NULL , 0x10 }, // hh , 2003/04/22 + { "", "HL-DT-ST DVD-ROM GDR8163B" , NULL , 0x10 }, // hh , 2004/05/19 + { "", "HL-DT-ST DVD-ROM GDR8164B" , NULL , 0x10 }, // hh , 2005/06/29 + { "", "HL-DT-ST DVD-ROM GDRH10N" , NULL , 0x10 }, // hh , 2006/03/07 + + { "", "HL-DT-ST DVD-ROM GDR8081N" , NULL , 0x10 }, // slim, 2001/08/27 + { "", "HL-DT-ST DVD-ROM GDR8082N" , NULL , 0x10 }, // slim, 2003/02/02 + { "", "HL-DT-ST DVD-ROM GDR8083N" , NULL , 0x10 }, // slim, 2003/02/02 + { "", "HL-DT-ST DVD-ROM GDR8085N" , NULL , 0x10 }, // slim, 2005/11/10 + + { "", "HL-DT-ST RW/DVD GCC-4080N" , NULL , 0x10 }, // slim, 2001/08/21 + { "", "HL-DT-ST RW/DVD_GCC-4080N" , NULL , 0x10 }, // slim, + { "", "HL-DT-ST RW/DVD GCC-4160N" , NULL , 0x10 }, // slim, 2002/04/08 + { "", "HL-DT-ST RW/DVD GCC-4240N" , NULL , 0x10 }, // slim, 2002/04/26 + { "", "HL-DT-ST RW/DVD GCC-4241N" , NULL , 0x10 }, // slim, 2003/04/07 + { "", "HL-DT-ST RW/DVD_GCC-4241N" , NULL , 0x10 }, // slim, 2004/03/07 + { "", "HL-DT-ST RW/DVD GCC-4242N" , NULL , 0x10 }, // slim, 2003/12/21 + { "", "HL-DT-ST RW/DVD GCC-4246N" , NULL , 0x10 }, // slim, 2005/05/23 + { "", "HL-DT-ST BD-RE GBW-H10N" , NULL , 0x10 }, // hh , 2006/06/27 + + { "", "HL-DT-ST DVDRAM GSA-4083N" , NULL , 0x10 }, // hh , 2006/05/17 + { "", "HL-DT-ST DVD+-RW GWA4083N" , NULL , 0x10 }, // hh , 2006/06/05 + + { "", "PIONEER DVD-RW DVR-106D" , NULL , 0x10 }, // hh , ? + { "", "ASUS DVD-RW DRW-0402P" , NULL , 0x10 }, // hh , ? + + + // Sony sourced some drives from LG also.... + + { NULL , NULL , NULL , 0x00 }, +}; + + +#ifdef ALLOC_DATA_PRAGMA +#pragma data_seg() +#endif diff --git a/storage/class/cdrom/src/guid.c b/storage/class/cdrom/src/guid.c new file mode 100644 index 00000000..8af1f877 --- /dev/null +++ b/storage/class/cdrom/src/guid.c @@ -0,0 +1,16 @@ +/*-- +Copyright (C) Microsoft Corporation. All rights reserved. +--*/ + +#include "initguid.h" +#include "ntddk.h" +#include "ntddstor.h" +#include "mountmgr.h" +#include "ioevent.h" +#include "devpkey.h" +#include "wdmguid.h" + +// no code, just GUIDs being defined + + + diff --git a/storage/class/cdrom/src/init.c b/storage/class/cdrom/src/init.c new file mode 100644 index 00000000..2c8bbd38 --- /dev/null +++ b/storage/class/cdrom/src/init.c @@ -0,0 +1,2741 @@ +/*-- + +Copyright (C) Microsoft Corporation. All rights reserved. + +Module Name: + + init.c + +Abstract: + + Initialization routines for CDROM + +Environment: + + kernel mode only + +Notes: + + +Revision History: + +--*/ + + +#include "ntddk.h" +#include "ntddstor.h" +#include "ntstrsafe.h" +#include "devpkey.h" + +#include "cdrom.h" +#include "scratch.h" +#include "mmc.h" + +#ifdef DEBUG_USE_WPP +#include "init.tmh" +#endif + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DeviceInitAllocateBuffers( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +DeviceRetrieveScsiAddress( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ PSCSI_ADDRESS ScsiAddress + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +DeviceRetrieveDescriptorsAndTransferLength( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension + ); + +_IRQL_requires_max_(APC_LEVEL) +VOID +DeviceScanSpecialDevices( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +DeviceInitMmcContext( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +DeviceGetMmcSupportInfo( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _Out_ PBOOLEAN IsMmcDevice + ); + +#if (NTDDI_VERSION >= NTDDI_WIN8) +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +DeviceIsPortable( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _Out_ PBOOLEAN IsPortable + ); +#endif + + +#ifdef ALLOC_PRAGMA + +#pragma alloc_text(PAGE, DeviceClaimRelease) +#pragma alloc_text(PAGE, DeviceEvtSelfManagedIoInit) + +#pragma alloc_text(PAGE, DeviceInitReleaseQueueContext) +#pragma alloc_text(PAGE, DeviceInitAllocateBuffers) +#pragma alloc_text(PAGE, DeviceInitPowerContext) +#pragma alloc_text(PAGE, DeviceCreateWellKnownName) +#pragma alloc_text(PAGE, DeviceRetrieveScsiAddress) +#pragma alloc_text(PAGE, DeviceRetrieveDescriptorsAndTransferLength) +#pragma alloc_text(PAGE, DeviceInitializeHotplugInfo) +#pragma alloc_text(PAGE, DeviceScanSpecialDevices) +#pragma alloc_text(PAGE, DeviceGetTimeOutValueFromRegistry) +#pragma alloc_text(PAGE, DeviceGetMmcSupportInfo) +#pragma alloc_text(PAGE, DeviceRetrieveDescriptor) +#pragma alloc_text(PAGE, DeviceRetrieveHackFlagsFromRegistry) +#pragma alloc_text(PAGE, DeviceScanForSpecial) +#pragma alloc_text(PAGE, DeviceHackFlagsScan) +#pragma alloc_text(PAGE, DeviceInitMmcContext) +#pragma alloc_text(PAGE, ScanForSpecialHandler) +#pragma alloc_text(PAGE, DeviceSetRawReadInfo) +#pragma alloc_text(PAGE, DeviceInitializeDvd) +#pragma alloc_text(PAGE, DeviceCacheDeviceInquiryData) + +#if (NTDDI_VERSION >= NTDDI_WIN8) +#pragma alloc_text(PAGE, DeviceIsPortable) +#endif + +#endif + +#pragma warning(push) +#pragma warning(disable:4152) // nonstandard extension, function/data pointer conversion in expression +#pragma warning(disable:26000) // read overflow reported because of pointer type conversion + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +DeviceClaimRelease( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ BOOLEAN Release + ) +/*++ + +Routine Description: + + This function claims a device in the port driver. The port driver object + is updated with the correct driver object if the device is successfully + claimed. + +Arguments: + + Device - The WDFDEVICE that needs to be claimed or released. + + Release - Indicates the logical unit should be released rather than claimed. + +Return Value: + + Returns a status indicating success or failure of the operation. + +--*/ +{ + NTSTATUS status; + SCSI_REQUEST_BLOCK srb = {0}; + WDF_MEMORY_DESCRIPTOR descriptor; + WDFREQUEST request; + WDF_OBJECT_ATTRIBUTES attributes; + + PAGED_CODE(); + + //Create a request + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, + CDROM_REQUEST_CONTEXT); + + status = WdfRequestCreate(&attributes, + DeviceExtension->IoTarget, + &request); + + if (NT_SUCCESS(status)) + { + //fill up srb structure + srb.OriginalRequest = WdfRequestWdmGetIrp(request); + NT_ASSERT(srb.OriginalRequest != NULL); + + srb.Length = sizeof(SCSI_REQUEST_BLOCK); + + srb.Function = Release + ? SRB_FUNCTION_RELEASE_DEVICE + : SRB_FUNCTION_CLAIM_DEVICE; + + + WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&descriptor, + &srb, + sizeof(srb)); + + status = WdfIoTargetSendInternalIoctlOthersSynchronously(DeviceExtension->IoTarget, + request, + IOCTL_SCSI_EXECUTE_NONE, + &descriptor, + NULL, + NULL, + NULL, + NULL); + + NT_ASSERT(!TEST_FLAG(srb.SrbFlags, SRB_FLAGS_FREE_SENSE_BUFFER)); + + // The request should be deleted. + WdfObjectDelete(request); + + if (!NT_SUCCESS(status)) + { + TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_PNP, + "DeviceClaimRelease: Failed to %s device, status: 0x%X\n", + Release ? "Release" : "Claim", + status)); + } + } + else + { + TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_PNP, + "DeviceClaimRelease: Failed to create request, status: 0x%X\n", + status)); + } + + if (Release) + { + // We only release the device when we don't want to manage it. + // The failure status does not matter. + status = STATUS_SUCCESS; + } + + return status; +} // end DeviceClaimRelease() + + +NTSTATUS +DeviceEvtSelfManagedIoInit( + _In_ WDFDEVICE Device + ) +/*++ + +Routine Description: + + This routine is called only once after the device is added in system, so it's used to do + hardware-dependent device initialization work and resource allocation. + If this routine fails, DeviceEvtSelfManagedIoCleanup will be invoked by the framework. + +Arguments: + + Device - Handle to device object + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PCDROM_DEVICE_EXTENSION deviceExtension = NULL; + + PAGED_CODE(); + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, + "DeviceEvtSelfManagedIoInit: WDFDEVICE %p is being started.\n", + Device)); + + deviceExtension = DeviceGetExtension(Device); + + // 1. Set/retrieve basic information, some of the following operations may depend on it + if (NT_SUCCESS(status)) + { + // We do not care if this function fails, SCSI address is mainly for debugging/tracing purposes. + (VOID) DeviceRetrieveScsiAddress(deviceExtension, &deviceExtension->ScsiAddress); + } + + if (NT_SUCCESS(status)) + { + status = DeviceRetrieveDescriptorsAndTransferLength(deviceExtension); + } + + if (NT_SUCCESS(status)) + { + // This function should be called after DeviceRetrieveDescriptorsAndTransferLength() + // It depends on MaxTransferLenth fields. + status = DeviceInitAllocateBuffers(deviceExtension); + } + + // 2. The following functions depend on the allocated buffers. + + // perf re-enable after failing. Q: Is this one used by cdrom.sys? + if (NT_SUCCESS(status)) + { + // allow perf to be re-enabled after a given number of failed IOs + // require this number to be at least CLASS_PERF_RESTORE_MINIMUM + ULONG t = CLASS_PERF_RESTORE_MINIMUM; + + DeviceGetParameter(deviceExtension, + CLASSP_REG_SUBKEY_NAME, + CLASSP_REG_PERF_RESTORE_VALUE_NAME, + &t); + if (t >= CLASS_PERF_RESTORE_MINIMUM) + { + deviceExtension->PrivateFdoData->Perf.ReEnableThreshhold = t; + } + } + + // 3. Retrieve information about special devices and hack flags. + if (NT_SUCCESS(status)) + { + DeviceRetrieveHackFlagsFromRegistry(deviceExtension); + // scan for bad items. + DeviceScanForSpecial(deviceExtension, CdRomBadItems, DeviceHackFlagsScan); + // Check to see if it's a special device that needs special error process. + DeviceScanSpecialDevices(deviceExtension); // may send command to device + } + + // 4. Initialize the hotplug information only after the ScanForSpecial routines, + // as it relies upon the hack flags - deviceExtension->PrivateFdoData->HackFlags. + if (NT_SUCCESS(status)) + { + status = DeviceInitializeHotplugInfo(deviceExtension); + } + + if (NT_SUCCESS(status)) + { + // cache the device's inquiry data + status = DeviceCacheDeviceInquiryData(deviceExtension); + if (!NT_SUCCESS(status)) + { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT, + "Failed to cache the device's inquiry data, failng %!STATUS!\n", + status + )); + } + } + + // 5. Initialize MMC context, media change notification stuff and read media capacity + if (NT_SUCCESS(status)) + { + status = DeviceInitializeMediaChangeDetection(deviceExtension); + } + if (NT_SUCCESS(status)) + { + status = DeviceInitMmcContext(deviceExtension); + } + if (NT_SUCCESS(status)) + { + status = DeviceInitializeZPODD(deviceExtension); + } + if (NT_SUCCESS(status)) + { + // Do READ CAPACITY. This SCSI command returns the last sector address + // on the device and the bytes per sector. These are used to calculate + // the drive capacity in bytes. + status = MediaReadCapacity(Device); + + // If READ CAPACITY succeeded, we can safely conclude that there is a media present + if (NT_SUCCESS(status)) + { + DeviceSetMediaChangeStateEx(deviceExtension, + MediaPresent, + NULL); + } + + // READ CAPACITY is not critical for init, ignore all errors occuring during its execution + status = STATUS_SUCCESS; + } + + // 6. Perform DVD-specific initialization + if (NT_SUCCESS(status)) + { + status = DeviceInitializeDvd(Device); + } + + // 7. Miscellaneous initialization actions + if (NT_SUCCESS(status)) + { + if (deviceExtension->PrivateFdoData != NULL) + { + deviceExtension->PrivateFdoData->Perf.OriginalSrbFlags = deviceExtension->SrbFlags; + } + + if (deviceExtension->DeviceAdditionalData.Mmc.IsWriter) + { + // OPC can really take this long per IMAPIv1 timeout.... + deviceExtension->TimeOutValue = max(deviceExtension->TimeOutValue, SCSI_CDROM_OPC_TIMEOUT); + } + } + + // 8. Enable the main timer, create ARC name as needed + if (NT_SUCCESS(status)) + { + // Device successfully added and initialized, increase CdRomCount. + IoGetConfigurationInformation()->CdRomCount++; + + deviceExtension->IsInitialized = TRUE; + + DeviceEnableMainTimer(deviceExtension); + + } + +#if (NTDDI_VERSION >= NTDDI_WIN8) + // 9. Set volume interface properties + if (NT_SUCCESS(status)) + { + BOOLEAN isCritical = FALSE; + BOOLEAN isPortable = FALSE; + BOOLEAN isRemovable = TEST_FLAG(deviceExtension->DeviceObject->Characteristics, FILE_REMOVABLE_MEDIA); + DEVPROP_BOOLEAN propCritical = DEVPROP_FALSE; + DEVPROP_BOOLEAN propPortable = DEVPROP_FALSE; + DEVPROP_BOOLEAN propRemovable = DEVPROP_FALSE; + + status = DeviceIsPortable(deviceExtension, &isPortable); + + if (NT_SUCCESS(status)) + { + if (isPortable) { + SET_FLAG(deviceExtension->DeviceObject->Characteristics, FILE_PORTABLE_DEVICE); + } + + propPortable = isPortable ? DEVPROP_TRUE : DEVPROP_FALSE; + + status = IoSetDeviceInterfacePropertyData(&deviceExtension->MountedDeviceInterfaceName, + &DEVPKEY_Storage_Portable, + 0, + 0, + DEVPROP_TYPE_BOOLEAN, + sizeof(DEVPROP_BOOLEAN), + &propPortable); + } + + if (NT_SUCCESS(status)) + { + propRemovable = isRemovable ? DEVPROP_TRUE : DEVPROP_FALSE; + + status = IoSetDeviceInterfacePropertyData(&deviceExtension->MountedDeviceInterfaceName, + &DEVPKEY_Storage_Removable_Media, + 0, + 0, + DEVPROP_TYPE_BOOLEAN, + sizeof(DEVPROP_BOOLEAN), + &propRemovable); + } + + if (NT_SUCCESS(status)) + { + isCritical = TEST_FLAG(deviceExtension->DeviceObject->Flags, + (DO_SYSTEM_SYSTEM_PARTITION | + DO_SYSTEM_BOOT_PARTITION | + DO_SYSTEM_CRITICAL_PARTITION)); + + propCritical = isCritical ? DEVPROP_TRUE : DEVPROP_FALSE; + + status = IoSetDeviceInterfacePropertyData(&deviceExtension->MountedDeviceInterfaceName, + &DEVPKEY_Storage_System_Critical, + 0, + 0, + DEVPROP_TYPE_BOOLEAN, + sizeof(DEVPROP_BOOLEAN), + &propCritical); + } + + } +#endif + + return status; +} + + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DeviceInitReleaseQueueContext( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension + ) +/*++ + +Routine Description: + + Part of device initialize routine. Initialize ReleaseQueue related stuff. + +Arguments: + + DeviceExtension - device extension of WDFDEVICE. + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + WDF_OBJECT_ATTRIBUTES attributes; + + PAGED_CODE(); + + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, + CDROM_REQUEST_CONTEXT); + attributes.ParentObject = DeviceExtension->Device; + + status = WdfRequestCreate(&attributes, + DeviceExtension->IoTarget, + &(DeviceExtension->ReleaseQueueRequest)); + + if (!NT_SUCCESS(status)) + { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "Cannot create the release queue request\n")); + + return status; + } + + // Initialize ReleaseQueueInputMemory, a wrapper around ReleaseQueueSrb + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + attributes.ParentObject = DeviceExtension->ReleaseQueueRequest; + + status = WdfMemoryCreatePreallocated(&attributes, + &DeviceExtension->ReleaseQueueSrb, + sizeof(SCSI_REQUEST_BLOCK), + &DeviceExtension->ReleaseQueueInputMemory); + if (!NT_SUCCESS(status)) + { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "Failed to allocate ReleaseQueueSrb.\n")); + + return status; + } + + // Preformat the release queue request here to ensure that this call will never + // fail during an actual release of the queue. + if (NT_SUCCESS(status)) + { + status = WdfIoTargetFormatRequestForInternalIoctlOthers(DeviceExtension->IoTarget, + DeviceExtension->ReleaseQueueRequest, + IOCTL_SCSI_EXECUTE_NONE, + DeviceExtension->ReleaseQueueInputMemory, + NULL, + NULL, + NULL, + NULL, + NULL); + } + + // Set a CompletionRoutine callback function for ReleaseQueueRequest. + if (NT_SUCCESS(status)) + { + WdfRequestSetCompletionRoutine(DeviceExtension->ReleaseQueueRequest, + DeviceReleaseQueueCompletion, + DeviceExtension->Device); + } + + // Create a spinlock for ReleaseQueueRequest + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + attributes.ParentObject = DeviceExtension->Device; + + status = WdfSpinLockCreate(&attributes, + &(DeviceExtension->ReleaseQueueSpinLock)); + + if (!NT_SUCCESS(status)) + { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, + "DeviceInitReleaseQueueContext: Cannot create the release queue spinlock\n")); + + return status; + } + + // Initialize miscellaneous ReleaseQueue related fields + DeviceExtension->ReleaseQueueNeeded = FALSE; + DeviceExtension->ReleaseQueueInProgress = FALSE; + DeviceExtension->ReleaseQueueSrb.Length = sizeof(SCSI_REQUEST_BLOCK); + + return status; +} + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DeviceInitPowerContext( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension + ) +/*++ + +Routine Description: + + Part of device initialize routine. Initialize PowerContext related stuff. + +Arguments: + + DeviceExtension - device extension of WDFDEVICE. + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + WDF_OBJECT_ATTRIBUTES attributes; + + PAGED_CODE(); + + // create request object for Power operations + + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, + CDROM_REQUEST_CONTEXT); + attributes.ParentObject = DeviceExtension->Device; + + status = WdfRequestCreate(&attributes, + DeviceExtension->IoTarget, + &(DeviceExtension->PowerContext.PowerRequest) ); + + if (!NT_SUCCESS(status)) + { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "Cannot create the power request object.\n")); + + return status; + } + + // Preformat the power request. With this being done, we never need to worry about + // WdfIoTargetFormatRequestForInternalIoctlOthers ever failing later. + status = WdfIoTargetFormatRequestForInternalIoctlOthers(DeviceExtension->IoTarget, + DeviceExtension->PowerContext.PowerRequest, + IOCTL_SCSI_EXECUTE_IN, + NULL, NULL, + NULL, NULL, + NULL, NULL); + return status; +} + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DeviceCreateWellKnownName( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension + ) +/*++ + +Routine Description: + + This routine creates a symbolic link to the cdrom device object + under \dosdevices. The number of the cdrom device does not neccessarily + match between \dosdevices and \device, but usually will be the same. + + Saves the buffer + +Arguments: + + DeviceObject - + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + UNICODE_STRING unicodeLinkName = {0}; + WCHAR wideLinkName[64] = {0}; + PWCHAR savedName; + + LONG cdromNumber = DeviceExtension->DeviceNumber; + + PAGED_CODE(); + + // if already linked, assert then return + if (DeviceExtension->DeviceAdditionalData.WellKnownName.Buffer != NULL) + { + + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_INIT, + "DeviceCreateWellKnownName: link already exists %p\n", + DeviceExtension->DeviceAdditionalData.WellKnownName.Buffer)); + + NT_ASSERT(FALSE); + + return STATUS_UNSUCCESSFUL; + } + + // find an unused CdRomNN to link to. + // It's doing this way because the same might be used for other device in another driver. + do + { + status = RtlStringCchPrintfW((NTSTRSAFE_PWSTR)wideLinkName, + RTL_NUMBER_OF(wideLinkName), + L"\\DosDevices\\CdRom%d", + cdromNumber); + if (!NT_SUCCESS(status)) + { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_INIT, + "DeviceCreateWellKnownName: Format symbolic link failed with error: 0x%X\n", status)); + return status; + } + + RtlInitUnicodeString(&unicodeLinkName, wideLinkName); + + status = WdfDeviceCreateSymbolicLink(DeviceExtension->Device, + &unicodeLinkName); + + cdromNumber++; + + } while((status == STATUS_OBJECT_NAME_COLLISION) || + (status == STATUS_OBJECT_NAME_EXISTS)); + + if (!NT_SUCCESS(status)) + { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_INIT, + "DeviceCreateWellKnownName: Error %lx linking %wZ to " + "device %wZ\n", + status, + &unicodeLinkName, + &(DeviceExtension->DeviceName))); + return status; + } + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, + "DeviceCreateWellKnownName: successfully linked %wZ " + "to device %wZ\n", + &unicodeLinkName, + &(DeviceExtension->DeviceName))); + + // Save away the symbolic link name in the driver data block. We need + // it so we can delete the link when the device is removed. + savedName = ExAllocatePoolWithTag(PagedPool, + unicodeLinkName.MaximumLength, + CDROM_TAG_STRINGS); + + if (savedName == NULL) + { + // Test Note: test path should excise here to see if the symbolic is deleted by framework. + // IoDeleteSymbolicLink(&unicodeLinkName); + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT, + "DeviceCreateWellKnownName: unable to allocate memory.\n")); + + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlZeroMemory(savedName, unicodeLinkName.MaximumLength); + RtlCopyMemory(savedName, unicodeLinkName.Buffer, unicodeLinkName.MaximumLength); + + RtlInitUnicodeString(&(DeviceExtension->DeviceAdditionalData.WellKnownName), savedName); + + // the name was saved and the link created + + return STATUS_SUCCESS; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +DeviceRetrieveScsiAddress( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ PSCSI_ADDRESS ScsiAddress + ) +/*++ + +Routine Description: + + retrieve SCSI address information and put into device extension + +Arguments: + + DeviceExtension - device context. + ScsiAddress - the buffer to put the scsi address info. + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status; + WDF_MEMORY_DESCRIPTOR outputDescriptor; + + PAGED_CODE(); + + if ((DeviceExtension == NULL) || + (ScsiAddress == NULL)) + { + return STATUS_INVALID_PARAMETER; + } + + //Get IOTARGET for sending request to port driver. + WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&outputDescriptor, + (PVOID)ScsiAddress, + sizeof(SCSI_ADDRESS)); + + status = WdfIoTargetSendIoctlSynchronously(DeviceExtension->IoTarget, + NULL, + IOCTL_SCSI_GET_ADDRESS, + NULL, + &outputDescriptor, + NULL, + NULL); + + if (!NT_SUCCESS(status)) + { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT, + "DeviceRetrieveScsiAddress: Get Address failed %lx\n", + status)); + } + else + { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT, + "GetAddress: Port %x, Path %x, Target %x, Lun %x\n", + ScsiAddress->PortNumber, + ScsiAddress->PathId, + ScsiAddress->TargetId, + ScsiAddress->Lun)); + } + + return status; +} + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DeviceInitAllocateBuffers( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension + ) +/*++ + +Routine Description: + + Part of device initialize routine. + Allocate all buffers in Device Extension. + +Arguments: + + DeviceExtension - device extension of WDFDEVICE. + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PVOID senseData = NULL; + + PAGED_CODE(); + + // allocate a private extension for class data + if (DeviceExtension->PrivateFdoData == NULL) + { + DeviceExtension->PrivateFdoData = ExAllocatePoolWithTag(NonPagedPoolNx, + sizeof(CDROM_PRIVATE_FDO_DATA), + CDROM_TAG_PRIVATE_DATA); + } + + if (DeviceExtension->PrivateFdoData == NULL) + { + status = STATUS_INSUFFICIENT_RESOURCES; + } + else + { + // initialize the struct's various fields. + RtlZeroMemory(DeviceExtension->PrivateFdoData, sizeof(CDROM_PRIVATE_FDO_DATA)); + } + + // Allocate request sense buffer. + senseData = ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned, + SENSE_BUFFER_SIZE, + CDROM_TAG_SENSE_INFO); + + if (senseData == NULL) + { + // The buffer cannot be allocated. + status = STATUS_INSUFFICIENT_RESOURCES; + } + else + { + // Set the sense data pointer in the device extension. + DeviceExtension->SenseData = senseData; + } + + // Allocate scratch buffer -- Must occur after determining + // max transfer size, but before other CD specific detection + // (which relies upon this buffer). + if (!ScratchBuffer_Allocate(DeviceExtension)) + { + status = STATUS_INSUFFICIENT_RESOURCES; + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT, + "Failed to allocate scratch buffer, failing %!STATUS!\n", + status + )); + } + + return status; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +DeviceRetrieveDescriptorsAndTransferLength( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension + ) +/*++ + +Routine Description: + + Part of device initialize routine. + Retrieve Device Descriptor and Adaptor Descriptor. + +Arguments: + + DeviceExtension - device extension of WDFDEVICE. + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + STORAGE_PROPERTY_ID propertyId; + + PAGED_CODE(); + + if (NT_SUCCESS(status)) + { + // Call port driver to get adapter capabilities. + propertyId = StorageAdapterProperty; + + status = DeviceRetrieveDescriptor(DeviceExtension->Device, + &propertyId, + (PSTORAGE_DESCRIPTOR_HEADER*)&DeviceExtension->AdapterDescriptor); + } + if (NT_SUCCESS(status)) + { + // Call port driver to get device descriptor. + propertyId = StorageDeviceProperty; + + status = DeviceRetrieveDescriptor(DeviceExtension->Device, + &propertyId, + (PSTORAGE_DESCRIPTOR_HEADER*)&DeviceExtension->DeviceDescriptor); + } + if (NT_SUCCESS(status)) + { + // Call port driver to get device power property. + // Not all port drivers support this property, and it's not fatal if this query fails. + propertyId = StorageDevicePowerProperty; + + (void) DeviceRetrieveDescriptor(DeviceExtension->Device, + &propertyId, + (PSTORAGE_DESCRIPTOR_HEADER*)&DeviceExtension->PowerDescriptor); + } + + if (NT_SUCCESS(status)) + { + // Determine the maximum page-aligned and non-page-aligned transfer + // lengths here, so we needn't do this in common READ/WRITE code paths + + // start with the number of pages the adapter can support + ULONG maxAlignedTransfer = DeviceExtension->AdapterDescriptor->MaximumPhysicalPages; + ULONG maxUnalignedTransfer = DeviceExtension->AdapterDescriptor->MaximumPhysicalPages; + + + // Unaligned buffers could cross a page boundary. + if (maxUnalignedTransfer > 1) + { + maxUnalignedTransfer--; + } + + // if we'd overflow multiplying by page size, just max out the + // transfer length allowed by the number of pages limit. + if (maxAlignedTransfer >= (((ULONG)-1) / PAGE_SIZE)) + { + maxAlignedTransfer = (ULONG)-1; + } + else + { + maxAlignedTransfer *= PAGE_SIZE; + } + + if (maxUnalignedTransfer >= (((ULONG)-1) / PAGE_SIZE)) + { + maxUnalignedTransfer = (ULONG)-1; + } + else + { + maxUnalignedTransfer *= PAGE_SIZE; + } + + // finally, take the smaller of the above and the adapter's + // reported maximum number of bytes per transfer. + maxAlignedTransfer = min(maxAlignedTransfer, DeviceExtension->AdapterDescriptor->MaximumTransferLength); + maxUnalignedTransfer = min(maxUnalignedTransfer, DeviceExtension->AdapterDescriptor->MaximumTransferLength); + + // Make sure the values are reasonable and not zero. + maxAlignedTransfer = max(maxAlignedTransfer, PAGE_SIZE); + maxUnalignedTransfer = max(maxUnalignedTransfer, PAGE_SIZE); + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, + "Device %p Max aligned/unaligned transfer size is %x/%x\n", + DeviceExtension->Device, + maxAlignedTransfer, + maxUnalignedTransfer + )); + DeviceExtension->DeviceAdditionalData.MaxPageAlignedTransferBytes = maxAlignedTransfer; + DeviceExtension->DeviceAdditionalData.MaxUnalignedTransferBytes = maxUnalignedTransfer; + } + else + { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DeviceRetrieveDescriptorsAndTransferLength failed %lx\n", status)); + } + + return status; +} + + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +DeviceRetrieveDescriptor( + _In_ WDFDEVICE Device, + _In_ PSTORAGE_PROPERTY_ID PropertyId, + _Outptr_ PSTORAGE_DESCRIPTOR_HEADER* Descriptor + ) +/*++ + +Routine Description: + + This routine will perform a query for the specified property id and will + allocate a non-paged buffer to store the data in. It is the responsibility + of the caller to ensure that this buffer is freed. + + This routine must be run at IRQL_PASSIVE_LEVEL + +Arguments: + + Device - the device object + PropertyId - type of property to retrieve + Descriptor - buffer allocated in this function to hold the descriptor data + +Return Value: + + status + +--*/ +{ + NTSTATUS status; + WDF_MEMORY_DESCRIPTOR memoryDescriptor; + + STORAGE_PROPERTY_QUERY query = {0}; + ULONG bufferLength = 0; + + PSTORAGE_DESCRIPTOR_HEADER descriptor = NULL; + PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(Device); + + PAGED_CODE(); + + // Set the passed-in descriptor pointer to NULL as default + *Descriptor = NULL; + + // On the first pass we just want to get the first few + // bytes of the descriptor so we can read it's size + query.PropertyId = *PropertyId; + query.QueryType = PropertyStandardQuery; + + descriptor = (PVOID)&query; + + NT_ASSERT(sizeof(STORAGE_PROPERTY_QUERY) >= (sizeof(ULONG)*2)); + + WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&memoryDescriptor, + (PVOID)&query, + sizeof(STORAGE_PROPERTY_QUERY)); + + status = WdfIoTargetSendIoctlSynchronously(deviceExtension->IoTarget, + NULL, + IOCTL_STORAGE_QUERY_PROPERTY, + &memoryDescriptor, + &memoryDescriptor, + NULL, + NULL); + + if(!NT_SUCCESS(status)) + { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_INIT, "DeviceRetrieveDescriptor: error %lx trying to " + "query properties #1\n", status)); + return status; + } + + if (descriptor->Size == 0) + { + // This DebugPrint is to help third-party driver writers + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_INIT, "DeviceRetrieveDescriptor: size returned was zero?! (status " + "%x\n", status)); + return STATUS_UNSUCCESSFUL; + } + + // This time we know how much data there is so we can + // allocate a buffer of the correct size + bufferLength = descriptor->Size; + NT_ASSERT(bufferLength >= sizeof(STORAGE_PROPERTY_QUERY)); + bufferLength = max(bufferLength, sizeof(STORAGE_PROPERTY_QUERY)); + + descriptor = ExAllocatePoolWithTag(NonPagedPoolNx, bufferLength, CDROM_TAG_DESCRIPTOR); + + if(descriptor == NULL) + { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_INIT, "DeviceRetrieveDescriptor: unable to memory for descriptor " + "(%d bytes)\n", bufferLength)); + return STATUS_INSUFFICIENT_RESOURCES; + } + + // setup the query again, as it was overwritten above + RtlZeroMemory(&query, sizeof(STORAGE_PROPERTY_QUERY)); + query.PropertyId = *PropertyId; + query.QueryType = PropertyStandardQuery; + + // copy the input to the new outputbuffer + RtlCopyMemory(descriptor, + &query, + sizeof(STORAGE_PROPERTY_QUERY)); + + WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&memoryDescriptor, + (PVOID)descriptor, + bufferLength); + + status = WdfIoTargetSendIoctlSynchronously(deviceExtension->IoTarget, + NULL, + IOCTL_STORAGE_QUERY_PROPERTY, + &memoryDescriptor, + &memoryDescriptor, + NULL, + NULL); + + if(!NT_SUCCESS(status)) + { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_INIT, "DeviceRetrieveDescriptor: error %lx trying to " + "query properties #1\n", status)); + FREE_POOL(descriptor); + + return status; + } + + // return the memory we've allocated to the caller + *Descriptor = descriptor; + + return status; +} // end DeviceRetrieveDescriptor() + +_IRQL_requires_max_(PASSIVE_LEVEL) +VOID +DeviceRetrieveHackFlagsFromRegistry( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension + ) +/*++ + +Routine Description: + + try to retrieve hack flages from registry and put the information in + device extension. + +Arguments: + + DeviceExtension - the device context + +Return Value: + + none + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + WDFKEY hardwareKey = NULL; + WDFKEY subKey = NULL; + ULONG deviceHacks = 0; + + DECLARE_CONST_UNICODE_STRING(subKeyName, CLASSP_REG_SUBKEY_NAME); + DECLARE_CONST_UNICODE_STRING(valueName, CLASSP_REG_HACK_VALUE_NAME); + + PAGED_CODE(); + + status = WdfDeviceOpenRegistryKey(DeviceExtension->Device, + PLUGPLAY_REGKEY_DEVICE, + KEY_READ, + WDF_NO_OBJECT_ATTRIBUTES, + &hardwareKey); + if (NT_SUCCESS(status)) + { + status = WdfRegistryOpenKey(hardwareKey, + &subKeyName, + KEY_READ, + WDF_NO_OBJECT_ATTRIBUTES, + &subKey); + + if (NT_SUCCESS(status)) + { + status = WdfRegistryQueryULong(subKey, + &valueName, + &deviceHacks); + if (NT_SUCCESS(status)) + { + // remove unknown values and save... + CLEAR_FLAG(deviceHacks, FDO_HACK_INVALID_FLAGS); + SET_FLAG(DeviceExtension->PrivateFdoData->HackFlags, deviceHacks); + } + + WdfRegistryClose(subKey); + } + + WdfRegistryClose(hardwareKey); + } + + + // + // we should modify the system hive to include another key for us to grab + // settings from. in this case: Classpnp\HackFlags + // + // the use of a DWORD value for the HackFlags allows 32 hacks w/o + // significant use of the registry, and also reduces OEM exposure. + // + // definition of bit flags: + // 0x00000001 -- Device succeeds PREVENT_MEDIUM_REMOVAL, but + // cannot actually prevent removal. + // 0x00000002 -- Device hard-hangs or times out for GESN requests. + // 0x00000008 -- Device does not support RESERVE(6) and RELEASE(6). + // 0x00000010 -- Device may incorrecly report operational changes in GESN. + // 0x00000020 -- Device does not support streaming READ(12) / WRITE(12). + // 0x00000040 -- Device does not support asynchronous notification. + // 0xffffff80 -- Currently reserved, may be used later. + // + + return; +} + +_IRQL_requires_max_(APC_LEVEL) +VOID DeviceScanForSpecial( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ CDROM_SCAN_FOR_SPECIAL_INFO DeviceList[], + _In_ PCDROM_SCAN_FOR_SPECIAL_HANDLER Function) +/*++ + +Routine Description: + + scan the list of devices that should be hacked or not supported. + +Arguments: + + DeviceExtension - the device context + DeviceList - the device list + Function - function used to scan from the list. + +Return Value: + + none + +--*/ +{ + PSTORAGE_DEVICE_DESCRIPTOR deviceDescriptor; + PUCHAR vendorId; + PUCHAR productId; + PUCHAR productRevision; + UCHAR nullString[] = ""; + + PAGED_CODE(); + NT_ASSERT(DeviceList); + NT_ASSERT(Function); + + if (DeviceList == NULL) + { + return; + } + if (Function == NULL) + { + return; + } + + deviceDescriptor = DeviceExtension->DeviceDescriptor; + + // SCSI sets offsets to -1, ATAPI sets to 0. check for both. + if (deviceDescriptor->VendorIdOffset != 0 && + deviceDescriptor->VendorIdOffset != -1) + { + vendorId = ((PUCHAR)deviceDescriptor); + vendorId += deviceDescriptor->VendorIdOffset; + } + else + { + vendorId = nullString; + } + + if (deviceDescriptor->ProductIdOffset != 0 && + deviceDescriptor->ProductIdOffset != -1) + { + productId = ((PUCHAR)deviceDescriptor); + productId += deviceDescriptor->ProductIdOffset; + } + else + { + productId = nullString; + } + + if (deviceDescriptor->ProductRevisionOffset != 0 && + deviceDescriptor->ProductRevisionOffset != -1) + { + productRevision = ((PUCHAR)deviceDescriptor); + productRevision += deviceDescriptor->ProductRevisionOffset; + } + else + { + productRevision = nullString; + } + + // loop while the device list is valid (not null-filled) + for (;(DeviceList->VendorId != NULL || + DeviceList->ProductId != NULL || + DeviceList->ProductRevision != NULL); DeviceList++) + { + if (StringsAreMatched(DeviceList->VendorId, (LPSTR)vendorId) && + StringsAreMatched(DeviceList->ProductId, (LPSTR)productId) && + StringsAreMatched(DeviceList->ProductRevision, (LPSTR)productRevision) + ) + { + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, "DeviceScanForSpecial: Found matching " + "controller Ven: %s Prod: %s Rev: %s\n", + (LPCSTR)vendorId, (LPCSTR)productId, (LPCSTR)productRevision)); + + // pass the context to the call back routine and exit + (Function)(DeviceExtension, DeviceList->Data); + + // for CHK builds, try to prevent wierd stacks by having a debug + // print here. it's a hack, but i know of no other way to prevent + // the stack from being wrong. + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, "DeviceScanForSpecial: " + "completed callback\n")); + return; + + } // else the strings did not match + + } // none of the devices matched. + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, "DeviceScanForSpecial: no match found for %p\n", + DeviceExtension->DeviceObject)); + return; + +} // end DeviceScanForSpecial() + +_IRQL_requires_max_(APC_LEVEL) +VOID +DeviceHackFlagsScan( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ ULONG_PTR Data + ) +{ + PAGED_CODE(); + + // remove invalid flags and save + CLEAR_FLAG(Data, FDO_HACK_INVALID_FLAGS); + SET_FLAG(DeviceExtension->PrivateFdoData->HackFlags, Data); + + return; +} + + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +DeviceInitializeHotplugInfo( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension + ) +/*++ + +Routine Description: + + Retrieve information into struc STORAGE_HOTPLUG_INFO in DeviceExtension + initialize the hotplug information only after the ScanForSpecial routines, + as it relies upon the hack flags - DeviceExtension->PrivateFdoData->HackFlags. + +Arguments: + + DeviceExtension - the device context + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PCDROM_PRIVATE_FDO_DATA fdoData = DeviceExtension->PrivateFdoData; + DEVICE_REMOVAL_POLICY deviceRemovalPolicy = 0; + ULONG resultLength = 0; + ULONG writeCacheOverride; + + PAGED_CODE(); + + // start with some default settings + RtlZeroMemory(&(fdoData->HotplugInfo), sizeof(STORAGE_HOTPLUG_INFO)); + + // set the size (aka version) + fdoData->HotplugInfo.Size = sizeof(STORAGE_HOTPLUG_INFO); + + // set if the device has removable media + if (DeviceExtension->DeviceDescriptor->RemovableMedia) + { + fdoData->HotplugInfo.MediaRemovable = TRUE; + } + else + { + fdoData->HotplugInfo.MediaRemovable = FALSE; + } + + // + // this refers to devices which, for reasons not yet understood, + // do not fail PREVENT_MEDIA_REMOVAL requests even though they + // have no way to lock the media into the drive. this allows + // the filesystems to turn off delayed-write caching for these + // devices as well. + // + + if (TEST_FLAG(DeviceExtension->PrivateFdoData->HackFlags, FDO_HACK_CANNOT_LOCK_MEDIA)) + { + fdoData->HotplugInfo.MediaHotplug = TRUE; + } + else + { + fdoData->HotplugInfo.MediaHotplug = FALSE; + } + + // Query the default removal policy from the kernel + status = WdfDeviceQueryProperty(DeviceExtension->Device, + DevicePropertyRemovalPolicy, + sizeof(DEVICE_REMOVAL_POLICY), + (PVOID)&deviceRemovalPolicy, + &resultLength); + if (NT_SUCCESS(status)) + { + if (resultLength != sizeof(DEVICE_REMOVAL_POLICY)) + { + status = STATUS_UNSUCCESSFUL; + } + } + + if (NT_SUCCESS(status)) + { + // Look into the registry to see if the user has chosen + // to override the default setting for the removal policy. + // User can override only if the default removal policy is + // orderly or suprise removal. + + if ((deviceRemovalPolicy == RemovalPolicyExpectOrderlyRemoval) || + (deviceRemovalPolicy == RemovalPolicyExpectSurpriseRemoval)) + { + DEVICE_REMOVAL_POLICY userRemovalPolicy = 0; + + DeviceGetParameter(DeviceExtension, + CLASSP_REG_SUBKEY_NAME, + CLASSP_REG_REMOVAL_POLICY_VALUE_NAME, + (PULONG)&userRemovalPolicy); + + // Validate the override value and use it only if it is an + // allowed value. + if ((userRemovalPolicy == RemovalPolicyExpectOrderlyRemoval) || + (userRemovalPolicy == RemovalPolicyExpectSurpriseRemoval)) + { + deviceRemovalPolicy = userRemovalPolicy; + } + } + + // use this info to set the DeviceHotplug setting + // don't rely on DeviceCapabilities, since it can't properly + // determine device relations, etc. let the kernel figure this + // stuff out instead. + if (deviceRemovalPolicy == RemovalPolicyExpectSurpriseRemoval) + { + fdoData->HotplugInfo.DeviceHotplug = TRUE; + } + else + { + fdoData->HotplugInfo.DeviceHotplug = FALSE; + } + + // this refers to the *filesystem* caching, but has to be included + // here since it's a per-device setting. this may change to be + // stored by the system in the future. + writeCacheOverride = FALSE; + DeviceGetParameter(DeviceExtension, + CLASSP_REG_SUBKEY_NAME, + CLASSP_REG_WRITE_CACHE_VALUE_NAME, + &writeCacheOverride); + + if (writeCacheOverride) + { + fdoData->HotplugInfo.WriteCacheEnableOverride = TRUE; + } + else + { + fdoData->HotplugInfo.WriteCacheEnableOverride = FALSE; + } + } + + if (!NT_SUCCESS(status)) + { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_INIT, "Could not initialize hotplug information %lx\n", status)); + } + + return status; +} + + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +DeviceInitMmcContext( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension + ) +/*++ + +Routine Description: + + This routine initializes and populates the internal data structures that are + used to discover various MMC-defined capabilities of the device. + + This routine will not clean up allocate resources if it fails - that + is left for device stop/removal routines + +Arguments: + + DeviceExtension - device extension + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + + PAGED_CODE(); + + DeviceExtension->DeviceAdditionalData.Mmc.IsMmc = FALSE; + DeviceExtension->DeviceAdditionalData.Mmc.IsAACS = FALSE; + DeviceExtension->DeviceAdditionalData.Mmc.IsWriter = FALSE; + DeviceExtension->DeviceAdditionalData.Mmc.WriteAllowed = FALSE; + DeviceExtension->DeviceAdditionalData.Mmc.IsCssDvd = FALSE; + DeviceExtension->DeviceAdditionalData.DriveDeviceType = FILE_DEVICE_CD_ROM; + + // Determine if the drive is MMC-Capable + if (NT_SUCCESS(status)) + { + status = DeviceGetMmcSupportInfo(DeviceExtension, + &DeviceExtension->DeviceAdditionalData.Mmc.IsMmc); + + if (!NT_SUCCESS(status)) + { + //Currently, only low resource error comes here. + //That is a success case for unsupporting this command. + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT, + "DeviceInitMmcContext: Failed to get the support info for GET CONFIGURATION " + "command, failng %!STATUS!\n", status + )); + + DeviceExtension->DeviceAdditionalData.Mmc.IsMmc = FALSE; + status = STATUS_SUCCESS; + } + } + + if (NT_SUCCESS(status) && DeviceExtension->DeviceAdditionalData.Mmc.IsMmc) + { + // the drive supports at least a subset of MMC commands + // (and therefore supports READ_CD, etc...) + + // allocate a buffer for all the capabilities and such + status = DeviceAllocateMmcResources(DeviceExtension->Device); + } + + if (NT_SUCCESS(status) && DeviceExtension->DeviceAdditionalData.Mmc.IsMmc) + { + PFEATURE_HEADER header = NULL; + FEATURE_NUMBER validationSchema; + ULONG blockingFactor; + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, + "DeviceInitMmcContext: FDO %p GET CONFIGURATION buffer %p\n", + DeviceExtension->Device, + DeviceExtension->DeviceAdditionalData.Mmc.CapabilitiesBuffer + )); + + // Update several properties using the retrieved Configuration Data. + + // print all the feature pages (DBG only) + DevicePrintAllFeaturePages(DeviceExtension->DeviceAdditionalData.Mmc.CapabilitiesBuffer, + DeviceExtension->DeviceAdditionalData.Mmc.CapabilitiesBufferSize); + + // if AACS feature exists, enable AACS flag in the driver + header = DeviceFindFeaturePage(DeviceExtension->DeviceAdditionalData.Mmc.CapabilitiesBuffer, + DeviceExtension->DeviceAdditionalData.Mmc.CapabilitiesBufferSize, + FeatureAACS); + if (header) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, + "DeviceInitMmcContext: Reporting AACS support for device due to " + "GET CONFIGURATION showing support\n" + )); + DeviceExtension->DeviceAdditionalData.Mmc.IsAACS = TRUE; + } + +#ifdef ENABLE_AACS_TESTING + DeviceExtension->DeviceAdditionalData.Mmc.IsAACS = TRUE; // just force it true for testing +#endif // ENABLE_AACS_TESTING + + // Check if it's a DVD device + header = DeviceFindFeaturePage(DeviceExtension->DeviceAdditionalData.Mmc.CapabilitiesBuffer, + DeviceExtension->DeviceAdditionalData.Mmc.CapabilitiesBufferSize, + FeatureDvdRead); + if (header != NULL) + { + DeviceExtension->DeviceAdditionalData.DriveDeviceType = FILE_DEVICE_DVD; + } + + // check if drive is writer + DeviceUpdateMmcWriteCapability(DeviceExtension->DeviceAdditionalData.Mmc.CapabilitiesBuffer, + DeviceExtension->DeviceAdditionalData.Mmc.CapabilitiesBufferSize, + FALSE, //Check if the drive has the ability to write. + (PBOOLEAN)&(DeviceExtension->DeviceAdditionalData.Mmc.IsWriter), + &validationSchema, + &blockingFactor); + + // check if there is a CSS protected DVD or CPPM-protected DVDAudio media in drive. + header = DeviceFindFeaturePage(DeviceExtension->DeviceAdditionalData.Mmc.CapabilitiesBuffer, + DeviceExtension->DeviceAdditionalData.Mmc.CapabilitiesBufferSize, + FeatureDvdCSS); + + DeviceExtension->DeviceAdditionalData.Mmc.IsCssDvd = (header != NULL) && (header->Current); + + // Flag the StartIo routine to update its state and hook in the error handler + DeviceExtension->DeviceAdditionalData.Mmc.UpdateState = CdromMmcUpdateRequired; + DeviceExtension->DeviceAdditionalData.ErrorHandler = DeviceErrorHandlerForMmc; + + SET_FLAG(DeviceExtension->DeviceFlags, DEV_SAFE_START_UNIT); + + // Read the CDROM mode sense page to get additional info for raw read requests. + // only valid for MMC devices + DeviceSetRawReadInfo(DeviceExtension); + } + + // Set Read-Only device flag for non-MMC device. + if (!(DeviceExtension->DeviceAdditionalData.Mmc.IsMmc)) + { + ULONG deviceCharacteristics = WdfDeviceGetCharacteristics(DeviceExtension->Device); + + deviceCharacteristics |= FILE_READ_ONLY_DEVICE; + + WdfDeviceSetCharacteristics(DeviceExtension->Device, deviceCharacteristics); + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, + "DeviceInitMmcContext: FDO %p Device is not an MMC compliant device, so setting " + "to read-only (legacy) mode", + DeviceExtension->Device + )); + } + + // Set DEV_SAFE_START_UNIT flag for newer devices. + if (DeviceExtension->DeviceAdditionalData.DriveDeviceType == FILE_DEVICE_DVD) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, + "DeviceInitMmcContext: DVD Devices require START UNIT\n")); + SET_FLAG(DeviceExtension->DeviceFlags, DEV_SAFE_START_UNIT); + + } + else if ((DeviceExtension->DeviceDescriptor->BusType != BusTypeScsi) && + (DeviceExtension->DeviceDescriptor->BusType != BusTypeAtapi) && + (DeviceExtension->DeviceDescriptor->BusType != BusTypeUnknown) + ) + { + // devices on the newer busses require START_UNIT + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, + "DeviceInitMmcContext: Devices for newer buses require START UNIT\n")); + SET_FLAG(DeviceExtension->DeviceFlags, DEV_SAFE_START_UNIT); + } + + return status; +} + + +_IRQL_requires_max_(PASSIVE_LEVEL) +ULONG +DeviceGetTimeOutValueFromRegistry() +/*++ + +Routine Description: + + get the device time out value from registry + +Arguments: + + None + +Return Value: + + ULONG - value of timeout + +--*/ +{ + NTSTATUS status; + WDFKEY registryKey = NULL; + ULONG timeOutValue = 0; + + DECLARE_CONST_UNICODE_STRING(registryValueName, L"TimeOutValue"); + + PAGED_CODE(); + + // open the service key. + status = WdfDriverOpenParametersRegistryKey(WdfGetDriver(), + KEY_READ, + WDF_NO_OBJECT_ATTRIBUTES, + ®istryKey); + + if (NT_SUCCESS(status)) + { + status = WdfRegistryQueryULong(registryKey, + ®istryValueName, + &timeOutValue); + + WdfRegistryClose(registryKey); + } + + if (!NT_SUCCESS(status)) + { + timeOutValue = 0; + } + + return timeOutValue; + +} // end DeviceGetTimeOutValueFromRegistry() + + +_IRQL_requires_max_(APC_LEVEL) +VOID +DeviceScanSpecialDevices( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension + ) +/*++ + +Routine Description: + + This function checks to see if an SCSI logical unit requires an special + initialization or error processing. + +Arguments: + + Device - device object. + +Return Value: + + None. + +--*/ +{ + + PAGED_CODE(); + + // set our hack flags + DeviceScanForSpecial(DeviceExtension, CdromHackItems, ScanForSpecialHandler); + + // + // All CDRom's can ignore the queue lock failure for power operations + // and do not require handling the SpinUp case (unknown result of sending + // a cdrom a START_UNIT command -- may eject disks?) + // + // We send the stop command mostly to stop outstanding asynch operations + // (like audio playback) from running when the system is powered off. + // Because of this and the unlikely chance that a PLAY command will be + // sent in the window between the STOP and the time the machine powers down + // we don't require queue locks. This is important because without them + // classpnp's power routines will send the START_STOP_UNIT command to the + // device whether or not it supports locking (atapi does not support locking + // and if we requested them we would end up not stopping audio on atapi + // devices). +// SET_FLAG(deviceExtension->ScanForSpecialFlags, CDROM_SPECIAL_DISABLE_SPIN_UP); +// SET_FLAG(deviceExtension->ScanForSpecialFlags, CDROM_SPECIAL_NO_QUEUE_LOCK); + + if (TEST_FLAG(DeviceExtension->DeviceAdditionalData.HackFlags, CDROM_HACK_TOSHIBA_SD_W1101)) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, + "DeviceScanSpecialDevices: Found Toshiba SD-W1101 DVD-RAM " + "-- This drive will *NOT* support DVD-ROM playback.\n")); + } + else if (TEST_FLAG(DeviceExtension->DeviceAdditionalData.HackFlags, CDROM_HACK_HITACHI_GD_2000)) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, + "DeviceScanSpecialDevices: Found Hitachi GD-2000\n")); + + // Setup an error handler to spin up the drive when it idles out + // since it seems to like to fail to spin itself back up on its + // own for a REPORT_KEY command. It may also lose the AGIDs that + // it has given, which will result in DVD playback failures. + // This routine will just do what it can... + DeviceExtension->DeviceAdditionalData.ErrorHandler = DeviceErrorHandlerForHitachiGD2000; + + // this drive may require START_UNIT commands to spin + // the drive up when it's spun itself down. + SET_FLAG(DeviceExtension->DeviceFlags, DEV_SAFE_START_UNIT); + } + else if (TEST_FLAG(DeviceExtension->DeviceAdditionalData.HackFlags, CDROM_HACK_FUJITSU_FMCD_10x)) + { + // When Read command is issued to FMCD-101 or FMCD-102 and there is a music + // cd in it. It takes longer time than SCSI_CDROM_TIMEOUT before returning + // error status. + DeviceExtension->TimeOutValue = 20; + } + else if (TEST_FLAG(DeviceExtension->DeviceAdditionalData.HackFlags, CDROM_HACK_DEC_RRD)) + { + NTSTATUS status; + PMODE_PARM_READ_WRITE_DATA modeParameters; + SCSI_REQUEST_BLOCK srb = {0}; + PCDB cdb; + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, + "DeviceScanSpecialDevices: Found DEC RRD.\n")); + + DeviceExtension->DeviceAdditionalData.IsDecRrd = TRUE; + + // Setup an error handler to reinitialize the cd rom after it is reset? + // + //DeviceExtension->DevInfo->ClassError = DecRrdProcessError; + + // Found a DEC RRD cd-rom. These devices do not pass MS HCT + // multi-media tests because the DEC firmware modifieds the block + // from the PC-standard 2K to 512. Change the block transfer size + // back to the PC-standard 2K by using a mode select command. + + modeParameters = ExAllocatePoolWithTag(NonPagedPoolNx, + sizeof(MODE_PARM_READ_WRITE_DATA), + CDROM_TAG_MODE_DATA); + if (modeParameters == NULL) + { + return; + } + + RtlZeroMemory(modeParameters, sizeof(MODE_PARM_READ_WRITE_DATA)); + RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK)); + + // Set the block length to 2K. + modeParameters->ParameterListHeader.BlockDescriptorLength = sizeof(MODE_PARAMETER_BLOCK); + + // Set block length to 2K (0x0800) in Parameter Block. + modeParameters->ParameterListBlock.BlockLength[0] = 0x00; //MSB + modeParameters->ParameterListBlock.BlockLength[1] = 0x08; + modeParameters->ParameterListBlock.BlockLength[2] = 0x00; //LSB + + // Build the mode select CDB. + srb.CdbLength = 6; + srb.TimeOutValue = DeviceExtension->TimeOutValue; + + cdb = (PCDB)srb.Cdb; + cdb->MODE_SELECT.PFBit = 1; + cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT; + cdb->MODE_SELECT.ParameterListLength = HITACHI_MODE_DATA_SIZE; + + // Send the request to the device. + status = DeviceSendSrbSynchronously(DeviceExtension->Device, + &srb, + modeParameters, + sizeof(MODE_PARM_READ_WRITE_DATA), + TRUE, + NULL); + + if (!NT_SUCCESS(status)) + { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT, + "DeviceScanSpecialDevices: Setting DEC RRD to 2K block" + "size failed [%x]\n", status)); + } + + ExFreePool(modeParameters); + } + + return; +} + +_IRQL_requires_max_(APC_LEVEL) +VOID +ScanForSpecialHandler( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ ULONG_PTR HackFlags + ) +{ + PAGED_CODE(); + + CLEAR_FLAG(HackFlags, CDROM_HACK_INVALID_FLAGS); + + DeviceExtension->DeviceAdditionalData.HackFlags = HackFlags; + + return; +} + + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +DeviceCacheDeviceInquiryData( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension + ) +/*++ + +Routine Description: + + get inquiry data from device and cache it into device extension + The first INQUIRY command sent is with 0x24 bytes required data, + as ATAport driver always sends this to enumerate devices and 0x24 + bytes is the minimum data device should return by spec. + +Arguments: + + DeviceExtension - device extension. + +Return Value: + + NTSTATUS. + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + SCSI_REQUEST_BLOCK srb = {0}; + PCDB cdb = (PCDB)(&srb.Cdb); + PINQUIRYDATA tmpInquiry = NULL; + + // by spec, device should return at least 36 bytes. + ULONG requestedInquiryTransferBytes = MINIMUM_CDROM_INQUIRY_SIZE; + BOOLEAN needResendCommand = TRUE; + BOOLEAN portDriverHack = FALSE; + + // this ensures that the strings vendorID, productID, and firmwareRevision + // are all available in the inquiry data. In addition, MMC spec requires + // all type 5 devices to have minimum 36 bytes of inquiry. + static const UCHAR minInquiryAdditionalLength = + MINIMUM_CDROM_INQUIRY_SIZE - + RTL_SIZEOF_THROUGH_FIELD(INQUIRYDATA, AdditionalLength); + + C_ASSERT( RTL_SIZEOF_THROUGH_FIELD(INQUIRYDATA, AdditionalLength) <= 8 ); + C_ASSERT( RTL_SIZEOF_THROUGH_FIELD(INQUIRYDATA, ProductRevisionLevel) == MINIMUM_CDROM_INQUIRY_SIZE ); + + PAGED_CODE(); + + // short-circuit here for if already cached for this device + // required to avoid use of scratch buffer after initialization + // of MCN code. + if (DeviceExtension->DeviceAdditionalData.CachedInquiryData != NULL) + { + NT_ASSERT(DeviceExtension->DeviceAdditionalData.CachedInquiryDataByteCount != 0); + return STATUS_SUCCESS; + } + + // 1. retrieve the inquiry data length + + // 1.1 allocate inquiry data buffer + tmpInquiry = ExAllocatePoolWithTag(NonPagedPoolNx, + requestedInquiryTransferBytes, + CDROM_TAG_INQUIRY); + if (tmpInquiry == NULL) + { + status = STATUS_INSUFFICIENT_RESOURCES; + } + + // 1.2 send INQUIRY command + if (NT_SUCCESS(status)) + { + srb.CdbLength = 6; + cdb->AsByte[0] = SCSIOP_INQUIRY; + cdb->AsByte[3] = (UCHAR)( requestedInquiryTransferBytes >> (8*1) ); + cdb->AsByte[4] = (UCHAR)( requestedInquiryTransferBytes >> (8*0) ); + + status = DeviceSendSrbSynchronously(DeviceExtension->Device, + &srb, + tmpInquiry, + requestedInquiryTransferBytes, + FALSE, + NULL); + } + + // 1.3 get required data length + if (NT_SUCCESS(status)) + { + if ((requestedInquiryTransferBytes == srb.DataTransferLength) && + (requestedInquiryTransferBytes == (tmpInquiry->AdditionalLength + + RTL_SIZEOF_THROUGH_FIELD(INQUIRYDATA, AdditionalLength))) ) + { + // device has only 36 bytes of INQUIRY data. do not need to resend the command. + needResendCommand = FALSE; + } + else + { + // workaround an ATAPI.SYS bug where additional length field is set to zero + if (tmpInquiry->AdditionalLength == 0) + { + tmpInquiry->AdditionalLength = minInquiryAdditionalLength; + portDriverHack = TRUE; + } + + requestedInquiryTransferBytes = + tmpInquiry->AdditionalLength + + RTL_SIZEOF_THROUGH_FIELD(INQUIRYDATA, AdditionalLength); + + if (requestedInquiryTransferBytes >= MINIMUM_CDROM_INQUIRY_SIZE) + { + needResendCommand = TRUE; + } + else + { + needResendCommand = FALSE; + //Length is small than minimum length, error out. + status = STATUS_DEVICE_PROTOCOL_ERROR; + } + } + } + + // 2. retrieve the inquiry data if still needed. + + // 2.1 Clean up. + if (NT_SUCCESS(status) && needResendCommand) + { + FREE_POOL(tmpInquiry); + RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK)); + + tmpInquiry = ExAllocatePoolWithTag(NonPagedPoolNx, + requestedInquiryTransferBytes, + CDROM_TAG_INQUIRY); + if (tmpInquiry == NULL) + { + status = STATUS_INSUFFICIENT_RESOURCES; + } + } + + // 2.2 resend INQUIRY command + if (NT_SUCCESS(status) && needResendCommand) + { + srb.CdbLength = 6; + cdb->AsByte[0] = SCSIOP_INQUIRY; + cdb->AsByte[3] = (UCHAR)( requestedInquiryTransferBytes >> (8*1) ); + cdb->AsByte[4] = (UCHAR)( requestedInquiryTransferBytes >> (8*0) ); + + status = DeviceSendSrbSynchronously( DeviceExtension->Device, + &srb, + tmpInquiry, + requestedInquiryTransferBytes, + FALSE, + NULL); + + if (!NT_SUCCESS(status)) + { + // Workaround for drive reports that it has more INQUIRY data than reality. + if ((srb.SrbStatus == SRB_STATUS_DATA_OVERRUN) && + (srb.DataTransferLength < requestedInquiryTransferBytes) && + (srb.DataTransferLength >= MINIMUM_CDROM_INQUIRY_SIZE)) + { + //Port driver says buffer size mismatch (buffer underrun), + //retry with the real buffer size it could return. + requestedInquiryTransferBytes = srb.DataTransferLength; + + FREE_POOL(tmpInquiry); + RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK)); + + tmpInquiry = ExAllocatePoolWithTag(NonPagedPoolNx, + requestedInquiryTransferBytes, + CDROM_TAG_INQUIRY); + if (tmpInquiry == NULL) + { + status = STATUS_INSUFFICIENT_RESOURCES; + } + else + { + srb.CdbLength = 6; + cdb->AsByte[0] = SCSIOP_INQUIRY; + cdb->AsByte[3] = (UCHAR)( requestedInquiryTransferBytes >> (8*1) ); + cdb->AsByte[4] = (UCHAR)( requestedInquiryTransferBytes >> (8*0) ); + + status = DeviceSendSrbSynchronously(DeviceExtension->Device, + &srb, + tmpInquiry, + requestedInquiryTransferBytes, + FALSE, + NULL); + } + } + } + + //Check the transferred data length for safe. + if (NT_SUCCESS(status)) + { + requestedInquiryTransferBytes = srb.DataTransferLength; + + if (requestedInquiryTransferBytes < MINIMUM_CDROM_INQUIRY_SIZE) + { + // should never occur + status = STATUS_DEVICE_PROTOCOL_ERROR; + } + } + + // ensure we got some non-zero data.... + // This is done so we don't accidentally work around the + // ATAPI.SYS bug when no data was transferred. + if (NT_SUCCESS(status) && portDriverHack) + { + PULONG tmp = (PULONG)tmpInquiry; + ULONG i = MINIMUM_CDROM_INQUIRY_SIZE / sizeof(ULONG); + C_ASSERT( RTL_SIZEOF_THROUGH_FIELD(INQUIRYDATA, ProductRevisionLevel) % sizeof(ULONG) == 0 ); + + // wouldn't you know it -- there is no RtlIsMemoryZero() function; Make one up. + for ( ; i != 0; i--) + { + if (*tmp != 0) + { + break; // out of this inner FOR loop -- guarantees 'i != 0' + } + tmp++; + } + + if (i == 0) // all loop'd successfully + { + // should never occur to successfully get all zero'd data + status = STATUS_DEVICE_PROTOCOL_ERROR; + } + } + } + + // if everything succeeded, then (and only then) modify the device extension + if (NT_SUCCESS(status)) + { + DeviceExtension->DeviceAdditionalData.CachedInquiryData = tmpInquiry; + DeviceExtension->DeviceAdditionalData.CachedInquiryDataByteCount = requestedInquiryTransferBytes; + } + else + { + FREE_POOL(tmpInquiry); + } + + return status; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +DeviceGetMmcSupportInfo( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _Out_ PBOOLEAN IsMmcDevice + ) +/*++ + +Routine Description: + + check if the device is MMC capable. + +Arguments: + + DeviceExtension - device extension. + +Return Value: + + NTSTATUS. + IsMmcDevice - TRUE (MMC capable); FALSE (not MMC device) + +--*/ +{ + NTSTATUS status; + ULONG size; + ULONG previouslyFailed; + + PAGED_CODE(); + + *IsMmcDevice = FALSE; + + // read the registry in case the drive failed previously, + // and a timeout is occurring. + previouslyFailed = FALSE; + DeviceGetParameter(DeviceExtension, + CDROM_SUBKEY_NAME, + CDROM_NON_MMC_DRIVE_NAME, + &previouslyFailed); + + if (previouslyFailed) + { + SET_FLAG(DeviceExtension->DeviceAdditionalData.HackFlags, CDROM_HACK_BAD_GET_CONFIG_SUPPORT); + } + + // read from the registry in case the drive reports bad profile lengths + previouslyFailed = FALSE; + DeviceGetParameter(DeviceExtension, + CDROM_SUBKEY_NAME, + CDROM_NON_MMC_VENDOR_SPECIFIC_PROFILE, + &previouslyFailed); + + if (previouslyFailed) + { + SET_FLAG(DeviceExtension->DeviceAdditionalData.HackFlags, CDROM_HACK_BAD_VENDOR_PROFILES); + } + + // check for the ProfileList feature to determine if the drive is MMC compliant + // and set the "size" local variable to total GetConfig data size available. + // NOTE: This will exit this function in some error paths. + { + GET_CONFIGURATION_HEADER localHeader = {0}; + ULONG usable = 0; + + status = DeviceGetConfiguration(DeviceExtension->Device, + &localHeader, + sizeof(GET_CONFIGURATION_HEADER), + &usable, + FeatureProfileList, + SCSI_GET_CONFIGURATION_REQUEST_TYPE_ALL); + + if (status == STATUS_INVALID_DEVICE_REQUEST || + status == STATUS_NO_MEDIA_IN_DEVICE || + status == STATUS_IO_DEVICE_ERROR || + status == STATUS_IO_TIMEOUT) + { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT, + "GetConfiguration Failed (%x), device %p not mmc-compliant\n", + status, DeviceExtension->DeviceObject + )); + + previouslyFailed = TRUE; + DeviceSetParameter( DeviceExtension, + CDROM_SUBKEY_NAME, + CDROM_NON_MMC_DRIVE_NAME, + previouslyFailed); + + return STATUS_SUCCESS; + } + else if (!NT_SUCCESS(status)) + { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT, + "GetConfiguration Failed, status %x -- defaulting to -ROM\n", + status)); + + return STATUS_SUCCESS; + } + else if (usable < sizeof(GET_CONFIGURATION_HEADER)) + { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT, + "GetConfiguration Failed, returned only %x bytes!\n", usable)); + previouslyFailed = TRUE; + DeviceSetParameter( DeviceExtension, + CDROM_SUBKEY_NAME, + CDROM_NON_MMC_DRIVE_NAME, + previouslyFailed); + + return STATUS_SUCCESS; + } + + size = (localHeader.DataLength[0] << 24) | + (localHeader.DataLength[1] << 16) | + (localHeader.DataLength[2] << 8) | + (localHeader.DataLength[3] << 0) ; + + + if ((size <= 4) || (size + 4 < size)) + { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT, + "GetConfiguration Failed, claims MMC support but doesn't " + "correctly return config length! (%x)\n", + size + )); + previouslyFailed = TRUE; + DeviceSetParameter( DeviceExtension, + CDROM_SUBKEY_NAME, + CDROM_NON_MMC_DRIVE_NAME, + previouslyFailed); + + return STATUS_SUCCESS; + } + else if ((size % 4) != 0) + { + if ((size % 2) != 0) + { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT, + "GetConfiguration Failed, returned odd number of bytes %x!\n", + size + )); + previouslyFailed = TRUE; + DeviceSetParameter( DeviceExtension, + CDROM_SUBKEY_NAME, + CDROM_NON_MMC_DRIVE_NAME, + previouslyFailed); + + return STATUS_SUCCESS; + } + else + { + if (TEST_FLAG(DeviceExtension->DeviceAdditionalData.HackFlags, CDROM_HACK_BAD_VENDOR_PROFILES)) + { + // we've already caught this and ASSERT'd once, so don't do it again + } + else + { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT, + "GetConfiguration returned a size that is not per spec (%x bytes), this is probably because of a vendor specific data header with a size not divisible by 4.\n", + size + )); + previouslyFailed = TRUE; + DeviceSetParameter(DeviceExtension, + CDROM_SUBKEY_NAME, + CDROM_NON_MMC_VENDOR_SPECIFIC_PROFILE, + previouslyFailed); + } + } + } + + size += 4; // sizeof the datalength fields + } + + *IsMmcDevice = TRUE; + + // This code doesn't handle total get config size over 64k + NT_ASSERT( size <= MAXUSHORT ); + + // Check for SCSI_GET_CONFIGURATION_REQUEST_TYPE_ONE support in the device. + // NOTE: This will exit this function in some error paths. + { + ULONG featureSize = sizeof(GET_CONFIGURATION_HEADER)+sizeof(FEATURE_HEADER); + ULONG usable = 0; + + PGET_CONFIGURATION_HEADER configBuffer = ExAllocatePoolWithTag( + NonPagedPoolNx, + featureSize, + CDROM_TAG_GET_CONFIG); + + if (configBuffer == NULL) + { + return STATUS_INSUFFICIENT_RESOURCES; + } + + // read the registry in case the drive failed previously, + // and a timeout is occurring. + previouslyFailed = FALSE; + DeviceGetParameter( DeviceExtension, + CDROM_SUBKEY_NAME, + CDROM_TYPE_ONE_GET_CONFIG_NAME, + &previouslyFailed); + + if (previouslyFailed) + { + SET_FLAG(DeviceExtension->DeviceAdditionalData.HackFlags, CDROM_HACK_BAD_TYPE_ONE_GET_CONFIG); + FREE_POOL(configBuffer); + return STATUS_SUCCESS; + } + + // Get only the config and feature header + status = DeviceGetConfiguration(DeviceExtension->Device, + configBuffer, + featureSize, + &usable, + FeatureProfileList, + SCSI_GET_CONFIGURATION_REQUEST_TYPE_ONE); + + if (!NT_SUCCESS(status) || (usable < featureSize)) + { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT, + "Type One GetConfiguration Failed. Usable buffer size: %d\n", usable)); + previouslyFailed = TRUE; + } + else + { + PFEATURE_HEADER featureHeader; + ULONG totalAvailableBytes = 0; + ULONG expectedAvailableBytes = 0; + + REVERSE_BYTES(&totalAvailableBytes, configBuffer->DataLength); + totalAvailableBytes += RTL_SIZEOF_THROUGH_FIELD(GET_CONFIGURATION_HEADER, DataLength); + + featureHeader = (PFEATURE_HEADER) ((PUCHAR)configBuffer + sizeof(GET_CONFIGURATION_HEADER)); + expectedAvailableBytes = sizeof(GET_CONFIGURATION_HEADER) + + sizeof(FEATURE_HEADER) + + featureHeader->AdditionalLength; + + if (totalAvailableBytes > expectedAvailableBytes) + { + // Device is returning more than required size. Most likely the device + // is returning TYPE ALL data. Set the flag to use TYPE ALL for TYPE ONE + // requets + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT, + "Type One GetConfiguration Failed. " + "Device returned %d bytes instead of %d bytes\n", + size, featureSize)); + + previouslyFailed = TRUE; + } + } + + FREE_POOL(configBuffer); + + if (previouslyFailed == TRUE) + { + DeviceSetParameter( DeviceExtension, + CDROM_SUBKEY_NAME, + CDROM_TYPE_ONE_GET_CONFIG_NAME, + previouslyFailed); + + SET_FLAG(DeviceExtension->DeviceAdditionalData.HackFlags, CDROM_HACK_BAD_TYPE_ONE_GET_CONFIG); + } + } + + return status; +} + + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DeviceSetRawReadInfo( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension + ) +/*++ + +Routine Description: + + This routine reads the CDROM capabilities mode page and save information + in the device extension needed for raw reads. + NOTE: this function is only valid for MMC device + +Arguments: + + DeviceExtension - device context + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PUCHAR buffer = NULL; + ULONG count = 0; + + PAGED_CODE(); + + // Check whether the device can return C2 error flag bits and the block + // error byte. If so, save this info and fill in appropriate flag during + // raw read requests. + + // Start by checking the GET_CONFIGURATION data + { + PFEATURE_DATA_CD_READ cdReadHeader = NULL; + ULONG additionalLength = sizeof(FEATURE_DATA_CD_READ) - sizeof(FEATURE_HEADER); + + cdReadHeader = DeviceFindFeaturePage(DeviceExtension->DeviceAdditionalData.Mmc.CapabilitiesBuffer, + DeviceExtension->DeviceAdditionalData.Mmc.CapabilitiesBufferSize, + FeatureCdRead); + + if ((cdReadHeader != NULL) && + (cdReadHeader->Header.AdditionalLength >= additionalLength) && + (cdReadHeader->C2ErrorData) + ) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, + "DeviceSetRawReadInfo: FDO %p GET_CONFIG shows ability to read C2 error bits\n", + DeviceExtension->DeviceObject + )); + DeviceExtension->DeviceAdditionalData.Mmc.ReadCdC2Pointers = TRUE; // Device returns C2 error info. + } + } + + // Unfortunately, the only way to check for the ability to read R-W subcode + // information is via MODE_SENSE. Do so here, and check the C2 bit as well + // in case the drive has a firmware bug where it fails to report this ability + // in GET_CONFIG (which some drives do). + for (count = 0; count < 6; count++) + { + SCSI_REQUEST_BLOCK srb = {0}; + PCDB cdb = (PCDB)srb.Cdb; + ULONG bufferLength = 0; + + // Build the MODE SENSE CDB. Try 10-byte CDB first. + if ((count/3) == 0) + { + bufferLength = sizeof(CDVD_CAPABILITIES_PAGE) + + sizeof(MODE_PARAMETER_HEADER10) + + sizeof(MODE_PARAMETER_BLOCK); + + cdb->MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10; + cdb->MODE_SENSE10.Dbd = 1; + cdb->MODE_SENSE10.PageCode = MODE_PAGE_CAPABILITIES; + cdb->MODE_SENSE10.AllocationLength[0] = (UCHAR)(bufferLength >> 8); + cdb->MODE_SENSE10.AllocationLength[1] = (UCHAR)(bufferLength >> 0); + srb.CdbLength = 10; + } + else + { + bufferLength = sizeof(CDVD_CAPABILITIES_PAGE) + + sizeof(MODE_PARAMETER_HEADER) + + sizeof(MODE_PARAMETER_BLOCK); + + cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE; + cdb->MODE_SENSE.Dbd = 1; + cdb->MODE_SENSE.PageCode = MODE_PAGE_CAPABILITIES; + cdb->MODE_SENSE.AllocationLength = (UCHAR)bufferLength; + srb.CdbLength = 6; + } + + // Set timeout value from device extension. + srb.TimeOutValue = DeviceExtension->TimeOutValue; + + buffer = ExAllocatePoolWithTag(NonPagedPoolNx, bufferLength, CDROM_TAG_MODE_DATA); + + if (buffer == NULL) + { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, + "DeviceSetRawReadInfo: cannot allocate " + "buffer, so not setting raw read info for FDO %p\n", + DeviceExtension->DeviceObject + )); + status = STATUS_INSUFFICIENT_RESOURCES; + goto FnExit; + } + + RtlZeroMemory(buffer, bufferLength); + + status = DeviceSendSrbSynchronously(DeviceExtension->Device, + &srb, + buffer, + bufferLength, + FALSE, + NULL); + + if (NT_SUCCESS(status) || + (status == STATUS_DATA_OVERRUN) || + (status == STATUS_BUFFER_OVERFLOW)) + { + PCDVD_CAPABILITIES_PAGE capabilities = NULL; + + // determine where the capabilities page really is + if ((count/3) == 0) + { + PMODE_PARAMETER_HEADER10 p = (PMODE_PARAMETER_HEADER10)buffer; + capabilities = (PCDVD_CAPABILITIES_PAGE)(buffer + + sizeof(MODE_PARAMETER_HEADER10) + + (p->BlockDescriptorLength[0] * 256) + + p->BlockDescriptorLength[1]); + } + else + { + PMODE_PARAMETER_HEADER p = (PMODE_PARAMETER_HEADER)buffer; + capabilities = (PCDVD_CAPABILITIES_PAGE)(buffer + + sizeof(MODE_PARAMETER_HEADER) + + p->BlockDescriptorLength); + } + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, + "DeviceSetRawReadInfo: FDO %p CDVD Capabilities buffer %p\n", + DeviceExtension->DeviceObject, + buffer + )); + + if (capabilities->PageCode == MODE_PAGE_CAPABILITIES) + { + if (capabilities->C2Pointers) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, + "DeviceSetRawReadInfo: FDO %p supports C2 error bits in READ_CD command\n", + DeviceExtension->DeviceObject + )); + DeviceExtension->DeviceAdditionalData.Mmc.ReadCdC2Pointers = TRUE; + } + + if (capabilities->RWSupported) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, + "DeviceSetRawReadInfo: FDO %p supports raw subcode in READ_CD command\n", + DeviceExtension->DeviceObject + )); + DeviceExtension->DeviceAdditionalData.Mmc.ReadCdSubCode = TRUE; + } + + break; + } + } + + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, + "DeviceSetRawReadInfo: FDO %p failed %x byte mode sense, status %x\n", + DeviceExtension->DeviceObject, + (((count/3) == 0) ? 10 : 6), + status + )); + + FREE_POOL(buffer); + } + + if (count == 6) + { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, + "DeviceSetRawReadInfo: FDO %p couldn't get mode sense data\n", + DeviceExtension->DeviceObject + )); + } + +FnExit: + + if (buffer) + { + FREE_POOL(buffer); + } + + return status; +} + + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DeviceInitializeDvd( + _In_ WDFDEVICE Device + ) +/*++ + +Routine Description: + + This routine sets the region of DVD drive + NOTE: this routine uses ScratchBuffer, it must be called after ScratchBuffer allocated. + +Arguments: + + Device - device object + +Return Value: + + NTSTATUS + +--*/ + +{ + NTSTATUS status = STATUS_SUCCESS; + PCDROM_DEVICE_EXTENSION deviceExtension; + PDVD_COPY_PROTECT_KEY copyProtectKey = NULL; + PDVD_RPC_KEY rpcKey = NULL; + ULONG bufferLen = 0; + size_t bytesReturned; + + PAGED_CODE(); + + deviceExtension = DeviceGetExtension(Device); + + // check to see if we have a DVD device + if (deviceExtension->DeviceAdditionalData.DriveDeviceType != FILE_DEVICE_DVD) + { + return STATUS_SUCCESS; + } + + // we got a DVD drive. + bufferLen = DVD_RPC_KEY_LENGTH; + copyProtectKey = (PDVD_COPY_PROTECT_KEY)ExAllocatePoolWithTag(PagedPool, + bufferLen, + DVD_TAG_RPC2_CHECK); + + if (copyProtectKey == NULL) + { + return STATUS_INSUFFICIENT_RESOURCES; + } + + // get the device region + RtlZeroMemory (copyProtectKey, bufferLen); + copyProtectKey->KeyLength = DVD_RPC_KEY_LENGTH; + copyProtectKey->KeyType = DvdGetRpcKey; + + // perform IOCTL_DVD_READ_KEY + status = DvdStartSessionReadKey(deviceExtension, + IOCTL_DVD_READ_KEY, + NULL, + copyProtectKey, + DVD_RPC_KEY_LENGTH, + copyProtectKey, + DVD_RPC_KEY_LENGTH, + &bytesReturned); + + if (NT_SUCCESS(status)) + { + rpcKey = (PDVD_RPC_KEY)copyProtectKey->KeyData; + + // TypeCode of zero means that no region has been set. + if (rpcKey->TypeCode == 0) + { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_PNP, + "DVD Initialize (%p): must choose DVD region\n", + Device)); + deviceExtension->DeviceAdditionalData.PickDvdRegion = 1; + + // set the device region code to be the same as region code on media. + if (deviceExtension->DeviceAdditionalData.Mmc.IsCssDvd) + { + DevicePickDvdRegion(Device); + } + } + } + + FREE_POOL(copyProtectKey); + + // return status of IOCTL_DVD_READ_KEY will be ignored. + return STATUS_SUCCESS; +} + + +#if (NTDDI_VERSION >= NTDDI_WIN8) +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +DeviceIsPortable( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _Out_ PBOOLEAN IsPortable + ) +/*++ + +Routine Description: + + This routine checks if the volume is on a portable storage device. + +Arguments: + + DeviceExtension - device context + IsPortable - device is portable + +Return Value: + + NTSTATUS. + +--*/ + +{ + DEVPROP_BOOLEAN isInternal = DEVPROP_FALSE; + BOOLEAN isPortable = FALSE; + ULONG size = 0; + NTSTATUS status = STATUS_SUCCESS; + DEVPROPTYPE type = DEVPROP_TYPE_EMPTY; + + PAGED_CODE(); + + *IsPortable = FALSE; + + // Check to see if the underlying device object is in local machine container + status = IoGetDevicePropertyData(DeviceExtension->LowerPdo, + &DEVPKEY_Device_InLocalMachineContainer, + 0, + 0, + sizeof(isInternal), + &isInternal, + &size, + &type); + + if (!NT_SUCCESS(status)) + { + goto Cleanup; + } + + NT_ASSERT(size == sizeof(isInternal)); + NT_ASSERT(type == DEVPROP_TYPE_BOOLEAN); + + // Volume is hot-pluggable if the disk pdo container id differs from that of root device + if (isInternal == DEVPROP_TRUE) + { + goto Cleanup; + } + + isPortable = TRUE; + + // Examine the bus type to ensure that this really is a fixed device + if (DeviceExtension->DeviceDescriptor->BusType == BusTypeFibre || + DeviceExtension->DeviceDescriptor->BusType == BusTypeiScsi || + DeviceExtension->DeviceDescriptor->BusType == BusTypeRAID) + { + isPortable = FALSE; + } + + *IsPortable = isPortable; + +Cleanup: + + return status; +} +#endif + + +#pragma warning(pop) // un-sets any local warning changes + diff --git a/storage/class/cdrom/src/ioctl.c b/storage/class/cdrom/src/ioctl.c new file mode 100644 index 00000000..49eeba49 --- /dev/null +++ b/storage/class/cdrom/src/ioctl.c @@ -0,0 +1,9132 @@ +/*-- + +Copyright (C) Microsoft Corporation. All rights reserved. + +Module Name: + + ioctl.c + +Abstract: + + Include all funtions for processing IOCTLs + +Environment: + + kernel mode only + +Notes: + + +Revision History: + +--*/ + +#include "stddef.h" +#include "string.h" + +#include "ntddk.h" +#include "ntddstor.h" +#include "cdrom.h" +#include "ioctl.h" +#include "scratch.h" +#include "mmc.h" + + +#ifdef DEBUG_USE_WPP +#include "ioctl.tmh" +#endif + + +#define FirstDriveLetter 'C' +#define LastDriveLetter 'Z' + +#if DBG + LPCSTR READ_DVD_STRUCTURE_FORMAT_STRINGS[DvdMaxDescriptor+1] = { + "Physical", + "Copyright", + "DiskKey", + "BCA", + "Manufacturer", + "Unknown" + }; +#endif // DBG + +_IRQL_requires_max_(APC_LEVEL) +VOID +GetConfigurationDataConversionTypeAllToTypeOne( + _In_ FEATURE_NUMBER RequestedFeature, + _In_ PSCSI_REQUEST_BLOCK Srb, + _Out_ size_t * DataLength + ); + +_IRQL_requires_max_(APC_LEVEL) +VOID +GetConfigurationDataSynthesize( + _In_reads_bytes_(InputBufferSize) PVOID InputBuffer, + _In_ ULONG InputBufferSize, + _Out_writes_bytes_(OutputBufferSize) PVOID OutputBuffer, + _In_ size_t OutputBufferSize, + _In_ FEATURE_NUMBER StartingFeature, + _In_ ULONG RequestType, + _Out_ size_t * DataLength + ); + +_IRQL_requires_max_(APC_LEVEL) +PCDB +RequestGetScsiPassThroughCdb( + _In_ PIRP Irp + ); + +#ifdef ALLOC_PRAGMA + +#pragma alloc_text(PAGE, DeviceIsPlayActive) +#pragma alloc_text(PAGE, RequestHandleGetDvdRegion) +#pragma alloc_text(PAGE, RequestHandleReadTOC) +#pragma alloc_text(PAGE, RequestHandleReadTocEx) +#pragma alloc_text(PAGE, RequestHandleGetConfiguration) +#pragma alloc_text(PAGE, RequestHandleGetDriveGeometry) +#pragma alloc_text(PAGE, RequestHandleDiskVerify) +#pragma alloc_text(PAGE, RequestHandleCheckVerify) +#pragma alloc_text(PAGE, RequestHandleFakePartitionInfo) +#pragma alloc_text(PAGE, RequestHandleEjectionControl) +#pragma alloc_text(PAGE, RequestHandleEnableStreaming) +#pragma alloc_text(PAGE, RequestHandleSendOpcInformation) +#pragma alloc_text(PAGE, RequestHandleGetPerformance) +#pragma alloc_text(PAGE, RequestHandleMcnSyncFakeIoctl) +#pragma alloc_text(PAGE, RequestHandleLoadEjectMedia) +#pragma alloc_text(PAGE, RequestHandleReserveRelease) +#pragma alloc_text(PAGE, RequestHandlePersistentReserve) +#pragma alloc_text(PAGE, DeviceHandleRawRead) +#pragma alloc_text(PAGE, DeviceHandlePlayAudioMsf) +#pragma alloc_text(PAGE, DeviceHandleReadQChannel) +#pragma alloc_text(PAGE, ReadQChannel) +#pragma alloc_text(PAGE, DeviceHandlePauseAudio) +#pragma alloc_text(PAGE, DeviceHandleResumeAudio) +#pragma alloc_text(PAGE, DeviceHandleSeekAudioMsf) +#pragma alloc_text(PAGE, DeviceHandleStopAudio) +#pragma alloc_text(PAGE, DeviceHandleGetSetVolume) +#pragma alloc_text(PAGE, DeviceHandleReadDvdStructure) +#pragma alloc_text(PAGE, ReadDvdStructure) +#pragma alloc_text(PAGE, DeviceHandleDvdEndSession) +#pragma alloc_text(PAGE, DeviceHandleDvdStartSessionReadKey) +#pragma alloc_text(PAGE, DvdStartSessionReadKey) +#pragma alloc_text(PAGE, DeviceHandleDvdSendKey) +#pragma alloc_text(PAGE, DvdSendKey) +#pragma alloc_text(PAGE, DeviceHandleSetReadAhead) +#pragma alloc_text(PAGE, DeviceHandleSetSpeed) +#pragma alloc_text(PAGE, RequestHandleExclusiveAccessQueryLockState) +#pragma alloc_text(PAGE, RequestHandleExclusiveAccessLockDevice) +#pragma alloc_text(PAGE, RequestHandleExclusiveAccessUnlockDevice) +#pragma alloc_text(PAGE, RequestHandleScsiPassThrough) +#pragma alloc_text(PAGE, RequestGetScsiPassThroughCdb) +#pragma alloc_text(PAGE, GetConfigurationDataConversionTypeAllToTypeOne) +#pragma alloc_text(PAGE, GetConfigurationDataSynthesize) + +#endif + +NTSTATUS +RequestHandleUnknownIoctl( + _In_ WDFDEVICE Device, + _In_ WDFREQUEST Request + ) +/*++ + +Routine Description: + + All unknown IOCTLs will be forward to lower level driver. + +Arguments: + + Device - device object + Request - request to be handled + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_UNSUCCESSFUL; + PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(Device); + PCDROM_REQUEST_CONTEXT requestContext = RequestGetContext(Request); + BOOLEAN syncRequired = requestContext->SyncRequired; + + ULONG sendOptionsFlags = 0; + BOOLEAN requestSent = FALSE; + + WdfRequestFormatRequestUsingCurrentType(Request); + + if (syncRequired) + { + sendOptionsFlags = WDF_REQUEST_SEND_OPTION_SYNCHRONOUS; + } + else + { + WdfRequestSetCompletionRoutine(Request, RequestDummyCompletionRoutine, NULL); + } + + status = RequestSend(deviceExtension, + Request, + deviceExtension->IoTarget, + sendOptionsFlags, + &requestSent); + + if (requestSent) + { + if (syncRequired) + { + // the request needs to be completed here. + RequestCompletion(deviceExtension, Request, status, WdfRequestGetInformation(Request)); + } + } + else + { + // failed to send the request to IoTarget + RequestCompletion(deviceExtension, Request, status, WdfRequestGetInformation(Request)); + } + + return status; +} + +_IRQL_requires_max_(APC_LEVEL) +BOOLEAN +DeviceIsPlayActive( + _In_ WDFDEVICE Device + ) +/*++ + +Routine Description: + + This routine determines if the cd is currently playing music. + +Arguments: + + Device - Device object. + +Return Value: + + BOOLEAN - TRUE if the device is playing music. + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(Device); + PSUB_Q_CURRENT_POSITION currentBuffer; + size_t bytesRead = 0; + + PAGED_CODE (); + + // if we don't think it is playing audio, don't bother checking. + if (!deviceExtension->DeviceAdditionalData.PlayActive) + { + return FALSE; + } + + // Allocate the required memory + NT_ASSERT(sizeof(SUB_Q_CURRENT_POSITION) >= sizeof(CDROM_SUB_Q_DATA_FORMAT)); + currentBuffer = ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned, + sizeof(SUB_Q_CURRENT_POSITION), + CDROM_TAG_PLAY_ACTIVE); + if (currentBuffer == NULL) + { + return FALSE; + } + + // set the options in the output buffer format + ((PCDROM_SUB_Q_DATA_FORMAT) currentBuffer)->Format = IOCTL_CDROM_CURRENT_POSITION; + ((PCDROM_SUB_Q_DATA_FORMAT) currentBuffer)->Track = 0; + + // Send SCSI command to read Q Channel information. + status = ReadQChannel(deviceExtension, + NULL, + currentBuffer, + sizeof(CDROM_SUB_Q_DATA_FORMAT), + currentBuffer, + sizeof(SUB_Q_CURRENT_POSITION), + &bytesRead); + + if (!NT_SUCCESS(status)) + { + ExFreePool(currentBuffer); + return FALSE; + } + + // update the playactive flag appropriately + if (currentBuffer->Header.AudioStatus == AUDIO_STATUS_IN_PROGRESS) + { + deviceExtension->DeviceAdditionalData.PlayActive = TRUE; + } + else + { + deviceExtension->DeviceAdditionalData.PlayActive = FALSE; + } + + ExFreePool(currentBuffer); + + return deviceExtension->DeviceAdditionalData.PlayActive; +} + +NTSTATUS +RequestHandleGetInquiryData( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength) +/*++ + +Routine Description: + + Handler for IOCTL_CDROM_GET_INQUIRY_DATA + +Arguments: + + DeviceExtension - device context + Request - request to be handled + RequestParameters - request parameter + DataLength - transferred data length + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PCDROM_DATA cdData = &(DeviceExtension->DeviceAdditionalData); + + *DataLength = 0; + + if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength == 0) + { + status = STATUS_BUFFER_TOO_SMALL; + } + else + { + PVOID outputBuffer = NULL; + + *DataLength = min(cdData->CachedInquiryDataByteCount, + RequestParameters.Parameters.DeviceIoControl.OutputBufferLength); + + status = WdfRequestRetrieveOutputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, + &outputBuffer, + NULL); + + if (NT_SUCCESS(status) && + (outputBuffer != NULL)) + { + // Always copy as much data as possible + RtlCopyMemory(outputBuffer, + cdData->CachedInquiryData, + *DataLength); + } + + // and finally decide between two possible status values + if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < cdData->CachedInquiryDataByteCount) + { + status = STATUS_BUFFER_OVERFLOW; + } + } + + return status; +} + + +NTSTATUS +RequestHandleGetMediaTypeEx( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + Handler for IOCTL_STORAGE_GET_MEDIA_TYPES_EX + +Arguments: + + DeviceExtension - device context + Request - request to be handled + DataLength - transferred data length + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PCDROM_DATA cdData = &(DeviceExtension->DeviceAdditionalData); + + PGET_MEDIA_TYPES mediaTypes = NULL; + PDEVICE_MEDIA_INFO mediaInfo = NULL; //&mediaTypes->MediaInfo[0]; + ULONG sizeNeeded = 0; + PZERO_POWER_ODD_INFO zpoddInfo = DeviceExtension->ZeroPowerODDInfo; + + *DataLength = 0; + + // Must run below dispatch level. + if (KeGetCurrentIrql() >= DISPATCH_LEVEL) + { + NT_ASSERT(FALSE); + return STATUS_INVALID_LEVEL; + } + + sizeNeeded = sizeof(GET_MEDIA_TYPES); + + // IsMmc is static... + if (cdData->Mmc.IsMmc) + { + sizeNeeded += sizeof(DEVICE_MEDIA_INFO) * 1; // return two media types + } + + status = WdfRequestRetrieveOutputBuffer(Request, + sizeNeeded, + (PVOID*)&mediaTypes, + NULL); + + if (NT_SUCCESS(status) && + (mediaTypes != NULL)) + { + mediaInfo = &mediaTypes->MediaInfo[0]; + + RtlZeroMemory(mediaTypes, sizeNeeded); + + // ISSUE-2000/5/11-henrygab - need to update GET_MEDIA_TYPES_EX + + mediaTypes->DeviceType = cdData->DriveDeviceType; + + mediaTypes->MediaInfoCount = 1; + mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaType = CD_ROM; + mediaInfo->DeviceSpecific.RemovableDiskInfo.NumberMediaSides = 1; + mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics = MEDIA_READ_ONLY; + mediaInfo->DeviceSpecific.RemovableDiskInfo.Cylinders.QuadPart = DeviceExtension->DiskGeometry.Cylinders.QuadPart; + mediaInfo->DeviceSpecific.RemovableDiskInfo.TracksPerCylinder = DeviceExtension->DiskGeometry.TracksPerCylinder; + mediaInfo->DeviceSpecific.RemovableDiskInfo.SectorsPerTrack = DeviceExtension->DiskGeometry.SectorsPerTrack; + mediaInfo->DeviceSpecific.RemovableDiskInfo.BytesPerSector = DeviceExtension->DiskGeometry.BytesPerSector; + + if (cdData->Mmc.IsMmc) + { + // also report a removable disk + mediaTypes->MediaInfoCount += 1; + + mediaInfo++; + mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaType = RemovableMedia; + mediaInfo->DeviceSpecific.RemovableDiskInfo.NumberMediaSides = 1; + mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics = MEDIA_READ_WRITE; + mediaInfo->DeviceSpecific.RemovableDiskInfo.Cylinders.QuadPart = DeviceExtension->DiskGeometry.Cylinders.QuadPart; + mediaInfo->DeviceSpecific.RemovableDiskInfo.TracksPerCylinder = DeviceExtension->DiskGeometry.TracksPerCylinder; + mediaInfo->DeviceSpecific.RemovableDiskInfo.SectorsPerTrack = DeviceExtension->DiskGeometry.SectorsPerTrack; + mediaInfo->DeviceSpecific.RemovableDiskInfo.BytesPerSector = DeviceExtension->DiskGeometry.BytesPerSector; + mediaInfo--; + + } + + // Status will either be success, if media is present, or no media. + // It would be optimal to base from density code and medium type, but not all devices + // have values for these fields. + + // Send a TUR to determine if media is present, only if the device is not in ZPODD mode. + if ((!EXCLUSIVE_MODE(cdData) || + EXCLUSIVE_OWNER(cdData, WdfRequestGetFileObject(Request))) && + ((zpoddInfo == NULL) || + (zpoddInfo->InZeroPowerState == FALSE))) + { + SCSI_REQUEST_BLOCK srb; + PCDB cdb = (PCDB)srb.Cdb; + + RtlZeroMemory(&srb,sizeof(SCSI_REQUEST_BLOCK)); + + srb.CdbLength = 6; + cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY; + + srb.TimeOutValue = CDROM_TEST_UNIT_READY_TIMEOUT; + + status = DeviceSendSrbSynchronously(DeviceExtension->Device, + &srb, + NULL, + 0, + FALSE, + Request); + + if (NT_SUCCESS(status)) + { + // set the disk's media as current if we can write to it. + if (cdData->Mmc.IsMmc && cdData->Mmc.WriteAllowed) + { + mediaInfo++; + SET_FLAG(mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics, + MEDIA_CURRENTLY_MOUNTED); + mediaInfo--; + } + else + { + SET_FLAG(mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics, + MEDIA_CURRENTLY_MOUNTED); + } + } + else + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, + "RequestHandleGetMediaTypeEx: GET_MEDIA_TYPES status of TUR - %lx\n", status)); + } + } + + // per legacy cdrom behavior, always return success + status = STATUS_SUCCESS; + } + + *DataLength = sizeNeeded; + + return status; +} + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +RequestHandleGetDvdRegion( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + Handler for IOCTL_DVD_GET_REGION + +Arguments: + + DeviceExtension - device context + Request - request to be handled + DataLength - transferred data length + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + + PVOID outputBuffer = NULL; + size_t bytesReturned = 0; + + PDVD_COPY_PROTECT_KEY copyProtectKey = NULL; + ULONG keyLength = 0; + PDVD_DESCRIPTOR_HEADER dvdHeader; + PDVD_COPYRIGHT_DESCRIPTOR copyRightDescriptor; + PDVD_REGION dvdRegion = NULL; + PDVD_READ_STRUCTURE readStructure = NULL; + PDVD_RPC_KEY rpcKey; + + PAGED_CODE (); + + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL, + "RequestHandleGetDvdRegion: [%p] IOCTL_DVD_GET_REGION\n", Request)); + + *DataLength = 0; + + // reject the request if it's not a DVD device. + if (DeviceExtension->DeviceAdditionalData.DriveDeviceType != FILE_DEVICE_DVD) + { + status = STATUS_INVALID_DEVICE_REQUEST; + } + + if (NT_SUCCESS(status)) + { + status = WdfRequestRetrieveOutputBuffer(Request, + sizeof(DVD_REGION), + &outputBuffer, + NULL); + } + + if (NT_SUCCESS(status)) + { + // figure out how much data buffer we need + keyLength = max((sizeof(DVD_DESCRIPTOR_HEADER) + sizeof(DVD_COPYRIGHT_DESCRIPTOR)), + sizeof(DVD_READ_STRUCTURE)); + keyLength = max(keyLength, + DVD_RPC_KEY_LENGTH); + + // round the size to nearest ULONGLONG -- why? + // could this be to deal with device alignment issues? + keyLength += sizeof(ULONGLONG) - (keyLength & (sizeof(ULONGLONG) - 1)); + + readStructure = ExAllocatePoolWithTag(NonPagedPoolNx, + keyLength, + DVD_TAG_READ_KEY); + if (readStructure == NULL) + { + status = STATUS_INSUFFICIENT_RESOURCES; + } + } + + if (NT_SUCCESS(status)) + { + RtlZeroMemory (readStructure, keyLength); + readStructure->Format = DvdCopyrightDescriptor; + + // use READ_STRUCTURE to read copyright descriptor + status = ReadDvdStructure(DeviceExtension, + Request, + readStructure, + keyLength, + readStructure, + sizeof(DVD_DESCRIPTOR_HEADER) + sizeof(DVD_COPYRIGHT_DESCRIPTOR), + &bytesReturned); + } + + if (NT_SUCCESS(status)) + { + // we got the copyright descriptor, so now get the region if possible + dvdHeader = (PDVD_DESCRIPTOR_HEADER) readStructure; + copyRightDescriptor = (PDVD_COPYRIGHT_DESCRIPTOR) dvdHeader->Data; + + // the original irp's systembuffer has a copy of the info that + // should be passed down in the request + dvdRegion = outputBuffer; + + dvdRegion->CopySystem = copyRightDescriptor->CopyrightProtectionType; + dvdRegion->RegionData = copyRightDescriptor->RegionManagementInformation; + + // now reuse the buffer to request the copy protection info + copyProtectKey = (PDVD_COPY_PROTECT_KEY) readStructure; + RtlZeroMemory (copyProtectKey, DVD_RPC_KEY_LENGTH); + copyProtectKey->KeyLength = DVD_RPC_KEY_LENGTH; + copyProtectKey->KeyType = DvdGetRpcKey; + + // send a request for READ_KEY + status = DvdStartSessionReadKey(DeviceExtension, + IOCTL_DVD_READ_KEY, + Request, + copyProtectKey, + DVD_RPC_KEY_LENGTH, + copyProtectKey, + DVD_RPC_KEY_LENGTH, + &bytesReturned); + } + + if (NT_SUCCESS(status)) + { + // the request succeeded. if a supported scheme is returned, + // then return the information to the caller + rpcKey = (PDVD_RPC_KEY) copyProtectKey->KeyData; + + if (rpcKey->RpcScheme == 1) + { + if (rpcKey->TypeCode) + { + dvdRegion->SystemRegion = ~rpcKey->RegionMask; + dvdRegion->ResetCount = rpcKey->UserResetsAvailable; + } + else + { + // the drive has not been set for any region + dvdRegion->SystemRegion = 0; + dvdRegion->ResetCount = rpcKey->UserResetsAvailable; + } + + *DataLength = sizeof(DVD_REGION); + } + else + { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, + "RequestHandleGetDvdRegion => rpcKey->RpcScheme != 1\n")); + status = STATUS_INVALID_DEVICE_REQUEST; + } + } + + // Clean up + if (readStructure != NULL) + { + ExFreePool(readStructure); + } + + return status; +} + +NTSTATUS +RequestValidateRawRead( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + Validate request of IOCTL_CDROM_RAW_READ + +Arguments: + + DeviceExtension - device context + Request - request to be handled + RequestParameters - request parameter + DataLength - transferred data length + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PCDROM_DATA cdData = &(DeviceExtension->DeviceAdditionalData); + + PVOID inputBuffer = NULL; + PIRP irp = NULL; + PIO_STACK_LOCATION currentStack = NULL; + + LARGE_INTEGER startingOffset = {0}; + ULONGLONG transferBytes = 0; + ULONGLONG endOffset; + ULONGLONG mdlBytes; + RAW_READ_INFO rawReadInfo = {0}; + + *DataLength = 0; + + irp = WdfRequestWdmGetIrp(Request); + currentStack = IoGetCurrentIrpStackLocation(irp); + + status = WdfRequestRetrieveInputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.InputBufferLength, + &inputBuffer, + NULL); + + // Check that ending sector is on disc and buffers are there and of + // correct size. + if (NT_SUCCESS(status) && + (RequestParameters.Parameters.DeviceIoControl.Type3InputBuffer == NULL)) + { + // This is a call from user space. This is the only time that we need to validate parameters. + // Validate the input and get the input buffer into Type3InputBuffer + // so the rest of the code will be uniform. + if (inputBuffer != NULL) + { + currentStack->Parameters.DeviceIoControl.Type3InputBuffer = inputBuffer; + RequestParameters.Parameters.DeviceIoControl.Type3InputBuffer = inputBuffer; + + if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength < sizeof(RAW_READ_INFO)) + { + *DataLength = sizeof(RAW_READ_INFO); + status = STATUS_BUFFER_TOO_SMALL; + } + } + else + { + status = STATUS_INVALID_PARAMETER; + } + } + + if (NT_SUCCESS(status)) + { + // Since this ioctl is METHOD_OUT_DIRECT, we need to copy away the input buffer before interpreting it. + // This prevents a malicious app from messing with the input buffer while we are interpreting it. + rawReadInfo = *(PRAW_READ_INFO)RequestParameters.Parameters.DeviceIoControl.Type3InputBuffer; + + startingOffset.QuadPart = rawReadInfo.DiskOffset.QuadPart; + + if ((rawReadInfo.TrackMode == CDDA) || + (rawReadInfo.TrackMode == YellowMode2) || + (rawReadInfo.TrackMode == XAForm2) ) + { + transferBytes = (ULONGLONG)rawReadInfo.SectorCount * RAW_SECTOR_SIZE; + } + else if (rawReadInfo.TrackMode == RawWithSubCode) + { + transferBytes = (ULONGLONG)rawReadInfo.SectorCount * CD_RAW_SECTOR_WITH_SUBCODE_SIZE; + } + else if (rawReadInfo.TrackMode == RawWithC2) + { + transferBytes = (ULONGLONG)rawReadInfo.SectorCount * CD_RAW_SECTOR_WITH_C2_SIZE; + } + else if (rawReadInfo.TrackMode == RawWithC2AndSubCode) + { + transferBytes = (ULONGLONG)rawReadInfo.SectorCount * CD_RAW_SECTOR_WITH_C2_AND_SUBCODE_SIZE; + } + else + { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, + "RequestValidateRawRead: Invalid TrackMode type %x for XA read\n", + rawReadInfo.TrackMode + )); + } + + endOffset = (ULONGLONG)rawReadInfo.SectorCount * COOKED_SECTOR_SIZE; + endOffset += startingOffset.QuadPart; + + // check for overflows.... + if (rawReadInfo.SectorCount == 0) + { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, + "RequestValidateRawRead: Invalid I/O parameters for XA " + "Read (zero sectors requested)\n")); + status = STATUS_INVALID_PARAMETER; + } + else if (transferBytes < (ULONGLONG)(rawReadInfo.SectorCount)) + { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, + "RequestValidateRawRead: Invalid I/O parameters for XA " + "Read (TransferBytes Overflow)\n")); + status = STATUS_INVALID_PARAMETER; + } + else if (endOffset < (ULONGLONG)startingOffset.QuadPart) + { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, + "RequestValidateRawRead: Invalid I/O parameters for XA " + "Read (EndingOffset Overflow)\n")); + status = STATUS_INVALID_PARAMETER; + } + else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < transferBytes) + { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, + "RequestValidateRawRead: Invalid I/O parameters for XA " + "Read (Bad buffer size)\n")); + status = STATUS_INVALID_PARAMETER; + } + else if (endOffset > (ULONGLONG)DeviceExtension->PartitionLength.QuadPart) + { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, + "RequestValidateRawRead: Invalid I/O parameters for XA " + "Read (Request Out of Bounds)\n")); + status = STATUS_INVALID_PARAMETER; + } + } + + if (NT_SUCCESS(status)) + { + // cannot validate the MdlAddress, since it is not included in any + // other location per the DDK and file system calls. + + // validate the mdl describes at least the number of bytes + // requested from us. + mdlBytes = (ULONGLONG)MmGetMdlByteCount(irp->MdlAddress); + if (mdlBytes < transferBytes) + { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, + "RequestValidateRawRead: Invalid MDL %s, Irp %p\n", + "size (5)", irp)); + status = STATUS_INVALID_PARAMETER; + } + } + + if (NT_SUCCESS(status)) + { + // check the buffer for alignment + // This is important for x86 as some busses (ie ATAPI) + // require word-aligned buffers. + if ( ((ULONG_PTR)MmGetMdlVirtualAddress(irp->MdlAddress)) & + DeviceExtension->AdapterDescriptor->AlignmentMask ) + { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, + "RequestValidateRawRead: Invalid I/O parameters for " + "XA Read (Buffer %p not aligned with mask %x\n", + RequestParameters.Parameters.DeviceIoControl.Type3InputBuffer, + DeviceExtension->AdapterDescriptor->AlignmentMask)); + status = STATUS_INVALID_PARAMETER; + } + } + + if (NT_SUCCESS(status)) + { + // Validate the request is not too large for the adapter + BOOLEAN bufferIsPageAligned = FALSE; + ULONG maxLength = 0; + + // if buffer is not page-aligned, then subtract one as the + // transfer could cross a page boundary. + if ((((ULONG_PTR)MmGetMdlVirtualAddress(irp->MdlAddress)) & (PAGE_SIZE-1)) == 0) + { + bufferIsPageAligned = TRUE; + } + + if (bufferIsPageAligned) + { + maxLength = cdData->MaxPageAlignedTransferBytes; + } + else + { + maxLength = cdData->MaxUnalignedTransferBytes; + } + + if (transferBytes > maxLength) + { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, + "RequestValidateRawRead: The XA Read (type %x) would require %I64x bytes, " + "but the adapter can only handle %x bytes (for a%saligned buffer)\n", + rawReadInfo.TrackMode, + transferBytes, + maxLength, + (bufferIsPageAligned ? " " : "n un") + )); + status = STATUS_INVALID_PARAMETER; + } + } + + if (NT_SUCCESS(status)) + { + // + // HACKHACK - REF #0001 + // The retry count will be in this irp's IRP_MN function, + // as the new irp was freed, and we therefore cannot use + // this irp's next stack location for this function. + // This may be a good location to store this info for + // when we remove RAW_READ (mode switching), as we will + // no longer have the nextIrpStackLocation to play with + // when that occurs + // + currentStack->MinorFunction = MAXIMUM_RETRIES; // HACKHACK - REF #0001 + } + + return status; +} + +NTSTATUS +RequestValidateReadTocEx( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + Validate request of IOCTL_CDROM_READ_TOC_EX + +Arguments: + + DeviceExtension - device context + Request - request to be handled + RequestParameters - request parameter + DataLength - transferred data length + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + + PCDROM_READ_TOC_EX inputBuffer = NULL; + + *DataLength = 0; + + if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength < + sizeof(CDROM_READ_TOC_EX)) + { + status = STATUS_INFO_LENGTH_MISMATCH; + } + else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < + MINIMUM_CDROM_READ_TOC_EX_SIZE) + { + status = STATUS_BUFFER_TOO_SMALL; + *DataLength = MINIMUM_CDROM_READ_TOC_EX_SIZE; + } + else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength > + ((USHORT)-1)) + { + status = STATUS_INVALID_PARAMETER; + } + else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength & + DeviceExtension->AdapterDescriptor->AlignmentMask) + { + status = STATUS_INVALID_PARAMETER; + } + + if (NT_SUCCESS(status)) + { + status = WdfRequestRetrieveInputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.InputBufferLength, + &inputBuffer, + NULL); + } + + if (NT_SUCCESS(status)) + { + if ((inputBuffer->Reserved1 != 0) || + (inputBuffer->Reserved2 != 0) || + (inputBuffer->Reserved3 != 0)) + { + status = STATUS_INVALID_PARAMETER; + } + // NOTE: when adding new formats, ensure that first two bytes + // specify the amount of additional data available. + else if ((inputBuffer->Format == CDROM_READ_TOC_EX_FORMAT_TOC ) || + (inputBuffer->Format == CDROM_READ_TOC_EX_FORMAT_FULL_TOC) || + (inputBuffer->Format == CDROM_READ_TOC_EX_FORMAT_CDTEXT )) + { + // SessionTrack field is used + } + else if ((inputBuffer->Format == CDROM_READ_TOC_EX_FORMAT_SESSION) || + (inputBuffer->Format == CDROM_READ_TOC_EX_FORMAT_PMA) || + (inputBuffer->Format == CDROM_READ_TOC_EX_FORMAT_ATIP)) + { + // SessionTrack field is reserved + if (inputBuffer->SessionTrack != 0) + { + status = STATUS_INVALID_PARAMETER; + } + } + else + { + status = STATUS_INVALID_PARAMETER; + } + } + + return status; +} + +NTSTATUS +RequestValidateReadToc( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + Validate request of IOCTL_CDROM_READ_TOC + +Arguments: + + DeviceExtension - device context + RequestParameters - request parameter + DataLength - transferred data length + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + + *DataLength = 0; + + if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < + sizeof(CDROM_TOC)) + { + // they didn't request the entire TOC -- use _EX version + // for partial transfers and such. + status = STATUS_BUFFER_TOO_SMALL; + *DataLength = sizeof(CDROM_TOC); + } + else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength & + DeviceExtension->AdapterDescriptor->AlignmentMask) + { + status = STATUS_INVALID_PARAMETER; + } + + return status; +} + +NTSTATUS +RequestValidateGetLastSession( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + Validate request of IOCTL_CDROM_GET_LAST_SESSION + +Arguments: + + DeviceExtension - device context + RequestParameters - request parameter + DataLength - transferred data length + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + + *DataLength = 0; + + if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < + sizeof(CDROM_TOC_SESSION_DATA)) + { + status = STATUS_BUFFER_TOO_SMALL; + *DataLength = sizeof(CDROM_TOC_SESSION_DATA); + } + else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength & + DeviceExtension->AdapterDescriptor->AlignmentMask) + { + status = STATUS_INVALID_PARAMETER; + } + + return status; +} + +NTSTATUS +RequestValidateReadQChannel( + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + Validate request of IOCTL_CDROM_READ_Q_CHANNEL + +Arguments: + + Request - request to be handled + RequestParameters - request parameter + DataLength - transferred data length + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PCDROM_SUB_Q_DATA_FORMAT inputBuffer = NULL; + ULONG transferByteCount = 0; + + *DataLength = 0; + + if(RequestParameters.Parameters.DeviceIoControl.InputBufferLength < + sizeof(CDROM_SUB_Q_DATA_FORMAT)) + { + status = STATUS_INFO_LENGTH_MISMATCH; + } + + if (NT_SUCCESS(status)) + { + status = WdfRequestRetrieveInputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.InputBufferLength, + &inputBuffer, + NULL); + } + + if (NT_SUCCESS(status)) + { + // check for all valid types of request + if (inputBuffer->Format == IOCTL_CDROM_CURRENT_POSITION) + { + transferByteCount = sizeof(SUB_Q_CURRENT_POSITION); + } + else if (inputBuffer->Format == IOCTL_CDROM_MEDIA_CATALOG) + { + transferByteCount = sizeof(SUB_Q_MEDIA_CATALOG_NUMBER); + } + else if (inputBuffer->Format == IOCTL_CDROM_TRACK_ISRC) + { + transferByteCount = sizeof(SUB_Q_TRACK_ISRC); + } + else + { + // Format not valid + status = STATUS_INVALID_PARAMETER; + } + } + + if (NT_SUCCESS(status)) + { + if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < + transferByteCount) + { + status = STATUS_BUFFER_TOO_SMALL; + *DataLength = transferByteCount; + } + } + + return status; +} + +NTSTATUS +RequestValidateDvdReadStructure( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + Validate request of IOCTL_DVD_READ_STRUCTURE + +Arguments: + + DeviceExtension - device context + RequestParameters - request parameter + DataLength - transferred data length + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + + *DataLength = 0; + + if (NT_SUCCESS(status)) + { + if(RequestParameters.Parameters.DeviceIoControl.InputBufferLength < + sizeof(DVD_READ_STRUCTURE)) + { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, + "RequestValidateDvdReadStructure - input buffer " + "length too small (was %d should be %d)\n", + (int)RequestParameters.Parameters.DeviceIoControl.InputBufferLength, + sizeof(DVD_READ_STRUCTURE))); + status = STATUS_INVALID_PARAMETER; + } + else if(RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < + sizeof(READ_DVD_STRUCTURES_HEADER)) + { + + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, + "RequestValidateDvdReadStructure - output buffer " + "cannot hold header information\n")); + status = STATUS_BUFFER_TOO_SMALL; + *DataLength = sizeof(READ_DVD_STRUCTURES_HEADER); + } + else if(RequestParameters.Parameters.DeviceIoControl.OutputBufferLength > + MAXUSHORT) + { + // key length must fit in two bytes + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, + "RequestValidateDvdReadStructure - output buffer " + "too large\n")); + status = STATUS_INVALID_PARAMETER; + } + else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength & + DeviceExtension->AdapterDescriptor->AlignmentMask) + { + status = STATUS_INVALID_PARAMETER; + } + else if (DeviceExtension->DeviceAdditionalData.DriveDeviceType != FILE_DEVICE_DVD) + { + // reject the request if it's not a DVD device. + status = STATUS_INVALID_DEVICE_REQUEST; + } + } + + return status; +} + +NTSTATUS +RequestValidateDvdStartSession( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + Validate request of IOCTL_DVD_START_SESSION + +Arguments: + + DeviceExtension - device context + RequestParameters - request parameter + DataLength - transferred data length + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + + *DataLength = 0; + + if (NT_SUCCESS(status)) + { + if(RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < + sizeof(DVD_SESSION_ID)) + { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, + "RequestValidateDvdStartSession: DVD_START_SESSION - output " + "buffer too small\n")); + status = STATUS_BUFFER_TOO_SMALL; + *DataLength = sizeof(DVD_SESSION_ID); + } + else if (DeviceExtension->DeviceAdditionalData.DriveDeviceType != FILE_DEVICE_DVD) + { + // reject the request if it's not a DVD device. + status = STATUS_INVALID_DEVICE_REQUEST; + } + } + + return status; +} + +NTSTATUS +RequestValidateDvdSendKey( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + Validate request of IOCTL_DVD_SEND_KEY, IOCTL_DVD_SEND_KEY2 + +Arguments: + + DeviceExtension - device context + Request - request to be handled + RequestParameters - request parameter + DataLength - transferred data length + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PDVD_COPY_PROTECT_KEY key = NULL; + + *DataLength = 0; + + status = WdfRequestRetrieveInputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.InputBufferLength, + &key, + NULL); + + if (NT_SUCCESS(status)) + { + if((RequestParameters.Parameters.DeviceIoControl.InputBufferLength < sizeof(DVD_COPY_PROTECT_KEY)) || + (RequestParameters.Parameters.DeviceIoControl.InputBufferLength != key->KeyLength)) + { + + // + // Key is too small to have a header or the key length doesn't + // match the input buffer length. Key must be invalid + // + + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, + "RequestValidateDvdSendKey: [%p] IOCTL_DVD_SEND_KEY - " + "key is too small or does not match KeyLength\n", + Request)); + status = STATUS_INVALID_PARAMETER; + } + } + + if (NT_SUCCESS(status)) + { + // allow only certain key type (non-destructive) to go through + // IOCTL_DVD_SEND_KEY (which only requires READ access to the device) + if (RequestParameters.Parameters.DeviceIoControl.IoControlCode == IOCTL_DVD_SEND_KEY) + { + if ((key->KeyType != DvdChallengeKey) && + (key->KeyType != DvdBusKey2) && + (key->KeyType != DvdInvalidateAGID)) + { + status = STATUS_INVALID_PARAMETER; + } + } + else if ((key->KeyType != DvdChallengeKey) && + (key->KeyType != DvdBusKey1) && + (key->KeyType != DvdBusKey2) && + (key->KeyType != DvdTitleKey) && + (key->KeyType != DvdAsf) && + (key->KeyType != DvdSetRpcKey) && + (key->KeyType != DvdGetRpcKey) && + (key->KeyType != DvdDiskKey) && + (key->KeyType != DvdInvalidateAGID)) + { + status = STATUS_INVALID_PARAMETER; + } + else if (DeviceExtension->DeviceAdditionalData.DriveDeviceType != FILE_DEVICE_DVD) + { + // reject the request if it's not a DVD device. + status = STATUS_INVALID_DEVICE_REQUEST; + } + } + + return status; +} + +NTSTATUS +RequestValidateGetConfiguration( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + Validate request of IOCTL_CDROM_GET_CONFIGURATION + +Arguments: + + DeviceExtension - device context + Request - request to be handled + RequestParameters - request parameter + DataLength - transferred data length + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + + *DataLength = 0; + + if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < + sizeof(GET_CONFIGURATION_HEADER)) + { + status = STATUS_BUFFER_TOO_SMALL; + *DataLength = sizeof(GET_CONFIGURATION_HEADER); + } + else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength > 0xffff) + { + // output buffer is too large + status = STATUS_INVALID_BUFFER_SIZE; + } + else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength & + DeviceExtension->AdapterDescriptor->AlignmentMask) + { + // buffer is not proper size multiple + status = STATUS_INVALID_PARAMETER; + } + + if (NT_SUCCESS(status)) + { + +#if BUILD_WOW64_ENABLED && defined(_WIN64) + + if (WdfRequestIsFrom32BitProcess(Request)) + { + PGET_CONFIGURATION_IOCTL_INPUT32 inputBuffer = NULL; + + if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength < + sizeof(GET_CONFIGURATION_IOCTL_INPUT32)) + { + status = STATUS_INFO_LENGTH_MISMATCH; + } + + // + // also verify the arguments are reasonable. + // + if (NT_SUCCESS(status)) + { + status = WdfRequestRetrieveInputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.InputBufferLength, + &inputBuffer, + NULL); + } + + if (NT_SUCCESS(status)) + { + if (inputBuffer->Feature > 0xffff) + { + status = STATUS_INVALID_PARAMETER; + } + else if ((inputBuffer->RequestType != SCSI_GET_CONFIGURATION_REQUEST_TYPE_ONE) && + (inputBuffer->RequestType != SCSI_GET_CONFIGURATION_REQUEST_TYPE_CURRENT) && + (inputBuffer->RequestType != SCSI_GET_CONFIGURATION_REQUEST_TYPE_ALL)) + { + status = STATUS_INVALID_PARAMETER; + } + else if (inputBuffer->Reserved[0] || inputBuffer->Reserved[1]) + { + status = STATUS_INVALID_PARAMETER; + } + } + } + else + +#endif + + { + PGET_CONFIGURATION_IOCTL_INPUT inputBuffer = NULL; + + if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength < + sizeof(GET_CONFIGURATION_IOCTL_INPUT)) + { + status = STATUS_INFO_LENGTH_MISMATCH; + } + + // also verify the arguments are reasonable. + if (NT_SUCCESS(status)) + { + status = WdfRequestRetrieveInputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.InputBufferLength, + &inputBuffer, + NULL); + } + + if (NT_SUCCESS(status)) + { + if (inputBuffer->Feature > 0xffff) + { + status = STATUS_INVALID_PARAMETER; + } + else if ((inputBuffer->RequestType != SCSI_GET_CONFIGURATION_REQUEST_TYPE_ONE) && + (inputBuffer->RequestType != SCSI_GET_CONFIGURATION_REQUEST_TYPE_CURRENT) && + (inputBuffer->RequestType != SCSI_GET_CONFIGURATION_REQUEST_TYPE_ALL)) + { + status = STATUS_INVALID_PARAMETER; + } + else if (inputBuffer->Reserved[0] || inputBuffer->Reserved[1]) + { + status = STATUS_INVALID_PARAMETER; + } + } + } + } + + return status; +} + +NTSTATUS +RequestValidateSetSpeed( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + Validate request of IOCTL_CDROM_SET_SPEED + +Arguments: + + DeviceExtension - device context + Request - request to be handled + RequestParameters - request parameter + DataLength - transferred data length + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PCDROM_DATA cdData = &(DeviceExtension->DeviceAdditionalData); + PCDROM_SET_SPEED inputBuffer = NULL; + ULONG requiredLength = 0; + + *DataLength = 0; + + if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength < sizeof(CDROM_SET_SPEED)) + { + status = STATUS_INFO_LENGTH_MISMATCH; + } + + if (NT_SUCCESS(status)) + { + // Get the request type using CDROM_SET_SPEED structure + status = WdfRequestRetrieveInputBuffer(Request, + sizeof(CDROM_SET_SPEED), + &inputBuffer, + NULL); + + } + + if (NT_SUCCESS(status)) + { + if (inputBuffer->RequestType > CdromSetStreaming) + { + // Unknown request type. + status = STATUS_INVALID_PARAMETER; + } + else if (inputBuffer->RequestType == CdromSetSpeed) + { + requiredLength = sizeof(CDROM_SET_SPEED); + } + else + { + // Don't send SET STREAMING command if this is not a MMC compliant device + if (cdData->Mmc.IsMmc == FALSE) + { + status = STATUS_INVALID_DEVICE_REQUEST; + } + + requiredLength = sizeof(CDROM_SET_STREAMING); + } + } + + if (NT_SUCCESS(status)) + { + if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength < requiredLength) + { + // Input buffer too small + status = STATUS_INFO_LENGTH_MISMATCH; + } + } + + return status; +} + +NTSTATUS +RequestValidateAacsReadMediaKeyBlock( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + Validate request of IOCTL_AACS_READ_MEDIA_KEY_BLOCK + +Arguments: + + DeviceExtension - device context + Request - request to be handled + RequestParameters - request parameter + DataLength - transferred data length + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PCDROM_DATA cdData = &(DeviceExtension->DeviceAdditionalData); + PAACS_LAYER_NUMBER layerNumber = NULL; + + *DataLength = 0; + + if (!cdData->Mmc.IsAACS) + { + status = STATUS_INVALID_DEVICE_REQUEST; + } + else if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength != sizeof(AACS_LAYER_NUMBER)) + { + status = STATUS_INFO_LENGTH_MISMATCH; + } + else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < 8) + { + // This is a variable-length structure, but we're pretty sure + // it can never be less than eight bytes... + *DataLength = 8; + status = STATUS_BUFFER_TOO_SMALL; + } + + if (NT_SUCCESS(status)) + { + status = WdfRequestRetrieveInputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.InputBufferLength, + &layerNumber, + NULL); + } + + if (NT_SUCCESS(status)) + { + if (*layerNumber > 255) + { + status = STATUS_INVALID_PARAMETER; + } + } + + return status; +} + +NTSTATUS +RequestValidateAacsStartSession( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + Validate request of IOCTL_AACS_START_SESSION + +Arguments: + + DeviceExtension - device context + RequestParameters - request parameter + DataLength - transferred data length + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PCDROM_DATA cdData = &(DeviceExtension->DeviceAdditionalData); + + *DataLength = 0; + + if (!cdData->Mmc.IsAACS) + { + status = STATUS_INVALID_DEVICE_REQUEST; + } + else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < sizeof(DVD_SESSION_ID)) + { + *DataLength = sizeof(DVD_SESSION_ID); + status = STATUS_BUFFER_TOO_SMALL; + } + else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength > sizeof(DVD_SESSION_ID)) + { + status = STATUS_INVALID_BUFFER_SIZE; + } + + return status; +} + +NTSTATUS +RequestValidateAacsSendCertificate( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + Validate request of IOCTL_AACS_SEND_CERTIFICATE + +Arguments: + + DeviceExtension - device context + Request - request to be handled + RequestParameters - request parameter + DataLength - transferred data length + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PCDROM_DATA cdData = &(DeviceExtension->DeviceAdditionalData); + PAACS_SEND_CERTIFICATE inputBuffer = NULL; + + *DataLength = 0; + + if (!cdData->Mmc.IsAACS) + { + status = STATUS_INVALID_DEVICE_REQUEST; + } + else if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength != sizeof(AACS_SEND_CERTIFICATE)) + { + status = STATUS_INFO_LENGTH_MISMATCH; + } + + if (NT_SUCCESS(status)) + { + status = WdfRequestRetrieveInputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.InputBufferLength, + &inputBuffer, + NULL); + } + + if (NT_SUCCESS(status)) + { + if (inputBuffer->SessionId > MAX_COPY_PROTECT_AGID) + { + status = STATUS_INVALID_PARAMETER; + } + } + + return status; +} + +NTSTATUS +RequestValidateAacsGetCertificate( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + Validate request of IOCTL_AACS_GET_CERTIFICATE + +Arguments: + + DeviceExtension - device context + Request - request to be handled + RequestParameters - request parameter + DataLength - transferred data length + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PCDROM_DATA cdData = &(DeviceExtension->DeviceAdditionalData); + PDVD_SESSION_ID sessionId = NULL; + + *DataLength = 0; + + if (!cdData->Mmc.IsAACS) + { + status = STATUS_INVALID_DEVICE_REQUEST; + } + else if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength != sizeof(DVD_SESSION_ID)) + { + status = STATUS_INFO_LENGTH_MISMATCH; + } + else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < sizeof(AACS_CERTIFICATE)) + { + *DataLength = sizeof(AACS_CERTIFICATE); + status = STATUS_BUFFER_TOO_SMALL; + } + else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength > sizeof(AACS_CERTIFICATE)) + { + status = STATUS_INVALID_BUFFER_SIZE; + } + + if (NT_SUCCESS(status)) + { + status = WdfRequestRetrieveInputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.InputBufferLength, + &sessionId, + NULL); + } + + if (NT_SUCCESS(status)) + { + if (*sessionId > MAX_COPY_PROTECT_AGID) + { + status = STATUS_INVALID_PARAMETER; + } + } + + return status; +} + +NTSTATUS +RequestValidateAacsGetChallengeKey( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + Validate request of IOCTL_AACS_GET_CHALLENGE_KEY + +Arguments: + + DeviceExtension - device context + Request - request to be handled + RequestParameters - request parameter + DataLength - transferred data length + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PCDROM_DATA cdData = &(DeviceExtension->DeviceAdditionalData); + PDVD_SESSION_ID sessionId = NULL; + + *DataLength = 0; + + if (!cdData->Mmc.IsAACS) + { + status = STATUS_INVALID_DEVICE_REQUEST; + } + else if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength != sizeof(DVD_SESSION_ID)) + { + status = STATUS_INFO_LENGTH_MISMATCH; + } + else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < sizeof(AACS_CHALLENGE_KEY)) + { + *DataLength = sizeof(AACS_CHALLENGE_KEY); + status = STATUS_BUFFER_TOO_SMALL; + } + else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength > sizeof(AACS_CHALLENGE_KEY)) + { + status = STATUS_INVALID_BUFFER_SIZE; + } + + if (NT_SUCCESS(status)) + { + status = WdfRequestRetrieveInputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.InputBufferLength, + &sessionId, + NULL); + } + + if (NT_SUCCESS(status)) + { + if (*sessionId > MAX_COPY_PROTECT_AGID) + { + status = STATUS_INVALID_PARAMETER; + } + } + + return status; +} + +NTSTATUS +RequestValidateAacsSendChallengeKey( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + Validate request of IOCTL_AACS_SEND_CHALLENGE_KEY + +Arguments: + + DeviceExtension - device context + Request - request to be handled + RequestParameters - request parameter + DataLength - transferred data length + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PCDROM_DATA cdData = &(DeviceExtension->DeviceAdditionalData); + PAACS_SEND_CHALLENGE_KEY inputBuffer = NULL; + + *DataLength = 0; + + if (!cdData->Mmc.IsAACS) + { + status = STATUS_INVALID_DEVICE_REQUEST; + } + else if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength != sizeof(AACS_SEND_CHALLENGE_KEY)) + { + status = STATUS_INFO_LENGTH_MISMATCH; + } + + if (NT_SUCCESS(status)) + { + status = WdfRequestRetrieveInputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.InputBufferLength, + &inputBuffer, + NULL); + } + + if (NT_SUCCESS(status)) + { + if (inputBuffer->SessionId > MAX_COPY_PROTECT_AGID) + { + status = STATUS_INVALID_PARAMETER; + } + } + + return status; +} + +NTSTATUS +RequestValidateAacsReadVolumeId( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + Validate request of IOCTL_AACS_READ_VOLUME_ID + +Arguments: + + DeviceExtension - device context + Request - request to be handled + RequestParameters - request parameter + DataLength - transferred data length + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PCDROM_DATA cdData = &(DeviceExtension->DeviceAdditionalData); + PDVD_SESSION_ID sessionId = NULL; + + *DataLength = 0; + + if (!cdData->Mmc.IsAACS) + { + status = STATUS_INVALID_DEVICE_REQUEST; + } + else if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength != sizeof(DVD_SESSION_ID)) + { + status = STATUS_INFO_LENGTH_MISMATCH; + } + else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < sizeof(AACS_VOLUME_ID)) + { + *DataLength = sizeof(AACS_VOLUME_ID); + status = STATUS_BUFFER_TOO_SMALL; + } + else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength > sizeof(AACS_VOLUME_ID)) + { + status = STATUS_INVALID_BUFFER_SIZE; + } + + if (NT_SUCCESS(status)) + { + status = WdfRequestRetrieveInputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.InputBufferLength, + &sessionId, + NULL); + } + + if (NT_SUCCESS(status)) + { + if (*sessionId > MAX_COPY_PROTECT_AGID) + { + status = STATUS_INVALID_PARAMETER; + } + } + + return status; +} + +NTSTATUS +RequestValidateAacsReadSerialNumber( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + Validate request of IOCTL_AACS_READ_SERIAL_NUMBER + +Arguments: + + DeviceExtension - device context + Request - request to be handled + RequestParameters - request parameter + DataLength - transferred data length + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PCDROM_DATA cdData = &(DeviceExtension->DeviceAdditionalData); + PDVD_SESSION_ID sessionId = NULL; + + *DataLength = 0; + + if (!cdData->Mmc.IsAACS) + { + status = STATUS_INVALID_DEVICE_REQUEST; + } + else if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength != sizeof(DVD_SESSION_ID)) + { + status = STATUS_INFO_LENGTH_MISMATCH; + } + else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < sizeof(AACS_SERIAL_NUMBER)) + { + *DataLength = sizeof(AACS_SERIAL_NUMBER); + status = STATUS_BUFFER_TOO_SMALL; + } + else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength > sizeof(AACS_SERIAL_NUMBER)) + { + status = STATUS_INVALID_BUFFER_SIZE; + } + + if (NT_SUCCESS(status)) + { + status = WdfRequestRetrieveInputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.InputBufferLength, + &sessionId, + NULL); + } + + if (NT_SUCCESS(status)) + { + if (*sessionId > MAX_COPY_PROTECT_AGID) + { + status = STATUS_INVALID_PARAMETER; + } + } + + return status; +} + +NTSTATUS +RequestValidateAacsReadMediaId( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + Validate request of IOCTL_AACS_READ_MEDIA_ID + +Arguments: + + DeviceExtension - device context + Request - request to be handled + RequestParameters - request parameter + DataLength - transferred data length + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PCDROM_DATA cdData = &(DeviceExtension->DeviceAdditionalData); + PDVD_SESSION_ID sessionId = NULL; + + *DataLength = 0; + + if (!cdData->Mmc.IsAACS) + { + status = STATUS_INVALID_DEVICE_REQUEST; + } + else if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength != sizeof(DVD_SESSION_ID)) + { + status = STATUS_INFO_LENGTH_MISMATCH; + } + else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < sizeof(AACS_MEDIA_ID)) + { + *DataLength = sizeof(AACS_MEDIA_ID); + status = STATUS_BUFFER_TOO_SMALL; + } + else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength > sizeof(AACS_MEDIA_ID)) + { + status = STATUS_INVALID_BUFFER_SIZE; + } + + if (NT_SUCCESS(status)) + { + status = WdfRequestRetrieveInputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.InputBufferLength, + &sessionId, + NULL); + } + + if (NT_SUCCESS(status)) + { + if (*sessionId > MAX_COPY_PROTECT_AGID) + { + status = STATUS_INVALID_PARAMETER; + } + } + + return status; +} + +NTSTATUS +RequestValidateAacsBindingNonce( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + Validate request of IOCTL_AACS_READ_BINDING_NONCE + IOCTL_AACS_GENERATE_BINDING_NONCE + +Arguments: + + DeviceExtension - device context + Request - request to be handled + RequestParameters - request parameter + DataLength - transferred data length + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PCDROM_DATA cdData = &(DeviceExtension->DeviceAdditionalData); + PAACS_READ_BINDING_NONCE inputBuffer = NULL; + + *DataLength = 0; + + if (!cdData->Mmc.IsAACS) + { + status = STATUS_INVALID_DEVICE_REQUEST; + } + else if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength != sizeof(AACS_READ_BINDING_NONCE)) + { + status = STATUS_INFO_LENGTH_MISMATCH; + } + else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < sizeof(AACS_BINDING_NONCE)) + { + *DataLength = sizeof(AACS_BINDING_NONCE); + status = STATUS_BUFFER_TOO_SMALL; + } + else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength > sizeof(AACS_BINDING_NONCE)) + { + status = STATUS_INVALID_BUFFER_SIZE; + } + + if (NT_SUCCESS(status)) + { + status = WdfRequestRetrieveInputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.InputBufferLength, + &inputBuffer, + NULL); + } + + if (NT_SUCCESS(status)) + { + if (inputBuffer->SessionId > MAX_COPY_PROTECT_AGID) + { + status = STATUS_INVALID_PARAMETER; + } + else if (inputBuffer->NumberOfSectors > 255) + { + status = STATUS_INVALID_PARAMETER; + } + else if (inputBuffer->StartLba > MAXULONG) + { + status = STATUS_INVALID_PARAMETER; + } + } + + return status; +} + +NTSTATUS +RequestValidateExclusiveAccess( + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + Validate request of IOCTL_CDROM_EXCLUSIVE_ACCESS + +Arguments: + + Request - request to be handled + RequestParameters - request parameter + DataLength - transferred data length + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PCDROM_EXCLUSIVE_ACCESS exclusiveAccess = NULL; + + *DataLength = 0; + + if (KeGetCurrentIrql() != PASSIVE_LEVEL) + { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "RequestValidateExclusiveAccess: IOCTL must be called at passive level.\n")); + status = STATUS_INVALID_DEVICE_REQUEST; + } + else if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength < sizeof(CDROM_EXCLUSIVE_ACCESS)) + { + + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "RequestValidateExclusiveAccess: Input buffer too small\n")); + status = STATUS_INFO_LENGTH_MISMATCH; + } + + if (NT_SUCCESS(status)) + { + status = WdfRequestRetrieveInputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.InputBufferLength, + &exclusiveAccess, + NULL); + } + + if (NT_SUCCESS(status)) + { + switch (exclusiveAccess->RequestType) + { + case ExclusiveAccessQueryState: + { + if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < + sizeof(CDROM_EXCLUSIVE_LOCK_STATE)) + { + // + // Output buffer too small. + // + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "RequestValidateExclusiveAccess: Output buffer too small\n")); + *DataLength = sizeof(CDROM_EXCLUSIVE_LOCK_STATE); + status = STATUS_BUFFER_TOO_SMALL; + } + break; + } + + case ExclusiveAccessLockDevice: + { + if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength < + sizeof(CDROM_EXCLUSIVE_LOCK)) + { + // + // Input buffer too small + // + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "RequestValidateExclusiveAccess: Input buffer too small\n")); + status = STATUS_INFO_LENGTH_MISMATCH; + } + break; + } + case ExclusiveAccessUnlockDevice: + { + // + // Nothing to check + // + break; + } + + default: + { + // + // Unknown request type. + // + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "RequestValidateExclusiveAccess: Invalid request type\n")); + status = STATUS_INVALID_PARAMETER; + } + } + } + + return status; +} + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +RequestHandleExclusiveAccessQueryLockState( + _In_ WDFDEVICE Device, + _In_ WDFREQUEST Request + ) +/*++ + +Routine Description: + + Handle request of IOCTL_CDROM_EXCLUSIVE_ACCESS with ExclusiveAccessQueryState + +Arguments: + + DeviceExtension - device context + Request - request to be handled + RequestParameters - request parameter + DataLength - transferred data length + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(Device); + PCDROM_DATA cdData = &deviceExtension->DeviceAdditionalData; + PCDROM_EXCLUSIVE_LOCK_STATE exclusiveLockState = NULL; + + PAGED_CODE(); + + status = WdfRequestRetrieveOutputBuffer(Request, + sizeof(CDROM_EXCLUSIVE_LOCK_STATE), + &exclusiveLockState, + NULL); + NT_ASSERT(NT_SUCCESS(status)); + + RtlZeroMemory(exclusiveLockState, sizeof(CDROM_EXCLUSIVE_LOCK_STATE)); + + if (EXCLUSIVE_MODE(cdData)) + { + // Device is locked for exclusive use + exclusiveLockState->LockState = TRUE; + + RtlCopyMemory(&exclusiveLockState->CallerName, + &cdData->CallerName, + CDROM_EXCLUSIVE_CALLER_LENGTH); + + } + else + { + // Device is not locked + exclusiveLockState->LockState = FALSE; + } + + RequestCompletion(deviceExtension, Request, status, sizeof(CDROM_EXCLUSIVE_LOCK_STATE)); + + return status; +} + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +RequestHandleExclusiveAccessLockDevice( + _In_ WDFDEVICE Device, + _In_ WDFREQUEST Request + ) +/*++ + +Routine Description: + + Handle request of IOCTL_CDROM_EXCLUSIVE_ACCESS with ExclusiveAccessLockDevice + +Arguments: + + DeviceExtension - device context + Request - request to be handled + RequestParameters - request parameter + DataLength - transferred data length + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(Device); + PCDROM_DATA cdData = &deviceExtension->DeviceAdditionalData; + PCDROM_EXCLUSIVE_LOCK exclusiveLock = NULL; + PIO_ERROR_LOG_PACKET logEntry; + + WDFFILEOBJECT fileObject = NULL; + ULONG idx = 0; + ULONG nameLength = 0; + + PAGED_CODE(); + + fileObject = WdfRequestGetFileObject(Request); + + if (fileObject == NULL) + { + status = STATUS_INVALID_HANDLE; + + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, + "RequestHandleExclusiveAccessLockDevice: FileObject is NULL, cannot grant exclusive access\n")); + } + + if (NT_SUCCESS(status)) + { + status = WdfRequestRetrieveInputBuffer(Request, + sizeof(CDROM_EXCLUSIVE_LOCK), + &exclusiveLock, + NULL); + } + + if (NT_SUCCESS(status)) + { + // Validate the caller name string + for (idx = 0; (idx < CDROM_EXCLUSIVE_CALLER_LENGTH) && (exclusiveLock->CallerName[idx] != '\0'); idx++) + { + if (!ValidChar(exclusiveLock->CallerName[idx])) + { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, + "RequestHandleExclusiveAccessLockDevice: Invalid characters in caller name\n")); + // error out + status = STATUS_INVALID_PARAMETER; + break; + } + } + } + + if (NT_SUCCESS(status)) + { + if ((idx == 0) || (idx >= CDROM_EXCLUSIVE_CALLER_LENGTH)) + { + + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, + "RequestHandleExclusiveAccessLockDevice: Not a valid null terminated string.\n")); + //error out + status = STATUS_INVALID_PARAMETER; + } + else + { + nameLength = idx+1; // Add 1 for the NULL character + NT_ASSERT(nameLength <= CDROM_EXCLUSIVE_CALLER_LENGTH); + } + } + + // If the file system is still mounted on this device fail the request, + // unless the force lock flag is set. + if (NT_SUCCESS(status)) + { + if ((TEST_FLAG(exclusiveLock->Access.Flags, CDROM_LOCK_IGNORE_VOLUME) == FALSE) && + IsVolumeMounted(deviceExtension->DeviceObject)) + { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, + "RequestHandleExclusiveAccessLockDevice: Unable to lock device, file system mounted\n")); + status = STATUS_INVALID_DEVICE_STATE; + } + } + + // Lock the device for exclusive access if the device is not already locked + if (NT_SUCCESS(status)) + { + if (InterlockedCompareExchangePointer((PVOID)&cdData->ExclusiveOwner, (PVOID)fileObject, NULL) == NULL) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, + "RequestHandleExclusiveAccessLockDevice: Entering exclusive mode! Device locked by file object %p\n", fileObject)); + + // Zero out the CallerName before storing it in the extension + RtlZeroMemory(&cdData->CallerName, CDROM_EXCLUSIVE_CALLER_LENGTH); + RtlCopyMemory(&cdData->CallerName, + &exclusiveLock->CallerName, + nameLength); + + // Send Exclusive Lock notification + DeviceSendNotification(deviceExtension, + &GUID_IO_CDROM_EXCLUSIVE_LOCK, + 0, + NULL); + + // Log an informational event with the caller name + logEntry = IoAllocateErrorLogEntry( + deviceExtension->DeviceObject, + sizeof(IO_ERROR_LOG_PACKET) + CDROM_EXCLUSIVE_CALLER_LENGTH); + + if (logEntry != NULL) + { + PUCHAR dumpDataPtr = (PUCHAR) logEntry->DumpData; + + logEntry->FinalStatus = STATUS_SUCCESS; + logEntry->ErrorCode = IO_CDROM_EXCLUSIVE_LOCK; + logEntry->SequenceNumber = 0; + logEntry->MajorFunctionCode = IRP_MJ_DEVICE_CONTROL; + logEntry->IoControlCode = IOCTL_CDROM_EXCLUSIVE_ACCESS; + logEntry->RetryCount = 0; + logEntry->UniqueErrorValue = 0x1; + logEntry->DumpDataSize = CDROM_EXCLUSIVE_CALLER_LENGTH; + + RtlCopyMemory(dumpDataPtr, + (PUCHAR)&cdData->CallerName, + CDROM_EXCLUSIVE_CALLER_LENGTH); + + // Write the error log packet. + IoWriteErrorLogEntry(logEntry); + } + + } + else + { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, + "RequestHandleExclusiveAccessLockDevice: Unable to lock device, device already locked.\n")); + + status = STATUS_ACCESS_DENIED; + } + } + + RequestCompletion(deviceExtension, Request, status, 0); + + return status; +} + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +RequestHandleExclusiveAccessUnlockDevice( + _In_ WDFDEVICE Device, + _In_ WDFREQUEST Request + ) +/*++ + +Routine Description: + + Handle request of IOCTL_CDROM_EXCLUSIVE_ACCESS with ExclusiveAccessUnlockDevice + +Arguments: + + Device - device handle + Request - request to be handled + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(Device); + PCDROM_EXCLUSIVE_ACCESS exclusiveAccess = NULL; + WDFFILEOBJECT fileObject = NULL; + + PAGED_CODE(); + + fileObject = WdfRequestGetFileObject(Request); + + if (fileObject == NULL) + { + // The device can be unlocked from exclusive mode only via the file object which locked it. + status = STATUS_INVALID_HANDLE; + + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, + "RequestHandleExclusiveAccessUnlockDevice: FileObject is NULL, cannot release exclusive access\n")); + } + + if (NT_SUCCESS(status)) + { + status = WdfRequestRetrieveInputBuffer(Request, + sizeof(PCDROM_EXCLUSIVE_ACCESS), + &exclusiveAccess, + NULL); + } + + if (NT_SUCCESS(status)) + { + status = DeviceUnlockExclusive(deviceExtension, fileObject, + TEST_FLAG(exclusiveAccess->Flags, CDROM_NO_MEDIA_NOTIFICATIONS)); + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "RequestHandleExclusiveAccessUnlockDevice: Device unlocked\n")); + } + + RequestCompletion(deviceExtension, Request, status, 0); + + return status; +} + +NTSTATUS +RequestHandleQueryPropertyRetrieveCachedData( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + Handle request of IOCTL_STORAGE_QUERY_PROPERTY when the required data is cached. + +Arguments: + + DeviceExtension - device context + Request - request to be handled + RequestParameters - request parameter + DataLength - transferred data length + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PSTORAGE_PROPERTY_QUERY inputBuffer = NULL; + + *DataLength = 0; + + status = WdfRequestRetrieveInputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.InputBufferLength, + &inputBuffer, + NULL); + + if (NT_SUCCESS(status)) + { + if (inputBuffer->PropertyId == StorageDeviceProperty) + { + // check output buffer length + if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength == 0) + { + // According to MSDN, an output buffer of size 0 can be used to determine if a property exists + // so this must be a success case with no data transferred + *DataLength = 0; + status = STATUS_SUCCESS; + } + else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < sizeof(STORAGE_DESCRIPTOR_HEADER)) + { + // Buffer too small + *DataLength = DeviceExtension->DeviceDescriptor->Size; + status = STATUS_BUFFER_TOO_SMALL; + } + else + { + PSTORAGE_DEVICE_DESCRIPTOR outputDescriptor = NULL; + CHAR* localDescriptorBuffer = (CHAR*)DeviceExtension->DeviceDescriptor; + + status = WdfRequestRetrieveOutputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, + &outputDescriptor, + NULL); + + if (NT_SUCCESS(status)) + { + // transfer as much data out as the buffer will allow + *DataLength = min(RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, + DeviceExtension->DeviceDescriptor->Size); + + RtlCopyMemory(outputDescriptor, + DeviceExtension->DeviceDescriptor, + *DataLength); + + // walk through and update offset variables to reflect data that didn't make it into the output buffer + if ((*DataLength >= RTL_SIZEOF_THROUGH_FIELD(STORAGE_DEVICE_DESCRIPTOR, VendorIdOffset)) && + (DeviceExtension->DeviceDescriptor->VendorIdOffset != 0) && + (DeviceExtension->DeviceDescriptor->VendorIdOffset != 0xFFFFFFFF)) + { + // set VendorIdOffset appropriately + if (*DataLength < + (DeviceExtension->DeviceDescriptor->VendorIdOffset + strlen(localDescriptorBuffer + DeviceExtension->DeviceDescriptor->VendorIdOffset))) + { + outputDescriptor->VendorIdOffset = 0; + } + } + + if ((*DataLength >= RTL_SIZEOF_THROUGH_FIELD(STORAGE_DEVICE_DESCRIPTOR, ProductIdOffset)) && + (DeviceExtension->DeviceDescriptor->ProductIdOffset != 0) && + (DeviceExtension->DeviceDescriptor->ProductIdOffset != 0xFFFFFFFF)) + { + // set ProductIdOffset appropriately + if (*DataLength < + (DeviceExtension->DeviceDescriptor->ProductIdOffset + strlen(localDescriptorBuffer + DeviceExtension->DeviceDescriptor->ProductIdOffset))) + { + outputDescriptor->ProductIdOffset = 0; + } + } + + if ((*DataLength >= RTL_SIZEOF_THROUGH_FIELD(STORAGE_DEVICE_DESCRIPTOR, ProductRevisionOffset)) && + (DeviceExtension->DeviceDescriptor->ProductRevisionOffset != 0) && + (DeviceExtension->DeviceDescriptor->ProductRevisionOffset != 0xFFFFFFFF)) + { + // set ProductRevisionOffset appropriately + if (*DataLength < + (DeviceExtension->DeviceDescriptor->ProductRevisionOffset + strlen(localDescriptorBuffer + DeviceExtension->DeviceDescriptor->ProductRevisionOffset))) + { + outputDescriptor->ProductRevisionOffset = 0; + } + } + + if ((*DataLength >= RTL_SIZEOF_THROUGH_FIELD(STORAGE_DEVICE_DESCRIPTOR, SerialNumberOffset)) && + (DeviceExtension->DeviceDescriptor->SerialNumberOffset != 0) && + (DeviceExtension->DeviceDescriptor->SerialNumberOffset != 0xFFFFFFFF)) + { + // set SerialNumberOffset appropriately + if (*DataLength < + (DeviceExtension->DeviceDescriptor->SerialNumberOffset + strlen(localDescriptorBuffer + DeviceExtension->DeviceDescriptor->SerialNumberOffset))) + { + // NOTE: setting this to 0 since that is what most port drivers do + // [this could cause issues with SCSI port devices whose clients expect -1 in this field] + outputDescriptor->SerialNumberOffset = 0; + } + } + status = STATUS_SUCCESS; + } + } + } //end of StorageDeviceProperty + else if (inputBuffer->PropertyId == StorageAdapterProperty) + { + if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength == 0) + { + // According to MSDN, an output buffer of size 0 can be used to determine if a property exists + // so this must be a success case with no data transferred + *DataLength = 0; + status = STATUS_SUCCESS; + } + else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < sizeof(STORAGE_DESCRIPTOR_HEADER)) + { + // Buffer too small + *DataLength = DeviceExtension->AdapterDescriptor->Size; + status = STATUS_BUFFER_TOO_SMALL; + } + else + { + PSTORAGE_ADAPTER_DESCRIPTOR outputDescriptor = NULL; + + status = WdfRequestRetrieveOutputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, + &outputDescriptor, + NULL); + if (NT_SUCCESS(status)) + { + // copy as much data out as the buffer will allow + *DataLength = min(RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, + DeviceExtension->AdapterDescriptor->Size); + + RtlCopyMemory(outputDescriptor, + DeviceExtension->AdapterDescriptor, + *DataLength); + + // set status + status = STATUS_SUCCESS; + } + } + } + } + + return status; +} + +NTSTATUS +RequestHandleQueryPropertyDeviceUniqueId( + _In_ WDFDEVICE Device, + _In_ WDFREQUEST Request + ) +/*++ + +Routine Description: + + Handle request of IOCTL_STORAGE_QUERY_PROPERTY with StorageDeviceUniqueIdProperty. + +Arguments: + + DeviceExtension - device context + Request - request to be handled + RequestParameters - request parameter + DataLength - transferred data length + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(Device); + PSTORAGE_PROPERTY_QUERY inputBuffer = NULL; + PSTORAGE_DESCRIPTOR_HEADER descHeader = NULL; + size_t outLength = 0; + WDF_REQUEST_PARAMETERS requestParameters; + + // Get the Request parameters + WDF_REQUEST_PARAMETERS_INIT(&requestParameters); + WdfRequestGetParameters(Request, &requestParameters); + + status = WdfRequestRetrieveInputBuffer(Request, + requestParameters.Parameters.DeviceIoControl.InputBufferLength, + &inputBuffer, + NULL); + + if (NT_SUCCESS(status)) + { + BOOLEAN overflow = FALSE; + BOOLEAN infoFound = FALSE; + + // Must run at less then dispatch. + if (KeGetCurrentIrql() >= DISPATCH_LEVEL) + { + NT_ASSERT(FALSE); + outLength = 0; + status = STATUS_INVALID_LEVEL; + } + else if (inputBuffer->QueryType == PropertyExistsQuery) + { + outLength = 0; + status = STATUS_SUCCESS; + } + else if (inputBuffer->QueryType != PropertyStandardQuery) + { + outLength = 0; + status = STATUS_NOT_SUPPORTED; + } + else + { + // Check AdditionalParameters validity. + if (inputBuffer->AdditionalParameters[0] == DUID_INCLUDE_SOFTWARE_IDS) + { + // Do nothing + } + else if (inputBuffer->AdditionalParameters[0] == DUID_HARDWARE_IDS_ONLY) + { + // Do nothing + } + else + { + outLength = 0; + status = STATUS_INVALID_PARAMETER; + } + + if (NT_SUCCESS(status) && + (outLength < sizeof(STORAGE_DESCRIPTOR_HEADER))) + { + outLength = 0; + status = STATUS_INFO_LENGTH_MISMATCH; + } + } + + // From this point forward the status depends on the overflow + // and infoFound flags. + if (NT_SUCCESS(status)) + { + outLength = requestParameters.Parameters.DeviceIoControl.OutputBufferLength; + status = WdfRequestRetrieveOutputBuffer(Request, + requestParameters.Parameters.DeviceIoControl.OutputBufferLength, + &descHeader, + NULL); + } + + if (NT_SUCCESS(status)) + { + RtlZeroMemory(descHeader, outLength); + + descHeader->Version = DUID_VERSION_1; + descHeader->Size = sizeof(STORAGE_DEVICE_UNIQUE_IDENTIFIER); + + // Try to build device unique id from StorageDeviceIdProperty. + status = RequestDuidGetDeviceIdProperty(deviceExtension, + Request, + requestParameters, + &outLength); + + if (status == STATUS_BUFFER_OVERFLOW) + { + overflow = TRUE; + } + + if (NT_SUCCESS(status)) + { + infoFound = TRUE; + } + + // Try to build device unique id from StorageDeviceProperty. + status = RequestDuidGetDeviceProperty(deviceExtension, + Request, + requestParameters, + &outLength); + + if (status == STATUS_BUFFER_OVERFLOW) + { + overflow = TRUE; + } + + if (NT_SUCCESS(status)) + { + infoFound = TRUE; + } + + // Return overflow, success, or a generic error. + if (overflow) + { + // If output buffer is STORAGE_DESCRIPTOR_HEADER, then return + // success to the user. Otherwise, send an error so the user + // knows a larger buffer is required. + if (outLength == sizeof(STORAGE_DESCRIPTOR_HEADER)) + { + status = STATUS_SUCCESS; + } + else + { + outLength = (ULONG)WdfRequestGetInformation(Request); + status = STATUS_BUFFER_OVERFLOW; + } + + } + else if (infoFound) + { + status = STATUS_SUCCESS; + + // Exercise the compare routine. This should always succeed. + NT_ASSERT(DuidExactMatch == CompareStorageDuids((PSTORAGE_DEVICE_UNIQUE_IDENTIFIER)descHeader, + (PSTORAGE_DEVICE_UNIQUE_IDENTIFIER)descHeader)); + + } + else + { + status = STATUS_NOT_FOUND; + } + } + } + + RequestCompletion(deviceExtension, Request, status, outLength); + + return status; +} + +NTSTATUS +RequestHandleQueryPropertyWriteCache( + _In_ WDFDEVICE Device, + _In_ WDFREQUEST Request + ) +/*++ + +Routine Description: + + Handle request of IOCTL_STORAGE_QUERY_PROPERTY with StorageDeviceWriteCacheProperty. + +Arguments: + + DeviceExtension - device context + Request - request to be handled + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(Device); + PSTORAGE_PROPERTY_QUERY query = NULL; + PSTORAGE_WRITE_CACHE_PROPERTY writeCache = NULL; + PMODE_PARAMETER_HEADER modeData = NULL; + PMODE_CACHING_PAGE pageData = NULL; + size_t length = 0; + ULONG information = 0; + PSCSI_REQUEST_BLOCK srb = NULL; + WDF_REQUEST_PARAMETERS requestParameters; + + // Get the Request parameters + WDF_REQUEST_PARAMETERS_INIT(&requestParameters); + WdfRequestGetParameters(Request, &requestParameters); + + status = WdfRequestRetrieveInputBuffer(Request, + requestParameters.Parameters.DeviceIoControl.InputBufferLength, + &query, + NULL); + + if (NT_SUCCESS(status)) + { + + // Must run at less then dispatch. + if (KeGetCurrentIrql() >= DISPATCH_LEVEL) + { + NT_ASSERT(FALSE); + status = STATUS_INVALID_LEVEL; + } + else if (query->QueryType == PropertyExistsQuery) + { + information = 0; + status = STATUS_SUCCESS; + } + else if (query->QueryType != PropertyStandardQuery) + { + status = STATUS_NOT_SUPPORTED; + } + } + + if (NT_SUCCESS(status)) + { + length = requestParameters.Parameters.DeviceIoControl.OutputBufferLength; + + if (length < sizeof(STORAGE_DESCRIPTOR_HEADER)) + { + status = STATUS_INFO_LENGTH_MISMATCH; + } + } + + if (NT_SUCCESS(status)) + { + status = WdfRequestRetrieveOutputBuffer(Request, + requestParameters.Parameters.DeviceIoControl.OutputBufferLength, + &writeCache, + NULL); + } + + if (NT_SUCCESS(status)) + { + RtlZeroMemory(writeCache, length); + + // Set version and required size. + writeCache->Version = sizeof(STORAGE_WRITE_CACHE_PROPERTY); + writeCache->Size = sizeof(STORAGE_WRITE_CACHE_PROPERTY); + + if (length < sizeof(STORAGE_WRITE_CACHE_PROPERTY)) + { + // caller only wants header information, bail out. + information = sizeof(STORAGE_DESCRIPTOR_HEADER); + status = STATUS_SUCCESS; + + RequestCompletion(deviceExtension, Request, status, information); + return status; + } + } + + if (NT_SUCCESS(status)) + { + srb = ExAllocatePoolWithTag(NonPagedPoolNx, + sizeof(SCSI_REQUEST_BLOCK) + + (sizeof(ULONG_PTR) * 2), + CDROM_TAG_SRB); + + if (srb == NULL) + { + status = STATUS_INSUFFICIENT_RESOURCES; + } + } + + if (NT_SUCCESS(status)) + { + RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK)); + + // Set known values + writeCache->NVCacheEnabled = FALSE; + writeCache->UserDefinedPowerProtection = TEST_FLAG(deviceExtension->DeviceFlags, DEV_POWER_PROTECTED); + + // Check for flush cache support by sending a sync cache command + // to the device. + + // Set timeout value and mark the request as not being a tagged request. + srb->Length = SCSI_REQUEST_BLOCK_SIZE; + srb->TimeOutValue = TimeOutValueGetCapValue(deviceExtension->TimeOutValue, 4); + srb->QueueTag = SP_UNTAGGED; + srb->QueueAction = SRB_SIMPLE_TAG_REQUEST; + srb->SrbFlags = deviceExtension->SrbFlags; + + srb->Function = SRB_FUNCTION_EXECUTE_SCSI; + srb->CdbLength = 10; + + srb->Cdb[0] = SCSIOP_SYNCHRONIZE_CACHE; + + status = DeviceSendSrbSynchronously(Device, + srb, + NULL, + 0, + TRUE, //flush drive cache + Request); + + if (NT_SUCCESS(status)) + { + writeCache->FlushCacheSupported = TRUE; + } + else + { + // Device does not support sync cache + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, + "RequestHandleQueryPropertyWriteCache: Synchronize cache failed with status 0x%X\n", status)); + writeCache->FlushCacheSupported = FALSE; + + // Reset the status if there was any failure + status = STATUS_SUCCESS; + } + + modeData = ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned, + MODE_PAGE_DATA_SIZE, + CDROM_TAG_MODE_DATA); + + if (modeData == NULL) + { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, + "RequestHandleQueryPropertyWriteCache: Unable to allocate mode data buffer\n")); + status = STATUS_INSUFFICIENT_RESOURCES; + } + } + + if (NT_SUCCESS(status)) + { + RtlZeroMemory(modeData, MODE_PAGE_DATA_SIZE); + + length = DeviceRetrieveModeSenseUsingScratch(deviceExtension, + (PCHAR)modeData, + MODE_PAGE_DATA_SIZE, + MODE_PAGE_CACHING, + MODE_SENSE_CURRENT_VALUES); + + if (length < sizeof(MODE_PARAMETER_HEADER)) + { + // Retry the request in case of a check condition. + length = DeviceRetrieveModeSenseUsingScratch(deviceExtension, + (PCHAR)modeData, + MODE_PAGE_DATA_SIZE, + MODE_PAGE_CACHING, + MODE_SENSE_CURRENT_VALUES); + + if (length < sizeof(MODE_PARAMETER_HEADER)) + { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, "RequestHandleQueryPropertyWriteCache: Mode Sense failed\n")); + status = STATUS_IO_DEVICE_ERROR; + } + } + } + + if (NT_SUCCESS(status)) + { + // If the length is greater than length indicated by the mode data reset + // the data to the mode data. + if (length > (ULONG) (modeData->ModeDataLength + 1)) + { + length = modeData->ModeDataLength + 1; + } + + // Look for caching page in the returned mode page data. + pageData = ModeSenseFindSpecificPage((PCHAR)modeData, + length, + MODE_PAGE_CACHING, + TRUE); + + // Check if valid caching page exists. + if (pageData == NULL) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "RequestHandleQueryPropertyWriteCache: Unable to find caching mode page.\n")); + + // Set write cache value as unknown. + writeCache->WriteCacheEnabled = WriteCacheEnableUnknown; + writeCache->WriteCacheType = WriteCacheTypeUnknown; + } + else + { + writeCache->WriteCacheEnabled = pageData->WriteCacheEnable + ? WriteCacheEnabled + : WriteCacheDisabled; + + writeCache->WriteCacheType = pageData->WriteCacheEnable + ? WriteCacheTypeWriteBack + : WriteCacheTypeUnknown; + } + + // Check write through support. + if (modeData->DeviceSpecificParameter & MODE_DSP_FUA_SUPPORTED) + { + writeCache->WriteThroughSupported = WriteThroughSupported; + } + else + { + writeCache->WriteThroughSupported = WriteThroughNotSupported; + } + + // Get the changeable caching mode page and check write cache is changeable. + RtlZeroMemory(modeData, MODE_PAGE_DATA_SIZE); + + length = DeviceRetrieveModeSenseUsingScratch(deviceExtension, + (PCHAR) modeData, + MODE_PAGE_DATA_SIZE, + MODE_PAGE_CACHING, + MODE_SENSE_CHANGEABLE_VALUES); + + if (length < sizeof(MODE_PARAMETER_HEADER)) + { + // Retry the request in case of a check condition. + length = DeviceRetrieveModeSenseUsingScratch(deviceExtension, + (PCHAR) modeData, + MODE_PAGE_DATA_SIZE, + MODE_PAGE_CACHING, + MODE_SENSE_CHANGEABLE_VALUES); + + if (length < sizeof(MODE_PARAMETER_HEADER)) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "RequestHandleQueryPropertyWriteCache: Mode Sense failed\n")); + + // If the device fails to return changeable pages, then + // set the write cache changeable value to unknown. + writeCache->WriteCacheChangeable = WriteCacheChangeUnknown; + information = sizeof(STORAGE_WRITE_CACHE_PROPERTY); + } + } + } + + if (NT_SUCCESS(status)) + { + // If the length is greater than length indicated by the mode data reset + // the data to the mode data. + if (length > (ULONG) (modeData->ModeDataLength + 1)) + { + length = modeData->ModeDataLength + 1; + } + + // Look for caching page in the returned mode page data. + pageData = ModeSenseFindSpecificPage((PCHAR)modeData, + length, + MODE_PAGE_CACHING, + TRUE); + // Check if valid caching page exists. + if (pageData == NULL) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "RequestHandleQueryPropertyWriteCache: Unable to find caching mode page.\n")); + + // Set write cache changeable value to unknown. + writeCache->WriteCacheChangeable = WriteCacheChangeUnknown; + } + else + { + writeCache->WriteCacheChangeable = pageData->WriteCacheEnable + ? WriteCacheChangeable + : WriteCacheNotChangeable; + } + + information = sizeof(STORAGE_WRITE_CACHE_PROPERTY); + + } + + FREE_POOL(srb); + FREE_POOL(modeData); + + RequestCompletion(deviceExtension, Request, status, information); + + return status; +} + +NTSTATUS +RequestValidateDvdReadKey( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + Validate request of IOCTL_DVD_READ_KEY + +Arguments: + + DeviceExtension - device context + Request - request to be handled + RequestParameters - request parameter + DataLength - transferred data length + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PDVD_COPY_PROTECT_KEY keyParameters = NULL; + ULONG keyLength = 0; + + *DataLength = 0; + + status = WdfRequestRetrieveInputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.InputBufferLength, + &keyParameters, + NULL); + + if (NT_SUCCESS(status)) + { + if(RequestParameters.Parameters.DeviceIoControl.InputBufferLength < sizeof(DVD_COPY_PROTECT_KEY)) + { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, + "DvdDeviceControl: EstablishDriveKey - challenge " + "key buffer too small\n")); + status = STATUS_INVALID_PARAMETER; + } + } + + if (NT_SUCCESS(status)) + { + switch(keyParameters->KeyType) + { + + case DvdChallengeKey: + { + C_ASSERT(sizeof(DVD_COPY_PROTECT_KEY) <= DVD_CHALLENGE_KEY_LENGTH); + keyLength = DVD_CHALLENGE_KEY_LENGTH; + break; + } + case DvdBusKey1: + case DvdBusKey2: + { + C_ASSERT(sizeof(DVD_COPY_PROTECT_KEY) <= DVD_BUS_KEY_LENGTH); + keyLength = DVD_BUS_KEY_LENGTH; + break; + } + case DvdTitleKey: + { + C_ASSERT(sizeof(DVD_COPY_PROTECT_KEY) <= DVD_TITLE_KEY_LENGTH); + keyLength = DVD_TITLE_KEY_LENGTH; + break; + } + case DvdAsf: + { + C_ASSERT(sizeof(DVD_COPY_PROTECT_KEY) <= DVD_ASF_LENGTH); + keyLength = DVD_ASF_LENGTH; + break; + } + case DvdDiskKey: + { + C_ASSERT(sizeof(DVD_COPY_PROTECT_KEY) <= DVD_DISK_KEY_LENGTH); + keyLength = DVD_DISK_KEY_LENGTH; + break; + } + case DvdGetRpcKey: + { + C_ASSERT(sizeof(DVD_COPY_PROTECT_KEY) <= DVD_RPC_KEY_LENGTH); + keyLength = DVD_RPC_KEY_LENGTH; + break; + } + default: + { + keyLength = sizeof(DVD_COPY_PROTECT_KEY); + break; + } + } + + if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < keyLength) + { + + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, + "DvdDeviceControl: EstablishDriveKey - output " + "buffer too small\n")); + status = STATUS_BUFFER_TOO_SMALL; + *DataLength = keyLength; + } + else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength & + DeviceExtension->AdapterDescriptor->AlignmentMask) + { + status = STATUS_INVALID_PARAMETER; + } + else if (DeviceExtension->DeviceAdditionalData.DriveDeviceType != FILE_DEVICE_DVD) + { + // reject the request if it's not a DVD device. + status = STATUS_INVALID_DEVICE_REQUEST; + } + } + + return status; +} + + +NTSTATUS +RequestValidateDvdEndSession( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + Handle request of IOCTL_DVD_END_SESSION + +Arguments: + + DeviceExtension - device context + Request - request to be handled + RequestParameters - request parameter + DataLength - transferred data length + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PDVD_SESSION_ID sessionId = NULL; + + UNREFERENCED_PARAMETER(DeviceExtension); + + *DataLength = 0; + + status = WdfRequestRetrieveInputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.InputBufferLength, + &sessionId, + NULL); + + if (NT_SUCCESS(status)) + { + if(RequestParameters.Parameters.DeviceIoControl.InputBufferLength < + sizeof(DVD_SESSION_ID)) + { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, + "DvdDeviceControl: EndSession - input buffer too " + "small\n")); + status = STATUS_INVALID_PARAMETER; + } + } + + return status; +} + + +NTSTATUS +RequestValidateAacsEndSession( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + Validate request of IOCTL_AACS_END_SESSION + +Arguments: + + DeviceExtension - device context + Request - request to be handled + RequestParameters - request parameter + DataLength - transferred data length + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PDVD_SESSION_ID sessionId = NULL; + PCDROM_DATA cdData = &(DeviceExtension->DeviceAdditionalData); + + *DataLength = 0; + + status = WdfRequestRetrieveInputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.InputBufferLength, + &sessionId, + NULL); + + if (NT_SUCCESS(status)) + { + if (!cdData->Mmc.IsAACS) + { + status = STATUS_INVALID_DEVICE_REQUEST; + } + else if(RequestParameters.Parameters.DeviceIoControl.InputBufferLength != sizeof(DVD_SESSION_ID)) + { + status = STATUS_INVALID_PARAMETER; + } + } + + return status; +} + + +NTSTATUS +RequestValidateEnableStreaming( + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + Validates an IOCTL_CDROM_ENABLE_STREAMING request + +Arguments: + + Request - request to be handled + RequestParameters - request parameters + DataLength - transferred data length + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + + PCDROM_STREAMING_CONTROL inputBuffer = NULL; + + *DataLength = 0; + + if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength < + sizeof(CDROM_STREAMING_CONTROL)) + { + status = STATUS_INFO_LENGTH_MISMATCH; + } + + if (NT_SUCCESS(status)) + { + // Get the request type using CDROM_STREAMING_CONTROL structure + status = WdfRequestRetrieveInputBuffer(Request, + sizeof(CDROM_STREAMING_CONTROL), + &inputBuffer, + NULL); + } + + if (NT_SUCCESS(status)) + { + if (inputBuffer->RequestType != CdromStreamingDisable && + inputBuffer->RequestType != CdromStreamingEnableForReadOnly && + inputBuffer->RequestType != CdromStreamingEnableForWriteOnly && + inputBuffer->RequestType != CdromStreamingEnableForReadWrite) + { + // Unknown request type + status = STATUS_INVALID_PARAMETER; + } + } + + return status; +} + + +NTSTATUS +RequestValidateSendOpcInformation( + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + Validates an IOCTL_CDROM_SEND_OPC_INFORMATION request + +Arguments: + + Request - request to be handled + RequestParameters - request parameters + DataLength - transferred data length + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + + PCDROM_SIMPLE_OPC_INFO inputBuffer = NULL; + + *DataLength = 0; + + if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength < + sizeof(CDROM_SIMPLE_OPC_INFO)) + { + status = STATUS_INFO_LENGTH_MISMATCH; + } + + if (NT_SUCCESS(status)) + { + // Get the request type using CDROM_SIMPLE_OPC_INFO structure + status = WdfRequestRetrieveInputBuffer(Request, + sizeof(CDROM_SIMPLE_OPC_INFO), + &inputBuffer, + NULL); + } + + if (NT_SUCCESS(status)) + { + if (inputBuffer->RequestType != SimpleOpcInfo) + { + // Unknown request type + status = STATUS_INVALID_PARAMETER; + } + } + + return status; +} + + +NTSTATUS +RequestValidateGetPerformance( + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + Validates an IOCTL_CDROM_GET_PERFORMANCE request + +Arguments: + + Request - request to be handled + RequestParameters - request parameter + DataLength - transferred data length + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PCDROM_WRITE_SPEED_REQUEST writeSpeedRequest = NULL; + PCDROM_PERFORMANCE_REQUEST performanceRequest = NULL; + + *DataLength = 0; + + // CDROM_WRITE_SPEED_REQUEST is the smallest performance request that we support. + // We use it to retrieve request type and then check input length more carefully + // on a per request type basis. + if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength < + sizeof(CDROM_WRITE_SPEED_REQUEST)) + { + status = STATUS_INFO_LENGTH_MISMATCH; + } + + if (NT_SUCCESS(status)) + { + status = WdfRequestRetrieveInputBuffer(Request, + sizeof(CDROM_WRITE_SPEED_REQUEST), + (PVOID*)&writeSpeedRequest, + NULL); + } + + if (NT_SUCCESS(status)) + { + if (writeSpeedRequest->RequestType == CdromPerformanceRequest) + { + // CDROM_PERFORMANCE_REQUEST is bigger than CDROM_WRITE_SPEED_REQUEST, + // so we perform more checks and retrieve more bytes through WDF. + if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength < + sizeof(CDROM_PERFORMANCE_REQUEST)) + { + status = STATUS_INFO_LENGTH_MISMATCH; + } + if (NT_SUCCESS(status)) + { + status = WdfRequestRetrieveInputBuffer(Request, + sizeof(CDROM_PERFORMANCE_REQUEST), + &performanceRequest, + NULL); + } + + if (!NT_SUCCESS(status)) + { + // just pass the status code from above + } + // validate all enum-type fields of CDROM_PERFORMANCE_REQUEST + else if (performanceRequest->PerformanceType != CdromReadPerformance && + performanceRequest->PerformanceType != CdromWritePerformance) + { + status = STATUS_INVALID_PARAMETER; + } + else if (performanceRequest->Exceptions != CdromReadPerformance && + performanceRequest->Exceptions != CdromEntirePerformanceList && + performanceRequest->Exceptions != CdromPerformanceExceptionsOnly) + { + status = STATUS_INVALID_PARAMETER; + } + else if (performanceRequest->Tolerance != Cdrom10Nominal20Exceptions) + { + status = STATUS_INVALID_PARAMETER; + } + } + else if (writeSpeedRequest->RequestType == CdromWriteSpeedRequest) + { + // No additional checks here: all remaining fields are ignored + // if RequestType == CdromWriteSpeedRequest. + } + else + { + status = STATUS_INVALID_PARAMETER; + } + } + + // finally, check output buffer length + if (NT_SUCCESS(status)) + { + if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < + sizeof(CDROM_PERFORMANCE_HEADER)) + { + status = STATUS_BUFFER_TOO_SMALL; + *DataLength = sizeof(CDROM_PERFORMANCE_HEADER); + } + else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength > + ((USHORT)-1)) + { + status = STATUS_INVALID_PARAMETER; + } + } + + return status; +} + + +_IRQL_requires_max_(APC_LEVEL) +PCDB +RequestGetScsiPassThroughCdb( + _In_ PIRP Irp + ) +/*++ + +Routine Description: + + Get the CDB structure from the SCSI pass through + +Arguments: + + Irp - request to be handled + +Return Value: + + PCDB + +--*/ +{ + PCDB cdb = NULL; + PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp); + ULONG inputBufferLength = 0; + PVOID inputBuffer = NULL; + BOOLEAN legacyPassThrough = FALSE; + + PAGED_CODE(); + + if (((currentIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_SCSI_PASS_THROUGH) || + (currentIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_SCSI_PASS_THROUGH_DIRECT) || + (currentIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_SCSI_PASS_THROUGH_EX) || + (currentIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_SCSI_PASS_THROUGH_DIRECT_EX)) && + (Irp->AssociatedIrp.SystemBuffer != NULL)) + { + inputBufferLength = currentIrpStack->Parameters.DeviceIoControl.InputBufferLength; + inputBuffer = Irp->AssociatedIrp.SystemBuffer; + legacyPassThrough = TRUE; + + if ((currentIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_SCSI_PASS_THROUGH_EX) || + (currentIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_SCSI_PASS_THROUGH_DIRECT_EX)) + { + legacyPassThrough = FALSE; + } + + // + // If this is a 32 bit application running on 64 bit then thunk the + // input structures to grab the cdb. + // + +#if BUILD_WOW64_ENABLED && defined(_WIN64) + + if (IoIs32bitProcess(Irp)) + { + if (legacyPassThrough) + { + if (inputBufferLength >= sizeof(SCSI_PASS_THROUGH32)) + { + cdb = (PCDB)((PSCSI_PASS_THROUGH32)inputBuffer)->Cdb; + } + } + else + { + if (inputBufferLength >= sizeof(SCSI_PASS_THROUGH32_EX)) + { + cdb = (PCDB)((PSCSI_PASS_THROUGH32_EX)inputBuffer)->Cdb; + } + } + + } + else + +#endif + + { + if (legacyPassThrough) + { + if (inputBufferLength >= sizeof(SCSI_PASS_THROUGH)) + { + cdb = (PCDB)((PSCSI_PASS_THROUGH)inputBuffer)->Cdb; + } + } + else + { + if (inputBufferLength >= sizeof(SCSI_PASS_THROUGH_EX)) + { + cdb = (PCDB)((PSCSI_PASS_THROUGH_EX)inputBuffer)->Cdb; + } + } + } + } + + return cdb; +} + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +RequestHandleScsiPassThrough( + _In_ WDFDEVICE Device, + _In_ WDFREQUEST Request + ) +/*++ + +Routine Description: + + Handle request of IOCTL_SCSI_PASS_THROUGH + IOCTL_SCSI_PASS_THROUGH_DIRECT + + The function sets the MinorFunction field of irpStack, + and pass the request to lower level driver. + +Arguments: + + Device - device object + Request - request to be handled + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_UNSUCCESSFUL; + PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(Device); + PIRP irp = WdfRequestWdmGetIrp(Request); + PZERO_POWER_ODD_INFO zpoddInfo = deviceExtension->ZeroPowerODDInfo; + PCDB cdb = NULL; + BOOLEAN isSoftEject = FALSE; + +#if DBG + PCDROM_REQUEST_CONTEXT requestContext = RequestGetContext(Request); +#endif + + + PAGED_CODE(); + +#if DBG + // SPTI is always processed in sync manner. + NT_ASSERT(requestContext->SyncRequired); +#endif + + if ((zpoddInfo != NULL) && + (zpoddInfo->LoadingMechanism == LOADING_MECHANISM_TRAY) && + (zpoddInfo->Load == 0)) // Drawer + { + cdb = RequestGetScsiPassThroughCdb(irp); + + if ((cdb != NULL) && + (cdb->AsByte[0] == SCSIOP_START_STOP_UNIT) && + (cdb->START_STOP.LoadEject == 1) && + (cdb->START_STOP.Start == 0)) + { + isSoftEject = TRUE; + } + } + + WdfRequestFormatRequestUsingCurrentType(Request); + + // Special for SPTI, set the MinorFunction. + { + PIO_STACK_LOCATION nextStack = IoGetNextIrpStackLocation(irp); + + nextStack->MinorFunction = 1; + } + + + status = RequestSend(deviceExtension, + Request, + deviceExtension->IoTarget, + WDF_REQUEST_SEND_OPTION_SYNCHRONOUS, + NULL); + + + if (!NT_SUCCESS(status) && + (isSoftEject != FALSE)) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, + "RequestHandleScsiPassThrough: soft eject detected, device marked as active\n")); + + DeviceMarkActive(deviceExtension, TRUE, FALSE); + } + + RequestCompletion(deviceExtension, Request, status, WdfRequestGetInformation(Request)); + + return status; +} + +NTSTATUS +RequestHandleMountQueryUniqueId( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + Handle request of IOCTL_MOUNTDEV_QUERY_UNIQUE_ID + +Arguments: + + DeviceExtension - device context + Request - request to be handled + RequestParameters - request parameter + DataLength - transferred data length + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PMOUNTDEV_UNIQUE_ID uniqueId = NULL; + + *DataLength = 0; + + if (!DeviceExtension->MountedDeviceInterfaceName.Buffer) + { + status = STATUS_INVALID_PARAMETER; + } + else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < sizeof(MOUNTDEV_UNIQUE_ID)) + { + *DataLength = sizeof(MOUNTDEV_UNIQUE_ID); + status = STATUS_BUFFER_TOO_SMALL; + } + + if (NT_SUCCESS(status)) + { + status = WdfRequestRetrieveOutputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, + &uniqueId, + NULL); + } + + if (NT_SUCCESS(status)) + { + RtlZeroMemory(uniqueId, RequestParameters.Parameters.DeviceIoControl.OutputBufferLength); + + uniqueId->UniqueIdLength = DeviceExtension->MountedDeviceInterfaceName.Length; + + if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < + (sizeof(USHORT) + DeviceExtension->MountedDeviceInterfaceName.Length)) + { + *DataLength = sizeof(MOUNTDEV_UNIQUE_ID); + status = STATUS_BUFFER_OVERFLOW; + } + } + + if (NT_SUCCESS(status)) + { + RtlCopyMemory(uniqueId->UniqueId, + DeviceExtension->MountedDeviceInterfaceName.Buffer, + uniqueId->UniqueIdLength); + + *DataLength = sizeof(USHORT) + uniqueId->UniqueIdLength; + status = STATUS_SUCCESS; + } + + return status; +} + +NTSTATUS +RequestHandleMountQueryDeviceName( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + Handle request of IOCTL_MOUNTDEV_QUERY_DEVICE_NAME + +Arguments: + + DeviceExtension - device context + Request - request to be handled + RequestParameters - request parameter + DataLength - transferred data length + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PMOUNTDEV_NAME name = NULL; + + *DataLength = 0; + + NT_ASSERT(DeviceExtension->DeviceName.Buffer); + + if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < sizeof(MOUNTDEV_NAME)) + { + status = STATUS_BUFFER_TOO_SMALL; + *DataLength = sizeof(MOUNTDEV_NAME); + } + + if (NT_SUCCESS(status)) + { + status = WdfRequestRetrieveOutputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, + &name, + NULL); + } + + if (NT_SUCCESS(status)) + { + RtlZeroMemory(name, RequestParameters.Parameters.DeviceIoControl.OutputBufferLength); + name->NameLength = DeviceExtension->DeviceName.Length; + + if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < + (sizeof(USHORT) + DeviceExtension->DeviceName.Length)) + { + status = STATUS_BUFFER_OVERFLOW; + *DataLength = sizeof(MOUNTDEV_NAME); + } + } + + if (NT_SUCCESS(status)) + { + RtlCopyMemory(name->Name, + DeviceExtension->DeviceName.Buffer, + name->NameLength); + + status = STATUS_SUCCESS; + *DataLength = sizeof(USHORT) + name->NameLength; + } + + return status; +} + +NTSTATUS +RequestHandleMountQuerySuggestedLinkName( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + Handle request of IOCTL_MOUNTDEV_QUERY_SUGGESTED_LINK_NAME + +Arguments: + + DeviceExtension - device context + Request - request to be handled + RequestParameters - request parameter + DataLength - transferred data length + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + + PMOUNTDEV_SUGGESTED_LINK_NAME suggestedName = NULL; + + WCHAR driveLetterNameBuffer[10] = {0}; + RTL_QUERY_REGISTRY_TABLE queryTable[2] = {0}; + PWSTR valueName = NULL; + UNICODE_STRING driveLetterName = {0}; + + *DataLength = 0; + + if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < + sizeof(MOUNTDEV_SUGGESTED_LINK_NAME)) + { + status = STATUS_BUFFER_TOO_SMALL; + *DataLength = sizeof(MOUNTDEV_SUGGESTED_LINK_NAME); + } + + if (NT_SUCCESS(status)) + { + valueName = ExAllocatePoolWithTag(PagedPool, + DeviceExtension->DeviceName.Length + sizeof(WCHAR), + CDROM_TAG_STRINGS); + if (valueName == NULL) + { + status = STATUS_INSUFFICIENT_RESOURCES; + } + } + + if (NT_SUCCESS(status)) + { + RtlCopyMemory(valueName, + DeviceExtension->DeviceName.Buffer, + DeviceExtension->DeviceName.Length); + valueName[DeviceExtension->DeviceName.Length/sizeof(WCHAR)] = 0; + + driveLetterName.Buffer = driveLetterNameBuffer; + driveLetterName.MaximumLength = sizeof(driveLetterNameBuffer); + driveLetterName.Length = 0; + + queryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_DIRECT; + queryTable[0].Name = valueName; + queryTable[0].EntryContext = &driveLetterName; + + status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, + L"\\Registry\\Machine\\System\\DISK", // why hard coded? + queryTable, NULL, NULL); + } + + if (NT_SUCCESS(status)) + { + if ((driveLetterName.Length == 4) && + (driveLetterName.Buffer[0] == '%') && + (driveLetterName.Buffer[1] == ':')) + { + driveLetterName.Buffer[0] = 0xFF; + } + else if ((driveLetterName.Length != 4) || + (driveLetterName.Buffer[0] < FirstDriveLetter) || + (driveLetterName.Buffer[0] > LastDriveLetter) || + (driveLetterName.Buffer[1] != ':')) + { + status = STATUS_NOT_FOUND; + } + } + + if (NT_SUCCESS(status)) + { + status = WdfRequestRetrieveOutputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, + &suggestedName, + NULL); + } + + if (NT_SUCCESS(status)) + { + RtlZeroMemory(suggestedName, RequestParameters.Parameters.DeviceIoControl.OutputBufferLength); + suggestedName->UseOnlyIfThereAreNoOtherLinks = TRUE; + suggestedName->NameLength = 28; + + *DataLength = FIELD_OFFSET(MOUNTDEV_SUGGESTED_LINK_NAME, Name) + 28; + + if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < *DataLength) + { + *DataLength = sizeof(MOUNTDEV_SUGGESTED_LINK_NAME); + status = STATUS_BUFFER_OVERFLOW; + } + } + + if (NT_SUCCESS(status)) + { + RtlDeleteRegistryValue(RTL_REGISTRY_ABSOLUTE, + L"\\Registry\\Machine\\System\\DISK", + valueName); + + RtlCopyMemory(suggestedName->Name, L"\\DosDevices\\", 24); + suggestedName->Name[12] = driveLetterName.Buffer[0]; + suggestedName->Name[13] = ':'; + } + + FREE_POOL(valueName); + + return status; +} + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +RequestHandleReadTOC( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + Handle request of IOCTL_CDROM_READ_TOC + IOCTL_CDROM_GET_LAST_SESSION + +Arguments: + + DeviceExtension - device context + Request - request to be handled + RequestParameters - request parameter + DataLength - transferred data length + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + VOID* outputBuffer = NULL; + + PAGED_CODE (); + + *DataLength = 0; + + if (DeviceIsPlayActive(DeviceExtension->Device)) + { + status = STATUS_DEVICE_BUSY; + } + + if (NT_SUCCESS(status)) + { + status = WdfRequestRetrieveOutputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, + &outputBuffer, + NULL); + } + + // handle the request + if (NT_SUCCESS(status)) + { + size_t transferSize; + CDB cdb; + + transferSize = min(RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, sizeof(CDROM_TOC)); + + RtlZeroMemory(outputBuffer, transferSize); + + ScratchBuffer_BeginUse(DeviceExtension); + + RtlZeroMemory(&cdb, sizeof(CDB)); + // Set up the CDB + if (RequestParameters.Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_GET_LAST_SESSION) + { + // Set format to return first and last session numbers. + cdb.READ_TOC.Format2 = CDROM_READ_TOC_EX_FORMAT_SESSION; + } + else + { + // Use MSF addressing + cdb.READ_TOC.Msf = 1; + } + + cdb.READ_TOC.OperationCode = SCSIOP_READ_TOC; + cdb.READ_TOC.AllocationLength[0] = (UCHAR)(transferSize >> 8); + cdb.READ_TOC.AllocationLength[1] = (UCHAR)(transferSize & 0xFF); + + status = ScratchBuffer_ExecuteCdb(DeviceExtension, Request, (ULONG)transferSize, TRUE, &cdb, 10); + + if (NT_SUCCESS(status)) + { + *DataLength = DeviceExtension->ScratchContext.ScratchSrb->DataTransferLength; + RtlCopyMemory(outputBuffer, + DeviceExtension->ScratchContext.ScratchBuffer, + *DataLength); + } + + ScratchBuffer_EndUse(DeviceExtension); + } + + return status; +} + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +RequestHandleReadTocEx( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + Handle request of IOCTL_CDROM_READ_TOC_EX + +Arguments: + + DeviceExtension - device context + Request - request to be handled + RequestParameters - request parameter + DataLength - transferred data length + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PCDROM_READ_TOC_EX inputBuffer = NULL; + VOID* outputBuffer = NULL; + + PAGED_CODE (); + + *DataLength = 0; + + if (DeviceIsPlayActive(DeviceExtension->Device)) + { + status = STATUS_DEVICE_BUSY; + } + + if (NT_SUCCESS(status)) + { + status = WdfRequestRetrieveInputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.InputBufferLength, + &inputBuffer, + NULL); + } + + if (NT_SUCCESS(status)) + { + status = WdfRequestRetrieveOutputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, + &outputBuffer, + NULL); + } + + // handle the request + if (NT_SUCCESS(status)) + { + size_t transferSize; + CDB cdb; + + transferSize = min(RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, MAXUSHORT); + ScratchBuffer_BeginUse(DeviceExtension); + + RtlZeroMemory(&cdb, sizeof(CDB)); + // Set up the CDB + cdb.READ_TOC.OperationCode = SCSIOP_READ_TOC; + cdb.READ_TOC.Msf = inputBuffer->Msf; + cdb.READ_TOC.Format2 = inputBuffer->Format; + cdb.READ_TOC.StartingTrack = inputBuffer->SessionTrack; + cdb.READ_TOC.AllocationLength[0] = (UCHAR)(transferSize >> 8); + cdb.READ_TOC.AllocationLength[1] = (UCHAR)(transferSize & 0xFF); + + status = ScratchBuffer_ExecuteCdb(DeviceExtension, Request, (ULONG)transferSize, TRUE, &cdb, 10); + + if (NT_SUCCESS(status)) + { + if (DeviceExtension->ScratchContext.ScratchSrb->DataTransferLength < MINIMUM_CDROM_READ_TOC_EX_SIZE) + { + *DataLength = 0; + status = STATUS_INVALID_DEVICE_REQUEST; + } + else + { + *DataLength = DeviceExtension->ScratchContext.ScratchSrb->DataTransferLength; + RtlCopyMemory(outputBuffer, + DeviceExtension->ScratchContext.ScratchBuffer, + *DataLength); + } + } + + ScratchBuffer_EndUse(DeviceExtension); + } + + return status; +} + + +_IRQL_requires_max_(APC_LEVEL) +VOID +GetConfigurationDataConversionTypeAllToTypeOne( + _In_ FEATURE_NUMBER RequestedFeature, + _In_ PSCSI_REQUEST_BLOCK Srb, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + Some CDROM devices do not handle the GET CONFIGURATION commands with + TYPE ONE request. The command will time out causing a bus reset. + To avoid this problem we set a device flag during start device if the device + fails a TYPE ONE request. If this flag is set the TYPE ONE requests will be + tried as TYPE ALL request and the data will be converted to TYPE ONE format + in this routine. + +Arguments: + + RequestedFeature - device context + Srb - request to be handled + DataLength - transfer data length + +Return Value: + + NTSTATUS + +--*/ +{ + PFEATURE_HEADER featureHeader = NULL; + FEATURE_NUMBER thisFeature; + ULONG totalLength = 0; + ULONG featureLength = 0; + ULONG headerLength = 0; + + PGET_CONFIGURATION_HEADER header = NULL; + + PAGED_CODE (); + + *DataLength = 0; + + if (Srb->DataTransferLength < RTL_SIZEOF_THROUGH_FIELD(GET_CONFIGURATION_HEADER, DataLength)) + { + // do not have valid data. + return; + } + + // Calculate the length of valid data available in the + // capabilities buffer from the DataLength field + header = (PGET_CONFIGURATION_HEADER) Srb->DataBuffer; + REVERSE_BYTES(&totalLength, header->DataLength); + + totalLength += RTL_SIZEOF_THROUGH_FIELD(GET_CONFIGURATION_HEADER, DataLength); + + // Make sure the we have enough data in the SRB + totalLength = min(totalLength, Srb->DataTransferLength); + + // If we have received enough data from the device + // check for the given feature. + if (totalLength >= (sizeof(GET_CONFIGURATION_HEADER) + sizeof(FEATURE_HEADER))) + { + // Feature information is present. Verify the feature. + featureHeader = (PFEATURE_HEADER)((PUCHAR)Srb->DataBuffer + sizeof(GET_CONFIGURATION_HEADER)); + + thisFeature = (featureHeader->FeatureCode[0] << 8) | (featureHeader->FeatureCode[1]); + + if (thisFeature == RequestedFeature) + { + // Calculate the feature length + featureLength = sizeof(FEATURE_HEADER) + featureHeader->AdditionalLength; + } + } + + // Calculate the total size + totalLength = sizeof(GET_CONFIGURATION_HEADER) + featureLength; + + headerLength = totalLength - + RTL_SIZEOF_THROUGH_FIELD(GET_CONFIGURATION_HEADER, DataLength); + + REVERSE_BYTES(header->DataLength, &headerLength); + + *DataLength = totalLength; + + return; +} + +_IRQL_requires_max_(APC_LEVEL) +VOID +GetConfigurationDataSynthesize( + _In_reads_bytes_(InputBufferSize) PVOID InputBuffer, + _In_ ULONG InputBufferSize, + _Out_writes_bytes_(OutputBufferSize) PVOID OutputBuffer, + _In_ size_t OutputBufferSize, + _In_ FEATURE_NUMBER StartingFeature, + _In_ ULONG RequestType, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + Get Configuration is a frequently used command, and we don't want it to wake + up the device in case it is in Zero Power state. Before entering Zero Power state, + the complete response of the command is saved in cache, and since the response + is always the same in case there is no media, we can synthesize the response + based on the user request. + +Arguments: + + InputBuffer - buffer containing cached command response + InputBufferSize - size of above buffer + OutputBuffer - buffer to fill in result + OutputBufferSize - size of above buffer + StartingFeature - requested Starting Feature Number + RequestType - requested Request Type + DataLength - transfer data length + +Return Value: + +--*/ +{ + PFEATURE_HEADER featureHeader = NULL; + ULONG validLength = 0; + ULONG featureLength = 0; + ULONG headerLength = 0; + PUCHAR buffer = NULL; + ULONG bytesRemaining = 0; + FEATURE_NUMBER featureCode = 0; + BOOLEAN shouldCopy = FALSE; + size_t copyLength = 0; + size_t transferedLength = 0; + size_t requiredLength = 0; + + PGET_CONFIGURATION_HEADER header = NULL; + + PAGED_CODE (); + + if (InputBufferSize < sizeof (GET_CONFIGURATION_HEADER)) + { + // do not have valid data. + *DataLength = 0; + + return; + } + + // Calculate the length of valid data available in the + // capabilities buffer from the DataLength field + header = (PGET_CONFIGURATION_HEADER) InputBuffer; + REVERSE_BYTES(&validLength, header->DataLength); + + validLength += RTL_SIZEOF_THROUGH_FIELD(GET_CONFIGURATION_HEADER, DataLength); + + // Make sure we have enough data + validLength = min(validLength, InputBufferSize); + + // Copy the header first + copyLength = min(OutputBufferSize, sizeof (GET_CONFIGURATION_HEADER)); + + RtlMoveMemory(OutputBuffer, + InputBuffer, + copyLength); + + transferedLength = copyLength; + requiredLength = sizeof (GET_CONFIGURATION_HEADER); + + if (validLength > sizeof (GET_CONFIGURATION_HEADER)) + { + buffer = header->Data; + bytesRemaining = validLength - sizeof (GET_CONFIGURATION_HEADER); + + // Ignore incomplete feature descriptor + while (bytesRemaining >= sizeof (FEATURE_HEADER)) + { + featureHeader = (PFEATURE_HEADER) buffer; + shouldCopy = FALSE; + + featureCode = (featureHeader->FeatureCode[0] << 8) | (featureHeader->FeatureCode[1]); + featureLength = sizeof (FEATURE_HEADER) + featureHeader->AdditionalLength; + + if (featureCode >= StartingFeature) + { + switch (RequestType) { + + case SCSI_GET_CONFIGURATION_REQUEST_TYPE_ALL: + + shouldCopy = TRUE; + break; + + case SCSI_GET_CONFIGURATION_REQUEST_TYPE_CURRENT: + + if (featureHeader->Current) + { + shouldCopy = TRUE; + } + break; + + case SCSI_GET_CONFIGURATION_REQUEST_TYPE_ONE: + + if (featureCode == StartingFeature) + { + shouldCopy = TRUE; + } + break; + + default: + + break; + } + } + + if (shouldCopy != FALSE) + { + copyLength = min(featureLength, bytesRemaining); + copyLength = min(copyLength, OutputBufferSize - transferedLength); + + RtlMoveMemory((PUCHAR) OutputBuffer + transferedLength, + buffer, + copyLength); + + transferedLength += copyLength; + requiredLength += featureLength; + } + + buffer += min(featureLength, bytesRemaining); + bytesRemaining -= min(featureLength, bytesRemaining); + } + } + + // Adjust Data Length field in header + if (transferedLength >= RTL_SIZEOF_THROUGH_FIELD(GET_CONFIGURATION_HEADER, DataLength)) + { + headerLength = (ULONG) requiredLength - RTL_SIZEOF_THROUGH_FIELD(GET_CONFIGURATION_HEADER, DataLength); + + header = (PGET_CONFIGURATION_HEADER) OutputBuffer; + REVERSE_BYTES(header->DataLength, &headerLength); + } + + *DataLength = transferedLength; + + return; +} + + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +RequestHandleGetConfiguration( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + Handle request of IOCTL_CDROM_GET_CONFIGURATION + +Arguments: + + DeviceExtension - device context + Request - request to be handled + RequestParameters - request parameter + DataLength - transferred data length + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PCDROM_DATA cdData = &(DeviceExtension->DeviceAdditionalData); + PGET_CONFIGURATION_IOCTL_INPUT inputBuffer = NULL; + VOID* outputBuffer = NULL; + size_t transferByteCount = 0; + PZERO_POWER_ODD_INFO zpoddInfo = DeviceExtension->ZeroPowerODDInfo; + BOOLEAN inZeroPowerState = FALSE; + + PAGED_CODE (); + + *DataLength = 0; + + // + if (!cdData->Mmc.IsMmc) + { + status = STATUS_INVALID_DEVICE_REQUEST; + } + else + { + status = WdfRequestRetrieveInputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.InputBufferLength, + &inputBuffer, + NULL); + } + + if (NT_SUCCESS(status)) + { + status = WdfRequestRetrieveOutputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, + &outputBuffer, + NULL); + } + + if (NT_SUCCESS(status)) + { + // If device is Zero Power state, there should be no media in device, thus we can synthesize the response + // from our cache. Avoid waking up the device in this case. + if ((zpoddInfo != NULL) && + (zpoddInfo->InZeroPowerState != FALSE)) + { + inZeroPowerState = TRUE; + } + + if ((inZeroPowerState == FALSE) || + (zpoddInfo->GetConfigurationBuffer == NULL)) + { + CDB cdb; + + //The maximum number of bytes that a Drive may return + //to describe its Features in one GET CONFIGURATION Command is 65,534 + transferByteCount = min(RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, (MAXUSHORT - 1)); + + // If this is a TYPE ONE request and if this device can't handle this + // request, then we need to send TYPE ALL request to the device and + // convert the data in the completion routine. If required allocate a big + // buffer to get both configuration and feature header. + if ((inputBuffer->RequestType == SCSI_GET_CONFIGURATION_REQUEST_TYPE_ONE) && + TEST_FLAG(cdData->HackFlags, CDROM_HACK_BAD_TYPE_ONE_GET_CONFIG)) + { + transferByteCount = max(transferByteCount, + sizeof(GET_CONFIGURATION_HEADER) + sizeof(FEATURE_HEADER)); + } + + ScratchBuffer_BeginUse(DeviceExtension); + + RtlZeroMemory(&cdb, sizeof(CDB)); + // Set up the CDB + cdb.GET_CONFIGURATION.OperationCode = SCSIOP_GET_CONFIGURATION; + cdb.GET_CONFIGURATION.AllocationLength[0] = (UCHAR)(transferByteCount >> 8); + cdb.GET_CONFIGURATION.AllocationLength[1] = (UCHAR)(transferByteCount & 0xff); + + cdb.GET_CONFIGURATION.StartingFeature[0] = (UCHAR)(inputBuffer->Feature >> 8); + cdb.GET_CONFIGURATION.StartingFeature[1] = (UCHAR)(inputBuffer->Feature & 0xff); + cdb.GET_CONFIGURATION.RequestType = (UCHAR)(inputBuffer->RequestType); + + // If the device does not support TYPE ONE get configuration commands + // then change the request type to TYPE ALL. Convert the returned data to + // TYPE ONE format in the completion routine. + if ((inputBuffer->RequestType == SCSI_GET_CONFIGURATION_REQUEST_TYPE_ONE) && + TEST_FLAG(cdData->HackFlags, CDROM_HACK_BAD_TYPE_ONE_GET_CONFIG)) + { + + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, + "DeviceHandleGetConfiguration: Changing TYPE_ONE Get Config to TYPE_ALL\n")); + cdb.GET_CONFIGURATION.RequestType = SCSI_GET_CONFIGURATION_REQUEST_TYPE_ALL; + } + + status = ScratchBuffer_ExecuteCdb(DeviceExtension, Request, (ULONG)transferByteCount, TRUE, &cdb, 12); + + if (NT_SUCCESS(status)) + { + if ((inputBuffer->RequestType == SCSI_GET_CONFIGURATION_REQUEST_TYPE_ONE) && + TEST_FLAG(cdData->HackFlags, CDROM_HACK_BAD_TYPE_ONE_GET_CONFIG)) + { + + if (DeviceExtension->ScratchContext.ScratchSrb->DataTransferLength < sizeof(GET_CONFIGURATION_HEADER)) + { + // Not enough data to calculate the data length. + // So assume feature is not present + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DeviceHandleGetConfiguration: No get config header!\n")); + *DataLength = 0; + status = STATUS_INVALID_DEVICE_REQUEST; + } + else + { + //Some CDROM devices do not handle the GET CONFIGURATION commands with + //TYPE ONE request. The command will time out causing a bus reset. + //To avoid this problem we set a device flag during start device if the device + //fails a TYPE ONE request. If this flag is set the TYPE ONE requests will be + //tried as TYPE ALL request and the data will be converted to TYPE ONE format + //in this routine. + GetConfigurationDataConversionTypeAllToTypeOne(inputBuffer->Feature, DeviceExtension->ScratchContext.ScratchSrb, DataLength); + *DataLength = min(*DataLength, RequestParameters.Parameters.DeviceIoControl.OutputBufferLength); + } + } + else + { + *DataLength = DeviceExtension->ScratchContext.ScratchSrb->DataTransferLength; + } + + // copy data to output buffer + if (NT_SUCCESS(status)) + { + RtlMoveMemory(outputBuffer, + DeviceExtension->ScratchContext.ScratchBuffer, + *DataLength); + } + } + + ScratchBuffer_EndUse(DeviceExtension); + } + else + { + // We are in Zero Power state, and our cached response is available. + // Synthesize the requested data. + GetConfigurationDataSynthesize(zpoddInfo->GetConfigurationBuffer, + zpoddInfo->GetConfigurationBufferSize, + outputBuffer, + RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, + inputBuffer->Feature, + inputBuffer->RequestType, + DataLength + ); + } + } + + return status; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +RequestHandleGetDriveGeometry( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + Handle request of IOCTL_DISK_GET_LENGTH_INFO + IOCTL_DISK_GET_DRIVE_GEOMETRY + IOCTL_DISK_GET_DRIVE_GEOMETRY_EX + IOCTL_CDROM_GET_DRIVE_GEOMETRY + IOCTL_CDROM_GET_DRIVE_GEOMETRY_EX + IOCTL_STORAGE_READ_CAPACITY + +Arguments: + + DeviceExtension - device context + Request - request to be handled + RequestParameters - request parameter + DataLength - transferred data length + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + VOID* outputBuffer = NULL; + + PAGED_CODE (); + + *DataLength = 0; + + status = WdfRequestRetrieveOutputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, + &outputBuffer, + NULL); + + // Issue ReadCapacity to update device extension + // with information for current media. + if (NT_SUCCESS(status)) + { + status = MediaReadCapacity(DeviceExtension->Device); + } + + if (NT_SUCCESS(status)) + { + switch(RequestParameters.Parameters.DeviceIoControl.IoControlCode) + { + case IOCTL_DISK_GET_LENGTH_INFO: + { + PGET_LENGTH_INFORMATION lengthInfo = (PGET_LENGTH_INFORMATION)outputBuffer; + + lengthInfo->Length = DeviceExtension->PartitionLength; + *DataLength = sizeof(GET_LENGTH_INFORMATION); + break; + } + case IOCTL_DISK_GET_DRIVE_GEOMETRY: + case IOCTL_CDROM_GET_DRIVE_GEOMETRY: + { + PDISK_GEOMETRY geometry = (PDISK_GEOMETRY)outputBuffer; + + *geometry = DeviceExtension->DiskGeometry; + *DataLength = sizeof(DISK_GEOMETRY); + break; + } + case IOCTL_DISK_GET_DRIVE_GEOMETRY_EX: + case IOCTL_CDROM_GET_DRIVE_GEOMETRY_EX: + { + PDISK_GEOMETRY_EX geometryEx = (PDISK_GEOMETRY_EX)outputBuffer; + + geometryEx->DiskSize = DeviceExtension->PartitionLength; + geometryEx->Geometry = DeviceExtension->DiskGeometry; + *DataLength = FIELD_OFFSET(DISK_GEOMETRY_EX, Data); + break; + } + case IOCTL_STORAGE_READ_CAPACITY: + { + PSTORAGE_READ_CAPACITY readCapacity = (PSTORAGE_READ_CAPACITY)outputBuffer; + + readCapacity->Version = sizeof(STORAGE_READ_CAPACITY); + readCapacity->Size = sizeof(STORAGE_READ_CAPACITY); + + readCapacity->BlockLength = DeviceExtension->DiskGeometry.BytesPerSector; + if (readCapacity->BlockLength > 0) + { + readCapacity->NumberOfBlocks.QuadPart = DeviceExtension->PartitionLength.QuadPart/readCapacity->BlockLength; + } + else + { + readCapacity->NumberOfBlocks.QuadPart = 0; + } + + readCapacity->DiskLength = DeviceExtension->PartitionLength; + + *DataLength = sizeof(STORAGE_READ_CAPACITY); + break; + } + default: + { + NT_ASSERT(FALSE); + break; + } + } // end of switch() + } + + return status; +} + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +RequestHandleDiskVerify( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + Handle request of IOCTL_DISK_VERIFY + +Arguments: + + DeviceExtension - device context + Request - request to be handled + RequestParameters - request parameter + DataLength - transferred data length + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PCDROM_DATA cdData = &(DeviceExtension->DeviceAdditionalData); + PVERIFY_INFORMATION verifyInfo = NULL; + + PAGED_CODE (); + + *DataLength = 0; + + if (!cdData->Mmc.WriteAllowed) + { + status = STATUS_MEDIA_WRITE_PROTECTED; + } + + if (NT_SUCCESS(status)) + { + status = WdfRequestRetrieveInputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.InputBufferLength, + &verifyInfo, + NULL); + } + + // handle the request + if (NT_SUCCESS(status)) + { + LARGE_INTEGER byteOffset = {0}; + + // Add disk offset to starting sector. + byteOffset.QuadPart = DeviceExtension->StartingOffset.QuadPart + + verifyInfo->StartingOffset.QuadPart; + + // prevent overflow returning success but only validating small area + if (((DeviceExtension->StartingOffset.QuadPart + verifyInfo->StartingOffset.QuadPart) < DeviceExtension->StartingOffset.QuadPart) || + ((verifyInfo->Length >> DeviceExtension->SectorShift) > MAXUSHORT) || + ((byteOffset.QuadPart >> DeviceExtension->SectorShift) > MAXULONG) ) + { + status = STATUS_INVALID_PARAMETER; + } + else + { + ULONG transferSize = 0; + ULONG timeoutValue = 0; + CDB cdb; + ULONG sectorOffset; + USHORT sectorCount; + + ScratchBuffer_BeginUse(DeviceExtension); + + // Convert byte offset to sector offset. + sectorOffset = (ULONG)(byteOffset.QuadPart >> DeviceExtension->SectorShift); + + // Convert ULONG byte count to USHORT sector count. + sectorCount = (USHORT)(verifyInfo->Length >> DeviceExtension->SectorShift); + + RtlZeroMemory(&cdb, sizeof(CDB)); + // Set up the CDB + cdb.CDB10.OperationCode = SCSIOP_VERIFY; + + // Move little endian values into CDB in big endian format. + cdb.CDB10.LogicalBlockByte0 = ((PFOUR_BYTE)§orOffset)->Byte3; + cdb.CDB10.LogicalBlockByte1 = ((PFOUR_BYTE)§orOffset)->Byte2; + cdb.CDB10.LogicalBlockByte2 = ((PFOUR_BYTE)§orOffset)->Byte1; + cdb.CDB10.LogicalBlockByte3 = ((PFOUR_BYTE)§orOffset)->Byte0; + + cdb.CDB10.TransferBlocksMsb = ((PFOUR_BYTE)§orCount)->Byte1; + cdb.CDB10.TransferBlocksLsb = ((PFOUR_BYTE)§orCount)->Byte0; + + // The verify command is used by the NT FORMAT utility and + // requests are sent down for 5% of the volume size. The + // request timeout value is calculated based on the number of + // sectors verified. + if (sectorCount != 0) + { + // sectorCount is a USHORT, so no overflow here... + timeoutValue = TimeOutValueGetCapValue(DeviceExtension->TimeOutValue, ((sectorCount + 128) / 128)); + } + + status = ScratchBuffer_ExecuteCdbEx(DeviceExtension, Request, transferSize, FALSE, &cdb, 10, timeoutValue); + + // nothing to do after the command finishes. + ScratchBuffer_EndUse(DeviceExtension); + } + } + + return status; +} + + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +RequestHandleCheckVerify( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + Handle request of IOCTL_STORAGE_CHECK_VERIFY2 + IOCTL_STORAGE_CHECK_VERIFY + +Arguments: + + DeviceExtension - device context + Request - request to be handled + RequestParameters - request parameter + DataLength - transferred data length + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + + PAGED_CODE (); + + *DataLength = 0; + + if (NT_SUCCESS(status)) + { + ULONG transferSize = 0; + CDB cdb; + + ScratchBuffer_BeginUse(DeviceExtension); + + RtlZeroMemory(&cdb, sizeof(CDB)); + // Set up the CDB + cdb.CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY; + + status = ScratchBuffer_ExecuteCdbEx(DeviceExtension, Request, transferSize, FALSE, &cdb, 6, CDROM_TEST_UNIT_READY_TIMEOUT); + + if (NT_SUCCESS(status)) + { + if((RequestParameters.Parameters.DeviceIoControl.IoControlCode == IOCTL_STORAGE_CHECK_VERIFY) && + (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength)) + { + PULONG outputBuffer = NULL; + status = WdfRequestRetrieveOutputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, + &outputBuffer, + NULL); + + if (outputBuffer != NULL) + { + *outputBuffer = DeviceExtension->MediaChangeCount; + *DataLength = sizeof(ULONG); + } + } + else + { + *DataLength = 0; + } + } + + // nothing to do after the command finishes. + ScratchBuffer_EndUse(DeviceExtension); + } + + return status; +} + + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +RequestHandleFakePartitionInfo( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + Handle request of IOCTL_DISK_GET_DRIVE_LAYOUT + IOCTL_DISK_GET_DRIVE_LAYOUT_EX + IOCTL_DISK_GET_PARTITION_INFO + IOCTL_DISK_GET_PARTITION_INFO_EX + +Arguments: + + DeviceExtension - device context + Request - request to be handled + RequestParameters - request parameter + DataLength - transferred data length + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + VOID* outputBuffer = NULL; + ULONG ioctl = RequestParameters.Parameters.DeviceIoControl.IoControlCode; + + PAGED_CODE (); + + *DataLength = 0; + + if (NT_SUCCESS(status)) + { + if ((ioctl != IOCTL_DISK_GET_DRIVE_LAYOUT) && + (ioctl != IOCTL_DISK_GET_DRIVE_LAYOUT_EX) && + (ioctl != IOCTL_DISK_GET_PARTITION_INFO) && + (ioctl != IOCTL_DISK_GET_PARTITION_INFO_EX)) + { + status = STATUS_INTERNAL_ERROR; + } + } + + if (NT_SUCCESS(status)) + { + status = WdfRequestRetrieveOutputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, + &outputBuffer, + NULL); + } + + // handle the request + if (NT_SUCCESS(status)) + { + switch (ioctl) + { + case IOCTL_DISK_GET_DRIVE_LAYOUT: + *DataLength = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION, PartitionEntry[1]); + RtlZeroMemory(outputBuffer, *DataLength); + break; + case IOCTL_DISK_GET_DRIVE_LAYOUT_EX: + *DataLength = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry[1]); + RtlZeroMemory(outputBuffer, *DataLength); + break; + case IOCTL_DISK_GET_PARTITION_INFO: + *DataLength = sizeof(PARTITION_INFORMATION); + RtlZeroMemory(outputBuffer, *DataLength); + break; + case IOCTL_DISK_GET_PARTITION_INFO_EX: + *DataLength = sizeof(PARTITION_INFORMATION_EX); + RtlZeroMemory(outputBuffer, *DataLength); + break; + default: + NT_ASSERT(!"Invalid ioctl should not have reached this point\n"); + break; + } + + // if we are getting the drive layout, then we need to start by + // adding some of the non-partition stuff that says we have + // exactly one partition available. + if (ioctl == IOCTL_DISK_GET_DRIVE_LAYOUT) + { + PDRIVE_LAYOUT_INFORMATION layout; + layout = (PDRIVE_LAYOUT_INFORMATION)outputBuffer; + layout->PartitionCount = 1; + layout->Signature = 1; + outputBuffer = (PVOID)(layout->PartitionEntry); + ioctl = IOCTL_DISK_GET_PARTITION_INFO; + } + else if (ioctl == IOCTL_DISK_GET_DRIVE_LAYOUT_EX) + { + PDRIVE_LAYOUT_INFORMATION_EX layoutEx; + layoutEx = (PDRIVE_LAYOUT_INFORMATION_EX)outputBuffer; + layoutEx->PartitionStyle = PARTITION_STYLE_MBR; + layoutEx->PartitionCount = 1; + layoutEx->Mbr.Signature = 1; + outputBuffer = (PVOID)(layoutEx->PartitionEntry); + ioctl = IOCTL_DISK_GET_PARTITION_INFO_EX; + } + + // NOTE: the local var 'ioctl' is now modified to either EX or + // non-EX version. the local var 'systemBuffer' is now pointing + // to the partition information structure. + if (ioctl == IOCTL_DISK_GET_PARTITION_INFO) + { + PPARTITION_INFORMATION partitionInfo; + partitionInfo = (PPARTITION_INFORMATION)outputBuffer; + partitionInfo->RewritePartition = FALSE; + partitionInfo->RecognizedPartition = TRUE; + partitionInfo->PartitionType = PARTITION_FAT32; + partitionInfo->BootIndicator = FALSE; + partitionInfo->HiddenSectors = 0; + partitionInfo->StartingOffset.QuadPart = 0; + partitionInfo->PartitionLength = DeviceExtension->PartitionLength; + partitionInfo->PartitionNumber = 0; + } + else + { + PPARTITION_INFORMATION_EX partitionInfo; + partitionInfo = (PPARTITION_INFORMATION_EX)outputBuffer; + partitionInfo->PartitionStyle = PARTITION_STYLE_MBR; + partitionInfo->RewritePartition = FALSE; + partitionInfo->Mbr.RecognizedPartition = TRUE; + partitionInfo->Mbr.PartitionType = PARTITION_FAT32; + partitionInfo->Mbr.BootIndicator = FALSE; + partitionInfo->Mbr.HiddenSectors = 0; + partitionInfo->StartingOffset.QuadPart = 0; + partitionInfo->PartitionLength = DeviceExtension->PartitionLength; + partitionInfo->PartitionNumber = 0; + } + } + + return status; +} + +NTSTATUS +RequestHandleGetDeviceNumber( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + Handle request of IOCTL_STORAGE_GET_DEVICE_NUMBER + +Arguments: + + DeviceExtension - device context + Request - request to be handled + RequestParameters - request parameter + DataLength - transferred data length + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + + *DataLength = 0; + + if(RequestParameters.Parameters.DeviceIoControl.OutputBufferLength >= + sizeof(STORAGE_DEVICE_NUMBER)) + { + PSTORAGE_DEVICE_NUMBER deviceNumber = NULL; + status = WdfRequestRetrieveOutputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, + &deviceNumber, + NULL); + if (NT_SUCCESS(status)) + { + deviceNumber->DeviceType = DeviceExtension->DeviceObject->DeviceType; + deviceNumber->DeviceNumber = DeviceExtension->DeviceNumber; + deviceNumber->PartitionNumber = (ULONG)-1; // legacy reason, return (-1) for this IOCTL. + + status = STATUS_SUCCESS; + *DataLength = sizeof(STORAGE_DEVICE_NUMBER); + } + } + else + { + status = STATUS_BUFFER_TOO_SMALL; + *DataLength = sizeof(STORAGE_DEVICE_NUMBER); + } + + return status; +} + +NTSTATUS +RequestHandleGetHotPlugInfo( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + Handle request of IOCTL_STORAGE_GET_HOTPLUG_INFO + +Arguments: + + DeviceExtension - device context + Request - request to be handled + RequestParameters - request parameter + DataLength - transferred data length + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + + *DataLength = 0; + + if(RequestParameters.Parameters.DeviceIoControl.OutputBufferLength >= + sizeof(STORAGE_HOTPLUG_INFO)) + { + PSTORAGE_HOTPLUG_INFO info = NULL; + status = WdfRequestRetrieveOutputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, + &info, + NULL); + if (NT_SUCCESS(status)) + { + *info = DeviceExtension->PrivateFdoData->HotplugInfo; + + status = STATUS_SUCCESS; + *DataLength = sizeof(STORAGE_HOTPLUG_INFO); + } + } + else + { + status = STATUS_BUFFER_TOO_SMALL; + *DataLength = sizeof(STORAGE_HOTPLUG_INFO); + } + + return status; +} + +NTSTATUS +RequestHandleSetHotPlugInfo( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + Handle request of IOCTL_STORAGE_SET_HOTPLUG_INFO + +Arguments: + + DeviceExtension - device context + Request - request to be handled + RequestParameters - request parameter + DataLength - transferred data length + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PSTORAGE_HOTPLUG_INFO info = NULL; + + *DataLength = 0; + + if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength < + sizeof(STORAGE_HOTPLUG_INFO)) + { + // Indicate unsuccessful status and no data transferred. + status = STATUS_INFO_LENGTH_MISMATCH; + } + + if (NT_SUCCESS(status)) + { + status = WdfRequestRetrieveInputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.InputBufferLength, + &info, + NULL); + } + + if (NT_SUCCESS(status)) + { + if (info->Size != DeviceExtension->PrivateFdoData->HotplugInfo.Size) + { + status = STATUS_INVALID_PARAMETER_1; + } + + if (info->MediaRemovable != DeviceExtension->PrivateFdoData->HotplugInfo.MediaRemovable) + { + status = STATUS_INVALID_PARAMETER_2; + } + + if (info->MediaHotplug != DeviceExtension->PrivateFdoData->HotplugInfo.MediaHotplug) + { + status = STATUS_INVALID_PARAMETER_3; + } + + if (info->WriteCacheEnableOverride != DeviceExtension->PrivateFdoData->HotplugInfo.WriteCacheEnableOverride) + { + status = STATUS_INVALID_PARAMETER_5; + } + } + + if (NT_SUCCESS(status)) + { + DeviceExtension->PrivateFdoData->HotplugInfo.DeviceHotplug = info->DeviceHotplug; + + // Store the user-defined override in the registry + DeviceSetParameter(DeviceExtension, + CLASSP_REG_SUBKEY_NAME, + CLASSP_REG_REMOVAL_POLICY_VALUE_NAME, + (info->DeviceHotplug) ? RemovalPolicyExpectSurpriseRemoval : RemovalPolicyExpectOrderlyRemoval); + } + + return status; +} + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +RequestHandleEventNotification( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_opt_ WDFREQUEST Request, + _In_opt_ PWDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + This routine handles the process of IOCTL_STORAGE_EVENT_NOTIFICATION + +Arguments: + + DeviceExtension - device context + + Request - request to be handled + + RequestParameters - request parameter + + DataLength - data transferred + +Return Value: + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PMEDIA_CHANGE_DETECTION_INFO info = NULL; + LONG requestInUse; + PSTORAGE_EVENT_NOTIFICATION eventBuffer = NULL; + + *DataLength = 0; + + info = DeviceExtension->MediaChangeDetectionInfo; + + // Since AN is ASYNCHRONOUS and can happen at any time, + // make certain not to do anything before properly initialized. + if ((!DeviceExtension->IsInitialized) || (info == NULL)) + { + status = STATUS_UNSUCCESSFUL; + } + + if (NT_SUCCESS(status) && (Request != NULL) && (RequestParameters != NULL)) { + + // + // Validate IOCTL parameters + // + if (RequestParameters->Parameters.DeviceIoControl.InputBufferLength < + sizeof(STORAGE_EVENT_NOTIFICATION)) { + status = STATUS_INFO_LENGTH_MISMATCH; + } + + // + // Check for an supported event + // + if (NT_SUCCESS(status)) { + status = WdfRequestRetrieveInputBuffer(Request, + RequestParameters->Parameters.DeviceIoControl.InputBufferLength, + &eventBuffer, + NULL); + if (NT_SUCCESS(status)) { + if ((eventBuffer->Version != STORAGE_EVENT_NOTIFICATION_VERSION_V1) || + (eventBuffer->Size != sizeof(STORAGE_EVENT_NOTIFICATION))) { + status = STATUS_INVALID_PARAMETER; + } else if ((eventBuffer->Events & + (STORAGE_EVENT_MEDIA_STATUS | STORAGE_EVENT_DEVICE_STATUS | STORAGE_EVENT_DEVICE_OPERATION)) == 0) { + status = STATUS_NOT_SUPPORTED; + } + } + } + + } + + if (NT_SUCCESS(status)) + { + if (info->MediaChangeDetectionDisableCount != 0) + { + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_MCN, + "RequestHandleEventNotification: device %p has detection disabled \n", + DeviceExtension->DeviceObject)); + status = STATUS_UNSUCCESSFUL; + } + } + + if (NT_SUCCESS(status)) + { + // if the request is not in use, mark it as such. + requestInUse = InterlockedCompareExchange((PLONG)&info->MediaChangeRequestInUse, 1, 0); + + if (requestInUse != 0) + { + status = STATUS_UNSUCCESSFUL; + } + } + + if (NT_SUCCESS(status)) + { + // The last MCN finished. ok to issue the new one. + RequestSetupMcnSyncIrp(DeviceExtension); + + // The irp will go into KMDF framework and a request will be created there to represent it. + IoCallDriver(DeviceExtension->DeviceObject, info->MediaChangeSyncIrp); + } + + return status; +} + + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +RequestHandleEjectionControl( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + Handle request of IOCTL_STORAGE_MEDIA_REMOVAL + IOCTL_STORAGE_EJECTION_CONTROL + +Arguments: + + DeviceExtension - device context + Request - request to be handled + RequestParameters - request parameter + DataLength - transferred data length + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PPREVENT_MEDIA_REMOVAL mediaRemoval = NULL; + + PAGED_CODE (); + + *DataLength = 0; + + if(RequestParameters.Parameters.DeviceIoControl.InputBufferLength < + sizeof(PREVENT_MEDIA_REMOVAL)) + { + status = STATUS_INFO_LENGTH_MISMATCH; + } + else + { + status = WdfRequestRetrieveInputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.InputBufferLength, + &mediaRemoval, + NULL); + } + + if (NT_SUCCESS(status)) + { + status = PerformEjectionControl(DeviceExtension, + Request, + ((RequestParameters.Parameters.DeviceIoControl.IoControlCode == IOCTL_STORAGE_EJECTION_CONTROL) + ? SecureMediaLock + : SimpleMediaLock), + mediaRemoval->PreventMediaRemoval); + } + + return status; +} + + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +RequestHandleEnableStreaming( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + Handles an IOCTL_CDROM_ENABLE_STREAMING request + +Arguments: + + DeviceExtension - device context + Request - request to be handled + DataLength - transferred data length + +Notes: + + This IOCTL is serialized because it changes read/write + behavior and we want to make sure that all previous + reads/writes have been completed before we change the + behavior. + +Return Value: + + NTSTATUS + +--*/ +{ + PCDROM_DATA cdData = &(DeviceExtension->DeviceAdditionalData); + PCDROM_PRIVATE_FDO_DATA fdoData = DeviceExtension->PrivateFdoData; + + WDFFILEOBJECT fileObject = NULL; + PFILE_OBJECT_CONTEXT fileObjectContext = NULL; + + NTSTATUS status = STATUS_SUCCESS; + PCDROM_STREAMING_CONTROL inputBuffer = NULL; + + BOOLEAN enforceStreamingRead = FALSE; + BOOLEAN enforceStreamingWrite = FALSE; + BOOLEAN streamingReadSupported, streamingWriteSupported; + + PAGED_CODE (); + + *DataLength = 0; + + status = WdfRequestRetrieveInputBuffer(Request, + sizeof(CDROM_STREAMING_CONTROL), + &inputBuffer, + NULL); + + if (NT_SUCCESS(status)) + { + // get file object context + fileObject = WdfRequestGetFileObject(Request); + if (fileObject != NULL) { + fileObjectContext = FileObjectGetContext(fileObject); + } + NT_ASSERT(fileObjectContext != NULL); + + if (fileObjectContext == NULL) + { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, + "RequestHandleEnableStreaming: cannot find file object context\n")); + status = STATUS_INVALID_HANDLE; + } + } + + if (NT_SUCCESS(status)) + { + if (inputBuffer->RequestType == CdromStreamingDisable) + { + enforceStreamingRead = FALSE; + enforceStreamingWrite = FALSE; + } + else if (inputBuffer->RequestType == CdromStreamingEnableForReadOnly) + { + enforceStreamingRead = TRUE; + enforceStreamingWrite = FALSE; + } + else if (inputBuffer->RequestType == CdromStreamingEnableForWriteOnly) + { + enforceStreamingRead = FALSE; + enforceStreamingWrite = TRUE; + } + else if (inputBuffer->RequestType == CdromStreamingEnableForReadWrite) + { + enforceStreamingRead = TRUE; + enforceStreamingWrite = TRUE; + } + + streamingReadSupported = cdData->Mmc.StreamingReadSupported && !TEST_FLAG(fdoData->HackFlags, FDO_HACK_NO_STREAMING); + streamingWriteSupported = cdData->Mmc.StreamingWriteSupported && !TEST_FLAG(fdoData->HackFlags, FDO_HACK_NO_STREAMING); + if ((enforceStreamingRead && !streamingReadSupported) || + (enforceStreamingWrite && !streamingWriteSupported)) + { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, + "RequestHandleEnableStreaming: requested Streaming mode is not supported\n")); + status = STATUS_INVALID_DEVICE_REQUEST; + } + else + { + fileObjectContext->EnforceStreamingRead = enforceStreamingRead; + fileObjectContext->EnforceStreamingWrite = enforceStreamingWrite; + } + } + + return status; +} + + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +RequestHandleSendOpcInformation( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + Handles an IOCTL_CDROM_SEND_OPC_INFORMATION request + +Arguments: + + DeviceExtension - device context + Request - request to be handled + DataLength - transferred data length + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PCDROM_SIMPLE_OPC_INFO inputBuffer = NULL; + + PAGED_CODE (); + + *DataLength = 0; + + status = WdfRequestRetrieveInputBuffer(Request, + sizeof(CDROM_SIMPLE_OPC_INFO), + (PVOID*)&inputBuffer, + NULL); + + if (NT_SUCCESS(status)) + { + CDB cdb; + + ScratchBuffer_BeginUse(DeviceExtension); + + RtlZeroMemory(&cdb, sizeof(CDB)); + + // we support only the simplest version for now + cdb.SEND_OPC_INFORMATION.OperationCode = SCSIOP_SEND_OPC_INFORMATION; + cdb.SEND_OPC_INFORMATION.DoOpc = 1; + cdb.SEND_OPC_INFORMATION.Exclude0 = (inputBuffer->Exclude0 ? 1 : 0); + cdb.SEND_OPC_INFORMATION.Exclude1 = (inputBuffer->Exclude1 ? 1 : 0); + + status = ScratchBuffer_ExecuteCdb(DeviceExtension, Request, 0, FALSE, &cdb, sizeof(cdb.SEND_OPC_INFORMATION)); + + // nothing to do after the command finishes + ScratchBuffer_EndUse(DeviceExtension); + } + + return status; +} + + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +RequestHandleGetPerformance( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + Handles an IOCTL_CDROM_GET_PERFORMANCE request + +Arguments: + + DeviceExtension - device context + Request - request to be handled + RequestParameters - request parameter + DataLength - transferred data length + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PCDROM_PERFORMANCE_REQUEST inputBuffer = NULL; + PVOID outputBuffer = NULL; + + PAGED_CODE (); + + *DataLength = 0; + + // Retrieve pointers to input/output data. The size has been validated earlier + // in RequestValidateGetPerformance, so we do not check it again. + if (NT_SUCCESS(status)) + { + status = WdfRequestRetrieveInputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.InputBufferLength, + (PVOID*)&inputBuffer, + NULL); + } + if (NT_SUCCESS(status)) + { + status = WdfRequestRetrieveOutputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, + &outputBuffer, + NULL); + } + + if (NT_SUCCESS(status)) + { + USHORT descriptorSize = 0; + USHORT descriptorCount = 0; + size_t transferSize = 0; + CDB cdb; + + ScratchBuffer_BeginUse(DeviceExtension); + + // Set up the CDB + RtlZeroMemory(&cdb, sizeof(CDB)); + + if (inputBuffer->RequestType == CdromPerformanceRequest) + { + cdb.GET_PERFORMANCE.Type = 0; + + // 10b is the only defined tolerance in MMCr6 + cdb.GET_PERFORMANCE.Tolerance = 2; + + switch (inputBuffer->Exceptions) { + case CdromNominalPerformance: + cdb.GET_PERFORMANCE.Except = 0; + descriptorSize = sizeof(CDROM_NOMINAL_PERFORMANCE_DESCRIPTOR); + break; + case CdromEntirePerformanceList: + cdb.GET_PERFORMANCE.Except = 1; + descriptorSize = sizeof(CDROM_NOMINAL_PERFORMANCE_DESCRIPTOR); + break; + case CdromPerformanceExceptionsOnly: + cdb.GET_PERFORMANCE.Except = 2; + descriptorSize = sizeof(CDROM_EXCEPTION_PERFORMANCE_DESCRIPTOR); + break; + } + + switch (inputBuffer->PerformanceType) { + case CdromReadPerformance: + cdb.GET_PERFORMANCE.Write = 0; break; + case CdromWritePerformance: + cdb.GET_PERFORMANCE.Write = 1; break; + } + + REVERSE_BYTES(&cdb.GET_PERFORMANCE.StartingLBA, &inputBuffer->StaringLba); + } + else if (inputBuffer->RequestType == CdromWriteSpeedRequest) + { + cdb.GET_PERFORMANCE.Type = 3; + descriptorSize = sizeof(CDROM_WRITE_SPEED_DESCRIPTOR); + } + + cdb.GET_PERFORMANCE.OperationCode = SCSIOP_GET_PERFORMANCE; + + // calculate how many descriptors can fit into the output buffer + if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength >= + sizeof(CDROM_PERFORMANCE_HEADER) && + RequestParameters.Parameters.DeviceIoControl.OutputBufferLength <= + MAXUSHORT && + descriptorSize > 0) + { + descriptorCount = (USHORT)(RequestParameters.Parameters.DeviceIoControl.OutputBufferLength - sizeof(CDROM_PERFORMANCE_HEADER)); + descriptorCount /= descriptorSize; + } + else + { + status = STATUS_INVALID_PARAMETER; + } + + REVERSE_BYTES_SHORT(&cdb.GET_PERFORMANCE.MaximumNumberOfDescriptors, &descriptorCount); + + // Calculate transfer size. We round it up to meet adapter requirements. + // Extra bytes are discarded later, when we copy data to the output buffer. + transferSize = RequestParameters.Parameters.DeviceIoControl.OutputBufferLength; + transferSize += DeviceExtension->AdapterDescriptor->AlignmentMask; + transferSize &= ~DeviceExtension->AdapterDescriptor->AlignmentMask; + + if (NT_SUCCESS(status)) + { + status = ScratchBuffer_ExecuteCdbEx(DeviceExtension, Request, (ULONG)transferSize, TRUE, &cdb, sizeof(cdb.GET_PERFORMANCE), CDROM_GET_PERFORMANCE_TIMEOUT); + } + + if (NT_SUCCESS(status)) + { + if (DeviceExtension->ScratchContext.ScratchSrb->DataTransferLength < sizeof(CDROM_PERFORMANCE_HEADER)) + { + *DataLength = 0; + status = STATUS_INVALID_DEVICE_REQUEST; + } + else + { + *DataLength = min(RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, + DeviceExtension->ScratchContext.ScratchSrb->DataTransferLength); + RtlCopyMemory(outputBuffer, + DeviceExtension->ScratchContext.ScratchBuffer, + *DataLength); + } + } + + ScratchBuffer_EndUse(DeviceExtension); + } + + return status; +} + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +RequestHandleMcnSyncFakeIoctl( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + Handles an IOCTL_MCN_SYNC_FAKE_IOCTL request + +Arguments: + + DeviceExtension - device context + DataLength - transferred data length + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PMEDIA_CHANGE_DETECTION_INFO info = DeviceExtension->MediaChangeDetectionInfo; + BOOLEAN shouldRetry = TRUE; + BOOLEAN requestSent = FALSE; + + PAGED_CODE (); + + *DataLength = 0; + + // + // Try to acquire the media change event. If we can't do it immediately + // then bail out and assume the caller will try again later. + // + while (shouldRetry) + { + status = RequestSetupMcnRequest(DeviceExtension, + info->Gesn.Supported); + + if (!NT_SUCCESS(status)) + { + shouldRetry = FALSE; + } + + if (NT_SUCCESS(status)) + { + requestSent = RequestSendMcnRequest(DeviceExtension); + + if (requestSent) + { + shouldRetry = RequestPostWorkMcnRequest(DeviceExtension); + } + else + { + shouldRetry = FALSE; + } + } + } + + // If there were any media change notifications that were not delivered + // for some reason, make an attempt to do so at this time. + DeviceSendDelayedMediaChangeNotifications(DeviceExtension); + + // Set the status and then complete the original request. + // The timer handler will be able to send the next request. + status = STATUS_SUCCESS; + + return status; +} + +BOOLEAN +RequestIsRealtimeStreaming( + _In_ WDFREQUEST Request, + _In_ BOOLEAN IsReadRequest + ) +/*++ + +Routine Description: + + Checks whether a given read/write request should + be performed in Real-Time Streaming mode. + +Arguments: + + Request - request to be checked + IsReadRequest - TRUE = read request; FALSE = write request + +Return Value: + + TRUE - a Real-Time Streaming operation has to be performed + FALSE - a normal (non-Streaming) operation has to be performed + +--*/ +{ + BOOLEAN useStreaming = FALSE; + + if (!useStreaming) { + // + // Check if we're required to use Streaming via I/O Stack Location flags + // + UCHAR currentStackLocationFlags = 0; + currentStackLocationFlags = RequestGetCurrentStackLocationFlags(Request); + + useStreaming = TEST_FLAG(currentStackLocationFlags, SL_REALTIME_STREAM); + } + + if (!useStreaming) { + // + // Check if we were previously requested to enforce Streaming for + // the file handle through which this request was sent. + // + + WDFFILEOBJECT fileObject; + PFILE_OBJECT_CONTEXT fileObjectContext; + + fileObject = WdfRequestGetFileObject(Request); + + if (fileObject != NULL) { + fileObjectContext = FileObjectGetContext(fileObject); + NT_ASSERT(fileObjectContext != NULL); + + if (IsReadRequest && fileObjectContext->EnforceStreamingRead) + { + useStreaming = TRUE; + } + + if (!IsReadRequest && fileObjectContext->EnforceStreamingWrite) + { + useStreaming = TRUE; + } + } + } + + return useStreaming; +} + + +NTSTATUS +RequestValidateReadWrite( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters + ) +/*++ + +Routine Description: + + Validate Read/Write request + +Arguments: + + DeviceExtension - device context + Request - request to be handled + RequestParameters - request parameter + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PCDROM_DATA cdData = &(DeviceExtension->DeviceAdditionalData); + + BOOLEAN isValid = TRUE; + LONGLONG startingOffset = 0; + size_t transferByteCount = 0; + PIRP irp = NULL; + PIO_STACK_LOCATION currentStack = NULL; + + irp = WdfRequestWdmGetIrp(Request); + currentStack = IoGetCurrentIrpStackLocation(irp); + + if (TEST_FLAG(DeviceExtension->DeviceObject->Flags, DO_VERIFY_VOLUME) && + (currentStack->MinorFunction != CDROM_VOLUME_VERIFY_CHECKED) && + !TEST_FLAG(currentStack->Flags, SL_OVERRIDE_VERIFY_VOLUME)) + { + // DO_VERIFY_VOLUME is set for the device object, + // but this request is not itself a verify request. + // So fail this request. + + //set the status for volume verification. + status = STATUS_VERIFY_REQUIRED; + } + + if (NT_SUCCESS(status)) + { + if (PLAY_ACTIVE(DeviceExtension)) + { + status = STATUS_DEVICE_BUSY; + } + } + + if (NT_SUCCESS(status)) + { + // If the device is in exclusive mode, check whether the request is from + // the handle that locked the device. + if (EXCLUSIVE_MODE(cdData) && !EXCLUSIVE_OWNER(cdData, WdfRequestGetFileObject(Request))) + { + // This request is not from the owner. We can't let the operation go. + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, "RequestValidateReadWrite: Access Denied! Device in exclusive mode.\n")); + + status = STATUS_ACCESS_DENIED; + } + } + + // Validate the request alignment. + if (NT_SUCCESS(status)) + { + if (RequestParameters.Type == WdfRequestTypeRead) + { + startingOffset = RequestParameters.Parameters.Read.DeviceOffset; + transferByteCount = RequestParameters.Parameters.Read.Length; + } + else + { + startingOffset = RequestParameters.Parameters.Write.DeviceOffset; + transferByteCount = RequestParameters.Parameters.Write.Length; + } + + if (!DeviceExtension->DiskGeometry.BytesPerSector) + { + DeviceExtension->DiskGeometry.BytesPerSector = 2048; + } + + if (!DeviceExtension->SectorShift) + { + DeviceExtension->SectorShift = 11; + } + + // Perform some basic validation up front + if (TEST_FLAG(startingOffset, DeviceExtension->DiskGeometry.BytesPerSector - 1) || + TEST_FLAG(transferByteCount, DeviceExtension->DiskGeometry.BytesPerSector - 1)) + { + status = STATUS_INVALID_DEVICE_REQUEST; + } + } + + // validate the request against the current mmc schema + if (NT_SUCCESS(status)) + { + FEATURE_NUMBER schema = cdData->Mmc.ValidationSchema; + + // We validate read requests according to the RandomWritable schema, except in the + // case of IncrementalStreamingWritable, wherein the drive is responsible for all + // of the verification + if (RequestParameters.Type == WdfRequestTypeRead) + { + if (!cdData->Mmc.WriteAllowed) + { + // standard legacy validation of read irps + // if writing is not allowed on the media + schema = FeatureRandomWritable; + } + else if (schema != FeatureIncrementalStreamingWritable) + { + // standard legacy validation of read irps + // if not using streaming writes on writable media + schema = FeatureRandomWritable; + } + } + + // Fail write requests to read-only media + if ((RequestParameters.Type == WdfRequestTypeWrite) && + !(cdData->Mmc.WriteAllowed)) + { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, "RequestValidateReadWrite: Write request to read-only media\n")); + isValid = FALSE; + } + + if (isValid) + { + switch (schema) + { + case FeatureDefectManagement: + case FeatureRandomWritable: + // Ensure that the request is within bounds for ROM drives. + // Writer drives do not need to have bounds as outbounds request should not damage the drive. + if(!cdData->Mmc.IsWriter) + { + if ((startingOffset >= DeviceExtension->PartitionLength.QuadPart) || + startingOffset < 0) + { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, "RequestValidateReadWrite: Request is out of bounds\n")); + isValid = FALSE; + + } + else + { + ULONGLONG bytesRemaining = DeviceExtension->PartitionLength.QuadPart - startingOffset; + + if ((ULONGLONG)transferByteCount > bytesRemaining) + { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, "RequestValidateReadWrite: Request is out of bounds\n")); + isValid = FALSE; + } + } + } + break; + + case FeatureRigidRestrictedOverwrite: + // Ensure that the number of blocks is a multiple of the blocking size + if (((transferByteCount >> DeviceExtension->SectorShift) % cdData->Mmc.Blocking) != 0) + { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, + "RequestValidateReadWrite: Number of blocks is not a multiple of the blocking size (%x)\n", + cdData->Mmc.Blocking)); + + isValid = FALSE; + } + // Fall through + case FeatureRestrictedOverwrite: + // Ensure that the request begins on a blocking boundary + if ((Int64ShrlMod32(startingOffset, DeviceExtension->SectorShift) % cdData->Mmc.Blocking) != 0) + { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, + "RequestValidateReadWrite: Starting block is not a multiple of the blocking size (%x)\n", + cdData->Mmc.Blocking)); + + isValid = FALSE; + } + break; + + case FeatureIncrementalStreamingWritable: + // Let the drive handle the verification + break; + + default: + // Unknown schema. Fail the request + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, + "RequestValidateReadWrite: Unknown validation schema (%x)\n", + schema)); + + isValid = FALSE; + break; + } //end of switch (schema) + } // end of if (isValid) + + if (!isValid) + { + status = STATUS_INVALID_DEVICE_REQUEST; + } + } // end of mmc schema validation + + // validate that the Real-Time Streaming requests meet device capabilties + if (NT_SUCCESS(status)) + { + // We do not check for FDO_HACK_NO_STREAMING in DeviceExtension->PrivateFdoData->HackFlags here, + // because we're going to hide device failures related to streaming reads/writes from the sender + // of the request. FDO_HACK_NO_STREAMING is going to be taken into account later during actual + // processing of the request. + if (RequestIsRealtimeStreaming(Request, RequestParameters.Type == WdfRequestTypeRead)) + { + if (RequestParameters.Type == WdfRequestTypeRead && !cdData->Mmc.StreamingReadSupported) + { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, + "RequestValidateReadWrite: Streaming reads are not supported.\n")); + + status = STATUS_INVALID_DEVICE_REQUEST; + } + if (RequestParameters.Type == WdfRequestTypeWrite && !cdData->Mmc.StreamingWriteSupported) + { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, + "RequestValidateReadWrite: Streaming writes are not supported.\n")); + + status = STATUS_INVALID_DEVICE_REQUEST; + } + } + } + + return status; +} + +NTSTATUS +RequestHandleReadWrite( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters + ) +/*++ + +Routine Description: + + Handle a read/write request + +Arguments: + + DeviceExtension - device context + Request - request to be handled + RequestParameters - request parameter + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PCDROM_DATA cdData = &(DeviceExtension->DeviceAdditionalData); + + size_t transferByteCount = 0; + PIRP irp = NULL; + PIO_STACK_LOCATION currentStack = NULL; + + PUCHAR dataBuffer; + + + irp = WdfRequestWdmGetIrp(Request); + currentStack = IoGetCurrentIrpStackLocation(irp); + dataBuffer = MmGetMdlVirtualAddress(irp->MdlAddress); + + if (NT_SUCCESS(status)) + { + if (RequestParameters.Type == WdfRequestTypeRead) + { + transferByteCount = RequestParameters.Parameters.Read.Length; + } + else + { + transferByteCount = RequestParameters.Parameters.Write.Length; + } + + if (transferByteCount == 0) + { + // Several parts of the code turn 0 into 0xffffffff, + // so don't process a zero-length request any further. + status = STATUS_SUCCESS; + RequestCompletion(DeviceExtension, Request, status, 0); + return status; + } + + // Add partition byte offset to make starting byte relative to + // beginning of disk. + currentStack->Parameters.Read.ByteOffset.QuadPart += (DeviceExtension->StartingOffset.QuadPart); + + //not very necessary as the starting offset for CD/DVD device is always 0. + if (RequestParameters.Type == WdfRequestTypeRead) + { + RequestParameters.Parameters.Read.DeviceOffset = currentStack->Parameters.Read.ByteOffset.QuadPart; + } + else + { + RequestParameters.Parameters.Write.DeviceOffset = currentStack->Parameters.Write.ByteOffset.QuadPart; + } + } + + if (NT_SUCCESS(status)) + { + ULONG entireXferLen = currentStack->Parameters.Read.Length; + ULONG maxLength = 0; + ULONG packetsCount = 0; + + PCDROM_SCRATCH_READ_WRITE_CONTEXT readWriteContext; + PCDROM_REQUEST_CONTEXT requestContext; + PCDROM_REQUEST_CONTEXT originalRequestContext; + + // get the count of packets we need to send. + if ((((ULONG_PTR)dataBuffer) & (PAGE_SIZE-1)) == 0) + { + maxLength = cdData->MaxPageAlignedTransferBytes; + } + else + { + maxLength = cdData->MaxUnalignedTransferBytes; + } + + packetsCount = entireXferLen / maxLength; + + if (entireXferLen % maxLength != 0) + { + packetsCount++; + } + + originalRequestContext = RequestGetContext(Request); + + + ScratchBuffer_BeginUse(DeviceExtension); + + readWriteContext = &DeviceExtension->ScratchContext.ScratchReadWriteContext; + requestContext = RequestGetContext(DeviceExtension->ScratchContext.ScratchRequest); + + readWriteContext->PacketsCount = packetsCount; + readWriteContext->EntireXferLen = entireXferLen; + readWriteContext->MaxLength = maxLength; + readWriteContext->StartingOffset = currentStack->Parameters.Read.ByteOffset; + readWriteContext->DataBuffer = dataBuffer; + readWriteContext->TransferedBytes = 0; + readWriteContext->IsRead = (RequestParameters.Type == WdfRequestTypeRead); + + requestContext->OriginalRequest = Request; + requestContext->DeviceExtension = DeviceExtension; + + // + // Setup the READ/WRITE fields in the original request which is what + // we use to properly synchronize cancellation logic between the + // cancel callback and the timer routine. + // + + originalRequestContext->ReadWriteIsCompleted = FALSE; + originalRequestContext->ReadWriteRetryInitialized = FALSE; + originalRequestContext->DeviceExtension = DeviceExtension; + + status = ScratchBuffer_PerformNextReadWrite(DeviceExtension, TRUE); + + // We do not call ScratchBuffer_EndUse here, because we're not releasing the scratch SRB. + // It will be released in the completion routine. + } + + return status; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +RequestHandleLoadEjectMedia( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + Handle request of IOCTL_STORAGE_EJECT_MEDIA + IOCTL_STORAGE_LOAD_MEDIA + IOCTL_STORAGE_LOAD_MEDIA2 + +Arguments: + + DeviceExtension - device context + Request - request to be handled + RequestParameters - request parameter + DataLength - transferred data length + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PZERO_POWER_ODD_INFO zpoddInfo = DeviceExtension->ZeroPowerODDInfo; + + PAGED_CODE (); + + *DataLength = 0; + + if (NT_SUCCESS(status)) + { + // Synchronize with ejection control and ejection cleanup code as + // well as other eject/load requests. + WdfWaitLockAcquire(DeviceExtension->EjectSynchronizationLock, NULL); + + if(DeviceExtension->ProtectedLockCount != 0) + { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, "RequestHandleLoadEjectMedia: call to eject protected locked " + "device - failure\n")); + status = STATUS_DEVICE_BUSY; + } + + if (NT_SUCCESS(status)) + { + SCSI_REQUEST_BLOCK srb; + PCDB cdb = (PCDB)srb.Cdb; + + RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK)); + + srb.CdbLength = 6; + + cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT; + cdb->START_STOP.LoadEject = 1; + + if(RequestParameters.Parameters.DeviceIoControl.IoControlCode == IOCTL_STORAGE_EJECT_MEDIA) + { + cdb->START_STOP.Start = 0; + + // We are sending down a soft eject, and in this case we should take an active ref + // if the command succeeds. + if ((zpoddInfo != NULL) && + (zpoddInfo->LoadingMechanism == LOADING_MECHANISM_TRAY) && + (zpoddInfo->Load == 0)) // Drawer + { + zpoddInfo->MonitorStartStopUnit = TRUE; + } + } + else + { + cdb->START_STOP.Start = 1; + } + + status = DeviceSendSrbSynchronously(DeviceExtension->Device, + &srb, + NULL, + 0, + FALSE, + Request); + + if (zpoddInfo != NULL) + { + zpoddInfo->MonitorStartStopUnit = FALSE; + } + } + + WdfWaitLockRelease(DeviceExtension->EjectSynchronizationLock); + } + + return status; +} + + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +RequestHandleReserveRelease( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + Handle request of IOCTL_STORAGE_RESERVE + IOCTL_STORAGE_RELEASE + +Arguments: + + DeviceExtension - device context + Request - request to be handled + RequestParameters - request parameter + DataLength - transferred data length + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PSCSI_REQUEST_BLOCK srb = NULL; + PCDB cdb = NULL; + ULONG ioctlCode = 0; + + PAGED_CODE (); + + *DataLength = 0; + + srb = ExAllocatePoolWithTag(NonPagedPoolNx, + sizeof(SCSI_REQUEST_BLOCK) + + (sizeof(ULONG_PTR) * 2), + CDROM_TAG_SRB); + + if (srb == NULL) + { + status = STATUS_INSUFFICIENT_RESOURCES; + } + + if (NT_SUCCESS(status)) + { + ioctlCode = RequestParameters.Parameters.DeviceIoControl.IoControlCode; + cdb = (PCDB)srb->Cdb; + RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK)); + + if (TEST_FLAG(DeviceExtension->PrivateFdoData->HackFlags, FDO_HACK_NO_RESERVE6)) + { + srb->CdbLength = 10; + cdb->CDB10.OperationCode = (ioctlCode == IOCTL_STORAGE_RESERVE) ? SCSIOP_RESERVE_UNIT10 : SCSIOP_RELEASE_UNIT10; + } + else + { + srb->CdbLength = 6; + cdb->CDB6GENERIC.OperationCode = (ioctlCode == IOCTL_STORAGE_RESERVE) ? SCSIOP_RESERVE_UNIT : SCSIOP_RELEASE_UNIT; + } + + // Set timeout value. + srb->TimeOutValue = DeviceExtension->TimeOutValue; + + // Send reserves as tagged requests. + if (ioctlCode == IOCTL_STORAGE_RESERVE) + { + SET_FLAG(srb->SrbFlags, SRB_FLAGS_QUEUE_ACTION_ENABLE); + srb->QueueAction = SRB_SIMPLE_TAG_REQUEST; + } + + status = DeviceSendSrbSynchronously(DeviceExtension->Device, + srb, + NULL, + 0, + FALSE, + Request); + // no data transfer. + *DataLength = 0; + + FREE_POOL(srb); + } + + return status; +} // end RequestHandleReserveRelease() + +__inline +BOOLEAN +ValidPersistentReserveScope( + UCHAR Scope) +{ + switch (Scope) { + case RESERVATION_SCOPE_LU: + case RESERVATION_SCOPE_ELEMENT: + + return TRUE; + + default: + + return FALSE; + } +} + +__inline +BOOLEAN +ValidPersistentReserveType( + UCHAR Type) +{ + switch (Type) { + case RESERVATION_TYPE_WRITE_EXCLUSIVE: + case RESERVATION_TYPE_EXCLUSIVE: + case RESERVATION_TYPE_WRITE_EXCLUSIVE_REGISTRANTS: + case RESERVATION_TYPE_EXCLUSIVE_REGISTRANTS: + + return TRUE; + + default: + + return FALSE; + } +} + +NTSTATUS +RequestValidatePersistentReserve( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + Validate request of IOCTL_STORAGE_PERSISTENT_RESERVE_IN + IOCTL_STORAGE_PERSISTENT_RESERVE_OUT + +Arguments: + + DeviceExtension - device context + Request - request to be handled + RequestParameters - request parameter + DataLength - transferred data length + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + ULONG ioctlCode = RequestParameters.Parameters.DeviceIoControl.IoControlCode; + + PPERSISTENT_RESERVE_COMMAND reserveCommand = NULL; + + *DataLength = 0; + + status = WdfRequestRetrieveInputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.InputBufferLength, + (PVOID*)&reserveCommand, + NULL); + if (NT_SUCCESS(status)) + { + if ((RequestParameters.Parameters.DeviceIoControl.InputBufferLength < sizeof(PERSISTENT_RESERVE_COMMAND)) || + (reserveCommand->Size < sizeof(PERSISTENT_RESERVE_COMMAND))) + { + *DataLength = 0; + status = STATUS_INFO_LENGTH_MISMATCH; + } + else if ((ULONG_PTR)reserveCommand & DeviceExtension->AdapterDescriptor->AlignmentMask) + { + // Check buffer alignment. Only an issue if another kernel mode component + // (not the I/O manager) allocates the buffer. + *DataLength = 0; + status = STATUS_INVALID_USER_BUFFER; + } + } + + if (NT_SUCCESS(status)) + { + if (ioctlCode == IOCTL_STORAGE_PERSISTENT_RESERVE_IN) + { + if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < reserveCommand->PR_IN.AllocationLength) + { + *DataLength = 0; + status = STATUS_INVALID_PARAMETER; + } + else + { + switch (reserveCommand->PR_IN.ServiceAction) + { + case RESERVATION_ACTION_READ_KEYS: + if (reserveCommand->PR_IN.AllocationLength < sizeof(PRI_REGISTRATION_LIST)) + { + *DataLength = 0; + status = STATUS_INVALID_PARAMETER; + } + break; + + case RESERVATION_ACTION_READ_RESERVATIONS: + if (reserveCommand->PR_IN.AllocationLength < sizeof(PRI_RESERVATION_LIST)) + { + *DataLength = 0; + status = STATUS_INVALID_PARAMETER; + } + break; + + default: + *DataLength = 0; + status = STATUS_INVALID_PARAMETER; + break; + } + } + } + else // case of IOCTL_STORAGE_PERSISTENT_RESERVE_OUT + { + // Verify ServiceAction, Scope, and Type + switch (reserveCommand->PR_OUT.ServiceAction) + { + case RESERVATION_ACTION_REGISTER: + case RESERVATION_ACTION_REGISTER_IGNORE_EXISTING: + case RESERVATION_ACTION_CLEAR: + // Scope and type ignored. + break; + + case RESERVATION_ACTION_RESERVE: + case RESERVATION_ACTION_RELEASE: + case RESERVATION_ACTION_PREEMPT: + case RESERVATION_ACTION_PREEMPT_ABORT: + if (!ValidPersistentReserveScope(reserveCommand->PR_OUT.Scope) || + !ValidPersistentReserveType(reserveCommand->PR_OUT.Type)) + { + *DataLength = 0; + status = STATUS_INVALID_PARAMETER; + } + break; + + default: + *DataLength = 0; + status = STATUS_INVALID_PARAMETER; + break; + } + + // Check input buffer for PR Out. + // Caller must include the PR parameter list. + if (NT_SUCCESS(status)) + { + if ((RequestParameters.Parameters.DeviceIoControl.InputBufferLength < + (sizeof(PERSISTENT_RESERVE_COMMAND) + sizeof(PRO_PARAMETER_LIST))) || + (reserveCommand->Size < RequestParameters.Parameters.DeviceIoControl.InputBufferLength)) + { + *DataLength = 0; + status = STATUS_INVALID_PARAMETER; + } + } + } // end of validation for IOCTL_STORAGE_PERSISTENT_RESERVE_OUT + } + + return status; +} // end RequestValidatePersistentReserve() + + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +RequestHandlePersistentReserve( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + Handle request of IOCTL_STORAGE_PERSISTENT_RESERVE_IN + IOCTL_STORAGE_PERSISTENT_RESERVE_OUT + +Arguments: + + DeviceExtension - device context + Request - request to be handled + RequestParameters - request parameter + DataLength - transferred data length + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + ULONG ioctlCode = RequestParameters.Parameters.DeviceIoControl.IoControlCode; + PSCSI_REQUEST_BLOCK srb = NULL; + PCDB cdb = NULL; + BOOLEAN writeToDevice; + + PPERSISTENT_RESERVE_COMMAND reserveCommand = NULL; + + PAGED_CODE (); + + *DataLength = 0; + + status = WdfRequestRetrieveInputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.InputBufferLength, + (PVOID*)&reserveCommand, + NULL); + if (NT_SUCCESS(status)) + { + srb = ExAllocatePoolWithTag(NonPagedPoolNx, + sizeof(SCSI_REQUEST_BLOCK) + + (sizeof(ULONG_PTR) * 2), + CDROM_TAG_SRB); + + if (srb == NULL) + { + status = STATUS_INSUFFICIENT_RESOURCES; + } + else + { + cdb = (PCDB)srb->Cdb; + RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK)); + } + } + + if (NT_SUCCESS(status)) + { + size_t dataBufLen = 0; + + // Fill in the CDB. + if (ioctlCode == IOCTL_STORAGE_PERSISTENT_RESERVE_IN) + { + cdb->PERSISTENT_RESERVE_IN.OperationCode = SCSIOP_PERSISTENT_RESERVE_IN; + cdb->PERSISTENT_RESERVE_IN.ServiceAction = reserveCommand->PR_IN.ServiceAction; + + REVERSE_BYTES_SHORT(&(cdb->PERSISTENT_RESERVE_IN.AllocationLength), + &(reserveCommand->PR_IN.AllocationLength)); + + dataBufLen = RequestParameters.Parameters.DeviceIoControl.OutputBufferLength; + writeToDevice = FALSE; + } + else + { + cdb->PERSISTENT_RESERVE_OUT.OperationCode = SCSIOP_PERSISTENT_RESERVE_OUT; + cdb->PERSISTENT_RESERVE_OUT.ServiceAction = reserveCommand->PR_OUT.ServiceAction; + cdb->PERSISTENT_RESERVE_OUT.Scope = reserveCommand->PR_OUT.Scope; + cdb->PERSISTENT_RESERVE_OUT.Type = reserveCommand->PR_OUT.Type; + + cdb->PERSISTENT_RESERVE_OUT.ParameterListLength[1] = (UCHAR)sizeof(PRO_PARAMETER_LIST); + + // Move the parameter list to the beginning of the data buffer (so it is aligned + // correctly and that the MDL describes it correctly). + RtlMoveMemory(reserveCommand, + reserveCommand->PR_OUT.ParameterList, + sizeof(PRO_PARAMETER_LIST)); + + dataBufLen = sizeof(PRO_PARAMETER_LIST); + writeToDevice = TRUE; + } + + srb->CdbLength = 10; + srb->QueueAction = SRB_SIMPLE_TAG_REQUEST; + + status = DeviceSendSrbSynchronously(DeviceExtension->Device, + srb, + reserveCommand, + (ULONG) dataBufLen, + writeToDevice, + Request); + + FREE_POOL(srb); + } + + return status; +} + +#if (NTDDI_VERSION >= NTDDI_WIN8) +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +RequestHandleAreVolumesReady( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + Handle request of IOCTL_DISK_ARE_VOLUMES_READY + +Arguments: + + DeviceExtension - device context + Request - request to be handled + RequestParameters - request parameter + DataLength - transferred data length + +Return Value: + + NTSTATUS + +--*/ +{ + BOOLEAN completeRequest = TRUE; + NTSTATUS status = STATUS_SUCCESS; + + UNREFERENCED_PARAMETER(RequestParameters); + + *DataLength = 0; + + if (DeviceExtension->IsVolumeOnlinePending == FALSE) + { + status = STATUS_SUCCESS; + goto Cleanup; + } + + // + // Add to the volume ready queue. No worries about request cancellation, + // since KMDF will automatically handle that while request is in queue. + // + status = WdfRequestForwardToIoQueue(Request, + DeviceExtension->ManualVolumeReadyQueue + ); + + if(!NT_SUCCESS(status)) + { + goto Cleanup; + } + + status = STATUS_PENDING; + completeRequest = FALSE; + +Cleanup: + + if (completeRequest) + { + RequestCompletion(DeviceExtension, Request, status, 0); + } + + return status; +} + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +RequestHandleVolumeOnline( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + Handle request of IOCTL_VOLUME_ONLINE / IOCTL_VOLUME_POST_ONLINE + +Arguments: + + DeviceExtension - device context + Request - request to be handled + RequestParameters - request parameter + DataLength - transferred data length + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + WDFREQUEST request; + PIRP irp = NULL; + PIO_STACK_LOCATION nextStack = NULL; + + UNREFERENCED_PARAMETER(RequestParameters); + + *DataLength = 0; + + DeviceExtension->IsVolumeOnlinePending = FALSE; + + // Complete all parked volume ready requests. + for (;;) + { + status = WdfIoQueueRetrieveNextRequest(DeviceExtension->ManualVolumeReadyQueue, + &request); + + if (!NT_SUCCESS(status)) + { + break; + } + + RequestCompletion(DeviceExtension, request, STATUS_SUCCESS, 0); + } + + // Change the IOCTL code to IOCTL_DISK_VOLUMES_ARE_READY, and forward the request down, + // so that if the underlying port driver will also know that volume is ready. + WdfRequestFormatRequestUsingCurrentType(Request); + irp = WdfRequestWdmGetIrp(Request); + nextStack = IoGetNextIrpStackLocation(irp); + + irp->AssociatedIrp.SystemBuffer = &DeviceExtension->DeviceNumber; + nextStack->Parameters.DeviceIoControl.OutputBufferLength = 0; + nextStack->Parameters.DeviceIoControl.InputBufferLength = sizeof (DeviceExtension->DeviceNumber); + nextStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_DISK_VOLUMES_ARE_READY; + + // Send the request straight down (synchronously). + RequestSend(DeviceExtension, + Request, + DeviceExtension->IoTarget, + WDF_REQUEST_SEND_OPTION_SYNCHRONOUS, + NULL); + + return STATUS_SUCCESS; +} +#endif + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +DeviceHandleRawRead( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + Handle request of IOCTL_CDROM_RAW_READ + +Arguments: + + DeviceExtension - device context + Request - request to be handled + RequestParameters - request parameter + DataLength - transferred data length + +Return Value: + + NTSTATUS + +--*/ +{ + // Determine whether the drive is currently in raw or cooked mode, + // and which command to use to read the data. + + NTSTATUS status = STATUS_SUCCESS; + PCDROM_DATA cdData = &(DeviceExtension->DeviceAdditionalData); + RAW_READ_INFO rawReadInfo = {0}; + PVOID outputVirtAddr = NULL; + ULONG startingSector; + + PIRP irp = WdfRequestWdmGetIrp(Request); + PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(irp); + + VOID* outputBuffer = NULL; + + PAGED_CODE (); + + *DataLength = 0; + + if (TEST_FLAG(DeviceExtension->DeviceObject->Flags, DO_VERIFY_VOLUME) && + (currentIrpStack->MinorFunction != CDROM_VOLUME_VERIFY_CHECKED) && + !TEST_FLAG(currentIrpStack->Flags, SL_OVERRIDE_VERIFY_VOLUME)) + { + // DO_VERIFY_VOLUME is set for the device object, + // but this request is not itself a verify request. + // So fail this request. + (VOID) MediaReadCapacity(DeviceExtension->Device); + + *DataLength = 0; + //set the status for volume verification. + status = STATUS_VERIFY_REQUIRED; + } + + if (NT_SUCCESS(status)) + { + // Since this ioctl is METHOD_OUT_DIRECT, we need to copy away + // the input buffer before interpreting it. This prevents a + // malicious app from messing with the input buffer while we + // are interpreting it. This is done in dispacth. + // + // Here, we are going to get the input buffer out of saved place. + rawReadInfo = *(PRAW_READ_INFO)currentIrpStack->Parameters.DeviceIoControl.Type3InputBuffer; + + if (currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength > 0) + { + // Make sure that any user buffer that we pass down to + // the hardware is properly aligned + NT_ASSERT(irp->MdlAddress); + outputVirtAddr = MmGetMdlVirtualAddress(irp->MdlAddress); + if ((ULONG_PTR)outputVirtAddr & DeviceExtension->AdapterDescriptor->AlignmentMask) + { + NT_ASSERT(!((ULONG_PTR)outputVirtAddr & DeviceExtension->AdapterDescriptor->AlignmentMask)); + *DataLength = 0; + status = STATUS_INVALID_PARAMETER; + } + } + else + { + status = STATUS_INVALID_PARAMETER; + } + } + + if (NT_SUCCESS(status)) + { + status = WdfRequestRetrieveOutputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, + &outputBuffer, + NULL); + } + + if (NT_SUCCESS(status)) + { + switch (rawReadInfo.TrackMode) + { + case CDDA: + case YellowMode2: + case XAForm2: + // no check needed. + break; + + case RawWithC2AndSubCode: + if (!cdData->Mmc.ReadCdC2Pointers || !cdData->Mmc.ReadCdSubCode) + { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, + "Request to read C2 & Subcode rejected. " + "Is C2 supported: %d Is Subcode supported: %d\n", + cdData->Mmc.ReadCdC2Pointers, + cdData->Mmc.ReadCdSubCode + )); + *DataLength = 0; + status = STATUS_INVALID_DEVICE_REQUEST; + } + break; + case RawWithC2: + if (!cdData->Mmc.ReadCdC2Pointers) + { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, + "Request to read C2 rejected because drive does not " + "report support for C2 pointers\n" + )); + *DataLength = 0; + status = STATUS_INVALID_DEVICE_REQUEST; + } + break; + case RawWithSubCode: + + if (!cdData->Mmc.ReadCdSubCode) + { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, + "Request to read subcode rejected because drive does " + "not report support for reading the subcode data\n" + )); + *DataLength = 0; + status = STATUS_INVALID_DEVICE_REQUEST; + } + break; + + default: + *DataLength = 0; + status = STATUS_INVALID_DEVICE_REQUEST; + break; + } + } + + if (NT_SUCCESS(status)) + { + PSCSI_REQUEST_BLOCK srb = DeviceExtension->ScratchContext.ScratchSrb; + PCDB cdb = (PCDB)(srb->Cdb); + + size_t transferByteCount; + BOOLEAN shouldRetry = TRUE; + ULONG timesAlreadyRetried = 0; + LONGLONG retryIn100nsUnits = 0; + + transferByteCount = RequestParameters.Parameters.DeviceIoControl.OutputBufferLength; + + ScratchBuffer_BeginUse(DeviceExtension); + + while (shouldRetry) + { + // Setup cdb depending upon the sector type we want. + switch (rawReadInfo.TrackMode) + { + case CDDA: + transferByteCount = rawReadInfo.SectorCount * RAW_SECTOR_SIZE; + cdb->READ_CD.ExpectedSectorType = CD_DA_SECTOR; + cdb->READ_CD.IncludeUserData = 1; + cdb->READ_CD.HeaderCode = 3; + cdb->READ_CD.IncludeSyncData = 1; + break; + + case YellowMode2: + transferByteCount = rawReadInfo.SectorCount * RAW_SECTOR_SIZE; + cdb->READ_CD.ExpectedSectorType = YELLOW_MODE2_SECTOR; + cdb->READ_CD.IncludeUserData = 1; + cdb->READ_CD.HeaderCode = 1; + cdb->READ_CD.IncludeSyncData = 1; + break; + + case XAForm2: + transferByteCount = rawReadInfo.SectorCount * RAW_SECTOR_SIZE; + cdb->READ_CD.ExpectedSectorType = FORM2_MODE2_SECTOR; + cdb->READ_CD.IncludeUserData = 1; + cdb->READ_CD.HeaderCode = 3; + cdb->READ_CD.IncludeSyncData = 1; + break; + + case RawWithC2AndSubCode: + transferByteCount = rawReadInfo.SectorCount * CD_RAW_SECTOR_WITH_C2_AND_SUBCODE_SIZE; + cdb->READ_CD.ExpectedSectorType = 0; // Any sector type + cdb->READ_CD.IncludeUserData = 1; + cdb->READ_CD.HeaderCode = 3; // Header and subheader returned + cdb->READ_CD.IncludeSyncData = 1; + cdb->READ_CD.ErrorFlags = 2; // C2 and block error + cdb->READ_CD.SubChannelSelection = 1; // raw subchannel data + break; + + case RawWithC2: + transferByteCount = rawReadInfo.SectorCount * CD_RAW_SECTOR_WITH_C2_SIZE; + cdb->READ_CD.ExpectedSectorType = 0; // Any sector type + cdb->READ_CD.IncludeUserData = 1; + cdb->READ_CD.HeaderCode = 3; // Header and subheader returned + cdb->READ_CD.IncludeSyncData = 1; + cdb->READ_CD.ErrorFlags = 2; // C2 and block error + break; + + case RawWithSubCode: + transferByteCount = rawReadInfo.SectorCount * CD_RAW_SECTOR_WITH_SUBCODE_SIZE; + cdb->READ_CD.ExpectedSectorType = 0; // Any sector type + cdb->READ_CD.IncludeUserData = 1; + cdb->READ_CD.HeaderCode = 3; // Header and subheader returned + cdb->READ_CD.IncludeSyncData = 1; + cdb->READ_CD.SubChannelSelection = 1; // raw subchannel data + break; + + default: + // should already checked before coming in loop. + NT_ASSERT(FALSE); + break; + } + + ScratchBuffer_SetupSrb(DeviceExtension, Request, (ULONG)transferByteCount, TRUE); + // Restore the buffer, buffer size and MdlAddress. They got changed but we don't want to use the scratch buffer. + { + PIRP scratchIrp = WdfRequestWdmGetIrp(DeviceExtension->ScratchContext.ScratchRequest); + scratchIrp->MdlAddress = irp->MdlAddress; + srb->DataBuffer = outputVirtAddr; + srb->DataTransferLength = (ULONG)transferByteCount; + } + // Calculate starting offset. + startingSector = (ULONG)(rawReadInfo.DiskOffset.QuadPart >> DeviceExtension->SectorShift); + + // Fill in CDB fields. + srb->CdbLength = 12; + + cdb->READ_CD.OperationCode = SCSIOP_READ_CD; + cdb->READ_CD.TransferBlocks[2] = (UCHAR) (rawReadInfo.SectorCount & 0xFF); + cdb->READ_CD.TransferBlocks[1] = (UCHAR) (rawReadInfo.SectorCount >> 8 ); + cdb->READ_CD.TransferBlocks[0] = (UCHAR) (rawReadInfo.SectorCount >> 16); + + cdb->READ_CD.StartingLBA[3] = (UCHAR) (startingSector & 0xFF); + cdb->READ_CD.StartingLBA[2] = (UCHAR) ((startingSector >> 8)); + cdb->READ_CD.StartingLBA[1] = (UCHAR) ((startingSector >> 16)); + cdb->READ_CD.StartingLBA[0] = (UCHAR) ((startingSector >> 24)); + + ScratchBuffer_SendSrb(DeviceExtension, TRUE, NULL); + + if ((DeviceExtension->ScratchContext.ScratchSrb->SrbStatus == SRB_STATUS_ABORTED) && + (DeviceExtension->ScratchContext.ScratchSrb->InternalStatus == STATUS_CANCELLED)) + { + shouldRetry = FALSE; + status = STATUS_CANCELLED; + } + else + { + shouldRetry = RequestSenseInfoInterpretForScratchBuffer(DeviceExtension, + timesAlreadyRetried, + &status, + &retryIn100nsUnits); + if (shouldRetry) + { + LARGE_INTEGER t; + t.QuadPart = -retryIn100nsUnits; + timesAlreadyRetried++; + KeDelayExecutionThread(KernelMode, FALSE, &t); + // keep items clean + ScratchBuffer_ResetItems(DeviceExtension, FALSE); + } + } + } + + if (NT_SUCCESS(status)) + { + *DataLength = srb->DataTransferLength; + } + + ScratchBuffer_EndUse(DeviceExtension); + } + + return status; +} + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DeviceHandlePlayAudioMsf( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + Handle request of IOCTL_CDROM_PLAY_AUDIO_MSF + +Arguments: + + DeviceExtension - device context + Request - request to be handled + RequestParameters - request parameter + DataLength - transferred data length + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PCDROM_PLAY_AUDIO_MSF inputBuffer = NULL; + + PAGED_CODE (); + + *DataLength = 0; + + status = WdfRequestRetrieveInputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.InputBufferLength, + (PVOID*)&inputBuffer, + NULL); + + + if (NT_SUCCESS(status)) + { + ULONG transferSize = 0; + CDB cdb; + + ScratchBuffer_BeginUse(DeviceExtension); + + RtlZeroMemory(&cdb, sizeof(CDB)); + // Set up the CDB + cdb.PLAY_AUDIO_MSF.OperationCode = SCSIOP_PLAY_AUDIO_MSF; + + cdb.PLAY_AUDIO_MSF.StartingM = inputBuffer->StartingM; + cdb.PLAY_AUDIO_MSF.StartingS = inputBuffer->StartingS; + cdb.PLAY_AUDIO_MSF.StartingF = inputBuffer->StartingF; + + cdb.PLAY_AUDIO_MSF.EndingM = inputBuffer->EndingM; + cdb.PLAY_AUDIO_MSF.EndingS = inputBuffer->EndingS; + cdb.PLAY_AUDIO_MSF.EndingF = inputBuffer->EndingF; + + status = ScratchBuffer_ExecuteCdb(DeviceExtension, Request, transferSize, FALSE, &cdb, 10); + + if (NT_SUCCESS(status)) + { + PLAY_ACTIVE(DeviceExtension) = TRUE; + *DataLength = 0; + } + + // nothing to do after the command finishes. + ScratchBuffer_EndUse(DeviceExtension); + } + + return status; +} + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DeviceHandleReadQChannel( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + Handle request of IOCTL_CDROM_READ_Q_CHANNEL + +Arguments: + + DeviceExtension - device context + Request - request to be handled + RequestParameters - request parameter + DataLength - transferred data length + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PVOID inputBuffer = NULL; + PVOID outputBuffer = NULL; + + PAGED_CODE (); + + *DataLength = 0; + + status = WdfRequestRetrieveInputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.InputBufferLength, + &inputBuffer, + NULL); + + if (NT_SUCCESS(status)) + { + status = WdfRequestRetrieveOutputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, + &outputBuffer, + NULL); + } + + if (NT_SUCCESS(status)) + { + status = ReadQChannel(DeviceExtension, + Request, + inputBuffer, + RequestParameters.Parameters.DeviceIoControl.InputBufferLength, + outputBuffer, + RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, + DataLength); + } + + return status; +} + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +ReadQChannel( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_opt_ WDFREQUEST OriginalRequest, + _In_ PVOID InputBuffer, + _In_ size_t InputBufferLength, + _In_ PVOID OutputBuffer, + _In_ size_t OutputBufferLength, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + base function to handle request of IOCTL_CDROM_READ_Q_CHANNEL + +Arguments: + + DeviceExtension - device context + OriginalRequest - original request to be handled + InputBuffer - input buffer + InputBufferLength - length of input buffer + OutputBuffer - output buffer + OutputBufferLength - length of output buffer + +Return Value: + + NTSTATUS + DataLength - returned data length + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + ULONG transferByteCount = 0; + CDB cdb; + PCDROM_SUB_Q_DATA_FORMAT inputBuffer = (PCDROM_SUB_Q_DATA_FORMAT)InputBuffer; + PSUB_Q_CHANNEL_DATA userChannelData = (PSUB_Q_CHANNEL_DATA)OutputBuffer; + + PAGED_CODE (); + + UNREFERENCED_PARAMETER(InputBufferLength); + + *DataLength = 0; + + // Set size of channel data -- however, this is dependent on + // what information we are requesting (which Format) + switch( inputBuffer->Format ) + { + case IOCTL_CDROM_CURRENT_POSITION: + transferByteCount = sizeof(SUB_Q_CURRENT_POSITION); + break; + + case IOCTL_CDROM_MEDIA_CATALOG: + transferByteCount = sizeof(SUB_Q_MEDIA_CATALOG_NUMBER); + break; + + case IOCTL_CDROM_TRACK_ISRC: + transferByteCount = sizeof(SUB_Q_TRACK_ISRC); + break; + } + + ScratchBuffer_BeginUse(DeviceExtension); + + RtlZeroMemory(&cdb, sizeof(CDB)); + // Set up the CDB + // Always logical unit 0, but only use MSF addressing + // for IOCTL_CDROM_CURRENT_POSITION + if (inputBuffer->Format==IOCTL_CDROM_CURRENT_POSITION) + { + cdb.SUBCHANNEL.Msf = CDB_USE_MSF; + } + + // Return subchannel data + cdb.SUBCHANNEL.SubQ = CDB_SUBCHANNEL_BLOCK; + + // Specify format of informatin to return + cdb.SUBCHANNEL.Format = inputBuffer->Format; + + // Specify which track to access (only used by Track ISRC reads) + if (inputBuffer->Format==IOCTL_CDROM_TRACK_ISRC) + { + cdb.SUBCHANNEL.TrackNumber = inputBuffer->Track; + } + + cdb.SUBCHANNEL.AllocationLength[0] = (UCHAR) (transferByteCount >> 8); + cdb.SUBCHANNEL.AllocationLength[1] = (UCHAR) (transferByteCount & 0xFF); + cdb.SUBCHANNEL.OperationCode = SCSIOP_READ_SUB_CHANNEL; + + status = ScratchBuffer_ExecuteCdb(DeviceExtension, OriginalRequest, transferByteCount, TRUE, &cdb, 10); + + if (NT_SUCCESS(status)) + { + PSUB_Q_CHANNEL_DATA subQPtr = DeviceExtension->ScratchContext.ScratchSrb->DataBuffer; + +#if DBG + switch( inputBuffer->Format ) + { + case IOCTL_CDROM_CURRENT_POSITION: + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL,"ReadQChannel: Audio Status is %u\n", subQPtr->CurrentPosition.Header.AudioStatus )); + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL,"ReadQChannel: ADR = 0x%x\n", subQPtr->CurrentPosition.ADR )); + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL,"ReadQChannel: Control = 0x%x\n", subQPtr->CurrentPosition.Control )); + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL,"ReadQChannel: Track = %u\n", subQPtr->CurrentPosition.TrackNumber )); + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL,"ReadQChannel: Index = %u\n", subQPtr->CurrentPosition.IndexNumber )); + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL,"ReadQChannel: Absolute Address = %x\n", *((PULONG)subQPtr->CurrentPosition.AbsoluteAddress) )); + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL,"ReadQChannel: Relative Address = %x\n", *((PULONG)subQPtr->CurrentPosition.TrackRelativeAddress) )); + break; + + case IOCTL_CDROM_MEDIA_CATALOG: + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL,"ReadQChannel: Audio Status is %u\n", subQPtr->MediaCatalog.Header.AudioStatus )); + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL,"ReadQChannel: Mcval is %u\n", subQPtr->MediaCatalog.Mcval )); + break; + + case IOCTL_CDROM_TRACK_ISRC: + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL,"ReadQChannel: Audio Status is %u\n", subQPtr->TrackIsrc.Header.AudioStatus )); + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL,"ReadQChannel: Tcval is %u\n", subQPtr->TrackIsrc.Tcval )); + break; + } +#endif + + // Update the play active status. + if (subQPtr->CurrentPosition.Header.AudioStatus == AUDIO_STATUS_IN_PROGRESS) + { + PLAY_ACTIVE(DeviceExtension) = TRUE; + } + else + { + PLAY_ACTIVE(DeviceExtension) = FALSE; + } + + // Check if output buffer is large enough to contain + // the data. + if (OutputBufferLength < DeviceExtension->ScratchContext.ScratchSrb->DataTransferLength) + { + DeviceExtension->ScratchContext.ScratchSrb->DataTransferLength = (ULONG)OutputBufferLength; + } + + // Copy our buffer into users. + RtlMoveMemory(userChannelData, + subQPtr, + DeviceExtension->ScratchContext.ScratchSrb->DataTransferLength); + + *DataLength = DeviceExtension->ScratchContext.ScratchSrb->DataTransferLength; + } + + // nothing to do after the command finishes. + ScratchBuffer_EndUse(DeviceExtension); + + return status; +} + + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DeviceHandlePauseAudio( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + Handle request of IOCTL_CDROM_PAUSE_AUDIO + +Arguments: + + DeviceExtension - device context + Request - request to be handled + DataLength - transferred data length + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + + PAGED_CODE (); + + *DataLength = 0; + + if (NT_SUCCESS(status)) + { + ULONG transferSize = 0; + CDB cdb; + + ScratchBuffer_BeginUse(DeviceExtension); + + RtlZeroMemory(&cdb, sizeof(CDB)); + // Set up the CDB + cdb.PAUSE_RESUME.OperationCode = SCSIOP_PAUSE_RESUME; + cdb.PAUSE_RESUME.Action = CDB_AUDIO_PAUSE; + + status = ScratchBuffer_ExecuteCdb(DeviceExtension, Request, transferSize, FALSE, &cdb, 10); + + if (NT_SUCCESS(status)) + { + PLAY_ACTIVE(DeviceExtension) = FALSE; + *DataLength = 0; + } + + // nothing to do after the command finishes. + ScratchBuffer_EndUse(DeviceExtension); + } + + return status; +} + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DeviceHandleResumeAudio( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + Handle request of IOCTL_CDROM_RESUME_AUDIO + +Arguments: + + DeviceExtension - device context + Request - request to be handled + DataLength - transferred data length + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + + PAGED_CODE (); + + *DataLength = 0; + + if (NT_SUCCESS(status)) + { + ULONG transferSize = 0; + CDB cdb; + + ScratchBuffer_BeginUse(DeviceExtension); + + RtlZeroMemory(&cdb, sizeof(CDB)); + // Set up the CDB + cdb.PAUSE_RESUME.OperationCode = SCSIOP_PAUSE_RESUME; + cdb.PAUSE_RESUME.Action = CDB_AUDIO_RESUME; + + status = ScratchBuffer_ExecuteCdb(DeviceExtension, Request, transferSize, FALSE, &cdb, 10); + + if (NT_SUCCESS(status)) + { + PLAY_ACTIVE(DeviceExtension) = TRUE; //not in original code. But we should set it. + *DataLength = 0; + } + + // nothing to do after the command finishes. + ScratchBuffer_EndUse(DeviceExtension); + } + + return status; +} + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DeviceHandleSeekAudioMsf( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + Handle request of IOCTL_CDROM_SEEK_AUDIO_MSF + +Arguments: + + DeviceExtension - device context + Request - request to be handled + RequestParameters - request parameter + DataLength - transferred data length + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PCDROM_SEEK_AUDIO_MSF inputBuffer = NULL; + + PAGED_CODE (); + + *DataLength = 0; + + status = WdfRequestRetrieveInputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.InputBufferLength, + (PVOID*)&inputBuffer, + NULL); + + if (NT_SUCCESS(status)) + { + ULONG transferSize = 0; + CDB cdb; + ULONG logicalBlockAddress; + + logicalBlockAddress = MSF_TO_LBA(inputBuffer->M, inputBuffer->S, inputBuffer->F); + + ScratchBuffer_BeginUse(DeviceExtension); + + RtlZeroMemory(&cdb, sizeof(CDB)); + // Set up the CDB + cdb.SEEK.OperationCode = SCSIOP_SEEK; + cdb.SEEK.LogicalBlockAddress[0] = ((PFOUR_BYTE)&logicalBlockAddress)->Byte3; + cdb.SEEK.LogicalBlockAddress[1] = ((PFOUR_BYTE)&logicalBlockAddress)->Byte2; + cdb.SEEK.LogicalBlockAddress[2] = ((PFOUR_BYTE)&logicalBlockAddress)->Byte1; + cdb.SEEK.LogicalBlockAddress[3] = ((PFOUR_BYTE)&logicalBlockAddress)->Byte0; + + status = ScratchBuffer_ExecuteCdb(DeviceExtension, Request, transferSize, FALSE, &cdb, 10); + + if (NT_SUCCESS(status)) + { + *DataLength = 0; + } + + // nothing to do after the command finishes. + + ScratchBuffer_EndUse(DeviceExtension); + } + + return status; +} + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DeviceHandleStopAudio( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _Out_ size_t * DataLength + ) +{ + NTSTATUS status = STATUS_SUCCESS; + + PAGED_CODE (); + + *DataLength = 0; + + if (NT_SUCCESS(status)) + { + ULONG transferSize = 0; + CDB cdb; + + ScratchBuffer_BeginUse(DeviceExtension); + + RtlZeroMemory(&cdb, sizeof(CDB)); + // Set up the CDB + cdb.START_STOP.OperationCode = SCSIOP_START_STOP_UNIT; + cdb.START_STOP.Immediate = 1; + cdb.START_STOP.Start = 0; + cdb.START_STOP.LoadEject = 0; + + status = ScratchBuffer_ExecuteCdb(DeviceExtension, Request, transferSize, FALSE, &cdb, 6); + + if (NT_SUCCESS(status)) + { + PLAY_ACTIVE(DeviceExtension) = FALSE; + *DataLength = 0; + } + + // nothing to do after the command finishes. + ScratchBuffer_EndUse(DeviceExtension); + } + + return status; +} + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DeviceHandleGetSetVolume( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + Handle request of IOCTL_CDROM_GET_VOLUME + IOCTL_CDROM_SET_VOLUME + +Arguments: + + DeviceExtension - device context + Request - request to be handled + RequestParameters - request parameter + DataLength - transferred data length + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + + PAGED_CODE (); + + *DataLength = 0; + + if (NT_SUCCESS(status)) + { + ULONG transferSize = MODE_DATA_SIZE; + CDB cdb; + + ScratchBuffer_BeginUse(DeviceExtension); + + RtlZeroMemory(&cdb, sizeof(CDB)); + // Set up the CDB + cdb.MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10; + cdb.MODE_SENSE10.PageCode = CDROM_AUDIO_CONTROL_PAGE; + cdb.MODE_SENSE10.AllocationLength[0] = (UCHAR)(MODE_DATA_SIZE >> 8); + cdb.MODE_SENSE10.AllocationLength[1] = (UCHAR)(MODE_DATA_SIZE & 0xFF); + + status = ScratchBuffer_ExecuteCdb(DeviceExtension, Request, transferSize, TRUE, &cdb, 10); + + if (NT_SUCCESS(status)) + { + if (RequestParameters.Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_GET_VOLUME) + { + PAUDIO_OUTPUT audioOutput; + PVOLUME_CONTROL volumeControl; + ULONG bytesTransferred; + + status = WdfRequestRetrieveOutputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, + (PVOID*)&volumeControl, + NULL); + if (NT_SUCCESS(status)) + { + audioOutput = ModeSenseFindSpecificPage((PCHAR)DeviceExtension->ScratchContext.ScratchSrb->DataBuffer, + DeviceExtension->ScratchContext.ScratchSrb->DataTransferLength, + CDROM_AUDIO_CONTROL_PAGE, + FALSE); + + // Verify the page is as big as expected. + bytesTransferred = (ULONG)((PCHAR)audioOutput - (PCHAR)DeviceExtension->ScratchContext.ScratchSrb->DataBuffer) + + sizeof(AUDIO_OUTPUT); + + if ((audioOutput != NULL) && + (DeviceExtension->ScratchContext.ScratchSrb->DataTransferLength >= bytesTransferred)) + { + ULONG i; + for (i=0; i<4; i++) + { + volumeControl->PortVolume[i] = audioOutput->PortOutput[i].Volume; + } + + // Set bytes transferred in IRP. + *DataLength = sizeof(VOLUME_CONTROL); + + } + else + { + *DataLength = 0; + status = STATUS_INVALID_DEVICE_REQUEST; + } + } + } + else //IOCTL_CDROM_SET_VOLUME + { + PAUDIO_OUTPUT audioInput = NULL; + PAUDIO_OUTPUT audioOutput = NULL; + PVOLUME_CONTROL volumeControl = NULL; + ULONG i,bytesTransferred,headerLength; + + status = WdfRequestRetrieveInputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.InputBufferLength, + (PVOID*)&volumeControl, + NULL); + + if (NT_SUCCESS(status)) + { + audioInput = ModeSenseFindSpecificPage((PCHAR)DeviceExtension->ScratchContext.ScratchSrb->DataBuffer, + DeviceExtension->ScratchContext.ScratchSrb->DataTransferLength, + CDROM_AUDIO_CONTROL_PAGE, + FALSE); + + // Check to make sure the mode sense data is valid before we go on + if(audioInput == NULL) + { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, + "Mode Sense Page %d not found\n", + CDROM_AUDIO_CONTROL_PAGE)); + + *DataLength = 0; + status = STATUS_INVALID_DEVICE_REQUEST; + } + } + + if (NT_SUCCESS(status)) + { + // keep items clean; clear the command history + ScratchBuffer_ResetItems(DeviceExtension, TRUE); + + headerLength = sizeof(MODE_PARAMETER_HEADER10); + bytesTransferred = sizeof(AUDIO_OUTPUT) + headerLength; + + // use the scratch buffer as input buffer. + // the content of this buffer will not be changed in the following loop. + audioOutput = (PAUDIO_OUTPUT)((PCHAR)DeviceExtension->ScratchContext.ScratchBuffer + headerLength); + + for (i=0; i<4; i++) + { + audioOutput->PortOutput[i].Volume = volumeControl->PortVolume[i]; + audioOutput->PortOutput[i].ChannelSelection = audioInput->PortOutput[i].ChannelSelection; + } + + audioOutput->CodePage = CDROM_AUDIO_CONTROL_PAGE; + audioOutput->ParameterLength = sizeof(AUDIO_OUTPUT) - 2; + audioOutput->Immediate = MODE_SELECT_IMMEDIATE; + + RtlZeroMemory(&cdb, sizeof(CDB)); + // Set up the CDB + cdb.MODE_SELECT10.OperationCode = SCSIOP_MODE_SELECT10; + cdb.MODE_SELECT10.ParameterListLength[0] = (UCHAR) (bytesTransferred >> 8); + cdb.MODE_SELECT10.ParameterListLength[1] = (UCHAR) (bytesTransferred & 0xFF); + cdb.MODE_SELECT10.PFBit = 1; + + status = ScratchBuffer_ExecuteCdb(DeviceExtension, Request, bytesTransferred, FALSE, &cdb, 10); + + } + *DataLength = 0; + } + } + + // nothing to do after the command finishes. + ScratchBuffer_EndUse(DeviceExtension); + } + + return status; +} + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DeviceHandleReadDvdStructure( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + Handle request of IOCTL_DVD_READ_STRUCTURE + +Arguments: + + DeviceExtension - device context + Request - request to be handled + RequestParameters - request parameter + DataLength - transferred data length + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PVOID inputBuffer = NULL; + PVOID outputBuffer = NULL; + + PAGED_CODE (); + + *DataLength = 0; + + status = WdfRequestRetrieveInputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.InputBufferLength, + &inputBuffer, + NULL); + + if (NT_SUCCESS(status)) + { + status = WdfRequestRetrieveOutputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, + &outputBuffer, + NULL); + } + + if (NT_SUCCESS(status)) + { + status = ReadDvdStructure(DeviceExtension, + Request, + inputBuffer, + RequestParameters.Parameters.DeviceIoControl.InputBufferLength, + outputBuffer, + RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, + DataLength); + } + + return status; +} + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +ReadDvdStructure( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_opt_ WDFREQUEST OriginalRequest, + _In_ PVOID InputBuffer, + _In_ size_t InputBufferLength, + _In_ PVOID OutputBuffer, + _In_ size_t OutputBufferLength, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + base function to handle request of IOCTL_DVD_START_SESSION + IOCTL_DVD_READ_KEY + +Arguments: + + DeviceExtension - device context + OriginalRequest - original request to be handled + InputBuffer - input buffer + InputBufferLength - length of input buffer + OutputBuffer - output buffer + OutputBufferLength - length of output buffer + +Return Value: + + NTSTATUS + DataLength - returned data length + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PDVD_READ_STRUCTURE request = (PDVD_READ_STRUCTURE)InputBuffer; + PDVD_DESCRIPTOR_HEADER header = (PDVD_DESCRIPTOR_HEADER)OutputBuffer; + CDB cdb; + + USHORT dataLength; + ULONG blockNumber; + PFOUR_BYTE fourByte; + + PAGED_CODE (); + + UNREFERENCED_PARAMETER(InputBufferLength); + + if (DeviceExtension->DeviceAdditionalData.DriveDeviceType != FILE_DEVICE_DVD) + { + *DataLength = 0; + return STATUS_INVALID_DEVICE_REQUEST; + } + + dataLength = (USHORT)OutputBufferLength; + blockNumber = (ULONG)(request->BlockByteOffset.QuadPart >> DeviceExtension->SectorShift); + fourByte = (PFOUR_BYTE)&blockNumber; + + ScratchBuffer_BeginUse(DeviceExtension); + + RtlZeroMemory(&cdb, sizeof(CDB)); + // Set up the CDB + cdb.READ_DVD_STRUCTURE.OperationCode = SCSIOP_READ_DVD_STRUCTURE; + cdb.READ_DVD_STRUCTURE.RMDBlockNumber[0] = fourByte->Byte3; + cdb.READ_DVD_STRUCTURE.RMDBlockNumber[1] = fourByte->Byte2; + cdb.READ_DVD_STRUCTURE.RMDBlockNumber[2] = fourByte->Byte1; + cdb.READ_DVD_STRUCTURE.RMDBlockNumber[3] = fourByte->Byte0; + cdb.READ_DVD_STRUCTURE.LayerNumber = request->LayerNumber; + cdb.READ_DVD_STRUCTURE.Format = (UCHAR)request->Format; + +#if DBG + { + if ((UCHAR)request->Format > DvdMaxDescriptor) + { + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL, + "READ_DVD_STRUCTURE format %x = %s (%x bytes)\n", + (UCHAR)request->Format, + READ_DVD_STRUCTURE_FORMAT_STRINGS[DvdMaxDescriptor], + dataLength + )); + } + else + { + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL, + "READ_DVD_STRUCTURE format %x = %s (%x bytes)\n", + (UCHAR)request->Format, + READ_DVD_STRUCTURE_FORMAT_STRINGS[(UCHAR)request->Format], + dataLength + )); + } + } +#endif // DBG + + if (request->Format == DvdDiskKeyDescriptor) + { + cdb.READ_DVD_STRUCTURE.AGID = (UCHAR)request->SessionId; + } + + cdb.READ_DVD_STRUCTURE.AllocationLength[0] = (UCHAR)(dataLength >> 8); + cdb.READ_DVD_STRUCTURE.AllocationLength[1] = (UCHAR)(dataLength & 0xff); + + status = ScratchBuffer_ExecuteCdb(DeviceExtension, OriginalRequest, dataLength, TRUE, &cdb, 12); + + if (NT_SUCCESS(status)) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, + "DvdDCCompletion - READ_STRUCTURE: descriptor format of %d\n", request->Format)); + + RtlMoveMemory(header, + DeviceExtension->ScratchContext.ScratchSrb->DataBuffer, + DeviceExtension->ScratchContext.ScratchSrb->DataTransferLength); + + // Cook the data. There are a number of fields that really + // should be byte-swapped for the caller. + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, + "DvdDCCompletion - READ_STRUCTURE:\n" + "\tHeader at %p\n" + "\tDvdDCCompletion - READ_STRUCTURE: data at %p\n" + "\tDataBuffer was at %p\n" + "\tDataTransferLength was %lx\n", + header, + header->Data, + DeviceExtension->ScratchContext.ScratchSrb->DataBuffer, + DeviceExtension->ScratchContext.ScratchSrb->DataTransferLength)); + + // First the fields in the header + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "READ_STRUCTURE: header->Length %lx -> ", + header->Length)); + + REVERSE_SHORT(&header->Length); + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "%lx\n", header->Length)); + + // Now the fields in the descriptor + if(request->Format == DvdPhysicalDescriptor) + { + ULONG tempLength = (DeviceExtension->ScratchContext.ScratchSrb->DataTransferLength > (ULONG)FIELD_OFFSET(DVD_DESCRIPTOR_HEADER, Data)) + ? (DeviceExtension->ScratchContext.ScratchSrb->DataTransferLength - FIELD_OFFSET(DVD_DESCRIPTOR_HEADER, Data)) + : 0; + + PDVD_LAYER_DESCRIPTOR layer = (PDVD_LAYER_DESCRIPTOR)&(header->Data[0]); + + // Make sure the buffer size is good for swapping bytes. + if (tempLength >= RTL_SIZEOF_THROUGH_FIELD(DVD_LAYER_DESCRIPTOR, StartingDataSector)) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "READ_STRUCTURE: StartingDataSector %lx -> ", + layer->StartingDataSector)); + REVERSE_LONG(&(layer->StartingDataSector)); + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "%lx\n", layer->StartingDataSector)); + } + if (tempLength >= RTL_SIZEOF_THROUGH_FIELD(DVD_LAYER_DESCRIPTOR, EndDataSector)) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "READ_STRUCTURE: EndDataSector %lx -> ", + layer->EndDataSector)); + REVERSE_LONG(&(layer->EndDataSector)); + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "%lx\n", layer->EndDataSector)); + } + if (tempLength >= RTL_SIZEOF_THROUGH_FIELD(DVD_LAYER_DESCRIPTOR, EndLayerZeroSector)) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "READ_STRUCTURE: EndLayerZeroSector %lx -> ", + layer->EndLayerZeroSector)); + REVERSE_LONG(&(layer->EndLayerZeroSector)); + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "%lx\n", layer->EndLayerZeroSector)); + } + } + + if (!NT_SUCCESS(status)) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "Status is %lx\n", status)); + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DvdDeviceControlCompletion - " + "IOCTL_DVD_READ_STRUCTURE: data transfer length of %d\n", + DeviceExtension->ScratchContext.ScratchSrb->DataTransferLength)); + } + + *DataLength = DeviceExtension->ScratchContext.ScratchSrb->DataTransferLength; + } + + ScratchBuffer_EndUse(DeviceExtension); + + return status; +} + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DeviceHandleDvdEndSession( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + Handle request of IOCTL_DVD_END_SESSION + +Arguments: + + DeviceExtension - device context + Request - request to be handled + RequestParameters - request parameter + DataLength - transferred data length + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PDVD_SESSION_ID sessionId = NULL; + + PAGED_CODE (); + + *DataLength = 0; + + status = WdfRequestRetrieveInputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.InputBufferLength, + (PVOID*)&sessionId, + NULL); + + if (NT_SUCCESS(status)) + { + ULONG transferSize = 0; + CDB cdb; + DVD_SESSION_ID currentSession = 0; + DVD_SESSION_ID limitSession = 0; + + if(*sessionId == DVD_END_ALL_SESSIONS) + { + currentSession = 0; + limitSession = MAX_COPY_PROTECT_AGID - 1; + } + else + { + currentSession = *sessionId; + limitSession = *sessionId; + } + + ScratchBuffer_BeginUse(DeviceExtension); + + do + { + RtlZeroMemory(&cdb, sizeof(CDB)); + // Set up the CDB + cdb.SEND_KEY.OperationCode = SCSIOP_SEND_KEY; + cdb.SEND_KEY.AGID = (UCHAR)(currentSession); + cdb.SEND_KEY.KeyFormat = DVD_INVALIDATE_AGID; + + status = ScratchBuffer_ExecuteCdb(DeviceExtension, Request, transferSize, FALSE, &cdb, 12); + + currentSession++; + } while ((currentSession <= limitSession) && NT_SUCCESS(status)); + + // nothing to do after the command finishes. + ScratchBuffer_EndUse(DeviceExtension); + } + + return status; +} + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DeviceHandleDvdStartSessionReadKey( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + Handle request of IOCTL_DVD_START_SESSION + IOCTL_DVD_READ_KEY + +Arguments: + + DeviceExtension - device context + Request - request to be handled + RequestParameters - request parameter + DataLength - transferred data length + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PDVD_COPY_PROTECT_KEY keyParameters = NULL; + PVOID outputBuffer = NULL; + + PAGED_CODE (); + + if (NT_SUCCESS(status)) + { + status = WdfRequestRetrieveOutputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, + &outputBuffer, + NULL); + } + + if (NT_SUCCESS(status) && RequestParameters.Parameters.DeviceIoControl.IoControlCode == IOCTL_DVD_READ_KEY) + { + status = WdfRequestRetrieveInputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.InputBufferLength, + (PVOID*)&keyParameters, + NULL); + } + + if (NT_SUCCESS(status)) + { + status = DvdStartSessionReadKey(DeviceExtension, + RequestParameters.Parameters.DeviceIoControl.IoControlCode, + Request, + keyParameters, + RequestParameters.Parameters.DeviceIoControl.InputBufferLength, + outputBuffer, + RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, + DataLength); + } + + return status; +} + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DvdStartSessionReadKey( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ ULONG IoControlCode, + _In_opt_ WDFREQUEST OriginalRequest, + _In_opt_ PVOID InputBuffer, + _In_ size_t InputBufferLength, + _In_ PVOID OutputBuffer, + _In_ size_t OutputBufferLength, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + base function to handle request of IOCTL_DVD_START_SESSION + IOCTL_DVD_READ_KEY + +Arguments: + + DeviceExtension - device context + IoControlCode - IOCTL_DVD_READ_KEY or IOCTL_DVD_START_SESSION + OriginalRequest - original request to be handled + InputBuffer - input buffer + InputBufferLength - length of input buffer + OutputBuffer - output buffer + OutputBufferLength - length of output buffer + +Return Value: + + NTSTATUS + DataLength - returned data length + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + ULONG keyLength = 0; + ULONG result = 0; + ULONG allocationLength; + PFOUR_BYTE fourByte; + PDVD_COPY_PROTECT_KEY keyParameters = (PDVD_COPY_PROTECT_KEY)InputBuffer; + + PAGED_CODE (); + + UNREFERENCED_PARAMETER(InputBufferLength); + + *DataLength = 0; + + fourByte = (PFOUR_BYTE)&allocationLength; + + if (IoControlCode == IOCTL_DVD_READ_KEY) + { + if (keyParameters == NULL) + { + status = STATUS_INTERNAL_ERROR; + } + + // First of all, initialize the DVD region of the drive, if it has not been set yet + if (NT_SUCCESS(status) && + (keyParameters->KeyType == DvdGetRpcKey) && + DeviceExtension->DeviceAdditionalData.Mmc.IsCssDvd) + { + DevicePickDvdRegion(DeviceExtension->Device); + } + + if (NT_SUCCESS(status) && + (keyParameters->KeyType == DvdDiskKey)) + { + // Special case - need to use READ DVD STRUCTURE command to get the disk key. + PDVD_COPY_PROTECT_KEY keyHeader = NULL; + PDVD_READ_STRUCTURE readStructureRequest = (PDVD_READ_STRUCTURE)keyParameters; + + // save the key header so we can restore the interesting parts later + keyHeader = ExAllocatePoolWithTag(NonPagedPoolNx, + sizeof(DVD_COPY_PROTECT_KEY), + DVD_TAG_READ_KEY); + + if(keyHeader == NULL) + { + // Can't save the context so return an error + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, + "DvdDeviceControl - READ_KEY: unable to allocate context\n")); + status = STATUS_INSUFFICIENT_RESOURCES; + } + + if (NT_SUCCESS(status)) + { + PREAD_DVD_STRUCTURES_HEADER rawKey = OutputBuffer; + PDVD_COPY_PROTECT_KEY outputKey = OutputBuffer; + + // save input parameters + RtlCopyMemory(keyHeader, + InputBuffer, + sizeof(DVD_COPY_PROTECT_KEY)); + + readStructureRequest->Format = DvdDiskKeyDescriptor; + readStructureRequest->BlockByteOffset.QuadPart = 0; + readStructureRequest->LayerNumber = 0; + readStructureRequest->SessionId = keyHeader->SessionId; + + status = ReadDvdStructure(DeviceExtension, + OriginalRequest, + InputBuffer, + sizeof(DVD_READ_STRUCTURE), + OutputBuffer, + sizeof(READ_DVD_STRUCTURES_HEADER) + sizeof(DVD_DISK_KEY_DESCRIPTOR), + DataLength); + + // fill the output buffer, it's not touched in DeviceHandleReadDvdStructure() + // for this specific request type: DvdDiskKeyDescriptor + if (NT_SUCCESS(status)) + { + // Shift the data down to its new position. + RtlMoveMemory(outputKey->KeyData, + rawKey->Data, + sizeof(DVD_DISK_KEY_DESCRIPTOR)); + + RtlCopyMemory(outputKey, + keyHeader, + sizeof(DVD_COPY_PROTECT_KEY)); + + outputKey->KeyLength = DVD_DISK_KEY_LENGTH; + + *DataLength = DVD_DISK_KEY_LENGTH; + } + else + { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, + "StartSessionReadKey Failed with status %x, %xI64 (%x) bytes\n", + status, + (unsigned int)*DataLength, + ((rawKey->Length[0] << 16) | rawKey->Length[1]) )); + } + + FREE_POOL(keyHeader); + } + + // special process finished. return from here. + return status; + } + + if (NT_SUCCESS(status)) + { + status = RtlULongSub((ULONG)OutputBufferLength, + (ULONG)sizeof(DVD_COPY_PROTECT_KEY), &result); + } + + if (NT_SUCCESS(status)) + { + status = RtlULongAdd(result, sizeof(CDVD_KEY_HEADER), &keyLength); + } + + if (NT_SUCCESS(status)) + { + //The data length field of REPORT KEY Command occupies two bytes + keyLength = min(keyLength, MAXUSHORT); + } + } + else //IOCTL_DVD_START_SESSION + { + keyParameters = NULL; + keyLength = sizeof(CDVD_KEY_HEADER) + sizeof(CDVD_REPORT_AGID_DATA); + status = STATUS_SUCCESS; + } + + if (NT_SUCCESS(status)) + { + CDB cdb; + + allocationLength = keyLength; + + // Defensive coding. Prefix cannot recognize this usage. + UNREFERENCED_PARAMETER(allocationLength); + + ScratchBuffer_BeginUse(DeviceExtension); + + RtlZeroMemory(&cdb, sizeof(CDB)); + // Set up the CDB + cdb.REPORT_KEY.OperationCode = SCSIOP_REPORT_KEY; + cdb.REPORT_KEY.AllocationLength[0] = fourByte->Byte1; + cdb.REPORT_KEY.AllocationLength[1] = fourByte->Byte0; + + // set the specific parameters.... + if(IoControlCode == IOCTL_DVD_READ_KEY) + { + if(keyParameters->KeyType == DvdTitleKey) + { + ULONG logicalBlockAddress; + + logicalBlockAddress = (ULONG)(keyParameters->Parameters.TitleOffset.QuadPart >> + DeviceExtension->SectorShift); + + fourByte = (PFOUR_BYTE)&(logicalBlockAddress); + + cdb.REPORT_KEY.LogicalBlockAddress[0] = fourByte->Byte3; + cdb.REPORT_KEY.LogicalBlockAddress[1] = fourByte->Byte2; + cdb.REPORT_KEY.LogicalBlockAddress[2] = fourByte->Byte1; + cdb.REPORT_KEY.LogicalBlockAddress[3] = fourByte->Byte0; + } + + cdb.REPORT_KEY.KeyFormat = (UCHAR)keyParameters->KeyType; + cdb.REPORT_KEY.AGID = (UCHAR)keyParameters->SessionId; + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, + "DvdStartSessionReadKey => sending irp %p (%s)\n", + OriginalRequest, "READ_KEY")); + } + else + { + cdb.REPORT_KEY.KeyFormat = DVD_REPORT_AGID; + cdb.REPORT_KEY.AGID = 0; + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, + "DvdStartSessionReadKey => sending irp %p (%s)\n", + OriginalRequest, "START_SESSION")); + } + + status = ScratchBuffer_ExecuteCdb(DeviceExtension, OriginalRequest, keyLength, TRUE, &cdb, 12); + + if (NT_SUCCESS(status)) + { + if(IoControlCode == IOCTL_DVD_READ_KEY) + { + NTSTATUS tempStatus; + PDVD_COPY_PROTECT_KEY copyProtectKey = (PDVD_COPY_PROTECT_KEY)OutputBuffer; + PCDVD_KEY_HEADER keyHeader = DeviceExtension->ScratchContext.ScratchSrb->DataBuffer; + ULONG dataLength; + ULONG transferLength; + + tempStatus = RtlULongSub(DeviceExtension->ScratchContext.ScratchSrb->DataTransferLength, + FIELD_OFFSET(CDVD_KEY_HEADER, Data), + &transferLength); + + dataLength = (keyHeader->DataLength[0] << 8) + keyHeader->DataLength[1]; + + if (NT_SUCCESS(tempStatus) && (dataLength >= 2)) + { + // Adjust the data length to ignore the two reserved bytes in the + // header. + dataLength -= 2; + + // take the minimum of the transferred length and the + // length as specified in the header. + if(dataLength < transferLength) + { + transferLength = dataLength; + } + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, + "DvdDeviceControlCompletion: [%p] - READ_KEY with " + "transfer length of (%d or %d) bytes\n", + OriginalRequest, + dataLength, + DeviceExtension->ScratchContext.ScratchSrb->DataTransferLength - 2)); + + // Copy the key data into the return buffer + if(copyProtectKey->KeyType == DvdTitleKey) + { + RtlMoveMemory(copyProtectKey->KeyData, + keyHeader->Data + 1, + transferLength - 1); + + copyProtectKey->KeyData[transferLength - 1] = 0; + + // If this is a title key then we need to copy the CGMS flags + // as well. + copyProtectKey->KeyFlags = *(keyHeader->Data); + + } + else + { + RtlMoveMemory(copyProtectKey->KeyData, + keyHeader->Data, + transferLength); + } + + copyProtectKey->KeyLength = sizeof(DVD_COPY_PROTECT_KEY); + copyProtectKey->KeyLength += transferLength; + + *DataLength = copyProtectKey->KeyLength; + } + else + { + //There is no valid data from drive. + //This may happen when Key Format = 0x3f that does not require data back from drive. + status = STATUS_SUCCESS; + *DataLength = 0; + } + } + else + { + PDVD_SESSION_ID sessionId = (PDVD_SESSION_ID)OutputBuffer; + PCDVD_KEY_HEADER keyHeader = DeviceExtension->ScratchContext.ScratchSrb->DataBuffer; + PCDVD_REPORT_AGID_DATA keyData = (PCDVD_REPORT_AGID_DATA)keyHeader->Data; + + *sessionId = keyData->AGID; + + *DataLength = sizeof(DVD_SESSION_ID); + } + } + + // nothing to do after the command finishes. + ScratchBuffer_EndUse(DeviceExtension); + } + + return status; +} + + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DeviceHandleDvdSendKey( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + Handle request of IOCTL_DVD_SEND_KEY + IOCTL_DVD_SEND_KEY2 + +Arguments: + + DeviceExtension - device context + Request - request to be handled + RequestParameters - request parameter + DataLength - transferred data length + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PVOID inputBuffer = NULL; + + PAGED_CODE (); + + *DataLength = 0; + + status = WdfRequestRetrieveInputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.InputBufferLength, + &inputBuffer, + NULL); + + if (NT_SUCCESS(status)) + { + status = DvdSendKey(DeviceExtension, + Request, + inputBuffer, + RequestParameters.Parameters.DeviceIoControl.InputBufferLength, + DataLength); + } + + return status; +} + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DvdSendKey( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_opt_ WDFREQUEST OriginalRequest, + _In_ PVOID InputBuffer, + _In_ size_t InputBufferLength, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + base function to handle request of IOCTL_DVD_SEND_KEY(2) + NOTE: cdrom does not process this IOCTL if the input buffer length is bigger than Port transfer length. + +Arguments: + + DeviceExtension - device context + OriginalRequest - original request to be handled + InputBuffer - input buffer + InputBufferLength - length of input buffer + +Return Value: + + NTSTATUS + DataLength - returned data length + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY)InputBuffer; + + ULONG keyLength = 0; + ULONG result = 0; + PFOUR_BYTE fourByte; + + PAGED_CODE (); + + UNREFERENCED_PARAMETER(InputBufferLength); + + *DataLength = 0; + + if (NT_SUCCESS(status)) + { + if ((key->KeyLength < sizeof(DVD_COPY_PROTECT_KEY)) || + ((key->KeyLength - sizeof(DVD_COPY_PROTECT_KEY)) > DeviceExtension->ScratchContext.ScratchBufferSize)) + { + NT_ASSERT(FALSE); + status = STATUS_INTERNAL_ERROR; + } + } + + if (NT_SUCCESS(status)) + { + status = RtlULongSub(key->KeyLength, sizeof(DVD_COPY_PROTECT_KEY), &result); + } + + if (NT_SUCCESS(status)) + { + status = RtlULongAdd(result, sizeof(CDVD_KEY_HEADER), &keyLength); + } + + if (NT_SUCCESS(status)) + { + keyLength = min(keyLength, DeviceExtension->ScratchContext.ScratchBufferSize); + + if (keyLength < 2) + { + status = STATUS_INVALID_PARAMETER; + } + } + + if (NT_SUCCESS(status)) + { + PCDVD_KEY_HEADER keyBuffer = NULL; + CDB cdb; + + ScratchBuffer_BeginUse(DeviceExtension); + + // prepare the input buffer + keyBuffer = (PCDVD_KEY_HEADER)DeviceExtension->ScratchContext.ScratchBuffer; + + // keylength is decremented here by two because the + // datalength does not include the header, which is two + // bytes. keylength is immediately incremented later + // by the same amount. + keyLength -= 2; + fourByte = (PFOUR_BYTE)&keyLength; + keyBuffer->DataLength[0] = fourByte->Byte1; + keyBuffer->DataLength[1] = fourByte->Byte0; + keyLength += 2; + + RtlMoveMemory(keyBuffer->Data, + key->KeyData, + key->KeyLength - sizeof(DVD_COPY_PROTECT_KEY)); + + RtlZeroMemory(&cdb, sizeof(CDB)); + // Set up the CDB + cdb.REPORT_KEY.OperationCode = SCSIOP_SEND_KEY; + + cdb.SEND_KEY.ParameterListLength[0] = fourByte->Byte1; + cdb.SEND_KEY.ParameterListLength[1] = fourByte->Byte0; + cdb.SEND_KEY.KeyFormat = (UCHAR)key->KeyType; + cdb.SEND_KEY.AGID = (UCHAR)key->SessionId; + + status = ScratchBuffer_ExecuteCdb(DeviceExtension, OriginalRequest, keyLength, FALSE, &cdb, 12); + + // nothing to do after the command finishes. + ScratchBuffer_EndUse(DeviceExtension); + } + + return status; +} + + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DeviceHandleSetReadAhead( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + Handle request of IOCTL_STORAGE_SET_READ_AHEAD + +Arguments: + + DeviceExtension - device context + Request - request to be handled + RequestParameters - request parameter + DataLength - transferred data length + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PSTORAGE_SET_READ_AHEAD readAhead = NULL; + + PAGED_CODE (); + + *DataLength = 0; + + status = WdfRequestRetrieveInputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.InputBufferLength, + (PVOID*)&readAhead, + NULL); + + if (NT_SUCCESS(status)) + { + ULONG transferSize = 0; + CDB cdb; + ULONG blockAddress; + PFOUR_BYTE fourByte = (PFOUR_BYTE)&blockAddress; + + ScratchBuffer_BeginUse(DeviceExtension); + + RtlZeroMemory(&cdb, sizeof(CDB)); + // Set up the CDB + cdb.SET_READ_AHEAD.OperationCode = SCSIOP_SET_READ_AHEAD; + + blockAddress = (ULONG)(readAhead->TriggerAddress.QuadPart >> + DeviceExtension->SectorShift); + + // Defensive coding. Prefix cannot recognize this usage. + UNREFERENCED_PARAMETER(blockAddress); + + cdb.SET_READ_AHEAD.TriggerLBA[0] = fourByte->Byte3; + cdb.SET_READ_AHEAD.TriggerLBA[1] = fourByte->Byte2; + cdb.SET_READ_AHEAD.TriggerLBA[2] = fourByte->Byte1; + cdb.SET_READ_AHEAD.TriggerLBA[3] = fourByte->Byte0; + + blockAddress = (ULONG)(readAhead->TargetAddress.QuadPart >> + DeviceExtension->SectorShift); + + cdb.SET_READ_AHEAD.ReadAheadLBA[0] = fourByte->Byte3; + cdb.SET_READ_AHEAD.ReadAheadLBA[1] = fourByte->Byte2; + cdb.SET_READ_AHEAD.ReadAheadLBA[2] = fourByte->Byte1; + cdb.SET_READ_AHEAD.ReadAheadLBA[3] = fourByte->Byte0; + + status = ScratchBuffer_ExecuteCdb(DeviceExtension, Request, transferSize, FALSE, &cdb, 12); + + if (NT_SUCCESS(status)) + { + *DataLength = 0; + } + + // nothing to do after the command finishes. + ScratchBuffer_EndUse(DeviceExtension); + } + + return status; +} + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DeviceHandleSetSpeed( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ) +/*++ + +Routine Description: + + Handle request of IOCTL_CDROM_SET_SPEED + +Arguments: + + DeviceExtension - device context + Request - request to be handled + RequestParameters - request parameter + DataLength - transferred data length + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PCDROM_DATA cdData = &(DeviceExtension->DeviceAdditionalData); + PCDROM_SET_SPEED inputBuffer = NULL; + + PAGED_CODE (); + + *DataLength = 0; + + status = WdfRequestRetrieveInputBuffer(Request, + RequestParameters.Parameters.DeviceIoControl.InputBufferLength, + (PVOID*)&inputBuffer, + NULL); + + if (NT_SUCCESS(status)) + { + ULONG transferSize = 0; + CDB cdb; + CDROM_SPEED_REQUEST requestType = inputBuffer->RequestType; + + ScratchBuffer_BeginUse(DeviceExtension); + + RtlZeroMemory(&cdb, sizeof(CDB)); + // Set up the CDB + if (requestType == CdromSetSpeed) + { + PCDROM_SET_SPEED speed = inputBuffer; + + cdb.SET_CD_SPEED.OperationCode = SCSIOP_SET_CD_SPEED; + cdb.SET_CD_SPEED.RotationControl = speed->RotationControl; + REVERSE_BYTES_SHORT(&cdb.SET_CD_SPEED.ReadSpeed, &speed->ReadSpeed); + REVERSE_BYTES_SHORT(&cdb.SET_CD_SPEED.WriteSpeed, &speed->WriteSpeed); + } + else + { + PCDROM_SET_STREAMING stream = (PCDROM_SET_STREAMING)inputBuffer; + PPERFORMANCE_DESCRIPTOR perfDescriptor; + + transferSize = sizeof(PERFORMANCE_DESCRIPTOR); + + perfDescriptor = DeviceExtension->ScratchContext.ScratchBuffer; + RtlZeroMemory(perfDescriptor, transferSize); + + perfDescriptor->RandomAccess = stream->RandomAccess; + perfDescriptor->Exact = stream->SetExact; + perfDescriptor->RestoreDefaults = stream->RestoreDefaults; + perfDescriptor->WriteRotationControl = stream->RotationControl; + + REVERSE_BYTES(&perfDescriptor->StartLba, &stream->StartLba); + REVERSE_BYTES(&perfDescriptor->EndLba, &stream->EndLba); + REVERSE_BYTES(&perfDescriptor->ReadSize, &stream->ReadSize); + REVERSE_BYTES(&perfDescriptor->ReadTime, &stream->ReadTime); + REVERSE_BYTES(&perfDescriptor->WriteSize, &stream->WriteSize); + REVERSE_BYTES(&perfDescriptor->WriteTime, &stream->WriteTime); + + cdb.SET_STREAMING.OperationCode = SCSIOP_SET_STREAMING; + REVERSE_BYTES_SHORT(&cdb.SET_STREAMING.ParameterListLength, &transferSize); + + // set value in extension by user inputs. + cdData->RestoreDefaults = stream->Persistent ? FALSE : TRUE; + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DeviceHandleSetSpeed: Restore default speed on media change set to %s\n", + cdData->RestoreDefaults ? "true" : "false")); + } + + status = ScratchBuffer_ExecuteCdb(DeviceExtension, Request, transferSize, FALSE, &cdb, 12); + + if (NT_SUCCESS(status)) + { + *DataLength = 0; + } + + // nothing to do after the command finishes. + ScratchBuffer_EndUse(DeviceExtension); + } + + return status; +} + + diff --git a/storage/class/cdrom/src/ioctl.h b/storage/class/cdrom/src/ioctl.h new file mode 100644 index 00000000..951561a9 --- /dev/null +++ b/storage/class/cdrom/src/ioctl.h @@ -0,0 +1,847 @@ +/*++ + +Copyright (C) Microsoft Corporation. All rights reserved. + +Module Name: + + ioctl.h + +Abstract: + + Functions to handle IOCTLs. + +Author: + +Environment: + + kernel mode only + +Notes: + + +Revision History: + +--*/ + +#ifndef __IOCTL_H__ +#define __IOCTL_H__ + +BOOLEAN +RequestDispatchProcessDirectly( + _In_ WDFDEVICE Device, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters + ); + +BOOLEAN +RequestDispatchToSequentialQueue( + _In_ WDFDEVICE Device, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters + ); + +BOOLEAN +RequestDispatchSyncWithSequentialQueue( + _In_ WDFDEVICE Device, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters + ); + +BOOLEAN +RequestDispatchSpecialIoctls( + _In_ WDFDEVICE Device, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters + ); + +BOOLEAN +RequestDispatchUnknownRequests( + _In_ WDFDEVICE Device, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters + ); + +// +// I/O Request Handlers +// + +// Handlers that are called directly in dispatch routine. + +NTSTATUS +RequestHandleGetInquiryData( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + +NTSTATUS +RequestHandleGetMediaTypeEx( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _Out_ size_t * DataLength + ); + +NTSTATUS +RequestHandleMountQueryUniqueId( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + +NTSTATUS +RequestHandleMountQueryDeviceName( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + +NTSTATUS +RequestHandleMountQuerySuggestedLinkName( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + +NTSTATUS +RequestHandleGetDeviceNumber( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + +NTSTATUS +RequestHandleGetHotPlugInfo( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + +NTSTATUS +RequestHandleSetHotPlugInfo( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +RequestHandleEventNotification( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_opt_ WDFREQUEST Request, + _In_opt_ PWDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + +// Handlers that are called in RequestProcessSerializedIoctl in a work item. + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +RequestHandleGetDvdRegion( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _Out_ size_t * DataLength + ); + +NTSTATUS +RequestHandleQueryPropertyRetrieveCachedData( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +RequestHandleReadTOC( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +RequestHandleReadTocEx( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +RequestHandleGetConfiguration( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +RequestHandleGetDriveGeometry( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +RequestHandleDiskVerify( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +RequestHandleCheckVerify( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +RequestHandleFakePartitionInfo( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +RequestHandleEjectionControl( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +RequestHandleLoadEjectMedia( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +RequestHandleMcnControl( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _Out_ size_t * DataLength + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +RequestHandleReserveRelease( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +RequestHandlePersistentReserve( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + +#if (NTDDI_VERSION >= NTDDI_WIN8) +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +RequestHandleAreVolumesReady( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +RequestHandleVolumeOnline( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); +#endif + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +DeviceHandleRawRead( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DeviceHandlePlayAudioMsf( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DeviceHandleReadQChannel( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DeviceHandlePauseAudio( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _Out_ size_t * DataLength + ); + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DeviceHandleResumeAudio( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _Out_ size_t * DataLength + ); + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DeviceHandleSeekAudioMsf( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DeviceHandleStopAudio( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _Out_ size_t * DataLength + ); + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DeviceHandleGetSetVolume( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DeviceHandleReadDvdStructure( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DeviceHandleDvdEndSession( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DeviceHandleDvdStartSessionReadKey( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DeviceHandleDvdSendKey( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DeviceHandleSetReadAhead( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DeviceHandleSetSpeed( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DeviceHandleAacsReadMediaKeyBlock( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DeviceHandleAacsStartSession( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DeviceHandleAacsEndSession( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DeviceHandleAacsSendCertificate( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DeviceHandleAacsGetCertificate( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DeviceHandleAacsGetChallengeKey( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DeviceHandleSendChallengeKey( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DeviceHandleReadVolumeId( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DeviceHandleAacsReadSerialNumber( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DeviceHandleAacsReadMediaId( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DeviceHandleAacsReadBindingNonce( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +DeviceHandleAacsGenerateBindingNonce( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +RequestHandleEnableStreaming( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _Out_ size_t * DataLength + ); + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +RequestHandleSendOpcInformation( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _Out_ size_t * DataLength + ); + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +RequestHandleGetPerformance( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +RequestHandleMcnSyncFakeIoctl( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _Out_ size_t * DataLength + ); + +// Handlers that will be called by Sync process. + +// RequestHandleUnknownIoctl could be called at DISPATCH_LEVEL. +NTSTATUS +RequestHandleUnknownIoctl( + _In_ WDFDEVICE Device, + _In_ WDFREQUEST Request + ); + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +RequestHandleExclusiveAccessQueryLockState( + _In_ WDFDEVICE Device, + _In_ WDFREQUEST Request + ); + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +RequestHandleExclusiveAccessLockDevice( + _In_ WDFDEVICE Device, + _In_ WDFREQUEST Request + ); + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +RequestHandleExclusiveAccessUnlockDevice( + _In_ WDFDEVICE Device, + _In_ WDFREQUEST Request + ); + +NTSTATUS +RequestHandleQueryPropertyDeviceUniqueId( + _In_ WDFDEVICE Device, + _In_ WDFREQUEST Request + ); + +NTSTATUS +RequestHandleQueryPropertyWriteCache( + _In_ WDFDEVICE Device, + _In_ WDFREQUEST Request + ); + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +RequestHandleScsiPassThrough( + _In_ WDFDEVICE Device, + _In_ WDFREQUEST Request + ); + +// Read/write handler called possibly at DISPATCH_LEVEL. + +NTSTATUS +RequestHandleReadWrite( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters + ); + +// +// I/O Request Validation helpers +// + +NTSTATUS +RequestValidateRawRead( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + +NTSTATUS +RequestValidateReadTocEx( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + +NTSTATUS +RequestValidateReadToc( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + +NTSTATUS +RequestValidateGetLastSession( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + +NTSTATUS +RequestValidateReadQChannel( + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + +NTSTATUS +RequestValidateDvdReadStructure( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + +NTSTATUS +RequestValidateDvdStartSession( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + +NTSTATUS +RequestValidateDvdSendKey( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + +NTSTATUS +RequestValidateDvdReadKey( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + +NTSTATUS +RequestValidateGetConfiguration( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + +NTSTATUS +RequestValidateSetSpeed( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + +NTSTATUS +RequestValidateAacsReadMediaKeyBlock( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + +NTSTATUS +RequestValidateAacsStartSession( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + +NTSTATUS +RequestValidateAacsSendCertificate( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + +NTSTATUS +RequestValidateAacsGetCertificate( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + +NTSTATUS +RequestValidateAacsGetChallengeKey( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + +NTSTATUS +RequestValidateAacsSendChallengeKey( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + +NTSTATUS +RequestValidateAacsReadVolumeId( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + +NTSTATUS +RequestValidateAacsReadSerialNumber( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + +NTSTATUS +RequestValidateAacsReadMediaId( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + +NTSTATUS +RequestValidateAacsBindingNonce( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + +NTSTATUS +RequestValidateExclusiveAccess( + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + +NTSTATUS +RequestValidateEnableStreaming( + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + +NTSTATUS +RequestValidateSendOpcInformation( + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + +NTSTATUS +RequestValidateGetPerformance( + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + +BOOLEAN +RequestIsRealtimeStreaming( + _In_ WDFREQUEST Request, + _In_ BOOLEAN IsReadRequest + ); + +NTSTATUS +RequestValidateReadWrite( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters + ); + +NTSTATUS +RequestValidatePersistentReserve( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + +NTSTATUS +RequestValidateDvdEndSession( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + +NTSTATUS +RequestValidateAacsEndSession( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ WDF_REQUEST_PARAMETERS RequestParameters, + _Out_ size_t * DataLength + ); + + +// +// completion routines +// + + + + +#endif // __IOCTL_H__ diff --git a/storage/class/cdrom/src/localwpp.ini b/storage/class/cdrom/src/localwpp.ini new file mode 100644 index 00000000..0e793609 --- /dev/null +++ b/storage/class/cdrom/src/localwpp.ini @@ -0,0 +1,17 @@ + +// this defines how to log a len/buffer pair. +// This function should be in trace.h +DEFINE_CPLX_TYPE(HEXDUMP, WPP_LOGHEXDUMP, xstr_t, ItemHEXDump,"s", _HEX_, 0,2); + +// DEFINE_CPLX_TYPE( +// name, // i.e. HEXDUMP // %!HEXDUMP! +// macro, // i.e. WPP_LOGHEXDUMP // Marshalling macro, defined in trace.h +// structure, // i.e. xstr_t // Argument type (structure to be created by above macro) +// item type, // i.e. ItemHEXDump // MOF type that TracePrt can understand +// format specifier, // i.e. "s" // a format specifier that TracePrt can understand +// ???? // i.e. _HEX_ // Type signature (becomes a part of function name) +// ???? // i.e. 0 // Weight (0 is variable data length) +// ???? // i.e. 2 // Slots used by this entry (optional, 1 default) +// ) + + diff --git a/storage/class/cdrom/src/mmc.c b/storage/class/cdrom/src/mmc.c new file mode 100644 index 00000000..3887cc2f --- /dev/null +++ b/storage/class/cdrom/src/mmc.c @@ -0,0 +1,1629 @@ +/*-- + +Copyright (C) Microsoft Corporation. All rights reserved. + +Module Name: + + mmc.c + +Abstract: + + Include all funtions relate to MMC + +Environment: + + kernel mode only + +Notes: + + +Revision History: + +--*/ + +#include "stddef.h" +#include "string.h" + +#include "ntddk.h" +#include "ntddstor.h" +#include "cdrom.h" +#include "mmc.h" +#include "scratch.h" + +#ifdef DEBUG_USE_WPP +#include "mmc.tmh" +#endif + +#ifdef ALLOC_PRAGMA + +#pragma alloc_text(PAGE, DeviceDeallocateMmcResources) +#pragma alloc_text(PAGE, DeviceAllocateMmcResources) +#pragma alloc_text(PAGE, DeviceUpdateMmcCapabilities) +#pragma alloc_text(PAGE, DeviceGetConfigurationWithAlloc) +#pragma alloc_text(PAGE, DeviceGetConfiguration) +#pragma alloc_text(PAGE, DeviceUpdateMmcWriteCapability) +#pragma alloc_text(PAGE, MmcDataFindFeaturePage) +#pragma alloc_text(PAGE, MmcDataFindProfileInProfiles) +#pragma alloc_text(PAGE, DeviceRetryTimeGuessBasedOnProfile) +#pragma alloc_text(PAGE, DeviceRetryTimeDetectionBasedOnModePage2A) +#pragma alloc_text(PAGE, DeviceRetryTimeDetectionBasedOnGetPerformance) + +#endif + +#pragma warning(push) +#pragma warning(disable:4214) // nonstandard extension used : bit field types other than int + +_IRQL_requires_max_(APC_LEVEL) +VOID +DeviceDeallocateMmcResources( + _In_ WDFDEVICE Device + ) +/*++ + +Routine Description: + + release MMC resources + +Arguments: + + Device - device object + +Return Value: + + none + +--*/ +{ + PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(Device); + PCDROM_DATA cddata = &(deviceExtension->DeviceAdditionalData); + PCDROM_MMC_EXTENSION mmcData = &cddata->Mmc; + + PAGED_CODE(); + + if (mmcData->CapabilitiesIrp) + { + IoFreeIrp(mmcData->CapabilitiesIrp); + mmcData->CapabilitiesIrp = NULL; + } + if (mmcData->CapabilitiesMdl) + { + IoFreeMdl(mmcData->CapabilitiesMdl); + mmcData->CapabilitiesMdl = NULL; + } + if (mmcData->CapabilitiesBuffer) + { + ExFreePool(mmcData->CapabilitiesBuffer); + mmcData->CapabilitiesBuffer = NULL; + } + if (mmcData->CapabilitiesRequest) + { + WdfObjectDelete(mmcData->CapabilitiesRequest); + mmcData->CapabilitiesRequest = NULL; + } + mmcData->CapabilitiesBufferSize = 0; + mmcData->IsMmc = FALSE; + mmcData->WriteAllowed = FALSE; + + return; +} + + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +DeviceAllocateMmcResources( + _In_ WDFDEVICE Device + ) +/*++ + +Routine Description: + + allocate all MMC resources needed + +Arguments: + + Device - device object + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(Device); + PCDROM_DATA cddata = &(deviceExtension->DeviceAdditionalData); + PCDROM_MMC_EXTENSION mmcData = &(cddata->Mmc); + WDF_OBJECT_ATTRIBUTES attributes = {0}; + + PAGED_CODE(); + + NT_ASSERT(mmcData->CapabilitiesBuffer == NULL); + NT_ASSERT(mmcData->CapabilitiesBufferSize == 0); + + // allocate the buffer and set the buffer size. + // retrieve drive configuration information. + status = DeviceGetConfigurationWithAlloc(Device, + &mmcData->CapabilitiesBuffer, + &mmcData->CapabilitiesBufferSize, + FeatureProfileList, + SCSI_GET_CONFIGURATION_REQUEST_TYPE_ALL); + if (!NT_SUCCESS(status)) + { + NT_ASSERT(mmcData->CapabilitiesBuffer == NULL); + NT_ASSERT(mmcData->CapabilitiesBufferSize == 0); + return status; + } + + NT_ASSERT(mmcData->CapabilitiesBuffer != NULL); + NT_ASSERT(mmcData->CapabilitiesBufferSize != 0); + + // Create an MDL over the new Buffer (allocated by DeviceGetConfiguration) + mmcData->CapabilitiesMdl = IoAllocateMdl(mmcData->CapabilitiesBuffer, + mmcData->CapabilitiesBufferSize, + FALSE, FALSE, NULL); + if (mmcData->CapabilitiesMdl == NULL) + { + ExFreePool(mmcData->CapabilitiesBuffer); + mmcData->CapabilitiesBuffer = NULL; + mmcData->CapabilitiesBufferSize = 0; + return STATUS_INSUFFICIENT_RESOURCES; + } + + // Create an IRP from which we will create a WDFREQUEST + mmcData->CapabilitiesIrp = IoAllocateIrp(deviceExtension->DeviceObject->StackSize + 1, FALSE); + if (mmcData->CapabilitiesIrp == NULL) + { + IoFreeMdl(mmcData->CapabilitiesMdl); + mmcData->CapabilitiesMdl = NULL; + ExFreePool(mmcData->CapabilitiesBuffer); + mmcData->CapabilitiesBuffer = NULL; + mmcData->CapabilitiesBufferSize = 0; + return STATUS_INSUFFICIENT_RESOURCES; + } + + // create WDF request object + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, + CDROM_REQUEST_CONTEXT); + status = WdfRequestCreateFromIrp(&attributes, + mmcData->CapabilitiesIrp, + FALSE, + &mmcData->CapabilitiesRequest); + if (!NT_SUCCESS(status)) + { + return status; + } + + return STATUS_SUCCESS; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +DeviceUpdateMmcCapabilities( + _In_ WDFDEVICE Device + ) +/*++ + +Routine Description: + + issue get congiguration command ans save result in device extension + +Arguments: + + Device - device object + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(Device); + PCDROM_DATA cdData = &(deviceExtension->DeviceAdditionalData); + PCDROM_MMC_EXTENSION mmcData = &(cdData->Mmc); + ULONG returnedBytes = 0; + LONG updateState; + + PAGED_CODE(); + + // first of all, check if we're still in the CdromMmcUpdateRequired state + // and, if yes, change it to CdromMmcUpdateStarted. + updateState = InterlockedCompareExchange((PLONG)&(cdData->Mmc.UpdateState), + CdromMmcUpdateStarted, + CdromMmcUpdateRequired); + if (updateState != CdromMmcUpdateRequired) { + // Mmc capabilities have been already updated or are in the process of + // being updated - just return STATUS_SUCCESS + return STATUS_SUCCESS; + } + + // default to read-only, no Streaming, non-blank + mmcData->WriteAllowed = FALSE; + mmcData->StreamingReadSupported = FALSE; + mmcData->StreamingWriteSupported = FALSE; + + // Issue command to update the drive capabilities. + // The failure of MMC update is not considered critical, + // so that we'll continue to process I/O even MMC update fails. + status = DeviceGetConfiguration(Device, + mmcData->CapabilitiesBuffer, + mmcData->CapabilitiesBufferSize, + &returnedBytes, + FeatureProfileList, + SCSI_GET_CONFIGURATION_REQUEST_TYPE_CURRENT); + + if (NT_SUCCESS(status) && // succeeded. + (mmcData->CapabilitiesBufferSize >= returnedBytes)) // not overflow. + { + // update whether or not writes are allowed + // this should be the *ONLY* place writes are set to allowed + { + BOOLEAN writeAllowed = FALSE; + FEATURE_NUMBER validationSchema = 0; + ULONG blockingFactor = 1; + + DeviceUpdateMmcWriteCapability(mmcData->CapabilitiesBuffer, + returnedBytes, + TRUE, + &writeAllowed, + &validationSchema, + &blockingFactor); + + mmcData->WriteAllowed = writeAllowed; + mmcData->ValidationSchema = validationSchema; + mmcData->Blocking = blockingFactor; + } + + // Check if Streaming reads/writes are supported and cache + // this information for later use. + { + PFEATURE_HEADER header; + ULONG minAdditionalLength; + + minAdditionalLength = FIELD_OFFSET(FEATURE_DATA_REAL_TIME_STREAMING, Reserved2) - + sizeof(FEATURE_HEADER); + + header = MmcDataFindFeaturePage(mmcData->CapabilitiesBuffer, + returnedBytes, + FeatureRealTimeStreaming); + + if ((header != NULL) && + (header->Current) && + (header->AdditionalLength >= minAdditionalLength)) + { + PFEATURE_DATA_REAL_TIME_STREAMING feature = (PFEATURE_DATA_REAL_TIME_STREAMING)header; + + // If Real-Time feature is current, then Streaming reads are supported for sure. + mmcData->StreamingReadSupported = TRUE; + + // Streaming writes are supported if an appropriate bit is set in the feature page. + mmcData->StreamingWriteSupported = (feature->StreamRecording == 1); + } + } + + // update the flag to reflect that if the media is CSS protected DVD or CPPM-protected DVDAudio + { + PFEATURE_HEADER header; + + header = DeviceFindFeaturePage(mmcData->CapabilitiesBuffer, + returnedBytes, + FeatureDvdCSS); + + mmcData->IsCssDvd = (header != NULL) && (header->Current); + } + + // Update the guesstimate for the drive's write speed + // Use the GetConfig profile first as a quick-guess based + // on media "type", then continue with media-specific + // queries for older media types, and use GET_PERFORMANCE + // for all unknown/future media types. + { + // pseudo-code: + // 1) Determine default based on profile (slowest for media) + // 2) Determine default based on MODE PAGE 2Ah + // 3) Determine default based on GET PERFORMANCE data + // 4) Choose fastest reported speed (-1 == none reported) + // 5) If all failed (returned -1), go with very safe (slow) default + // + // This ensures that the retries do not overload the drive's processor. + // Sending at highest possible speed for the media is OK, because the + // major downside is drive processor usage. (bus usage too, but most + // storage is becoming a point-to-point link.) + + FEATURE_PROFILE_TYPE const profile = + mmcData->CapabilitiesBuffer->CurrentProfile[0] << (8*1) | + mmcData->CapabilitiesBuffer->CurrentProfile[1] << (8*0) ; + LONGLONG t1 = (LONGLONG)-1; + LONGLONG t2 = (LONGLONG)-1; + LONGLONG t3 = (LONGLONG)-1; + LONGLONG t4 = (LONGLONG)-1; + LONGLONG final; + + t1 = DeviceRetryTimeGuessBasedOnProfile(profile); + t2 = DeviceRetryTimeDetectionBasedOnModePage2A(deviceExtension); + t3 = DeviceRetryTimeDetectionBasedOnGetPerformance(deviceExtension, TRUE); + t4 = DeviceRetryTimeDetectionBasedOnGetPerformance(deviceExtension, FALSE); + + // use the "fastest" value returned + final = MAXLONGLONG; + if (t4 != -1) + { + final = min(final, t4); + } + if (t3 != -1) + { + final = min(final, t3); + } + if (t2 != -1) + { + final = min(final, t2); + } + if (t1 != -1) + { + final = min(final, t1); + } + if (final == MAXLONGLONG) + { + // worst case -- use relatively slow default.... + final = WRITE_RETRY_DELAY_CD_4x; + } + + cdData->ReadWriteRetryDelay100nsUnits = final; + } + + } + else + { + // Rediscovery of MMC capabilities has failed - we'll need to retry + cdData->Mmc.UpdateState = CdromMmcUpdateRequired; + } + + // Change the state to CdromMmcUpdateComplete if it is CdromMmcUpdateStarted. + // If it is not, some error must have happened while this function was executed + // and the state is CdromMmcUpdateRequired now. In that case, we want to perform + // everything again, so we do not set CdromMmcUpdateComplete. + InterlockedCompareExchange((PLONG)&(cdData->Mmc.UpdateState), + CdromMmcUpdateComplete, + CdromMmcUpdateStarted); + + return status; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +DeviceGetConfigurationWithAlloc( + _In_ WDFDEVICE Device, + _Outptr_result_bytebuffer_all_(*BytesReturned) + PGET_CONFIGURATION_HEADER* Buffer, // this routine allocates this memory + _Out_ PULONG BytesReturned, + FEATURE_NUMBER const StartingFeature, + ULONG const RequestedType + ) +/*++ + +Routine Description: + + This function will allocates configuration buffer and set the size. + +Arguments: + + Device - device object + Buffer - to be allocated by this function + BytesReturned - size of the buffer + StartingFeature - the starting point of the feature list + RequestedType - + +Return Value: + + NTSTATUS + +NOTE: does not handle case where more than 65000 bytes are returned, + which requires multiple calls with different starting feature + numbers. + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + GET_CONFIGURATION_HEADER header = {0}; // eight bytes, not a lot + PGET_CONFIGURATION_HEADER buffer = NULL; + ULONG returned = 0; + ULONG size = 0; + ULONG i = 0; + + PAGED_CODE(); + + *Buffer = NULL; + *BytesReturned = 0; + + // send the first request down to just get the header + status = DeviceGetConfiguration(Device, + &header, + sizeof(header), + &returned, + StartingFeature, + RequestedType); + + // now send command again, using information returned to allocate just enough memory + if (NT_SUCCESS(status)) + { + size = header.DataLength[0] << 24 | + header.DataLength[1] << 16 | + header.DataLength[2] << 8 | + header.DataLength[3] << 0 ; + + // the loop is in case that the retrieved data length is bigger than last time reported. + for (i = 0; (i < 4) && NT_SUCCESS(status); i++) + { + // the datalength field is the size *following* itself, so adjust accordingly + size += 4*sizeof(UCHAR); + + // make sure the size is reasonable + if (size <= sizeof(FEATURE_HEADER)) + { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, + "DeviceGetConfigurationWithAlloc: drive reports only %x bytes?\n", + size)); + status = STATUS_UNSUCCESSFUL; + } + + if (NT_SUCCESS(status)) + { + // allocate the memory + buffer = (PGET_CONFIGURATION_HEADER)ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned, + size, + CDROM_TAG_FEATURE); + + if (buffer == NULL) + { + status = STATUS_INSUFFICIENT_RESOURCES; + } + } + + if (NT_SUCCESS(status)) + { + // send the first request down to just get the header + status = DeviceGetConfiguration(Device, + buffer, + size, + &returned, + StartingFeature, + RequestedType); + + if (!NT_SUCCESS(status)) + { + ExFreePool(buffer); + } + else if (returned > size) + { + ExFreePool(buffer); + status = STATUS_INTERNAL_ERROR; + } + } + + // command succeeded. + if (NT_SUCCESS(status)) + { + returned = buffer->DataLength[0] << 24 | + buffer->DataLength[1] << 16 | + buffer->DataLength[2] << 8 | + buffer->DataLength[3] << 0 ; + returned += 4*sizeof(UCHAR); + + if (returned <= size) + { + *Buffer = buffer; + *BytesReturned = returned; // amount of 'safe' memory + // succes, get out of loop. + status = STATUS_SUCCESS; + break; + } + else + { + // the data size is bigger than the buffer size, retry using new size.... + size = returned; + ExFreePool(buffer); + buffer = NULL; + } + } + } // end of for() loop + } + + if (!NT_SUCCESS(status)) + { + // it failed after a number of attempts, so just fail. + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, + "DeviceGetConfigurationWithAlloc: Failed %d attempts to get all feature " + "information\n", i)); + } + + return status; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +DeviceGetConfiguration( + _In_ WDFDEVICE Device, + _Out_writes_bytes_to_(BufferSize, *ValidBytes) + PGET_CONFIGURATION_HEADER Buffer, + _In_ ULONG const BufferSize, + _Out_ PULONG ValidBytes, + _In_ FEATURE_NUMBER const StartingFeature, + _In_ ULONG const RequestedType + ) +/*++ + +Routine Description: + + This function is used to get configuration data. + +Arguments: + + Device - device object + Buffer - buffer address to hold data. + BufferSize - size of the buffer + ValidBytes - valid data size in buffer + StartingFeature - the starting point of the feature list + RequestedType - + +Return Value: + + NTSTATUS + +NOTE: does not handle case where more than 64k bytes are returned, + which requires multiple calls with different starting feature + numbers. + +--*/ +{ + NTSTATUS status; + PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(Device); + SCSI_REQUEST_BLOCK srb; + PCDB cdb = (PCDB)srb.Cdb; + + PAGED_CODE(); + + NT_ASSERT(ValidBytes); + + // when system is low resources we can receive empty buffer + if (Buffer == NULL || BufferSize < sizeof(GET_CONFIGURATION_HEADER)) + { + return STATUS_BUFFER_TOO_SMALL; + } + + *ValidBytes = 0; + + RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK)); + RtlZeroMemory(Buffer, BufferSize); + + if (TEST_FLAG(deviceExtension->DeviceAdditionalData.HackFlags, CDROM_HACK_BAD_GET_CONFIG_SUPPORT)) + { + return STATUS_INVALID_DEVICE_REQUEST; + } + +#pragma warning(push) +#pragma warning(disable: 6386) // OACR will complain buffer overrun: the writable size is 'BufferSize' bytes, but '65532' + // bytes might be written, which is impossible because BufferSize > 0xFFFC. + + if (BufferSize > 0xFFFC) + { + // cannot request more than 0xFFFC bytes in one request + // Eventually will "stitch" together multiple requests if needed + // Today, no drive has anywhere close to 4k..... + return DeviceGetConfiguration(Device, + Buffer, + 0xFFFC, + ValidBytes, + StartingFeature, + RequestedType); + } +#pragma warning(pop) + + //Start real work + srb.TimeOutValue = CDROM_GET_CONFIGURATION_TIMEOUT; + srb.CdbLength = 10; + + cdb->GET_CONFIGURATION.OperationCode = SCSIOP_GET_CONFIGURATION; + cdb->GET_CONFIGURATION.RequestType = (UCHAR)RequestedType; + cdb->GET_CONFIGURATION.StartingFeature[0] = (UCHAR)(StartingFeature >> 8); + cdb->GET_CONFIGURATION.StartingFeature[1] = (UCHAR)(StartingFeature & 0xff); + cdb->GET_CONFIGURATION.AllocationLength[0] = (UCHAR)(BufferSize >> 8); + cdb->GET_CONFIGURATION.AllocationLength[1] = (UCHAR)(BufferSize & 0xff); + + status = DeviceSendSrbSynchronously(Device, + &srb, + Buffer, + BufferSize, + FALSE, + NULL); + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, + "DeviceGetConfiguration: Status was %x\n", status)); + + if (NT_SUCCESS(status) || + (status == STATUS_BUFFER_OVERFLOW) || + (status == STATUS_DATA_OVERRUN)) + { + ULONG returned = srb.DataTransferLength; + PGET_CONFIGURATION_HEADER header = (PGET_CONFIGURATION_HEADER)Buffer; + ULONG available = (header->DataLength[0] << (8*3)) | + (header->DataLength[1] << (8*2)) | + (header->DataLength[2] << (8*1)) | + (header->DataLength[3] << (8*0)) ; + + available += RTL_SIZEOF_THROUGH_FIELD(GET_CONFIGURATION_HEADER, DataLength); + + _Analysis_assume_(srb.DataTransferLength <= BufferSize); + + // The true usable amount of data returned is the lesser of + // * the returned data per the srb.DataTransferLength field + // * the total size per the GET_CONFIGURATION_HEADER + // This is because ATAPI can't tell how many bytes really + // were transferred on success when using DMA. + if (available < returned) + { + returned = available; + } + + NT_ASSERT(returned <= BufferSize); + *ValidBytes = (ULONG)returned; + + //This is succeed case + status = STATUS_SUCCESS; + } + else + { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, + "DeviceGetConfiguration: failed %x\n", status)); + } + + return status; +} + + +_IRQL_requires_max_(APC_LEVEL) +VOID +DeviceUpdateMmcWriteCapability( + _In_reads_bytes_(BufferSize) + PGET_CONFIGURATION_HEADER Buffer, + ULONG const BufferSize, + BOOLEAN const CurrentOnly, // TRUE == can drive write now, FALSE == can drive ever write + _Out_ PBOOLEAN Writable, + _Out_ PFEATURE_NUMBER ValidationSchema, + _Out_ PULONG BlockingFactor + ) +/*++ + +Routine Description: + + This function will allocates configuration buffer and set the size. + +Arguments: + + Buffer - + BufferSize - size of the buffer + CurrentOnly - valid data size in buffer + Writable - the buffer is allocationed in non-paged pool. + validationSchema - the starting point of the feature list + BlockingFactor - + +Return Value: + + NTSTATUS + +NOTE: does not handle case where more than 64k bytes are returned, + which requires multiple calls with different starting feature + numbers. + +--*/ +{ + // + // this routine is used to check if the drive can currently (current==TRUE) + // or can ever (current==FALSE) write to media with the current CDROM.SYS + // driver. this check parses the GET_CONFIGURATION response data to search + // for the appropriate features and/or if they are current. + // + // this function should not allocate any resources, and thus may safely + // return from any point within the function. + // + PAGED_CODE(); + + *Writable = FALSE; + *ValidationSchema = 0; + *BlockingFactor = 1; + + // + // if the drive supports hardware defect management and random writes, that's + // sufficient to allow writes. + // + { + PFEATURE_HEADER defectHeader; + PFEATURE_HEADER writableHeader; + + defectHeader = MmcDataFindFeaturePage(Buffer, + BufferSize, + FeatureDefectManagement); + writableHeader = MmcDataFindFeaturePage(Buffer, + BufferSize, + FeatureRandomWritable); + + if (defectHeader == NULL || writableHeader == NULL) + { + // cannot write this way + } + else if (!CurrentOnly) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, + "DeviceUpdateMmcWriteCapability => Writes supported (defect management)\n")); + *Writable = TRUE; + return; + } + else if (defectHeader->Current && writableHeader->Current) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, + "DeviceUpdateMmcWriteCapability => Writes *allowed* (defect management)\n")); + *Writable = TRUE; + *ValidationSchema = FeatureDefectManagement; + return; + } + } + + // Certain validation schema require the blocking factor + // This is a best-effort attempt to ensure that illegal + // requests do not make it to drive + { + PFEATURE_HEADER header; + ULONG additionalLength; + + // Certain validation schema require the blocking factor + // This is a best-effort attempt to ensure that illegal + // requests do not make it to drive + additionalLength = RTL_SIZEOF_THROUGH_FIELD(FEATURE_DATA_RANDOM_READABLE, Blocking) - sizeof(FEATURE_HEADER); + + header = MmcDataFindFeaturePage(Buffer, + BufferSize, + FeatureRandomReadable); + + if ((header != NULL) && + (header->Current) && + (header->AdditionalLength >= additionalLength)) + { + PFEATURE_DATA_RANDOM_READABLE feature = (PFEATURE_DATA_RANDOM_READABLE)header; + *BlockingFactor = (feature->Blocking[0] << 8) | feature->Blocking[1]; + } + } + + // the majority of features to indicate write capability + // indicate this by a single feature existance/current bit. + // thus, can use a table-based method for the majority + // of the detection.... + { + typedef struct { + FEATURE_NUMBER FeatureToFind; // the ones allowed + FEATURE_NUMBER ValidationSchema; // and their related schema + } FEATURE_TO_WRITE_SCHEMA_MAP; + + static FEATURE_TO_WRITE_SCHEMA_MAP const FeaturesToAllowWritesWith[] = { + { FeatureRandomWritable, FeatureRandomWritable }, + { FeatureRigidRestrictedOverwrite, FeatureRigidRestrictedOverwrite }, + { FeatureRestrictedOverwrite, FeatureRestrictedOverwrite }, + { FeatureIncrementalStreamingWritable, FeatureIncrementalStreamingWritable }, + }; + + ULONG count; + for (count = 0; count < RTL_NUMBER_OF(FeaturesToAllowWritesWith); count++) + { + PFEATURE_HEADER header = MmcDataFindFeaturePage(Buffer, + BufferSize, + FeaturesToAllowWritesWith[count].FeatureToFind); + if (header == NULL) + { + // cannot write using this method + } + else if (!CurrentOnly) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, + "DeviceUpdateMmcWriteCapability => Writes supported (feature %04x)\n", + FeaturesToAllowWritesWith[count].FeatureToFind + )); + *Writable = TRUE; + return; + } + else if (header->Current) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, + "DeviceUpdateMmcWriteCapability => Writes *allowed* (feature %04x)\n", + FeaturesToAllowWritesWith[count].FeatureToFind + )); + *Writable = TRUE; + *ValidationSchema = FeaturesToAllowWritesWith[count].ValidationSchema; + return; + } + } // end count loop + } + + // unfortunately, DVD+R media doesn't require IncrementalStreamingWritable feature + // to be explicitly set AND it has a seperate bit in the feature to indicate + // being able to write to this media type. Thus, use a special case of the above code. + { + PFEATURE_DATA_DVD_PLUS_R header; + ULONG additionalLength = FIELD_OFFSET(FEATURE_DATA_DVD_PLUS_R, Reserved2[0]) - sizeof(FEATURE_HEADER); + header = MmcDataFindFeaturePage(Buffer, + BufferSize, + FeatureDvdPlusR); + + if (header == NULL || (header->Header.AdditionalLength < additionalLength) || (!header->Write)) + { + // cannot write this way + } + else if (!CurrentOnly) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, + "DeviceUpdateMmcWriteCapability => Writes supported (feature %04x)\n", + FeatureDvdPlusR + )); + *Writable = TRUE; + return; + } + else if (header->Header.Current) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, + "DeviceUpdateMmcWriteCapability => Writes *allowed* (feature %04x)\n", + FeatureDvdPlusR + )); + *Writable = TRUE; + *ValidationSchema = FeatureIncrementalStreamingWritable; + return; + } + } + + // unfortunately, DVD+R DL media doesn't require IncrementalStreamingWritable feature + // to be explicitly set AND it has a seperate bit in the feature to indicate + // being able to write to this media type. Thus, use a special case of the above code. + { + PFEATURE_DATA_DVD_PLUS_R_DUAL_LAYER header; + ULONG additionalLength = FIELD_OFFSET(FEATURE_DATA_DVD_PLUS_R_DUAL_LAYER, Reserved2[0]) - sizeof(FEATURE_HEADER); + header = MmcDataFindFeaturePage(Buffer, + BufferSize, + FeatureDvdPlusRDualLayer); + + if (header == NULL || (header->Header.AdditionalLength < additionalLength) || (!header->Write)) + { + // cannot write this way + } + else if (!CurrentOnly) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, + "DeviceUpdateMmcWriteCapability => Writes supported (feature %04x)\n", + FeatureDvdPlusRDualLayer + )); + *Writable = TRUE; + return; + } + else if (header->Header.Current) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, + "DeviceUpdateMmcWriteCapability => Writes *allowed* (feature %04x)\n", + FeatureDvdPlusRDualLayer + )); + *Writable = TRUE; + *ValidationSchema = FeatureIncrementalStreamingWritable; + return; + } + } + + // There are currently a number of drives on the market + // that fail to report: + // (a) FeatureIncrementalStreamingWritable as current + // for CD-R / DVD-R profile. + // (b) FeatureRestrictedOverwrite as current for CD-RW + // profile + // (c) FeatureRigidRestrictedOverwrite as current for + // DVD-RW profile + // + // Thus, use the profiles also. + { + PFEATURE_HEADER header; + header = MmcDataFindFeaturePage(Buffer, + BufferSize, + FeatureProfileList); + + if (header != NULL && header->Current) + { + // verify buffer bounds -- the below routine presumes full profile list provided + PUCHAR bufferEnd = ((PUCHAR)Buffer) + BufferSize; + PUCHAR headerEnd = ((PUCHAR)header) + header->AdditionalLength + RTL_SIZEOF_THROUGH_FIELD(FEATURE_HEADER, AdditionalLength); + if (bufferEnd >= headerEnd) // this _should_ never occurr, but.... + { + // Profiles don't contain any data other than current/not current. + // thus, can generically loop through them to see if any of the + // below (in order of preference) are current. + typedef struct { + FEATURE_PROFILE_TYPE ProfileToFind; // the ones allowed + FEATURE_NUMBER ValidationSchema; // and their related schema + } PROFILE_TO_WRITE_SCHEMA_MAP; + + static PROFILE_TO_WRITE_SCHEMA_MAP const ProfilesToAllowWritesWith[] = { + { ProfileDvdRewritable, FeatureRigidRestrictedOverwrite }, + { ProfileCdRewritable, FeatureRestrictedOverwrite }, + { ProfileDvdRecordable, FeatureIncrementalStreamingWritable }, + { ProfileCdRecordable, FeatureIncrementalStreamingWritable }, + }; + + ULONG count; + for (count = 0; count < RTL_NUMBER_OF(ProfilesToAllowWritesWith); count++) + { + BOOLEAN exists = FALSE; + MmcDataFindProfileInProfiles((PFEATURE_DATA_PROFILE_LIST)header, + ProfilesToAllowWritesWith[count].ProfileToFind, + CurrentOnly, + &exists); + if (exists) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, + "DeviceUpdateMmcWriteCapability => Writes %s (profile %04x)\n", + (CurrentOnly ? "*allowed*" : "supported"), + FeatureDvdPlusR + )); + + *Writable = TRUE; + *ValidationSchema = ProfilesToAllowWritesWith[count].ValidationSchema; + return; + } + } // end count loop + } // end if (bufferEnd >= headerEnd) + + } // end if (header != NULL && header->Current) + } + + // nothing matched to say it's writable..... + return; +} + +_IRQL_requires_max_(APC_LEVEL) +PVOID +MmcDataFindFeaturePage( + _In_reads_bytes_(Length) + PGET_CONFIGURATION_HEADER FeatureBuffer, + ULONG const Length, + FEATURE_NUMBER const Feature + ) +/*++ + +Routine Description: + + search the specific feature from feature list buffer + +Arguments: + + FeatureBuffer - buffer of feature list + Length - size of the buffer + Feature - feature wanted to find + +Return Value: + + PVOID - if found, pointer of starting address of the specific feature. + otherwise, NULL. + +--*/ +{ + PUCHAR buffer; + PUCHAR limit; + ULONG validLength; + + PAGED_CODE(); + + if (Length < sizeof(GET_CONFIGURATION_HEADER) + sizeof(FEATURE_HEADER)) { + return NULL; + } + + // Calculate the length of valid data available in the + // capabilities buffer from the DataLength field + REVERSE_BYTES(&validLength, FeatureBuffer->DataLength); + validLength += RTL_SIZEOF_THROUGH_FIELD(GET_CONFIGURATION_HEADER, DataLength); + + // set limit to point to first illegal address + limit = (PUCHAR)FeatureBuffer; + limit += min(Length, validLength); + + // set buffer to point to first page + buffer = FeatureBuffer->Data; + + // loop through each page until we find the requested one, or + // until it's not safe to access the entire feature header + // (if equal, have exactly enough for the feature header) + while (buffer + sizeof(FEATURE_HEADER) <= limit) + { + PFEATURE_HEADER header = (PFEATURE_HEADER)buffer; + FEATURE_NUMBER thisFeature; + + thisFeature = (header->FeatureCode[0] << 8) | + (header->FeatureCode[1]); + + if (thisFeature == Feature) + { + PUCHAR temp; + + // if don't have enough memory to safely access all the feature + // information, return NULL + temp = buffer; + temp += sizeof(FEATURE_HEADER); + temp += header->AdditionalLength; + + if (temp > limit) + { + // this means the transfer was cut-off, an insufficiently + // small buffer was given, or other arbitrary error. since + // it's not safe to view the amount of data (even though + // the header is safe) in this feature, pretend it wasn't + // transferred at all... + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, + "Feature %x exists, but not safe to access all its " + "data. returning NULL\n", Feature)); + return NULL; + } + else + { + return buffer; + } + } + + if ((header->AdditionalLength % 4) && + !(Feature >= 0xff00 && Feature <= 0xffff)) + { + return NULL; + } + + buffer += sizeof(FEATURE_HEADER); + buffer += header->AdditionalLength; + + } + return NULL; +} + +_IRQL_requires_max_(APC_LEVEL) +VOID +MmcDataFindProfileInProfiles( + _In_ FEATURE_DATA_PROFILE_LIST const* ProfileHeader, + _In_ FEATURE_PROFILE_TYPE const ProfileToFind, + _In_ BOOLEAN const CurrentOnly, + _Out_ PBOOLEAN Found + ) +/*++ + +Routine Description: + + search the specific feature from feature list buffer + +Arguments: + + ProfileHeader - buffer of profile list + ProfileToFind - profile to be found + CurrentOnly - + +Return Value: + + Found - found or not + +--*/ +{ + FEATURE_DATA_PROFILE_LIST_EX const * profile; + ULONG numberOfProfiles; + ULONG i; + + PAGED_CODE(); + + // initialize output + *Found = FALSE; + + // sanity check + if (ProfileHeader->Header.AdditionalLength % 2 != 0) + { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, + "Profile total length %x is not integral multiple of 4\n", + ProfileHeader->Header.AdditionalLength)); + NT_ASSERT(FALSE); + return; + } + + // calculate number of profiles + numberOfProfiles = ProfileHeader->Header.AdditionalLength / 4; + profile = ProfileHeader->Profiles; // zero-sized array + + // loop through profiles + for (i = 0; i < numberOfProfiles; i++) + { + FEATURE_PROFILE_TYPE currentProfile; + + currentProfile = (profile->ProfileNumber[0] << 8) | + (profile->ProfileNumber[1] & 0xff); + + if (currentProfile == ProfileToFind) + { + if (profile->Current || (!CurrentOnly)) + { + *Found = TRUE; + } + } + + profile++; + } + + return; +} + +_IRQL_requires_max_(APC_LEVEL) +_Ret_range_(-1,MAXIMUM_RETRY_FOR_SINGLE_IO_IN_100NS_UNITS) +LONGLONG +DeviceRetryTimeGuessBasedOnProfile( + FEATURE_PROFILE_TYPE const Profile + ) +/*++ + +Routine Description: + + determine the retry time based on profile + +Arguments: + + Profile - + +Return Value: + + LONGLONG - retry time + +--*/ +{ + LONGLONG result = -1; // this means we have no idea + + PAGED_CODE(); + + switch (Profile) + { + case ProfileInvalid: // = 0x0000, + case ProfileNonRemovableDisk: // = 0x0001, + case ProfileRemovableDisk: // = 0x0002, + case ProfileMOErasable: // = 0x0003, + case ProfileMOWriteOnce: // = 0x0004, + case ProfileAS_MO: // = 0x0005, + // Reserved 0x0006 - 0x0007, + // Reserved 0x000b - 0x000f, + // Reserved 0x0017 - 0x0019 + // Reserved 0x001C - 001F + // Reserved 0x0023 - 0x0029 + // Reserved 0x002C - 0x003F + // Reserved 0x0044 - 0x004F + // Reserved 0x0053 - 0xfffe + case ProfileNonStandard: // = 0xffff + default: + { + NOTHING; // no default + break; + } + + case ProfileCdrom: // = 0x0008, + case ProfileCdRecordable: // = 0x0009, + case ProfileCdRewritable: // = 0x000a, + case ProfileDDCdrom: // = 0x0020, // obsolete + case ProfileDDCdRecordable: // = 0x0021, // obsolete + case ProfileDDCdRewritable: // = 0x0022, // obsolete + { + // 4x is ok as all CD drives have + // at least 64k*4 (256k) buffer + // and this is just a first-pass + // guess based only on profile + result = WRITE_RETRY_DELAY_CD_4x; + break; + } + case ProfileDvdRom: // = 0x0010, + case ProfileDvdRecordable: // = 0x0011, + case ProfileDvdRam: // = 0x0012, + case ProfileDvdRewritable: // = 0x0013, // restricted overwrite + case ProfileDvdRWSequential: // = 0x0014, + case ProfileDvdDashRLayerJump: // = 0x0016, + case ProfileDvdPlusRW: // = 0x001A, + case ProfileDvdPlusR: // = 0x001B, + { + result = WRITE_RETRY_DELAY_DVD_1x; + break; + } + case ProfileDvdDashRDualLayer: // = 0x0015, + case ProfileDvdPlusRWDualLayer: // = 0x002A, + case ProfileDvdPlusRDualLayer: // = 0x002B, + { + result = WRITE_RETRY_DELAY_DVD_1x; + break; + } + + case ProfileBDRom: // = 0x0040, + case ProfileBDRSequentialWritable: // = 0x0041, // BD-R 'SRM' + case ProfileBDRRandomWritable: // = 0x0042, // BD-R 'RRM' + case ProfileBDRewritable: // = 0x0043, + { + // I could not find specifications for the + // minimal 1x data rate for BD media. Use + // HDDVD values for now, since they are + // likely to be similar. Also, all media + // except for CD, DVD, and AS-MO should + // already fully support GET_CONFIG, so + // this guess is only used if we fail to + // get a performance descriptor.... + result = WRITE_RETRY_DELAY_HDDVD_1x; + break; + } + + case ProfileHDDVDRom: // = 0x0050, + case ProfileHDDVDRecordable: // = 0x0051, + case ProfileHDDVDRam: // = 0x0052, + { + // All HDDVD drives support GET_PERFORMANCE + // so this guess is fine at 1x.... + result = WRITE_RETRY_DELAY_HDDVD_1x; + break; + } + + // addition of any further profile types is not + // technically required as GET PERFORMANCE + // should succeed for all future drives. However, + // it is useful in case GET PERFORMANCE does + // fail for other reasons (i.e. bus resets, etc) + + } // end switch(Profile) + + return result; +} + +_IRQL_requires_max_(APC_LEVEL) +_Ret_range_(-1,MAXIMUM_RETRY_FOR_SINGLE_IO_IN_100NS_UNITS) +LONGLONG +DeviceRetryTimeDetectionBasedOnModePage2A( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension + ) +/*++ + +Routine Description: + + determine the retry time based on mode sense data + +Arguments: + + DeviceExtension - device context + +Return Value: + + LONGLONG - retry time + +--*/ +{ + NTSTATUS status; + ULONG transferSize = min(0xFFF0, DeviceExtension->ScratchContext.ScratchBufferSize); + CDB cdb; + LONGLONG result = -1; + + PAGED_CODE(); + + ScratchBuffer_BeginUse(DeviceExtension); + + RtlZeroMemory(&cdb, sizeof(CDB)); + // Set up the CDB + cdb.MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10; + cdb.MODE_SENSE10.Dbd = 1; + cdb.MODE_SENSE10.PageCode = MODE_PAGE_CAPABILITIES; + cdb.MODE_SENSE10.AllocationLength[0] = (UCHAR)(transferSize >> 8); + cdb.MODE_SENSE10.AllocationLength[1] = (UCHAR)(transferSize & 0xFF); + + status = ScratchBuffer_ExecuteCdb(DeviceExtension, NULL, transferSize, TRUE, &cdb, 10); + + // analyze the data on success.... + if (NT_SUCCESS(status)) + { + MODE_PARAMETER_HEADER10 const* header = DeviceExtension->ScratchContext.ScratchBuffer; + CDVD_CAPABILITIES_PAGE const* page = NULL; + ULONG dataLength = (header->ModeDataLength[0] << (8*1)) | + (header->ModeDataLength[1] << (8*0)) ; + + // no possible overflow + if (dataLength != 0) + { + dataLength += RTL_SIZEOF_THROUGH_FIELD(MODE_PARAMETER_HEADER10, ModeDataLength); + } + + // If it's not abundantly clear, we really don't trust the drive + // to be returning valid data. Get the page pointer and usable + // size of the page here... + if (dataLength < sizeof(MODE_PARAMETER_HEADER10)) + { + dataLength = 0; + } + else if (dataLength > DeviceExtension->ScratchContext.ScratchBufferSize) + { + dataLength = 0; + } + else if ((header->BlockDescriptorLength[1] == 0) && + (header->BlockDescriptorLength[0] == 0)) + { + dataLength -= sizeof(MODE_PARAMETER_HEADER10); + page = (CDVD_CAPABILITIES_PAGE const *)(header + 1); + } + else if ((header->BlockDescriptorLength[1] == 0) && + (header->BlockDescriptorLength[0] == sizeof(MODE_PARAMETER_BLOCK))) + { + dataLength -= sizeof(MODE_PARAMETER_HEADER10); + dataLength -= min(dataLength, sizeof(MODE_PARAMETER_BLOCK)); + page = (CDVD_CAPABILITIES_PAGE const *) + ( ((PUCHAR)header) + + sizeof(MODE_PARAMETER_HEADER10) + + sizeof(MODE_PARAMETER_BLOCK) + ); + } + + // Change dataLength from the size available per the header to + // the size available per the page itself. + if ((page != NULL) && + (dataLength >= RTL_SIZEOF_THROUGH_FIELD(CDVD_CAPABILITIES_PAGE, PageLength)) + ) + { + dataLength = min(dataLength, ((ULONG)(page->PageLength) + 2)); + } + + // Ignore the page if the fastest write speed field isn't available. + if ((page != NULL) && + (dataLength < RTL_SIZEOF_THROUGH_FIELD(CDVD_CAPABILITIES_PAGE, WriteSpeedMaximum)) + ) + { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT, + "ModePage 2Ah was requested, but drive reported " + "only %x bytes (%x needed). Ignoring.\n", + dataLength, + RTL_SIZEOF_THROUGH_FIELD(CDVD_CAPABILITIES_PAGE, WriteSpeedMaximum) + )); + page = NULL; + } + + // Verify the page we requested is the one the drive actually provided + if ((page != NULL) && (page->PageCode != MODE_PAGE_CAPABILITIES)) + { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT, + "ModePage 2Ah was requested, but drive reported " + "page %x\n", + page->PageCode + )); + page = NULL; + } + + // If _everything_ succeeded, then use the speed value in the page! + if (page != NULL) + { + ULONG temp = + (page->WriteSpeedMaximum[0] << (8*1)) | + (page->WriteSpeedMaximum[1] << (8*0)) ; + // stored as 1,000 byte increments... + temp *= 1000; + // typically stored at 2448 bytes/sector due to CD media + // error up to 20% high by presuming it returned 2048 data + // and convert to sectors/second + temp /= 2048; + // currently: sectors/sec + // ignore too-small or zero values + if (temp != 0) + { + result = ConvertSectorsPerSecondTo100nsUnitsFor64kWrite(temp); + } + } + } + + ScratchBuffer_EndUse(DeviceExtension); + + return result; +} + + +_IRQL_requires_max_(APC_LEVEL) +_Ret_range_(-1,MAXIMUM_RETRY_FOR_SINGLE_IO_IN_100NS_UNITS) +LONGLONG +DeviceRetryTimeDetectionBasedOnGetPerformance( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ BOOLEAN UseLegacyNominalPerformance + ) +/*++ + +Routine Description: + + determine the retry time based on get performance data + +Arguments: + + DeviceExtension - device context + UseLegacyNominalPerformance - + +Return Value: + + LONGLONG - retry time + +--*/ +{ + typedef struct _GET_PERFORMANCE_HEADER { + UCHAR TotalDataLength[4]; // not including this field + UCHAR Except : 1; + UCHAR Write : 1; + UCHAR Reserved0 : 6; + UCHAR Reserved1[3]; + } GET_PERFORMANCE_HEADER, *PGET_PERFORMANCE_HEADER; + C_ASSERT( sizeof(GET_PERFORMANCE_HEADER) == 8); + + typedef struct _GET_PERFORMANCE_NOMINAL_PERFORMANCE_DESCRIPTOR { + UCHAR StartLba[4]; + UCHAR StartPerformance[4]; + UCHAR EndLba[4]; + UCHAR EndPerformance[4]; + } GET_PERFORMANCE_NOMINAL_PERFORMANCE_DESCRIPTOR, *PGET_PERFORMANCE_NOMINAL_PERFORMANCE_DESCRIPTOR; + C_ASSERT( sizeof(GET_PERFORMANCE_NOMINAL_PERFORMANCE_DESCRIPTOR) == 16); + + + typedef struct _GET_PERFORMANCE_WRITE_SPEED_DESCRIPTOR { + UCHAR MixedReadWrite : 1; + UCHAR GuaranteedForWholeMedia : 1; + UCHAR Reserved0_RDD : 1; + UCHAR WriteRotationControl : 2; + UCHAR Reserved1 : 3; + UCHAR Reserved2[3]; + + UCHAR MediaCapacity[4]; + UCHAR ReadSpeedKilobytesPerSecond[4]; + UCHAR WriteSpeedKilobytesPerSecond[4]; + } GET_PERFORMANCE_WRITE_SPEED_DESCRIPTOR, *PGET_PERFORMANCE_WRITE_SPEED_DESCRIPTOR; + C_ASSERT( sizeof(GET_PERFORMANCE_WRITE_SPEED_DESCRIPTOR) == 16); + + ////// + + NTSTATUS status; + LONGLONG result = -1; + + // transfer size -- descriptors + 8 byte header + // Note: this size is identical for both descriptor types + C_ASSERT( sizeof(GET_PERFORMANCE_WRITE_SPEED_DESCRIPTOR) == sizeof(GET_PERFORMANCE_NOMINAL_PERFORMANCE_DESCRIPTOR)); + + ULONG const maxDescriptors = min(200, (DeviceExtension->ScratchContext.ScratchBufferSize-sizeof(GET_PERFORMANCE_HEADER))/sizeof(GET_PERFORMANCE_WRITE_SPEED_DESCRIPTOR)); + ULONG validDescriptors = 0; + ULONG transferSize = sizeof(GET_PERFORMANCE_HEADER) + (maxDescriptors*sizeof(GET_PERFORMANCE_WRITE_SPEED_DESCRIPTOR)); + CDB cdb; + + PAGED_CODE(); + + ScratchBuffer_BeginUse(DeviceExtension); + + RtlZeroMemory(&cdb, sizeof(CDB)); + // Set up the CDB + if (UseLegacyNominalPerformance) + { + cdb.GET_PERFORMANCE.OperationCode = SCSIOP_GET_PERFORMANCE; + cdb.GET_PERFORMANCE.Except = 0; + cdb.GET_PERFORMANCE.Write = 1; + cdb.GET_PERFORMANCE.Tolerance = 2; // only defined option + cdb.GET_PERFORMANCE.MaximumNumberOfDescriptors[1] = (UCHAR)maxDescriptors; + cdb.GET_PERFORMANCE.Type = 0; // legacy nominal descriptors + } + else + { + cdb.GET_PERFORMANCE.OperationCode = SCSIOP_GET_PERFORMANCE; + cdb.GET_PERFORMANCE.MaximumNumberOfDescriptors[1] = (UCHAR)maxDescriptors; + cdb.GET_PERFORMANCE.Type = 3; // write speed + } + + status = ScratchBuffer_ExecuteCdbEx(DeviceExtension, NULL, transferSize, TRUE, &cdb, 12, CDROM_GET_PERFORMANCE_TIMEOUT); + + // determine how many valid descriptors there actually are + if (NT_SUCCESS(status)) + { + GET_PERFORMANCE_HEADER const* header = (GET_PERFORMANCE_HEADER const*)DeviceExtension->ScratchContext.ScratchBuffer; + ULONG temp1 = (header->TotalDataLength[0] << (8*3)) | + (header->TotalDataLength[1] << (8*2)) | + (header->TotalDataLength[2] << (8*1)) | + (header->TotalDataLength[3] << (8*0)) ; + + // adjust data size for header + if (temp1 + (ULONG)RTL_SIZEOF_THROUGH_FIELD(GET_PERFORMANCE_HEADER, TotalDataLength) < temp1) + { + temp1 = 0; + } + else if (temp1 != 0) + { + temp1 += RTL_SIZEOF_THROUGH_FIELD(GET_PERFORMANCE_HEADER, TotalDataLength); + } + + if (temp1 == 0) + { + // no data returned + } + else if (temp1 <= sizeof(GET_PERFORMANCE_HEADER)) + { + // only the header returned, no descriptors + } + else if (UseLegacyNominalPerformance && + ((header->Except != 0) || (header->Write == 0)) + ) + { + // bad data being returned -- ignore it + } + else if (!UseLegacyNominalPerformance && + ((header->Except != 0) || (header->Write != 0)) + ) + { + // returning Performance (Type 0) data, not requested Write Speed (Type 3) data + } + else if ( (temp1 - sizeof(GET_PERFORMANCE_HEADER)) % sizeof(GET_PERFORMANCE_WRITE_SPEED_DESCRIPTOR) != 0) + { + // Note: this size is identical for both descriptor types + C_ASSERT( sizeof(GET_PERFORMANCE_WRITE_SPEED_DESCRIPTOR) == sizeof(GET_PERFORMANCE_NOMINAL_PERFORMANCE_DESCRIPTOR)); + + // not returning valid data.... + } + else // save how many are usable + { + // Note: this size is identical for both descriptor types + C_ASSERT( sizeof(GET_PERFORMANCE_WRITE_SPEED_DESCRIPTOR) == sizeof(GET_PERFORMANCE_NOMINAL_PERFORMANCE_DESCRIPTOR)); + + // take the smaller usable value + temp1 = min(temp1, DeviceExtension->ScratchContext.ScratchSrb->DataTransferLength); + // then determine the usable descriptors + validDescriptors = (temp1 - sizeof(GET_PERFORMANCE_HEADER)) / sizeof(GET_PERFORMANCE_WRITE_SPEED_DESCRIPTOR); + } + } + + // The drive likely supports this command. + // Verify the data makes sense. + if (NT_SUCCESS(status)) + { + ULONG i; + GET_PERFORMANCE_HEADER const* header = (GET_PERFORMANCE_HEADER const*)DeviceExtension->ScratchContext.ScratchBuffer; + GET_PERFORMANCE_WRITE_SPEED_DESCRIPTOR const* descriptor = (GET_PERFORMANCE_WRITE_SPEED_DESCRIPTOR const*)(header+1); // pointer math + + // NOTE: We could write this loop twice, once for each write descriptor type + // However, the only fields of interest are the writeKBps field (Type 3) and + // the EndPerformance field (Type 0), which both exist in the same exact + // location and have essentially the same meaning. So, just use the same + // loop/structure pointers for both of the to simplify the readability of + // this code. The C_ASSERT()s here verify this at compile-time. + + C_ASSERT( sizeof(GET_PERFORMANCE_WRITE_SPEED_DESCRIPTOR) == sizeof(GET_PERFORMANCE_NOMINAL_PERFORMANCE_DESCRIPTOR)); + C_ASSERT( FIELD_OFFSET(GET_PERFORMANCE_WRITE_SPEED_DESCRIPTOR, WriteSpeedKilobytesPerSecond) == + FIELD_OFFSET(GET_PERFORMANCE_NOMINAL_PERFORMANCE_DESCRIPTOR, EndPerformance) + ); + C_ASSERT( RTL_FIELD_SIZE(GET_PERFORMANCE_WRITE_SPEED_DESCRIPTOR, WriteSpeedKilobytesPerSecond) == + RTL_FIELD_SIZE(GET_PERFORMANCE_NOMINAL_PERFORMANCE_DESCRIPTOR, EndPerformance) + ); + + // loop through them all, and find the fastest listed write speed + for (i = 0; NT_SUCCESS(status) && (i WriteSpeedKilobytesPerSecond[0] << (8*3)) | + (descriptor->WriteSpeedKilobytesPerSecond[1] << (8*2)) | + (descriptor->WriteSpeedKilobytesPerSecond[2] << (8*1)) | + (descriptor->WriteSpeedKilobytesPerSecond[3] << (8*0)) ; + + // Avoid overflow and still have good estimates + // 0x1 0000 0000 / 1000 == 0x00418937 == maximum writeKBps to multiple first + ULONG const sectorsPerSecond = + (writeKBps > 0x00418937) ? // would overflow occur by multiplying by 1000? + ((writeKBps / 2048) * 1000) : // must divide first, minimal loss of accuracy + ((writeKBps * 1000) / 2048) ; // must multiply first, avoid loss of accuracy + + if (sectorsPerSecond <= 0) + { + break; // out of the loop -- no longer valid data (very defensive programming) + } + + // we have at least one valid result, so prevent returning -1 as our result + if (result == -1) { result = MAXIMUM_RETRY_FOR_SINGLE_IO_IN_100NS_UNITS; } + + // take the fastest speed (smallest wait time) we've found thus far + result = min(result, ConvertSectorsPerSecondTo100nsUnitsFor64kWrite(sectorsPerSecond)); + } + } + + ScratchBuffer_EndUse(DeviceExtension); + + return result; +} + +#pragma warning(pop) // un-sets any local warning changes diff --git a/storage/class/cdrom/src/mmc.h b/storage/class/cdrom/src/mmc.h new file mode 100644 index 00000000..51c03309 --- /dev/null +++ b/storage/class/cdrom/src/mmc.h @@ -0,0 +1,122 @@ +/*++ + +Copyright (C) Microsoft Corporation. All rights reserved. + +Module Name: + + mmc.h + +Abstract: + + Functions for MMC area. + +Author: + +Environment: + + kernel mode only + +Notes: + + +Revision History: + +--*/ + +#ifndef __MMC_H__ +#define __MMC_H__ + +_IRQL_requires_max_(APC_LEVEL) +VOID +DeviceDeallocateMmcResources( + _In_ WDFDEVICE Device + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +DeviceAllocateMmcResources( + _In_ WDFDEVICE Device + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +DeviceUpdateMmcCapabilities( + _In_ WDFDEVICE Device + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +DeviceGetConfigurationWithAlloc( + _In_ WDFDEVICE Device, + _Outptr_result_bytebuffer_all_(*BytesReturned) + PGET_CONFIGURATION_HEADER * Buffer, + _Out_ PULONG BytesReturned, + FEATURE_NUMBER const StartingFeature, + ULONG const RequestedType + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +DeviceGetConfiguration( + _In_ WDFDEVICE Device, + _Out_writes_bytes_to_(BufferSize, *ValidBytes) + PGET_CONFIGURATION_HEADER Buffer, + _In_ ULONG const BufferSize, + _Out_ PULONG ValidBytes, + _In_ FEATURE_NUMBER const StartingFeature, + _In_ ULONG const RequestedType + ); + +_IRQL_requires_max_(APC_LEVEL) +VOID +DeviceUpdateMmcWriteCapability( + _In_reads_bytes_(BufferSize) + PGET_CONFIGURATION_HEADER Buffer, + ULONG const BufferSize, + BOOLEAN const CurrentOnly, // TRUE == can drive write now, FALSE == can drive ever write + _Out_ PBOOLEAN Writable, + _Out_ PFEATURE_NUMBER ValidationSchema, + _Out_ PULONG BlockingFactor + ); + +_IRQL_requires_max_(APC_LEVEL) +PVOID +MmcDataFindFeaturePage( + _In_reads_bytes_(Length) + PGET_CONFIGURATION_HEADER FeatureBuffer, + ULONG const Length, + FEATURE_NUMBER const Feature + ); + +_IRQL_requires_max_(APC_LEVEL) +VOID +MmcDataFindProfileInProfiles( + _In_ FEATURE_DATA_PROFILE_LIST const* ProfileHeader, + _In_ FEATURE_PROFILE_TYPE const ProfileToFind, + _In_ BOOLEAN const CurrentOnly, + _Out_ PBOOLEAN Found + ); + +_IRQL_requires_max_(APC_LEVEL) +_Ret_range_(-1,MAXIMUM_RETRY_FOR_SINGLE_IO_IN_100NS_UNITS) +LONGLONG +DeviceRetryTimeGuessBasedOnProfile( + FEATURE_PROFILE_TYPE const Profile + ); + +_IRQL_requires_max_(APC_LEVEL) +_Ret_range_(-1,MAXIMUM_RETRY_FOR_SINGLE_IO_IN_100NS_UNITS) +LONGLONG +DeviceRetryTimeDetectionBasedOnModePage2A( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension + ); + +_IRQL_requires_max_(APC_LEVEL) +_Ret_range_(-1,MAXIMUM_RETRY_FOR_SINGLE_IO_IN_100NS_UNITS) +LONGLONG +DeviceRetryTimeDetectionBasedOnGetPerformance( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ BOOLEAN UseLegacyNominalPerformance + ); + +#endif // __MMC_H__ diff --git a/storage/class/cdrom/src/pnppower.c b/storage/class/cdrom/src/pnppower.c new file mode 100644 index 00000000..56f239e4 --- /dev/null +++ b/storage/class/cdrom/src/pnppower.c @@ -0,0 +1,684 @@ +/*-- + +Copyright (C) Microsoft Corporation. All rights reserved. + +Module Name: + + pnppower.c + +Abstract: + + Functions to handle PnP and Power IRPs. + +Environment: + + kernel mode only + +Notes: + optical devices do not need to issue SPIN UP when power up. + The device itself should SPIN UP to process commands. + + +Revision History: + +--*/ + + +#include "ntddk.h" +#include "wdfcore.h" + +#include "cdrom.h" +#include "ioctl.h" +#include "scratch.h" +#include "mmc.h" + +#ifdef DEBUG_USE_WPP +#include "pnppower.tmh" +#endif + + +NTSTATUS +DeviceScratchSyncCache( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension + ); + +NTSTATUS +DeviceScratchPreventMediaRemoval( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ BOOLEAN Prevent + ); + +NTSTATUS +RequestIssueShutdownFlush( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ PIRP Irp + ); + +IO_COMPLETION_ROUTINE RequestProcessPowerIrpCompletion; + +EVT_WDF_REQUEST_COMPLETION_ROUTINE RequestUnlockQueueCompletion; + +#ifdef ALLOC_PRAGMA + +#pragma alloc_text(PAGE, DevicePowerSettingCallback) + +#endif + +#pragma warning(push) +#pragma warning(disable:4152) // nonstandard extension, function/data pointer conversion in expression + +#pragma warning(disable:28118) // Dispatch routines for IRP_MJ_SHUTDOWN, IRP_MJ_FLUSH_BUFFERS occur at PASSIVE_LEVEL. + // WDF defines EVT_WDFDEVICE_WDM_IRP_PREPROCESS with _IRQL_requires_max_(DISPATCH_LEVEL), + // triggering a false positive for this warning. + +NTSTATUS +RequestProcessShutdownFlush( + WDFDEVICE Device, + PIRP Irp + ) +/*++ + +Routine Description: + + process IRP: IRP_MJ_SHUTDOWN, IRP_MJ_FLUSH_BUFFERS + +Arguments: + + Device - device object + Irp - the irp + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PIO_STACK_LOCATION currentStack = NULL; + PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(Device); + + //add trace info + + // acquire the shutdown/flush lock + WdfWaitLockAcquire(deviceExtension->ShutdownFlushWaitLock, NULL); + + currentStack = IoGetCurrentIrpStackLocation(Irp); + + // finish all current requests + WdfIoQueueStopSynchronously(deviceExtension->SerialIOQueue); + + // sync cache + if (NT_SUCCESS(status)) + { + // safe to use scratch srb to send the request. + status = DeviceScratchSyncCache(deviceExtension); + } + + // For SHUTDOWN, allow media removal. + if (NT_SUCCESS(status)) + { + if (currentStack->MajorFunction == IRP_MJ_SHUTDOWN) + { + // safe to use scratch srb to send the request. + status = DeviceScratchPreventMediaRemoval(deviceExtension, FALSE); + } + } + + // Use original IRP, send SRB_FUNCTION_SHUTDOWN or SRB_FUNCTION_FLUSH (no retry) + if (NT_SUCCESS(status)) + { + status = RequestIssueShutdownFlush(deviceExtension, Irp); + } + + // restart queue to allow processing further requests. + WdfIoQueueStart(deviceExtension->SerialIOQueue); + + // release the shutdown/flush lock + WdfWaitLockRelease(deviceExtension->ShutdownFlushWaitLock); + + // 6. complete the irp + Irp->IoStatus.Status = status; + IoCompleteRequest(Irp, 0); + + return status; +} + +NTSTATUS +RequestProcessSetPower( + WDFDEVICE Device, + PIRP Irp + ) +/*++ + +Routine Description: + + process IRP: IRP_MJ_POWER + +Arguments: + + Device - device object + Irp - the irp + +Return Value: + + NTSTATUS + +--*/ +{ + PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(Device); + PIO_STACK_LOCATION currentStack; + NTSTATUS status; + BOOLEAN IrpMarkedPending = FALSE; + + currentStack = IoGetCurrentIrpStackLocation(Irp); + + if ((currentStack->Parameters.Power.Type == DevicePowerState) && + (currentStack->Parameters.Power.State.DeviceState != PowerDeviceD0)) + { + // We need to unlock the device queue in D3 postprocessing. + IoCopyCurrentIrpStackLocationToNext(Irp); + IoSetCompletionRoutine(Irp, + RequestProcessPowerIrpCompletion, + deviceExtension, + TRUE, + TRUE, + TRUE); + + // Mark the Irp pending as we'll defer the I/O completion. + IoMarkIrpPending(Irp); + IrpMarkedPending = TRUE; + } + else { + + IoSkipCurrentIrpStackLocation(Irp); + } + +#pragma warning(push) +#pragma warning(disable: 28193) // OACR will complain that the status variable is not examined. + + // + // Deliver the IRP back to the framework. + // + + status = WdfDeviceWdmDispatchPreprocessedIrp(Device, Irp); + + if (IrpMarkedPending) + { + UNREFERENCED_PARAMETER(status); + return STATUS_PENDING; + } + +#pragma warning(pop) + + return status; +} + +// use scratch SRB to issue SYNC CACHE command. +NTSTATUS +DeviceScratchSyncCache( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension + ) +/*++ + +Routine Description: + + use scratch buffer to send SYNC CACHE command + +Arguments: + + DeviceExtension - device context + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + ULONG transferSize = 0; + CDB cdb; + + ScratchBuffer_BeginUse(DeviceExtension); + + RtlZeroMemory(&cdb, sizeof(CDB)); + // Set up the CDB + cdb.SYNCHRONIZE_CACHE10.OperationCode = SCSIOP_SYNCHRONIZE_CACHE; + //srb->QueueTag = SP_UNTAGGED; + //srb->QueueAction = SRB_SIMPLE_TAG_REQUEST; + + status = ScratchBuffer_ExecuteCdbEx(DeviceExtension, NULL, transferSize, FALSE, &cdb, 10, TimeOutValueGetCapValue(DeviceExtension->TimeOutValue, 4)); + + ScratchBuffer_EndUse(DeviceExtension); + + return status; +} + +NTSTATUS +DeviceScratchPreventMediaRemoval( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ BOOLEAN Prevent + ) +/*++ + +Routine Description: + + use scratch SRB to issue ALLOW/PREVENT MEDIA REMOVAL command. + +Arguments: + + DeviceExtension - device context + Prevent - TRUE (prevent media removal); FALSE (allow media removal) + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + ULONG transferSize = 0; + CDB cdb; + + ScratchBuffer_BeginUse(DeviceExtension); + + RtlZeroMemory(&cdb, sizeof(CDB)); + // Set up the CDB + cdb.MEDIA_REMOVAL.OperationCode = SCSIOP_MEDIUM_REMOVAL; + cdb.MEDIA_REMOVAL.Prevent = Prevent; + //srb->QueueTag = SP_UNTAGGED; + //srb->QueueAction = SRB_SIMPLE_TAG_REQUEST; + + status = ScratchBuffer_ExecuteCdb(DeviceExtension, NULL, transferSize, FALSE, &cdb, 6); + + ScratchBuffer_EndUse(DeviceExtension); + + return status; +} + +NTSTATUS +RequestIssueShutdownFlush( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ PIRP Irp + ) +/*++ + +Routine Description: + + issue SRB function Flush/Shutdown command. + +Arguments: + + DeviceExtension - device context + Irp - the irp + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PSCSI_REQUEST_BLOCK srb = DeviceExtension->ScratchContext.ScratchSrb; + PIO_STACK_LOCATION currentStack = NULL; + + ULONG transferSize = 0; + BOOLEAN shouldRetry = TRUE; + ULONG timesAlreadyRetried = 0; + LONGLONG retryIn100nsUnits = 0; + + + currentStack = IoGetCurrentIrpStackLocation(Irp); + + + ScratchBuffer_BeginUse(DeviceExtension); + + // no retry needed. + { + ScratchBuffer_SetupSrb(DeviceExtension, NULL, transferSize, FALSE); + + // Set up the SRB/CDB + srb->QueueTag = SP_UNTAGGED; + srb->QueueAction = SRB_SIMPLE_TAG_REQUEST; + srb->TimeOutValue = TimeOutValueGetCapValue(DeviceExtension->TimeOutValue, 4); + srb->CdbLength = 0; + + if (currentStack->MajorFunction == IRP_MJ_SHUTDOWN) + { + srb->Function = SRB_FUNCTION_SHUTDOWN; + } + else + { + srb->Function = SRB_FUNCTION_FLUSH; + } + + ScratchBuffer_SendSrb(DeviceExtension, TRUE, NULL); + + shouldRetry = RequestSenseInfoInterpretForScratchBuffer(DeviceExtension, + timesAlreadyRetried, + &status, + &retryIn100nsUnits); + UNREFERENCED_PARAMETER(shouldRetry); //defensive coding, avoid PREFAST warning. + UNREFERENCED_PARAMETER(status); //defensive coding, avoid PREFAST warning. + + // retrieve the real status from the request. + status = WdfRequestGetStatus(DeviceExtension->ScratchContext.ScratchRequest); + } + + ScratchBuffer_EndUse(DeviceExtension); + + + return status; +} + +VOID +RequestUnlockQueueCompletion ( + _In_ WDFREQUEST Request, + _In_ WDFIOTARGET Target, + _In_ PWDF_REQUEST_COMPLETION_PARAMS Params, + _In_ WDFCONTEXT Context + ) +{ + PIRP Irp = Context; + WDFDEVICE device = WdfIoTargetGetDevice(Target); + PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(device); + + UNREFERENCED_PARAMETER(Request); + UNREFERENCED_PARAMETER(Params); + + deviceExtension->PowerContext.Options.LockQueue = FALSE; + + PowerContextEndUse(deviceExtension); + + // Complete the original power irp + IoCompleteRequest( Irp, IO_NO_INCREMENT ); +} + +NTSTATUS +RequestProcessPowerIrpCompletion( + _In_ PDEVICE_OBJECT DeviceObject, + _In_ PIRP Irp, + _In_reads_opt_(_Inexpressible_("varies")) PVOID Context + ) +/*++ + +Routine Description: + + Free the Irp. + +Arguments: + + DeviceObject - device that the completion routine fires on. + + Irp - The irp to be completed. + + Context - IRP context + +Return Value: + NTSTATUS + +--*/ +{ + PCDROM_DEVICE_EXTENSION deviceExtension = Context; + PIO_STACK_LOCATION currentStack; + + UNREFERENCED_PARAMETER(DeviceObject); + + if (Irp->PendingReturned) + { + IoMarkIrpPending( Irp ); + } + + currentStack = IoGetCurrentIrpStackLocation(Irp); + + NT_ASSERT(currentStack->Parameters.Power.Type == DevicePowerState); + NT_ASSERT(currentStack->Parameters.Power.State.DeviceState != PowerDeviceD0); + + _Analysis_assume_(deviceExtension != NULL); + + deviceExtension->PowerContext.PowerChangeState.PowerDown++; + + // Step 5. UNLOCK QUEUE + if (deviceExtension->PowerContext.Options.LockQueue) + { + (VOID)DeviceSendPowerDownProcessRequest(deviceExtension, + RequestUnlockQueueCompletion, + Irp); + + // Let the completion routine complete the Irp + return STATUS_MORE_PROCESSING_REQUIRED; + } + + // Release the power context if it wasn't already done as part of D0Exit handling + if (deviceExtension->PowerContext.InUse) + { + PowerContextEndUse(deviceExtension); + } + + return STATUS_CONTINUE_COMPLETION; +} + + +_IRQL_requires_max_(DISPATCH_LEVEL) +NTSTATUS +PowerContextReuseRequest( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension + ) +/*++ + +Routine Description: + + reset fields for the request. + +Arguments: + + DeviceExtension - device context + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + WDF_REQUEST_REUSE_PARAMS reuseParams; + PIRP irp = NULL; + + RtlZeroMemory(&(DeviceExtension->PowerContext.SenseData), sizeof(DeviceExtension->PowerContext.SenseData)); + RtlZeroMemory(&(DeviceExtension->PowerContext.Srb), sizeof(DeviceExtension->PowerContext.Srb)); + + irp = WdfRequestWdmGetIrp(DeviceExtension->PowerContext.PowerRequest); + + // Re-use the previously created PowerRequest object and format it + WDF_REQUEST_REUSE_PARAMS_INIT(&reuseParams, WDF_REQUEST_REUSE_NO_FLAGS, STATUS_NOT_SUPPORTED); + status = WdfRequestReuse(DeviceExtension->PowerContext.PowerRequest, &reuseParams); + if (NT_SUCCESS(status)) + { + // This request was preformated during initialization so this call should never fail. + status = WdfIoTargetFormatRequestForInternalIoctlOthers(DeviceExtension->IoTarget, + DeviceExtension->PowerContext.PowerRequest, + IOCTL_SCSI_EXECUTE_IN, + NULL, NULL, + NULL, NULL, + NULL, NULL); + + if (!NT_SUCCESS(status)) + { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, + "PowerContextReuseRequest: WdfIoTargetFormatRequestForInternalIoctlOthers failed, %!STATUS!\n", + status)); + } + } + + // Do some basic initialization of the PowerRequest, the rest will be done by the caller + // of this function + if (NT_SUCCESS(status)) + { + PIO_STACK_LOCATION nextStack = NULL; + + nextStack = IoGetNextIrpStackLocation(irp); + + nextStack->MajorFunction = IRP_MJ_SCSI; + nextStack->Parameters.Scsi.Srb = &(DeviceExtension->PowerContext.Srb); + + DeviceExtension->PowerContext.Srb.Length = sizeof(SCSI_REQUEST_BLOCK); + DeviceExtension->PowerContext.Srb.OriginalRequest = irp; + + DeviceExtension->PowerContext.Srb.SenseInfoBuffer = &(DeviceExtension->PowerContext.SenseData); + DeviceExtension->PowerContext.Srb.SenseInfoBufferLength = SENSE_BUFFER_SIZE; + } + + return status; +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +NTSTATUS +PowerContextBeginUse( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension + ) +/*++ + +Routine Description: + + initialize fields in power context + +Arguments: + + DeviceExtension - device context + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + + NT_ASSERT(!DeviceExtension->PowerContext.InUse); + + DeviceExtension->PowerContext.InUse = TRUE; + DeviceExtension->PowerContext.RetryCount = MAXIMUM_RETRIES; + DeviceExtension->PowerContext.RetryIntervalIn100ns = 0; + + KeQueryTickCount(&DeviceExtension->PowerContext.StartTime); + + RtlZeroMemory(&(DeviceExtension->PowerContext.Options), sizeof(DeviceExtension->PowerContext.Options)); + RtlZeroMemory(&(DeviceExtension->PowerContext.PowerChangeState), sizeof(DeviceExtension->PowerContext.PowerChangeState)); + + status = PowerContextReuseRequest(DeviceExtension); + + RequestClearSendTime(DeviceExtension->PowerContext.PowerRequest); + + return status; +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +NTSTATUS +PowerContextEndUse( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension + ) +/*++ + +Routine Description: + + inidate that power context using is finished. + +Arguments: + + DeviceExtension - device context + +Return Value: + + NTSTATUS + +--*/ +{ + NT_ASSERT(DeviceExtension->PowerContext.InUse); + + DeviceExtension->PowerContext.InUse = FALSE; + + KeQueryTickCount(&DeviceExtension->PowerContext.CompleteTime); + + return STATUS_SUCCESS; +} + + +_Function_class_(POWER_SETTING_CALLBACK) +_IRQL_requires_same_ +NTSTATUS +DevicePowerSettingCallback( + _In_ LPCGUID SettingGuid, + _In_reads_bytes_(ValueLength) PVOID Value, + _In_ ULONG ValueLength, + _Inout_opt_ PVOID Context + ) +/*++ +Description: + + This function is the callback for power setting notifications (registered + when ClasspGetD3IdleTimeout() is called for the first time). + + Currently, this function is used to get the disk idle timeout value from + the system power settings. + + This function is guaranteed to be called at PASSIVE_LEVEL. + +Arguments: + + SettingGuid - The power setting GUID. + Value - Pointer to the power setting value. + ValueLength - Size of the Value buffer. + Context - The FDO's device extension. + +Return Value: + + STATUS_SUCCESS + +--*/ +{ + PCDROM_DEVICE_EXTENSION DeviceExtension = Context; + MONITOR_DISPLAY_STATE DisplayState; + + PAGED_CODE(); + + if (IsEqualGUID(SettingGuid, &GUID_CONSOLE_DISPLAY_STATE)) { + + if ((ValueLength == sizeof(ULONG)) && (Value != NULL)) { + + DisplayState = *((PULONG)Value); + + _Analysis_assume_(DeviceExtension != NULL); + + // + // Power setting callbacks are asynchronous so make sure the device + // is completely initialized before taking any actions. + // + if (DeviceExtension->IsInitialized) { + + // + // If monitor is off, change media change requests to not keep device active. + // This allows the devices to go to sleep if there are no other active requests. + // + + if (DisplayState == PowerMonitorOff) { + + // + // Mark the device inactive so that it can enter a low power state. + // + + DeviceMarkActive(DeviceExtension, FALSE, TRUE); + SET_FLAG(DeviceExtension->MediaChangeDetectionInfo->SrbFlags, SRB_FLAGS_NO_KEEP_AWAKE); + } + else + { + CLEAR_FLAG(DeviceExtension->MediaChangeDetectionInfo->SrbFlags, SRB_FLAGS_NO_KEEP_AWAKE); + DeviceMarkActive(DeviceExtension, TRUE, TRUE); + } + } + } + } + + return STATUS_SUCCESS; +} + +#pragma warning(pop) // un-sets any local warning changes + diff --git a/storage/class/cdrom/src/scratch.c b/storage/class/cdrom/src/scratch.c new file mode 100644 index 00000000..fdd37f5f --- /dev/null +++ b/storage/class/cdrom/src/scratch.c @@ -0,0 +1,1464 @@ +/*-- + +Copyright (C) Microsoft Corporation. All rights reserved. + +Module Name: + + scratch.c + +Abstract: + + Functions for using common scratch buffer + +Environment: + + kernel mode only + +Notes: + + +Revision History: + +--*/ + +#include "stddef.h" +#include "string.h" + +#include "ntddk.h" +#include "ntddstor.h" +#include "cdrom.h" +#include "ioctl.h" +#include "scratch.h" +#include "mmc.h" + +#ifdef DEBUG_USE_WPP +#include "scratch.tmh" +#endif + +// Forward declarations +EVT_WDF_REQUEST_COMPLETION_ROUTINE ScratchBuffer_ReadWriteCompletionRoutine; + +#ifdef ALLOC_PRAGMA + +#pragma alloc_text(PAGE, ScratchBuffer_Deallocate) +#pragma alloc_text(PAGE, ScratchBuffer_Allocate) +#pragma alloc_text(PAGE, ScratchBuffer_SetupSrb) +#pragma alloc_text(PAGE, ScratchBuffer_ExecuteCdbEx) + +#endif + +_IRQL_requires_max_(APC_LEVEL) +VOID +ScratchBuffer_Deallocate( + _Inout_ PCDROM_DEVICE_EXTENSION DeviceExtension + ) +/*++ + +Routine Description: + + release all resources allocated for scratch. + +Arguments: + + DeviceExtension - device extension + +Return Value: + + none + +--*/ +{ + PAGED_CODE (); + + NT_ASSERT(DeviceExtension->ScratchContext.ScratchInUse == 0); + + if (DeviceExtension->ScratchContext.ScratchHistory != NULL) + { + ExFreePool(DeviceExtension->ScratchContext.ScratchHistory); + DeviceExtension->ScratchContext.ScratchHistory = NULL; + } + if (DeviceExtension->ScratchContext.ScratchSense != NULL) + { + ExFreePool(DeviceExtension->ScratchContext.ScratchSense); + DeviceExtension->ScratchContext.ScratchSense = NULL; + } + if (DeviceExtension->ScratchContext.ScratchSrb != NULL) + { + ExFreePool(DeviceExtension->ScratchContext.ScratchSrb); + DeviceExtension->ScratchContext.ScratchSrb = NULL; + } + if (DeviceExtension->ScratchContext.ScratchBufferSize != 0) + { + DeviceExtension->ScratchContext.ScratchBufferSize = 0; + } + if (DeviceExtension->ScratchContext.ScratchBufferMdl != NULL) + { + IoFreeMdl(DeviceExtension->ScratchContext.ScratchBufferMdl); + DeviceExtension->ScratchContext.ScratchBufferMdl = NULL; + } + if (DeviceExtension->ScratchContext.ScratchBuffer != NULL) + { + ExFreePool(DeviceExtension->ScratchContext.ScratchBuffer); + DeviceExtension->ScratchContext.ScratchBuffer = NULL; + } + + if (DeviceExtension->ScratchContext.PartialMdl != NULL) + { + IoFreeMdl(DeviceExtension->ScratchContext.PartialMdl); + DeviceExtension->ScratchContext.PartialMdl = NULL; + } + + if (DeviceExtension->ScratchContext.ScratchRequest != NULL) + { + PIRP irp = WdfRequestWdmGetIrp(DeviceExtension->ScratchContext.ScratchRequest); + if (irp->MdlAddress) + { + irp->MdlAddress = NULL; + } + WdfObjectDelete(DeviceExtension->ScratchContext.ScratchRequest); + DeviceExtension->ScratchContext.ScratchRequest = NULL; + } + + return; +} + +_IRQL_requires_max_(APC_LEVEL) +BOOLEAN +ScratchBuffer_Allocate( + _Inout_ PCDROM_DEVICE_EXTENSION DeviceExtension + ) +/*++ + +Routine Description: + + allocate resources allocated for scratch. + +Arguments: + + DeviceExtension - device extension + +Return Value: + + none + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + + PAGED_CODE (); + + NT_ASSERT(DeviceExtension->ScratchContext.ScratchInUse == 0); + + // quick-exit if already allocated + if ((DeviceExtension->ScratchContext.ScratchBuffer != NULL) && + (DeviceExtension->ScratchContext.ScratchBufferMdl != NULL) && + (DeviceExtension->ScratchContext.ScratchBufferSize != 0) && + (DeviceExtension->ScratchContext.ScratchRequest != NULL) && + (DeviceExtension->ScratchContext.ScratchSrb != NULL) && + (DeviceExtension->ScratchContext.ScratchHistory != NULL) && + (DeviceExtension->ScratchContext.PartialMdl != NULL) + ) + { + return TRUE; + } + + // validate max transfer already determined + NT_ASSERT(DeviceExtension->DeviceAdditionalData.MaxPageAlignedTransferBytes != 0); + + // validate no partially-saved state + NT_ASSERT(DeviceExtension->ScratchContext.ScratchBuffer == NULL); + NT_ASSERT(DeviceExtension->ScratchContext.ScratchBufferMdl == NULL); + NT_ASSERT(DeviceExtension->ScratchContext.ScratchBufferSize == 0); + NT_ASSERT(DeviceExtension->ScratchContext.ScratchRequest == NULL); + NT_ASSERT(DeviceExtension->ScratchContext.PartialMdl == NULL); + + // limit the scratch buffer to between 4k and 64k (so data length fits into USHORT -- req'd for many commands) + DeviceExtension->ScratchContext.ScratchBufferSize = min(DeviceExtension->DeviceAdditionalData.MaxPageAlignedTransferBytes, (64*1024)); + + // allocate the buffer + if (NT_SUCCESS(status)) + { + DeviceExtension->ScratchContext.ScratchBuffer = ExAllocatePoolWithTag(NonPagedPoolNx, + DeviceExtension->ScratchContext.ScratchBufferSize, + CDROM_TAG_SCRATCH); + if (DeviceExtension->ScratchContext.ScratchBuffer == NULL) + { + status = STATUS_INSUFFICIENT_RESOURCES; + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT, + "Failed to allocate scratch buffer of %x bytes\n", + DeviceExtension->ScratchContext.ScratchBufferSize + )); + } + else if (BYTE_OFFSET(DeviceExtension->ScratchContext.ScratchBuffer) != 0) + { + status = STATUS_INTERNAL_ERROR; + TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_INIT, + "Allocation of %x bytes non-paged pool was not " + "allocated on page boundary? STATUS_INTERNAL_ERROR\n", + DeviceExtension->ScratchContext.ScratchBufferSize + )); + } + } + + // allocate the MDL + if (NT_SUCCESS(status)) + { + DeviceExtension->ScratchContext.ScratchBufferMdl = IoAllocateMdl(DeviceExtension->ScratchContext.ScratchBuffer, + DeviceExtension->ScratchContext.ScratchBufferSize, + FALSE, FALSE, NULL); + if (DeviceExtension->ScratchContext.ScratchBufferMdl == NULL) + { + status = STATUS_INSUFFICIENT_RESOURCES; + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT, + "Failed to allocate MDL for %x byte buffer\n", + DeviceExtension->ScratchContext.ScratchBufferSize + )); + } + else + { + MmBuildMdlForNonPagedPool(DeviceExtension->ScratchContext.ScratchBufferMdl); + } + } + + // create the request + if (NT_SUCCESS(status)) + { + WDF_OBJECT_ATTRIBUTES attributes; + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, + CDROM_REQUEST_CONTEXT); + + status = WdfRequestCreate(&attributes, + DeviceExtension->IoTarget, + &DeviceExtension->ScratchContext.ScratchRequest); + + if ((!NT_SUCCESS(status)) || + (DeviceExtension->ScratchContext.ScratchRequest == NULL)) + { + status = STATUS_INSUFFICIENT_RESOURCES; + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT, + "Failed to allocate scratch MDL \n")); + } + } + + // allocate the srb + if (NT_SUCCESS(status)) + { + DeviceExtension->ScratchContext.ScratchSrb = ExAllocatePoolWithTag(NonPagedPoolNx, + sizeof(SCSI_REQUEST_BLOCK), + CDROM_TAG_SCRATCH); + + if (DeviceExtension->ScratchContext.ScratchSrb == NULL) + { + status = STATUS_INSUFFICIENT_RESOURCES; + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT, + "Failed to allocate scratch SRB\n")); + } + } + + // allocate the sense buffer + if (NT_SUCCESS(status)) + { + DeviceExtension->ScratchContext.ScratchSense = ExAllocatePoolWithTag(NonPagedPoolNx, + sizeof(SENSE_DATA), + CDROM_TAG_SCRATCH); + + if (DeviceExtension->ScratchContext.ScratchSense == NULL) + { + status = STATUS_INSUFFICIENT_RESOURCES; + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT, + "Failed to allocate scratch sense data\n" + )); + } + } + + // allocate the SRB history data + if (NT_SUCCESS(status)) + { + size_t allocationSize = sizeof(SRB_HISTORY) - sizeof(SRB_HISTORY_ITEM); + allocationSize += 20 * sizeof(SRB_HISTORY_ITEM); + + DeviceExtension->ScratchContext.ScratchHistory = ExAllocatePoolWithTag(NonPagedPoolNx, + allocationSize, + CDROM_TAG_SCRATCH); + if (DeviceExtension->ScratchContext.ScratchHistory == NULL) + { + status = STATUS_INSUFFICIENT_RESOURCES; + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT, + "Failed to allocate scratch history buffer\n" + )); + } + else + { + // must be initialized here... + RtlZeroMemory(DeviceExtension->ScratchContext.ScratchHistory, allocationSize); + DeviceExtension->ScratchContext.ScratchHistory->TotalHistoryCount = 20; + } + } + + // allocate the MDL + if (NT_SUCCESS(status)) + { + ULONG transferLength = 0; + + status = RtlULongAdd(DeviceExtension->DeviceAdditionalData.MaxPageAlignedTransferBytes, PAGE_SIZE, &transferLength); + if (NT_SUCCESS(status)) + { + DeviceExtension->ScratchContext.PartialMdlIsBuilt = FALSE; + DeviceExtension->ScratchContext.PartialMdl = IoAllocateMdl(NULL, + transferLength, + FALSE, + FALSE, + NULL); + if (DeviceExtension->ScratchContext.PartialMdl == NULL) + { + status = STATUS_INSUFFICIENT_RESOURCES; + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT, + "Failed to allocate MDL for %x byte buffer\n", + DeviceExtension->ScratchContext.ScratchBufferSize + )); + } + else + { + NT_ASSERT(DeviceExtension->ScratchContext.PartialMdl->Size >= + (CSHORT)(sizeof(MDL) + BYTES_TO_PAGES(DeviceExtension->DeviceAdditionalData.MaxPageAlignedTransferBytes) * sizeof(PFN_NUMBER))); + } + } + else + { + status = STATUS_INTEGER_OVERFLOW; + } + } + + // cleanup on failure + if (!NT_SUCCESS(status)) + { + ScratchBuffer_Deallocate(DeviceExtension); + } + + return NT_SUCCESS(status); +} + + +VOID +ScratchBuffer_ResetItems( + _Inout_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ BOOLEAN ResetRequestHistory + ) +/*++ + +Routine Description: + + reset scratch items for reuse. + +Arguments: + + DeviceExtension - device extension + ResetRequestHistory - reset history fields or not + +Return Value: + + none + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + WDF_REQUEST_REUSE_PARAMS reuseParams; + PIRP irp = NULL; + + NT_ASSERT(DeviceExtension->ScratchContext.ScratchHistory != NULL); + NT_ASSERT(DeviceExtension->ScratchContext.ScratchSense != NULL); + NT_ASSERT(DeviceExtension->ScratchContext.ScratchSrb != NULL); + NT_ASSERT(DeviceExtension->ScratchContext.ScratchRequest != NULL); + NT_ASSERT(DeviceExtension->ScratchContext.ScratchBufferSize != 0); + NT_ASSERT(DeviceExtension->ScratchContext.ScratchBuffer != NULL); + NT_ASSERT(DeviceExtension->ScratchContext.ScratchBufferMdl != NULL); + NT_ASSERT(DeviceExtension->ScratchContext.ScratchInUse != 0); + + irp = WdfRequestWdmGetIrp(DeviceExtension->ScratchContext.ScratchRequest); + + if (ResetRequestHistory) + { + PSRB_HISTORY history = DeviceExtension->ScratchContext.ScratchHistory; + RtlZeroMemory(history->History, sizeof(SRB_HISTORY_ITEM) * history->TotalHistoryCount); + history->ClassDriverUse[0] = 0; + history->ClassDriverUse[1] = 0; + history->ClassDriverUse[2] = 0; + history->ClassDriverUse[3] = 0; + history->UsedHistoryCount = 0; + } + + // re-use the KMDF request object + + // deassign the MdlAddress, this is the value we assign explicitly. + // this is to prevent WdfRequestReuse to release the Mdl unexpectly. + if (irp->MdlAddress) + { + irp->MdlAddress = NULL; + } + + WDF_REQUEST_REUSE_PARAMS_INIT(&reuseParams, WDF_REQUEST_REUSE_NO_FLAGS, STATUS_NOT_SUPPORTED); + status = WdfRequestReuse(DeviceExtension->ScratchContext.ScratchRequest, &reuseParams); + // WDF request to format the request befor sending it + if (NT_SUCCESS(status)) + { + // clean up completion routine. + WdfRequestSetCompletionRoutine(DeviceExtension->ScratchContext.ScratchRequest, NULL, NULL); + + status = WdfIoTargetFormatRequestForInternalIoctlOthers(DeviceExtension->IoTarget, + DeviceExtension->ScratchContext.ScratchRequest, + IOCTL_SCSI_EXECUTE_IN, + NULL, NULL, + NULL, NULL, + NULL, NULL); + if (!NT_SUCCESS(status)) + { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, + "ScratchBuffer_ResetItems: WdfIoTargetFormatRequestForInternalIoctlOthers failed, %!STATUS!\n", + status)); + } + } + + RtlZeroMemory(DeviceExtension->ScratchContext.ScratchSense, sizeof(SENSE_DATA)); + RtlZeroMemory(DeviceExtension->ScratchContext.ScratchSrb, sizeof(SCSI_REQUEST_BLOCK)); + + return; +} + + +NTSTATUS +ScratchBuffer_PerformNextReadWrite( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ BOOLEAN FirstTry + ) +/*++ + +Routine Description: + + This function asynchronously sends the next read/write SRB down the stack. + +Arguments: + + DeviceExtension - Device extension + +Return Value: + + none + +--*/ +{ + PCDROM_SCRATCH_READ_WRITE_CONTEXT readWriteContext = &DeviceExtension->ScratchContext.ScratchReadWriteContext; + PCDROM_REQUEST_CONTEXT requestContext = RequestGetContext(DeviceExtension->ScratchContext.ScratchRequest); + WDFREQUEST originalRequest = requestContext->OriginalRequest; + NTSTATUS status = STATUS_SUCCESS; + + ULONG transferSize; + BOOLEAN usePartialMdl; + + transferSize = min((readWriteContext->EntireXferLen - readWriteContext->TransferedBytes), readWriteContext->MaxLength); + + if (FirstTry) + { + DeviceExtension->ScratchContext.NumRetries = 0; + } + + ScratchBuffer_ResetItems(DeviceExtension, FALSE); + + usePartialMdl = (readWriteContext->PacketsCount > 1 || readWriteContext->TransferedBytes > 0); + + ScratchBuffer_SetupReadWriteSrb(DeviceExtension, + originalRequest, + readWriteContext->StartingOffset, + transferSize, + readWriteContext->DataBuffer, + readWriteContext->IsRead, + usePartialMdl + ); + + WdfRequestSetCompletionRoutine(DeviceExtension->ScratchContext.ScratchRequest, + ScratchBuffer_ReadWriteCompletionRoutine, DeviceExtension); + + status = ScratchBuffer_SendSrb(DeviceExtension, FALSE, (FirstTry ? &readWriteContext->SrbHistoryItem : NULL)); + + return status; +} + + +VOID +ScratchBuffer_ReadWriteTimerRoutine( + struct _KDPC *Dpc, + PVOID DeferredContext, + PVOID SystemArgument1, + PVOID SystemArgument2 + ) +/*++ + +Routine Description: + + Timer routine for retrying read and write requests. + +Arguments: + + Timer - WDF timer + +Return Value: + + none + +--*/ +{ + PCDROM_DEVICE_EXTENSION deviceExtension = NULL; + PCDROM_SCRATCH_READ_WRITE_CONTEXT readWriteContext = NULL; + WDFREQUEST originalRequest = NULL; + PCDROM_REQUEST_CONTEXT requestContext = NULL; + NTSTATUS status = STATUS_SUCCESS; + KIRQL oldIrql; + + UNREFERENCED_PARAMETER(Dpc); + UNREFERENCED_PARAMETER(SystemArgument1); + UNREFERENCED_PARAMETER(SystemArgument2); + + if (DeferredContext == NULL) + { + // This is impossible, but definition of KDEFERRED_ROUTINE allows optional argument, + // and thus OACR will complain. + + return; + } + + originalRequest = (WDFREQUEST) DeferredContext; + requestContext = RequestGetContext(originalRequest); + + KeAcquireSpinLock(&requestContext->ReadWriteCancelSpinLock, &oldIrql); + + if (!requestContext->ReadWriteIsCompleted) + { + // As the first step, unregister the cancellation routine + status = WdfRequestUnmarkCancelable(originalRequest); + } + else + { + status = STATUS_CANCELLED; + } + + KeReleaseSpinLock(&requestContext->ReadWriteCancelSpinLock, oldIrql); + + if (status != STATUS_CANCELLED) + { + deviceExtension = requestContext->DeviceExtension; + readWriteContext = &deviceExtension->ScratchContext.ScratchReadWriteContext; + + // We use timer only for retries, that's why the second parameter is always FALSE + status = ScratchBuffer_PerformNextReadWrite(deviceExtension, FALSE); + + if (!NT_SUCCESS(status)) + { + ScratchBuffer_EndUse(deviceExtension); + RequestCompletion(deviceExtension, originalRequest, status, readWriteContext->TransferedBytes); + } + } + + // + // Drop the extra reference + // + WdfObjectDereference(originalRequest); +} + + +EVT_WDF_REQUEST_CANCEL ScratchBuffer_ReadWriteEvtRequestCancel; + +VOID +ScratchBuffer_ReadWriteEvtRequestCancel( + _In_ WDFREQUEST Request + ) +/*++ + +Routine Description: + + Cancels a request waiting for the read/write timer to expire. This function does not + support cancellation of requests that have already been sent down. + +Arguments: + + Request - WDF request + +Return Value: + + none + +--*/ +{ + PCDROM_REQUEST_CONTEXT requestContext = RequestGetContext(Request); + PCDROM_DEVICE_EXTENSION deviceExtension = requestContext->DeviceExtension; + PCDROM_SCRATCH_READ_WRITE_CONTEXT readWriteContext = &deviceExtension->ScratchContext.ScratchReadWriteContext; + KIRQL oldIrql; + + KeAcquireSpinLock(&requestContext->ReadWriteCancelSpinLock, &oldIrql); + + if (KeCancelTimer(&requestContext->ReadWriteTimer)) + { + // + // Timer is canceled, we own the request. Drop the reference we took before + // queueing the timer. + // + WdfObjectDereference(Request); + } + else + { + // + // Timer will run and drop the reference but it won't complete the request + // because we set IsCompleted to TRUE + // + } + + requestContext->ReadWriteIsCompleted = TRUE; + + KeReleaseSpinLock(&requestContext->ReadWriteCancelSpinLock, oldIrql); + + ScratchBuffer_EndUse(deviceExtension); + + // If WdfTimerStop returned TRUE, it means this request was scheduled for a retry + // and the retry has not happened yet. We just need to cancel it and release the scratch buffer. + RequestCompletion(deviceExtension, Request, STATUS_CANCELLED, readWriteContext->TransferedBytes); +} + +VOID +ScratchBuffer_ReadWriteCompletionRoutine( + _In_ WDFREQUEST Request, + _In_ WDFIOTARGET Target, + _In_ PWDF_REQUEST_COMPLETION_PARAMS Params, + _In_ WDFCONTEXT Context + ) +/*++ + +Routine Description: + + Read/write request completion routine. + +Arguments: + Request - WDF request + Target - The IO target the request was completed by. + Params - the request completion parameters + Context - context + +Return Value: + + none + +--*/ +{ + PCDROM_DEVICE_EXTENSION deviceExtension = (PCDROM_DEVICE_EXTENSION) Context; + PCDROM_SCRATCH_READ_WRITE_CONTEXT readWriteContext = &deviceExtension->ScratchContext.ScratchReadWriteContext; + NTSTATUS status = STATUS_SUCCESS; + PCDROM_REQUEST_CONTEXT requestContext = RequestGetContext(deviceExtension->ScratchContext.ScratchRequest); + WDFREQUEST originalRequest = requestContext->OriginalRequest; + + if (!NT_SUCCESS(WdfRequestGetStatus(Request))) + { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT, + "WdfRequestSend: %lx\n", + WdfRequestGetStatus(Request) + )); + } + + UNREFERENCED_PARAMETER(Params); + UNREFERENCED_PARAMETER(Target); + + // We are not calling ScratchBuffer_BeginUse / ScratchBuffer_EndUse in this function, because we already own + // the scratch buffer if this function is being called. + + if ((deviceExtension->ScratchContext.ScratchSrb->SrbStatus == SRB_STATUS_ABORTED) && + (deviceExtension->ScratchContext.ScratchSrb->InternalStatus == STATUS_CANCELLED)) + { + // The request has been cancelled, just need to complete it + } + else if (SRB_STATUS(deviceExtension->ScratchContext.ScratchSrb->SrbStatus) != SRB_STATUS_SUCCESS) + { + // The SCSI command that we sent down has failed, retry it if necessary + BOOLEAN shouldRetry = TRUE; + LONGLONG retryIn100nsUnits = 0; + + shouldRetry = RequestSenseInfoInterpretForScratchBuffer(deviceExtension, + deviceExtension->ScratchContext.NumRetries, + &status, + &retryIn100nsUnits); + + if (shouldRetry) + { + deviceExtension->ScratchContext.NumRetries++; + + if (retryIn100nsUnits == 0) + { + // We take a shortcut here by calling ScratchBuffer_PerformNextReadWrite directly: + // this helps to avoid unnecessary context switch. + status = ScratchBuffer_PerformNextReadWrite(deviceExtension, FALSE); + + if (NT_SUCCESS(status)) + { + // We're not done with the request yet, no need to complete it now + return; + } + } + else + { + PCDROM_REQUEST_CONTEXT originalRequestContext = RequestGetContext(originalRequest); + KIRQL oldIrql; + + // + // Initialize the spin lock and timer local to the original request. + // + if (!originalRequestContext->ReadWriteRetryInitialized) + { + KeInitializeSpinLock(&originalRequestContext->ReadWriteCancelSpinLock); + KeInitializeTimer(&originalRequestContext->ReadWriteTimer); + KeInitializeDpc(&originalRequestContext->ReadWriteDpc, ScratchBuffer_ReadWriteTimerRoutine, originalRequest); + originalRequestContext->ReadWriteRetryInitialized = TRUE; + } + + KeAcquireSpinLock(&requestContext->ReadWriteCancelSpinLock, &oldIrql); + + status = WdfRequestMarkCancelableEx(originalRequest, ScratchBuffer_ReadWriteEvtRequestCancel); + + if (status == STATUS_CANCELLED) + { + requestContext->ReadWriteIsCompleted = TRUE; + + KeReleaseSpinLock(&requestContext->ReadWriteCancelSpinLock, oldIrql); + } + else + { + LARGE_INTEGER t; + + t.QuadPart = -retryIn100nsUnits; + + WdfObjectReference(originalRequest); + + // Use negative time to indicate that we want a relative delay + KeSetTimer(&originalRequestContext->ReadWriteTimer, + t, + &originalRequestContext->ReadWriteDpc + ); + + KeReleaseSpinLock(&requestContext->ReadWriteCancelSpinLock, oldIrql); + + return; + } + } + } + } + else + { + // The SCSI command has succeeded + readWriteContext->DataBuffer += deviceExtension->ScratchContext.ScratchSrb->DataTransferLength; + readWriteContext->StartingOffset.QuadPart += deviceExtension->ScratchContext.ScratchSrb->DataTransferLength; + readWriteContext->TransferedBytes += deviceExtension->ScratchContext.ScratchSrb->DataTransferLength; + readWriteContext->PacketsCount--; + + // Update the SRB history item + if (readWriteContext->SrbHistoryItem) + { + ULONG senseSize; + + // Query the tick count and store in the history + KeQueryTickCount(&readWriteContext->SrbHistoryItem->TickCountCompleted); + + // Copy the SRB Status... + readWriteContext->SrbHistoryItem->SrbStatus = deviceExtension->ScratchContext.ScratchSrb->SrbStatus; + + // Determine the amount of valid sense data + if (deviceExtension->ScratchContext.ScratchSrb->SenseInfoBufferLength >= + RTL_SIZEOF_THROUGH_FIELD(SENSE_DATA, AdditionalSenseLength)) + { + PSENSE_DATA sense = (PSENSE_DATA)deviceExtension->ScratchContext.ScratchSrb->SenseInfoBuffer; + senseSize = RTL_SIZEOF_THROUGH_FIELD(SENSE_DATA, AdditionalSenseLength) + + sense->AdditionalSenseLength; + senseSize = min(senseSize, sizeof(SENSE_DATA)); + } + else + { + senseSize = deviceExtension->ScratchContext.ScratchSrb->SenseInfoBufferLength; + } + + // Normalize the sense data copy in the history + RtlZeroMemory(&(readWriteContext->SrbHistoryItem->NormalizedSenseData), sizeof(SENSE_DATA)); + RtlCopyMemory(&(readWriteContext->SrbHistoryItem->NormalizedSenseData), + deviceExtension->ScratchContext.ScratchSrb->SenseInfoBuffer, senseSize); + } + + // Check whether we need to send more SCSI commands to complete the request + if (readWriteContext->PacketsCount > 0) + { + status = ScratchBuffer_PerformNextReadWrite(deviceExtension, TRUE); + + if (NT_SUCCESS(status)) + { + // We're not done with the request yet, no need to complete it now + return; + } + } + } + + ScratchBuffer_EndUse(deviceExtension); + + + RequestCompletion(deviceExtension, originalRequest, status, readWriteContext->TransferedBytes); +} + +_IRQL_requires_max_(APC_LEVEL) +VOID +ScratchBuffer_SetupSrb( + _Inout_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_opt_ WDFREQUEST OriginalRequest, + _In_ ULONG MaximumTransferLength, + _In_ BOOLEAN GetDataFromDevice + ) +/*++ + +Routine Description: + + setup scratch SRB for sending out. + +Arguments: + + DeviceExtension - device extension + OriginalRequest - original request delivered by WDF + MaximumTransferLength - transfer length + GetDataFromDevice - TRUE (get data from device); FALSE (send data to device) + +Return Value: + + none + +--*/ +{ + WDFREQUEST request = DeviceExtension->ScratchContext.ScratchRequest; + PIRP irp = WdfRequestWdmGetIrp(request); + PSCSI_REQUEST_BLOCK srb = DeviceExtension->ScratchContext.ScratchSrb; + PIO_STACK_LOCATION irpStack = NULL; + PCDROM_REQUEST_CONTEXT requestContext = RequestGetContext(request); + + PAGED_CODE (); + + requestContext->OriginalRequest = OriginalRequest; + + // set to use the full scratch buffer via the scratch SRB + irpStack = IoGetNextIrpStackLocation(irp); + irpStack->MajorFunction = IRP_MJ_SCSI; + if (MaximumTransferLength == 0) + { + irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_NONE; + } + else if (GetDataFromDevice) + { + irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_IN; + } + else + { + irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_OUT; + } + irpStack->Parameters.Scsi.Srb = srb; + + if (MaximumTransferLength > 0) + { + // the Irp must show the MDL's address for the transfer + irp->MdlAddress = DeviceExtension->ScratchContext.ScratchBufferMdl; + + srb->DataBuffer = DeviceExtension->ScratchContext.ScratchBuffer; + } + + // prepare the SRB with default values + srb->Length = SCSI_REQUEST_BLOCK_SIZE; + srb->Function = SRB_FUNCTION_EXECUTE_SCSI; + srb->QueueAction = SRB_SIMPLE_TAG_REQUEST; + srb->SrbStatus = 0; + srb->ScsiStatus = 0; + srb->NextSrb = NULL; + srb->OriginalRequest = irp; + srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE; + srb->SenseInfoBuffer = DeviceExtension->ScratchContext.ScratchSense; + + srb->CdbLength = 16; // to cause failures if not set correctly -- CD devices limited to 12 bytes for now... + + srb->DataTransferLength = min(DeviceExtension->ScratchContext.ScratchBufferSize, MaximumTransferLength); + srb->TimeOutValue = DeviceExtension->TimeOutValue; + srb->SrbFlags = DeviceExtension->SrbFlags; + SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER); + SET_FLAG(srb->SrbFlags, SRB_FLAGS_NO_QUEUE_FREEZE); + + if (MaximumTransferLength == 0) + { + SET_FLAG(srb->SrbFlags, SRB_FLAGS_NO_DATA_TRANSFER); + } + else if (GetDataFromDevice) + { + SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_IN); + } + else + { + SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_OUT); + } +} + + +NTSTATUS +ScratchBuffer_SendSrb( + _Inout_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ BOOLEAN SynchronousSrb, + _When_(SynchronousSrb, _Pre_null_) + _When_(!SynchronousSrb, _In_opt_) + PSRB_HISTORY_ITEM *SrbHistoryItem + ) +/*++ + +Routine Description: + + Send the command from the scratch SRB to lower driver and retry if necessary. + +Arguments: + + DeviceExtension - device extension + SynchronousSrb - indicates whether the SRB needs to be sent synchronously or nor + SrbHistoryItem - storage for SRB history item, if this is an asynchronous request + +Return Value: + + none + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PSCSI_REQUEST_BLOCK srb = DeviceExtension->ScratchContext.ScratchSrb; + PSRB_HISTORY history = DeviceExtension->ScratchContext.ScratchHistory; + PSRB_HISTORY_ITEM item = NULL; + BOOLEAN requestCancelled = FALSE; + + srb->InternalStatus = 0; + srb->SrbStatus = 0; + + // allocate/update history pre-command, if it is a synchronous request or we were supplied + // with a storage for the history item + if (SynchronousSrb || SrbHistoryItem != NULL) + { + // sending a packet implies a new history unit is to be used. + NT_ASSERT( history->UsedHistoryCount <= history->TotalHistoryCount ); + + // if already all used up, remove at least one history unit + if (history->UsedHistoryCount == history->TotalHistoryCount ) + { + CompressSrbHistoryData(history); + NT_ASSERT( history->UsedHistoryCount < history->TotalHistoryCount ); + } + + // thus, since we are about to increment the count, it must now be less... + NT_ASSERT( history->UsedHistoryCount < history->TotalHistoryCount ); + + // increment the number of history units in use + history->UsedHistoryCount++; + + // determine index to use + item = &( history->History[ history->UsedHistoryCount-1 ] ); + + if (SrbHistoryItem != NULL) + { + *SrbHistoryItem = item; + } + + // zero out the history item + RtlZeroMemory(item, sizeof(SRB_HISTORY_ITEM)); + + // Query the tick count and store in the history + KeQueryTickCount(&item->TickCountSent); + } + + // get cancellation status; + { + PCDROM_REQUEST_CONTEXT requestContext = RequestGetContext(DeviceExtension->ScratchContext.ScratchRequest); + + if (requestContext->OriginalRequest != NULL) + { + requestCancelled = WdfRequestIsCanceled(requestContext->OriginalRequest); + } + } + + if (!requestCancelled) + { + status = RequestSend(DeviceExtension, + DeviceExtension->ScratchContext.ScratchRequest, + DeviceExtension->IoTarget, + SynchronousSrb ? WDF_REQUEST_SEND_OPTION_SYNCHRONOUS : 0, + NULL); + + // If this is a synchronous request, update the history item immediately, including "normalized" sense data + if (SynchronousSrb) + { + ULONG senseSize; + + // Query the tick count and store in the history + KeQueryTickCount(&item->TickCountCompleted); + + // Copy the SRB Status + item->SrbStatus = srb->SrbStatus; + + // Determine the amount of valid sense data + if (srb->SenseInfoBufferLength >= RTL_SIZEOF_THROUGH_FIELD(SENSE_DATA, AdditionalSenseLength)) + { + PSENSE_DATA sense = (PSENSE_DATA)srb->SenseInfoBuffer; + senseSize = RTL_SIZEOF_THROUGH_FIELD(SENSE_DATA, AdditionalSenseLength) + + sense->AdditionalSenseLength; + senseSize = min(senseSize, sizeof(SENSE_DATA)); + } + else + { + senseSize = srb->SenseInfoBufferLength; + } + + // Normalize the sense data copy in the history + RtlZeroMemory(&(item->NormalizedSenseData), sizeof(SENSE_DATA)); + RtlCopyMemory(&(item->NormalizedSenseData), srb->SenseInfoBuffer, senseSize); + } + } + else + { + DeviceExtension->ScratchContext.ScratchSrb->SrbStatus = SRB_STATUS_ABORTED; + DeviceExtension->ScratchContext.ScratchSrb->InternalStatus = (ULONG)STATUS_CANCELLED; + status = STATUS_CANCELLED; + } + + return status; +} + +VOID +CompressSrbHistoryData( + _Inout_ PSRB_HISTORY RequestHistory + ) +/*++ + +Routine Description: + + compress the SRB history data. + +Arguments: + + RequestHistory - SRB history data + +Return Value: + + RequestHistory - compressed history data + +--*/ +{ + ULONG i; + NT_ASSERT( RequestHistory->UsedHistoryCount == RequestHistory->TotalHistoryCount ); + ValidateSrbHistoryDataPresumptions(RequestHistory); + + for (i=0; i < RequestHistory->UsedHistoryCount; i++) + { + // for each item... + PSRB_HISTORY_ITEM toMatch = &( RequestHistory->History[i] ); + // hint: read const qualifiers backwards. i.e. srbstatus is a const UCHAR + // so, "UCHAR const * const x" is read "x is a const pointer to a const UCHAR" + // unfortunately, "const UCHAR" is equivalent to "UCHAR const", which causes + // people no end of confusion due to its widespread use. + UCHAR const srbStatus = toMatch->SrbStatus; + UCHAR const sense = toMatch->NormalizedSenseData.SenseKey; + UCHAR const asc = toMatch->NormalizedSenseData.AdditionalSenseCode; + UCHAR const ascq = toMatch->NormalizedSenseData.AdditionalSenseCodeQualifier; + ULONG j; + + // see if there are any at higher indices with identical Sense/ASC/ASCQ + for (j = i+1; (toMatch->ClassDriverUse != 0xFF) && (j < RequestHistory->UsedHistoryCount); j++) + { + PSRB_HISTORY_ITEM found = &( RequestHistory->History[j] ); + // close enough match? + if ((srbStatus == found->SrbStatus) && + (sense == found->NormalizedSenseData.SenseKey) && + (asc == found->NormalizedSenseData.AdditionalSenseCode) && + (ascq == found->NormalizedSenseData.AdditionalSenseCodeQualifier)) { + + // add the fields to keep reasonable track of delay times. + if (toMatch->MillisecondsDelayOnRetry + found->MillisecondsDelayOnRetry < toMatch->MillisecondsDelayOnRetry) { + toMatch->MillisecondsDelayOnRetry = MAXULONG; + } else { + toMatch->MillisecondsDelayOnRetry += found->MillisecondsDelayOnRetry; + } + + // this found item cannot contain any compressed entries because + // the first entry with a given set of sense/asc/ascq will always + // either be full (0xFF) or be the only partially-full entry with + // that sense/asc/ascq. + NT_ASSERT(found->ClassDriverUse == 0); + // add the counts so we still know how many retries total + toMatch->ClassDriverUse++; + + + // if not the last entry, need to move later entries earlier in the array + if (j != RequestHistory->UsedHistoryCount-1) { + // how many entries remain? + SIZE_T remainingBytes = RequestHistory->UsedHistoryCount - 1 - j; + remainingBytes *= sizeof(SRB_HISTORY_ITEM); + + // note that MOVE is required due to overlapping entries + RtlMoveMemory(found, found+1, remainingBytes); + + // Finally, decrement the number of used history count and + // decrement j to rescan the current location again + --RequestHistory->UsedHistoryCount; + --j; + } // end moving of array elements around + } // end of close enough match + } // end j loop + } // end i loop + + // unable to compress duplicate sense/asc/ascq, so just lose the most recent data + if (RequestHistory->UsedHistoryCount == RequestHistory->TotalHistoryCount) + { + PSRB_HISTORY_ITEM item = &( RequestHistory->History[ RequestHistory->TotalHistoryCount-1 ] ); + RequestHistory->ClassDriverUse[0] += item->ClassDriverUse; // how many did we "lose"? + RequestHistory->UsedHistoryCount--; + } + + // finally, zero any that are no longer in use + NT_ASSERT( RequestHistory->UsedHistoryCount != RequestHistory->TotalHistoryCount); + { + SIZE_T bytesToZero = RequestHistory->TotalHistoryCount - RequestHistory->UsedHistoryCount; + bytesToZero *= sizeof(SRB_HISTORY_ITEM); + RtlZeroMemory(&(RequestHistory->History[RequestHistory->UsedHistoryCount]), bytesToZero); + } + + ValidateSrbHistoryDataPresumptions(RequestHistory); + return; +} + +VOID +ValidateSrbHistoryDataPresumptions( + _In_ SRB_HISTORY const * RequestHistory + ) +{ +#if DBG + // validate that all fully-compressed items are before any non-fully-compressed items of any particular sense/asc/ascq + // validate that there is at most one partially-compressed item of any particular sense/asc/ascq + // validate that all items of any particular sense/asc/ascq that are uncompressed are at the end + // THUS: A(255) A(255) A( 40) A( 0) A( 0) is legal for all types with A as sense/asc/ascq + // A(0) B(255) A( 0) B( 17) B( 0) is also legal because A/B are different types of error + + ULONG i; + for (i = 0; i < RequestHistory->UsedHistoryCount; i++) + { + SRB_HISTORY_ITEM const * toMatch = &( RequestHistory->History[i] ); + UCHAR const srbStatus = toMatch->SrbStatus; + UCHAR const sense = toMatch->NormalizedSenseData.SenseKey; + UCHAR const asc = toMatch->NormalizedSenseData.AdditionalSenseCode; + UCHAR const ascq = toMatch->NormalizedSenseData.AdditionalSenseCodeQualifier; + ULONG j; + + BOOLEAN foundPartiallyCompressedItem = + (toMatch->ClassDriverUse != 0) && + (toMatch->ClassDriverUse != 0xFF) ; + BOOLEAN foundUncompressedItem = + (toMatch->ClassDriverUse == 0) ; + + for (j = i+1; j < RequestHistory->UsedHistoryCount; j++) + { + SRB_HISTORY_ITEM const * found = &( RequestHistory->History[j] ); + if ((srbStatus == found->SrbStatus) && + (sense == found->NormalizedSenseData.SenseKey) && + (asc == found->NormalizedSenseData.AdditionalSenseCode) && + (ascq == found->NormalizedSenseData.AdditionalSenseCodeQualifier) + ) + { + // found a matching type, so validate ordering rules + if (foundUncompressedItem && (found->ClassDriverUse != 0)) + { + DbgPrintEx(DPFLTR_CDROM_ID, DPFLTR_ERROR_LEVEL, + "History data has compressed history following uncompressed history " + "for srbstatus/sense/asc/ascq of %02x/%02x/%02x/%02x at indices %d (%08x) and %d (%08x)\n", + srbStatus, sense, asc, ascq, + i,i, j,j + ); + NT_ASSERT(FALSE); + } + else if (foundPartiallyCompressedItem && (found->ClassDriverUse == 0xFF)) + { + DbgPrintEx(DPFLTR_CDROM_ID, DPFLTR_ERROR_LEVEL, + "History data has fully compressed history following partially compressed history " + "for srbstatus/sense/asc/ascq of %02x/%02x/%02x/%02x at indices %d (%08x) and %d (%08x)\n", + srbStatus, sense, asc, ascq, + i,i, j,j + ); + NT_ASSERT(FALSE); + } + + // update if we have now found partially compressed and/or uncompressed items + if (found->ClassDriverUse == 0) + { + foundUncompressedItem = TRUE; + } + else if (found->ClassDriverUse != 0xFF) + { + foundPartiallyCompressedItem = TRUE; + } + } // end match of (toMatch,found) + } // end loop j + } // end loop i +#else + UNREFERENCED_PARAMETER(RequestHistory); +#endif + return; +} + +VOID +ScratchBuffer_SetupReadWriteSrb( + _Inout_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST OriginalRequest, + _In_ LARGE_INTEGER StartingOffset, + _In_ ULONG RequiredLength, + _Inout_updates_bytes_(RequiredLength) UCHAR* DataBuffer, + _In_ BOOLEAN IsReadRequest, + _In_ BOOLEAN UsePartialMdl + ) +/*++ + +Routine Description: + + setup SRB for read/write request. + +Arguments: + + DeviceExtension - device extension + OriginalRequest - read/write request + StartingOffset - read/write starting offset + DataBuffer - buffer for read/write + IsReadRequest - TRUE (read); FALSE (write) + +Return Value: + + none + +--*/ +{ + //NOTE: R/W request not use the ScratchBuffer, instead, it uses the buffer associated with IRP. + + PSCSI_REQUEST_BLOCK srb = DeviceExtension->ScratchContext.ScratchSrb; + PCDB cdb = (PCDB)srb->Cdb; + LARGE_INTEGER logicalBlockAddr; + ULONG numTransferBlocks; + + PIRP originalIrp = WdfRequestWdmGetIrp(OriginalRequest); + + PIRP irp = WdfRequestWdmGetIrp(DeviceExtension->ScratchContext.ScratchRequest); + PIO_STACK_LOCATION irpStack = NULL; + + PCDROM_REQUEST_CONTEXT requestContext = RequestGetContext(DeviceExtension->ScratchContext.ScratchRequest); + + requestContext->OriginalRequest = OriginalRequest; + + + logicalBlockAddr.QuadPart = Int64ShrlMod32(StartingOffset.QuadPart, DeviceExtension->SectorShift); + numTransferBlocks = RequiredLength >> DeviceExtension->SectorShift; + + // set to use the full scratch buffer via the scratch SRB + irpStack = IoGetNextIrpStackLocation(irp); + irpStack->MajorFunction = IRP_MJ_SCSI; + if (IsReadRequest) + { + irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_IN; + } + else + { + irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_OUT; + } + irpStack->Parameters.Scsi.Srb = srb; + + // prepare the SRB with default values + srb->Length = SCSI_REQUEST_BLOCK_SIZE; + srb->Function = SRB_FUNCTION_EXECUTE_SCSI; + srb->QueueAction = SRB_SIMPLE_TAG_REQUEST; + srb->SrbStatus = 0; + srb->ScsiStatus = 0; + srb->NextSrb = NULL; + srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE; + srb->SenseInfoBuffer = DeviceExtension->ScratchContext.ScratchSense; + + srb->DataBuffer = DataBuffer; + srb->DataTransferLength = RequiredLength; + + srb->QueueSortKey = logicalBlockAddr.LowPart; + if (logicalBlockAddr.QuadPart > 0xFFFFFFFF) + { + // + // If the requested LBA is more than max ULONG set the + // QueueSortKey to the maximum value, so that these + // requests can be added towards the end of the queue. + // + srb->QueueSortKey = 0xFFFFFFFF; + } + + srb->OriginalRequest = irp; + srb->TimeOutValue = DeviceExtension->TimeOutValue; + + if (RequestIsRealtimeStreaming(OriginalRequest, IsReadRequest) && + !TEST_FLAG(DeviceExtension->PrivateFdoData->HackFlags, FDO_HACK_NO_STREAMING)) + { + if (IsReadRequest) + { + RtlZeroMemory(&cdb->READ12, sizeof(cdb->READ12)); + REVERSE_BYTES(&cdb->READ12.LogicalBlock, &logicalBlockAddr.LowPart); + REVERSE_BYTES(&cdb->READ12.TransferLength, &numTransferBlocks); + cdb->READ12.Streaming = 1; + cdb->READ12.OperationCode = SCSIOP_READ12; + srb->CdbLength = sizeof(cdb->READ12); + } + else + { + RtlZeroMemory(&cdb->WRITE12, sizeof(cdb->WRITE12)); + REVERSE_BYTES(&cdb->WRITE12.LogicalBlock, &logicalBlockAddr.LowPart); + REVERSE_BYTES(&cdb->WRITE12.TransferLength, &numTransferBlocks); + cdb->WRITE12.Streaming = 1; + cdb->WRITE12.OperationCode = SCSIOP_WRITE12; + srb->CdbLength = sizeof(cdb->WRITE12); + } + } + else + { + RtlZeroMemory(&cdb->CDB10, sizeof(cdb->CDB10)); + cdb->CDB10.LogicalBlockByte0 = ((PFOUR_BYTE)&logicalBlockAddr.LowPart)->Byte3; + cdb->CDB10.LogicalBlockByte1 = ((PFOUR_BYTE)&logicalBlockAddr.LowPart)->Byte2; + cdb->CDB10.LogicalBlockByte2 = ((PFOUR_BYTE)&logicalBlockAddr.LowPart)->Byte1; + cdb->CDB10.LogicalBlockByte3 = ((PFOUR_BYTE)&logicalBlockAddr.LowPart)->Byte0; + cdb->CDB10.TransferBlocksMsb = ((PFOUR_BYTE)&numTransferBlocks)->Byte1; + cdb->CDB10.TransferBlocksLsb = ((PFOUR_BYTE)&numTransferBlocks)->Byte0; + cdb->CDB10.OperationCode = (IsReadRequest) ? SCSIOP_READ : SCSIOP_WRITE; + srb->CdbLength = sizeof(cdb->CDB10); + } + + // Set SRB and IRP flags + srb->SrbFlags = DeviceExtension->SrbFlags; + if (TEST_FLAG(originalIrp->Flags, IRP_PAGING_IO) || + TEST_FLAG(originalIrp->Flags, IRP_SYNCHRONOUS_PAGING_IO)) + { + SET_FLAG(srb->SrbFlags, SRB_CLASS_FLAGS_PAGING); + } + + SET_FLAG(srb->SrbFlags, (IsReadRequest) ? SRB_FLAGS_DATA_IN : SRB_FLAGS_DATA_OUT); + SET_FLAG(srb->SrbFlags, SRB_FLAGS_ADAPTER_CACHE_ENABLE); + + // + // If the request is not split, we can use the original IRP MDL. If the + // request needs to be split, we need to use a partial MDL. The partial MDL + // is needed because more than one driver might be mapping the same MDL + // and this causes problems. + // + if (UsePartialMdl == FALSE) + { + irp->MdlAddress = originalIrp->MdlAddress; + } + else + { + if (DeviceExtension->ScratchContext.PartialMdlIsBuilt != FALSE) + { + MmPrepareMdlForReuse(DeviceExtension->ScratchContext.PartialMdl); + } + + IoBuildPartialMdl(originalIrp->MdlAddress, DeviceExtension->ScratchContext.PartialMdl, srb->DataBuffer, srb->DataTransferLength); + DeviceExtension->ScratchContext.PartialMdlIsBuilt = TRUE; + irp->MdlAddress = DeviceExtension->ScratchContext.PartialMdl; + } + + //DBGLOGSENDPACKET(Pkt); + //HISTORYLOGSENDPACKET(Pkt); + + // + // Set the original irp here for SFIO. + // + srb->SrbExtension = (PVOID)(originalIrp); + + return; +} + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +ScratchBuffer_ExecuteCdbEx( + _Inout_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_opt_ WDFREQUEST OriginalRequest, + _In_ ULONG TransferSize, + _In_ BOOLEAN GetDataFromDevice, + _In_ PCDB Cdb, + _In_ UCHAR OprationLength, + _In_ ULONG TimeoutValue + ) +/*++ + +Routine Description: + + Use Scratch buffer to send the Cdb, check error and retry if necessary. + +Arguments: + + DeviceExtension - device context + OriginalRequest - original request that requires this CDB operation + TransferSize - Data transfer size required + GetFromDevice - TRUE if getting data from device. + Cdb - SCSI command + OprationLength - SCSI command length: 6, 10 or 12 + TimeoutValue - if > 0, use it as timeout value for command + if 0, use the default device timeout value + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PSCSI_REQUEST_BLOCK srb = DeviceExtension->ScratchContext.ScratchSrb; + PCDB cdb = (PCDB)(srb->Cdb); + + BOOLEAN shouldRetry = TRUE; + ULONG timesAlreadyRetried = 0; + LONGLONG retryIn100nsUnits = 0; + + PAGED_CODE (); + + while (shouldRetry) + { + ScratchBuffer_SetupSrb(DeviceExtension, OriginalRequest, TransferSize, GetDataFromDevice); + + // Set up the SRB/CDB + RtlCopyMemory(cdb, Cdb, sizeof(CDB)); + + srb->CdbLength = OprationLength; + + if (TimeoutValue > 0) + { + srb->TimeOutValue = TimeoutValue; + } + + ScratchBuffer_SendSrb(DeviceExtension, TRUE, NULL); + + if ((DeviceExtension->ScratchContext.ScratchSrb->SrbStatus == SRB_STATUS_ABORTED) && + (DeviceExtension->ScratchContext.ScratchSrb->InternalStatus == STATUS_CANCELLED)) + { + shouldRetry = FALSE; + status = STATUS_CANCELLED; + } + else + { + shouldRetry = RequestSenseInfoInterpretForScratchBuffer(DeviceExtension, + timesAlreadyRetried, + &status, + &retryIn100nsUnits); + if (shouldRetry) + { + LARGE_INTEGER t; + t.QuadPart = -retryIn100nsUnits; + timesAlreadyRetried++; + KeDelayExecutionThread(KernelMode, FALSE, &t); + // keep items clean + ScratchBuffer_ResetItems(DeviceExtension, FALSE); + } + } + } + + return status; +} + + diff --git a/storage/class/cdrom/src/scratch.h b/storage/class/cdrom/src/scratch.h new file mode 100644 index 00000000..92d75328 --- /dev/null +++ b/storage/class/cdrom/src/scratch.h @@ -0,0 +1,187 @@ +/*++ + +Copyright (C) Microsoft Corporation. All rights reserved. + +Module Name: + + mmc.h + +Abstract: + + Functions/macros for using the scratch buffer and scratch request/SRB + in the serial I/O queue context + +Author: + +Environment: + + kernel mode only + +Notes: + + +Revision History: + +--*/ + +#ifndef __SCRATCH_H__ +#define __SCRATCH_H__ + + +_IRQL_requires_max_(APC_LEVEL) +VOID +ScratchBuffer_Deallocate( + _Inout_ PCDROM_DEVICE_EXTENSION DeviceExtension + ); + +_IRQL_requires_max_(APC_LEVEL) +BOOLEAN +ScratchBuffer_Allocate( + _Inout_ PCDROM_DEVICE_EXTENSION DeviceExtension + ); + +VOID +ScratchBuffer_ResetItems( + _Inout_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ BOOLEAN ResetRequestHistory + ); + +_IRQL_requires_max_(APC_LEVEL) +VOID +ScratchBuffer_SetupSrb( + _Inout_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_opt_ WDFREQUEST OriginalRequest, + _In_ ULONG MaximumTransferLength, + _In_ BOOLEAN GetDataFromDevice + ); + +VOID +ScratchBuffer_SetupReadWriteSrb( + _Inout_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST OriginalRequest, + _In_ LARGE_INTEGER StartingOffset, + _In_ ULONG RequiredLength, + _Inout_updates_bytes_(RequiredLength) UCHAR* DataBuffer, + _In_ BOOLEAN IsReadRequest, + _In_ BOOLEAN UsePartialMdl + ); + +NTSTATUS +ScratchBuffer_SendSrb( + _Inout_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ BOOLEAN SynchronousSrb, + _When_(SynchronousSrb, _Pre_null_) + _When_(!SynchronousSrb, _In_opt_) + PSRB_HISTORY_ITEM *SrbHistoryItem + ); + +NTSTATUS +ScratchBuffer_PerformNextReadWrite( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ BOOLEAN FirstTry + ); + +#if DBG + #define ScratchBuffer_BeginUse(context) ScratchBuffer_BeginUseX((context), __FILE__, __LINE__) +#else + #define ScratchBuffer_BeginUse(context) ScratchBuffer_BeginUseX((context), NULL, (ULONG)-1) +#endif + +__inline VOID ScratchBuffer_BeginUseX(_Inout_ PCDROM_DEVICE_EXTENSION DeviceExtension, _In_opt_ LPCSTR File, ULONG Line) +{ + // NOTE: these are not "real" locks. They are simply to help + // avoid multiple uses of the scratch buffer. Thus, it + // is not critical to have atomic operations here. + PVOID tmp = InterlockedCompareExchangePointer((PVOID)&(DeviceExtension->ScratchContext.ScratchInUse), (PVOID)-1, NULL); + NT_ASSERT(tmp == NULL); + UNREFERENCED_PARAMETER(tmp); //defensive coding, avoid PREFAST warning. + DeviceExtension->ScratchContext.ScratchInUseFileName = File; + DeviceExtension->ScratchContext.ScratchInUseLineNumber = Line; + ScratchBuffer_ResetItems(DeviceExtension, TRUE); + RequestClearSendTime(DeviceExtension->ScratchContext.ScratchRequest); + return; +} +__inline VOID ScratchBuffer_EndUse(_Inout_ PCDROM_DEVICE_EXTENSION DeviceExtension) +{ + // NOTE: these are not "real" locks. They are simply to help + // avoid multiple uses of the scratch buffer. Thus, it + // is not critical to have atomic operations here. + + // On lock release, we erase ScratchInUseFileName and ScratchInUseLineNumber _before_ releasing ScratchInUse, + // because otherwise we may erase these after the lock has been acquired again by another thread. We store the + // old values of ScratchInUseFileName and ScratchInUseLineNumber in local variables to facilitate debugging, + // if the ASSERT at the end of the function is hit. + PCSTR scratchInUseFileName; + ULONG scratchInUseLineNumber; + PVOID tmp; + + scratchInUseFileName = DeviceExtension->ScratchContext.ScratchInUseFileName; + scratchInUseLineNumber = DeviceExtension->ScratchContext.ScratchInUseLineNumber; + UNREFERENCED_PARAMETER(scratchInUseFileName); + UNREFERENCED_PARAMETER(scratchInUseLineNumber); + DeviceExtension->ScratchContext.ScratchInUseFileName = NULL; + DeviceExtension->ScratchContext.ScratchInUseLineNumber = 0; + + // + // If we have used the PartialMdl in the scratch context we should notify MM that we will be reusing it + // otherwise it may leak System VA if some one below us has mapped the same. + // + + if (DeviceExtension->ScratchContext.PartialMdlIsBuilt != FALSE) + { + MmPrepareMdlForReuse(DeviceExtension->ScratchContext.PartialMdl); + DeviceExtension->ScratchContext.PartialMdlIsBuilt = FALSE; + } + + tmp = InterlockedCompareExchangePointer((PVOID)&(DeviceExtension->ScratchContext.ScratchInUse), NULL, (PVOID)-1); + NT_ASSERT(tmp == ((PVOID)-1)); + UNREFERENCED_PARAMETER(tmp); //defensive coding, avoid PREFAST warning. + return; +} + +VOID +CompressSrbHistoryData( + _Inout_ PSRB_HISTORY RequestHistory + ); + +VOID +ValidateSrbHistoryDataPresumptions( + _In_ SRB_HISTORY const* RequestHistory + ); + +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +ScratchBuffer_ExecuteCdbEx( + _Inout_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_opt_ WDFREQUEST OriginalRequest, + _In_ ULONG TransferSize, + _In_ BOOLEAN GetDataFromDevice, + _In_ PCDB Cdb, + _In_ UCHAR OprationLength, + _In_ ULONG TimeoutValue + ); + +_IRQL_requires_max_(APC_LEVEL) +__inline +NTSTATUS +ScratchBuffer_ExecuteCdb( + _Inout_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_opt_ WDFREQUEST OriginalRequest, + _In_ ULONG TransferSize, + _In_ BOOLEAN GetDataFromDevice, + _In_ PCDB Cdb, + _In_ UCHAR OprationLength + ) +{ + return ScratchBuffer_ExecuteCdbEx(DeviceExtension, + OriginalRequest, + TransferSize, + GetDataFromDevice, + Cdb, + OprationLength, + 0); +} + +KDEFERRED_ROUTINE ScratchBuffer_ReadWriteTimerRoutine; + +#endif //__SCRATCH_H__ diff --git a/storage/class/cdrom/src/sense.c b/storage/class/cdrom/src/sense.c new file mode 100644 index 00000000..7033c6ce --- /dev/null +++ b/storage/class/cdrom/src/sense.c @@ -0,0 +1,2600 @@ +/*-- + +Copyright (C) Microsoft Corporation. All rights reserved. + +Module Name: + + sense.c + +Abstract: + + This file contains the methods needed to accurately + determine how to retry requests on CDROM device types. + +Environment: + + kernel mode only + +Revision History: + +--*/ + +#include "stddef.h" +#include "string.h" + +#include "ntddk.h" +#include "ntddstor.h" +#include "cdrom.h" +#include "ntstrsafe.h" + + +#ifdef DEBUG_USE_WPP +#include "sense.tmh" +#endif + +// Forward declarations +VOID +SenseInfoInterpretRefineByIoControl( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ ULONG IoControlCode, + _In_ BOOLEAN OverrideVerifyVolume, + _Inout_ BOOLEAN* Retry, + _Inout_ NTSTATUS* Status + ); + + +#ifdef ALLOC_PRAGMA + +#pragma alloc_text(PAGE, SenseInfoInterpretRefineByIoControl) + +#endif + + +// +// FROM CLASSPNP\CLASSP.H +// Lots of retries of synchronized SCSI commands that devices may not +// even support really slows down the system (especially while booting). +// (Even GetDriveCapacity may be failed on purpose if an external disk is powered off). +// If a disk cannot return a small initialization buffer at startup +// in two attempts (with delay interval) then we cannot expect it to return +// data consistently with four retries. +// So don't set the retry counts as high here as for data SRBs. +// +// If we find that these requests are failing consecutively, +// despite the retry interval, on otherwise reliable media, +// then we should either increase the retry interval for +// that failure or (by all means) increase these retry counts as appropriate. +// + +#define TOTAL_COUNT_RETRY_DEFAULT 4 +#define TOTAL_COUNT_RETRY_LOCK_MEDIA 1 +#define TOTAL_COUNT_RETRY_MODESENSE 1 +#define TOTAL_COUNT_RETRY_READ_CAPACITY 1 + + +#define TOTAL_SECONDS_RETRY_TIME_WRITE 160 +#define TOTAL_SECONDS_RETRY_TIME_MEDIUM_REMOVAL 120 + +typedef struct _ERROR_LOG_CONTEXT { + BOOLEAN LogError; + BOOLEAN ErrorUnhandled; + NTSTATUS ErrorCode; + ULONG UniqueErrorValue; + ULONG BadSector; +} ERROR_LOG_CONTEXT, *PERROR_LOG_CONTEXT; + +NTSTATUS +DeviceErrorHandlerForMmc( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ PSCSI_REQUEST_BLOCK Srb, + _Inout_ PNTSTATUS Status, + _Inout_ PBOOLEAN Retry + ) +/*++ + +Routine Description: + + this routine will be used for error handler for all MMC devices. + it's invoked by DeviceErrorHandler()that invoked by SenseInfoInterpret() or GESN + + This routine just checks for media change sense/asc/ascq and + also for other events, such as bus resets. this is used to + determine if the device behaviour has changed, to allow for + read and write operations to be allowed and/or disallowed. + +Arguments: + + DeviceExtension - device context + Srb - SRB structure for analyze + +Return Value: + + NTSTATUS + Status - + Retry - + +--*/ +{ + BOOLEAN mediaChange = FALSE; + PCDB cdb = (PCDB)Srb->Cdb; + + if (TEST_FLAG(Srb->SrbStatus, SRB_STATUS_AUTOSENSE_VALID)) + { + PSENSE_DATA senseBuffer = Srb->SenseInfoBuffer; + + // the following sense keys could indicate a change in capabilities. + + // we used to expect this to be serialized, and only hit from our + // own routine. we now allow some requests to continue during our + // processing of the capabilities update in order to allow + // IoReadPartitionTable() to succeed. + switch (senseBuffer->SenseKey & 0xf) + { + + case SCSI_SENSE_NOT_READY: + { + if (senseBuffer->AdditionalSenseCode == SCSI_ADSENSE_NO_MEDIA_IN_DEVICE) + { + if (DeviceExtension->DeviceAdditionalData.Mmc.WriteAllowed) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, + "DeviceErrorHandlerForMmc: media removed, writes will be " + "failed until new media detected\n")); + } + + // NOTE - REF #0002 + DeviceExtension->DeviceAdditionalData.Mmc.WriteAllowed = FALSE; + } + else if (senseBuffer->AdditionalSenseCode == SCSI_ADSENSE_LUN_NOT_READY) + { + if (senseBuffer->AdditionalSenseCodeQualifier == SCSI_SENSEQ_BECOMING_READY) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, + "DeviceErrorHandlerForMmc: media becoming ready, " + "SHOULD notify shell of change time by sending " + "GESN request immediately!\n")); + } + else if (((senseBuffer->AdditionalSenseCodeQualifier == SCSI_SENSEQ_OPERATION_IN_PROGRESS) || + (senseBuffer->AdditionalSenseCodeQualifier == SCSI_SENSEQ_LONG_WRITE_IN_PROGRESS) + ) && + ((Srb->Cdb[0] == SCSIOP_READ) || + (Srb->Cdb[0] == SCSIOP_READ6) || + (Srb->Cdb[0] == SCSIOP_READ_CAPACITY) || + (Srb->Cdb[0] == SCSIOP_READ_CD) || + (Srb->Cdb[0] == SCSIOP_READ_CD_MSF) || + (Srb->Cdb[0] == SCSIOP_READ_TOC) || + (Srb->Cdb[0] == SCSIOP_WRITE) || + (Srb->Cdb[0] == SCSIOP_WRITE6) || + (Srb->Cdb[0] == SCSIOP_READ_TRACK_INFORMATION) || + (Srb->Cdb[0] == SCSIOP_READ_DISK_INFORMATION) + ) + ) + { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, + "DeviceErrorHandlerForMmc: LONG_WRITE or " + "OP_IN_PROGRESS for limited subset of cmds -- " + "setting retry to TRUE\n")); + *Retry = TRUE; + *Status = STATUS_DEVICE_BUSY; + } + } + break; + } // end SCSI_SENSE_NOT_READY + + case SCSI_SENSE_UNIT_ATTENTION: + { + switch (senseBuffer->AdditionalSenseCode) + { + case SCSI_ADSENSE_MEDIUM_CHANGED: + { + // always update if the medium may have changed + + // NOTE - REF #0002 + DeviceExtension->DeviceAdditionalData.Mmc.WriteAllowed = FALSE; + DeviceExtension->DeviceAdditionalData.Mmc.UpdateState = CdromMmcUpdateRequired; + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, + "DeviceErrorHandlerForMmc: media change detected, need to " + "update drive capabilities\n")); + mediaChange = TRUE; + break; + + } // end SCSI_ADSENSE_MEDIUM_CHANGED + + case SCSI_ADSENSE_BUS_RESET: + { + // NOTE - REF #0002 + DeviceExtension->DeviceAdditionalData.Mmc.WriteAllowed = FALSE; + DeviceExtension->DeviceAdditionalData.Mmc.UpdateState = CdromMmcUpdateRequired; + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, + "DeviceErrorHandlerForMmc: bus reset detected, need to " + "update drive capabilities\n")); + break; + + } // end SCSI_ADSENSE_BUS_RESET + + case SCSI_ADSENSE_OPERATOR_REQUEST: + { + + BOOLEAN b = FALSE; + + switch (senseBuffer->AdditionalSenseCodeQualifier) + { + case SCSI_SENSEQ_MEDIUM_REMOVAL: + { + // eject notification currently handled by classpnp + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, + "DeviceErrorHandlerForMmc: Eject requested by user\n")); + *Retry = TRUE; + *Status = STATUS_DEVICE_BUSY; + break; + } + + case SCSI_SENSEQ_WRITE_PROTECT_DISABLE: + b = TRUE; + case SCSI_SENSEQ_WRITE_PROTECT_ENABLE: + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, + "DeviceErrorHandlerForMmc: Write protect %s requested " + "by user\n", + (b ? "disable" : "enable"))); + *Retry = TRUE; + *Status = STATUS_DEVICE_BUSY; + // NOTE - REF #0002 + DeviceExtension->DeviceAdditionalData.Mmc.WriteAllowed = FALSE; + DeviceExtension->DeviceAdditionalData.Mmc.UpdateState = CdromMmcUpdateRequired; + + break; + } + + } // end of AdditionalSenseCodeQualifier switch + + + break; + + } // end SCSI_ADSENSE_OPERATOR_REQUEST + + default: + { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, + "DeviceErrorHandlerForMmc: Unit attention %02x/%02x\n", + senseBuffer->AdditionalSenseCode, + senseBuffer->AdditionalSenseCodeQualifier)); + break; + } + + } // end of AdditionSenseCode switch + break; + + } // end SCSI_SENSE_UNIT_ATTENTION + + case SCSI_SENSE_ILLEGAL_REQUEST: + { + if (senseBuffer->AdditionalSenseCode == SCSI_ADSENSE_WRITE_PROTECT) + { + if (DeviceExtension->DeviceAdditionalData.Mmc.WriteAllowed) + { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, + "DeviceErrorHandlerForMmc: media was writable, but " + "failed request with WRITE_PROTECT error...\n")); + } + // NOTE - REF #0002 + // do not update all the capabilities just because + // we can't write to the disc. + DeviceExtension->DeviceAdditionalData.Mmc.WriteAllowed = FALSE; + } + break; + } // end SCSI_SENSE_ILLEGAL_REQUEST + + } // end of SenseKey switch + + // Check if we failed to set the DVD region key and send appropriate error + if (cdb->CDB16.OperationCode == SCSIOP_SEND_KEY) + { + if (cdb->SEND_KEY.KeyFormat == DvdSetRpcKey) + { + if (senseBuffer->AdditionalSenseCode == SCSI_ADSENSE_NO_MEDIA_IN_DEVICE) + { + // media of appropriate region required + *Status = STATUS_NO_MEDIA_IN_DEVICE; + *Retry = FALSE; + } + else if ((senseBuffer->SenseKey == SCSI_SENSE_ILLEGAL_REQUEST) && + (senseBuffer->AdditionalSenseCode == SCSI_ADSENSE_COPY_PROTECTION_FAILURE) && + (senseBuffer->AdditionalSenseCodeQualifier == SCSI_SENSEQ_MEDIA_CODE_MISMATCHED_TO_LOGICAL_UNIT)) + { + // media of appropriate region required + *Status = STATUS_CSS_REGION_MISMATCH; + *Retry = FALSE; + } + else if ((senseBuffer->SenseKey == SCSI_SENSE_ILLEGAL_REQUEST) && + (senseBuffer->AdditionalSenseCode == SCSI_ADSENSE_INVALID_MEDIA) && + (senseBuffer->AdditionalSenseCodeQualifier == SCSI_SENSEQ_INCOMPATIBLE_FORMAT)) + { + // media of appropriate region required + *Status = STATUS_CSS_REGION_MISMATCH; + *Retry = FALSE; + } + } + } + } // end of SRB_STATUS_AUTOSENSE_VALID + + // On media change, if device speed should be reset to default then + // queue a workitem to send the commands to the device. Do this on + // media arrival as some device will fail this command if no media + // is present. Ignore the fake media change from classpnp driver. + if ((mediaChange == TRUE) && (*Status != STATUS_MEDIA_CHANGED)) + { + if (DeviceExtension->DeviceAdditionalData.RestoreDefaults == TRUE) + { + NTSTATUS status = STATUS_SUCCESS; + WDF_OBJECT_ATTRIBUTES attributes; + WDF_WORKITEM_CONFIG workitemConfig; + WDFWORKITEM workItem; + + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + attributes.ParentObject = DeviceExtension->Device; + + WDF_WORKITEM_CONFIG_INIT(&workitemConfig, + DeviceRestoreDefaultSpeed); + + status = WdfWorkItemCreate(&workitemConfig, + &attributes, + &workItem); + if (!NT_SUCCESS(status)) + { + return STATUS_SUCCESS; + } + + WdfWorkItemEnqueue(workItem); + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, + "DeviceErrorHandlerForMmc: Restore device default speed for %p\n", + DeviceExtension->DeviceObject)); + } + } + return STATUS_SUCCESS; +} + +NTSTATUS +DeviceErrorHandlerForHitachiGD2000( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ PSCSI_REQUEST_BLOCK Srb, + _Inout_ PNTSTATUS Status, + _Inout_ PBOOLEAN Retry + ) +/*++ + +Routine Description: + + error handler for HITACHI CDR-1750S, CDR-3650/1650S + + This routine checks the type of error. If the error suggests that the + drive has spun down and cannot reinitialize itself, send a + START_UNIT or READ to the device. This will force the drive to spin + up. This drive also loses the AGIDs it has granted when it spins down, + which may result in playback failure the first time around. + +Arguments: + + DeviceExtension - the device object. + + Srb - Supplies a pointer to the failing Srb. + + Status - return the final status for this command? + + Retry - return if the command should be retried. + +Return Value: + + None. + +--*/ +{ + PSENSE_DATA senseBuffer = Srb->SenseInfoBuffer; + + if (!TEST_FLAG(Srb->SrbStatus, SRB_STATUS_AUTOSENSE_VALID)) + { + return STATUS_SUCCESS; //nobody cares about this return value yet. + } + + if (((senseBuffer->SenseKey & 0xf) == SCSI_SENSE_HARDWARE_ERROR) && + (senseBuffer->AdditionalSenseCode == 0x44)) + { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, + "DeviceErrorHandlerForHitachiGD2000 (%p) => Internal Target " + "Failure Detected -- spinning up drive\n", DeviceExtension->Device)); + + // the request should be retried because the device isn't ready + *Retry = TRUE; + *Status = STATUS_DEVICE_NOT_READY; + + // send a START_STOP unit to spin up the drive + // NOTE: this temporarily violates the StartIo serialization + // mechanism, but the completion routine on this will NOT + // call StartNextPacket(), so it's a temporary disruption + // of the serialization only. + DeviceSendStartUnit(DeviceExtension->Device); + } + + return STATUS_SUCCESS; +} + + +VOID +SenseInfoRequestGetInformation( + _In_ WDFREQUEST Request, + _Out_ UCHAR* MajorFunctionCode, + _Out_ ULONG* IoControlCode, + _Out_ BOOLEAN* OverrideVerifyVolume, + _Out_ ULONGLONG* Total100nsSinceFirstSend + ) +{ + PCDROM_REQUEST_CONTEXT requestContext = RequestGetContext(Request); + + *MajorFunctionCode = 0; + *IoControlCode = 0; + *OverrideVerifyVolume = FALSE; + *Total100nsSinceFirstSend = 0; + + if (requestContext->OriginalRequest != NULL) + { + PIO_STACK_LOCATION originalIrpStack = NULL; + + PIRP originalIrp = WdfRequestWdmGetIrp(requestContext->OriginalRequest); + + if (originalIrp != NULL) + { + originalIrpStack = IoGetCurrentIrpStackLocation(originalIrp); + } + + if (originalIrpStack != NULL) + { + *MajorFunctionCode = originalIrpStack->MajorFunction; + + if (*MajorFunctionCode == IRP_MJ_DEVICE_CONTROL) + { + *IoControlCode = originalIrpStack->Parameters.DeviceIoControl.IoControlCode; + } + + *OverrideVerifyVolume = TEST_FLAG(originalIrpStack->Flags, SL_OVERRIDE_VERIFY_VOLUME); + } + } + + // Calculate time past since the request was first time sent. + if (requestContext->TimeSentDownFirstTime.QuadPart > 0) + { + LARGE_INTEGER tmp; + KeQueryTickCount(&tmp); + tmp.QuadPart -= requestContext->TimeSentDownFirstTime.QuadPart; + tmp.QuadPart *= KeQueryTimeIncrement(); + *Total100nsSinceFirstSend = tmp.QuadPart; + } + else + { + // set to -1 if field TimeSentDownFirstTime not set. + *Total100nsSinceFirstSend = (ULONGLONG) -1; + } + + return; +} + +BOOLEAN +SenseInfoInterpretByAdditionalSenseCode( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ PSCSI_REQUEST_BLOCK Srb, + _In_ UCHAR AdditionalSenseCode, + _In_ UCHAR AdditionalSenseCodeQual, + _Inout_ NTSTATUS* Status, + _Inout_ BOOLEAN* Retry, + _Out_ _Deref_out_range_(0,100) ULONG* RetryIntervalInSeconds, + _Inout_ PERROR_LOG_CONTEXT LogContext + ) +/* + This function will interpret error based on ASC/ASCQ. + + If the error code is not processed in this function, e.g. return value is TRUE, + caller needs to call SenseInfoInterpretBySenseKey() for further interpret. +*/ +{ + BOOLEAN needFurtherInterpret = TRUE; + PSENSE_DATA senseBuffer = (PSENSE_DATA)Srb->SenseInfoBuffer; + + // set default values for retry fields. + *Status = STATUS_IO_DEVICE_ERROR; + *Retry = TRUE; + *RetryIntervalInSeconds = 0; + + switch (AdditionalSenseCode) + { + case SCSI_ADSENSE_LUN_NOT_READY: + { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, + "SenseInfoInterpretByAdditionalSenseCode: Lun not ready\n")); + + // + // Many non-WHQL certified drives (mostly CD-RW) return + // 2/4/0 when they have no media instead of the obvious choice of: + // + // SCSI_SENSE_NOT_READY/SCSI_ADSENSE_NO_MEDIA_IN_DEVICE + // + // These drives should not pass WHQL certification due to this discrepency. + // + // However, we have to retry on 2/4/0 (Not ready, LUN not ready, no info) + // and also 3/2/0 (no seek complete). + // + // These conditions occur when the shell tries to examine an + // injected CD (e.g. for autoplay) before the CD is spun up. + // + // The drive should be returning an ASCQ of SCSI_SENSEQ_BECOMING_READY + // (0x01) in order to comply with WHQL standards. + // + // The default retry timeout of one second is acceptable to balance + // these discrepencies. don't modify the status, though.... + // + + switch (AdditionalSenseCodeQual) + { + case SCSI_SENSEQ_OPERATION_IN_PROGRESS: + { + DEVICE_EVENT_BECOMING_READY notReady = {0}; + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, + "SenseInfoInterpretByAdditionalSenseCode: Operation In Progress\n")); + + needFurtherInterpret = FALSE; + + *Retry = TRUE; + *RetryIntervalInSeconds = NOT_READY_RETRY_INTERVAL; + *Status = STATUS_DEVICE_NOT_READY; + + notReady.Version = 1; + notReady.Reason = 2; + notReady.Estimated100msToReady = *RetryIntervalInSeconds * 10; + DeviceSendNotification(DeviceExtension, + &GUID_IO_DEVICE_BECOMING_READY, + sizeof(DEVICE_EVENT_BECOMING_READY), + ¬Ready); + + break; + } + + case SCSI_SENSEQ_BECOMING_READY: + { + DEVICE_EVENT_BECOMING_READY notReady = {0}; + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, + "SenseInfoInterpretByAdditionalSenseCode: In process of becoming ready\n")); + + needFurtherInterpret = FALSE; + + *Retry = TRUE; + *RetryIntervalInSeconds = NOT_READY_RETRY_INTERVAL; + *Status = STATUS_DEVICE_NOT_READY; + + notReady.Version = 1; + notReady.Reason = 1; + notReady.Estimated100msToReady = *RetryIntervalInSeconds * 10; + DeviceSendNotification(DeviceExtension, + &GUID_IO_DEVICE_BECOMING_READY, + sizeof(DEVICE_EVENT_BECOMING_READY), + ¬Ready); + + break; + } + + case SCSI_SENSEQ_LONG_WRITE_IN_PROGRESS: + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, + "SenseInfoInterpretByAdditionalSenseCode: Long write in progress\n")); + + needFurtherInterpret = FALSE; + + // This has been seen as a transcient failure on some drives + *Status = STATUS_DEVICE_NOT_READY; + *Retry = TRUE; + // Set retry interval to be 0 as the drive can be ready at anytime. + *RetryIntervalInSeconds = 0; + + break; + } + + case SCSI_SENSEQ_MANUAL_INTERVENTION_REQUIRED: + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, + "SenseInfoInterpretByAdditionalSenseCode: Manual intervention required\n")); + + needFurtherInterpret = FALSE; + + *Status = STATUS_NO_MEDIA_IN_DEVICE; + *Retry = FALSE; + *RetryIntervalInSeconds = NOT_READY_RETRY_INTERVAL; + + break; + } + + case SCSI_SENSEQ_FORMAT_IN_PROGRESS: + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, + "SenseInfoInterpretByAdditionalSenseCode: Format in progress\n")); + + needFurtherInterpret = FALSE; + + *Status = STATUS_DEVICE_NOT_READY; + *Retry = FALSE; + *RetryIntervalInSeconds = NOT_READY_RETRY_INTERVAL; + + break; + } + + case SCSI_SENSEQ_CAUSE_NOT_REPORTABLE: + case SCSI_SENSEQ_INIT_COMMAND_REQUIRED: + default: + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, + "SenseInfoInterpretByAdditionalSenseCode: Initializing command required\n")); + + needFurtherInterpret = FALSE; + + *Status = STATUS_DEVICE_NOT_READY; + *Retry = TRUE; + *RetryIntervalInSeconds = 0; + + // This sense code/additional sense code combination may indicate + // that the device needs to be started. + if (TEST_FLAG(DeviceExtension->DeviceFlags, DEV_SAFE_START_UNIT) && + !TEST_FLAG(Srb->SrbFlags, SRB_CLASS_FLAGS_LOW_PRIORITY)) + { + DeviceSendStartUnit(DeviceExtension->Device); + } + + break; + } + } // end switch (AdditionalSenseCodeQual) + break; + + } // end case (SCSI_ADSENSE_LUN_NOT_READY) + + case SCSI_ADSENSE_NO_MEDIA_IN_DEVICE: + { + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, + "SenseInfoInterpretByAdditionalSenseCode: No Media in device.\n")); + + needFurtherInterpret = FALSE; + + *Status = STATUS_NO_MEDIA_IN_DEVICE; + *Retry = FALSE; + + if (AdditionalSenseCodeQual == 0xCC) + { + // The IMAPIv1 filter returns this ASCQ value while it is burning CD media, and we want + // to preserve this functionality for compatibility reasons. + // We want to indicate that the media is not present to most applications; + // but RSM has to know that the media is still in the drive (i.e. the drive is not free). + DeviceSetMediaChangeStateEx(DeviceExtension, MediaUnavailable, NULL); + } + else + { + DeviceSetMediaChangeStateEx(DeviceExtension, MediaNotPresent, NULL); + } + + break; + } // end case SCSI_ADSENSE_NO_MEDIA_IN_DEVICE + + case SCSI_ADSENSE_INVALID_MEDIA: + { + switch (AdditionalSenseCodeQual) + { + + case SCSI_SENSEQ_UNKNOWN_FORMAT: + { + needFurtherInterpret = FALSE; + + // Log error only if this is a paging request + *Status = STATUS_UNRECOGNIZED_MEDIA; + *Retry = FALSE; + + LogContext->LogError = TEST_FLAG(Srb->SrbFlags, SRB_CLASS_FLAGS_PAGING); + LogContext->UniqueErrorValue = 256; + LogContext->ErrorCode = IO_ERR_BAD_BLOCK; + + break; + } + + case SCSI_SENSEQ_INCOMPATIBLE_FORMAT: + { + needFurtherInterpret = FALSE; + + *Status = STATUS_UNRECOGNIZED_MEDIA; + *Retry = FALSE; + + LogContext->LogError = FALSE; + + break; + } + + case SCSI_SENSEQ_CLEANING_CARTRIDGE_INSTALLED: + { + needFurtherInterpret = FALSE; + + *Status = STATUS_CLEANER_CARTRIDGE_INSTALLED; + *Retry = FALSE; + + LogContext->LogError = FALSE; + LogContext->UniqueErrorValue = 256; + LogContext->ErrorCode = IO_ERR_BAD_BLOCK; + break; + } + + default: + { + needFurtherInterpret = TRUE; + break; + } + } // end case AdditionalSenseCodeQual + + break; + } // end case SCSI_ADSENSE_NO_MEDIA_IN_DEVICE + + case SCSI_ADSENSE_NO_SEEK_COMPLETE: + { + switch (AdditionalSenseCodeQual) + { + + case 0x00: + { + needFurtherInterpret = FALSE; + + *Status = STATUS_DEVICE_DATA_ERROR; + *Retry = TRUE; + *RetryIntervalInSeconds = 0; + LogContext->LogError = TRUE; + LogContext->UniqueErrorValue = 256; + LogContext->ErrorCode = IO_ERR_BAD_BLOCK; + break; + } + + default: + { + needFurtherInterpret = TRUE; + break; + } + } + + break; + } // end case SCSI_ADSENSE_NO_SEEK_COMPLETE + + case SCSI_ADSENSE_LUN_COMMUNICATION: + { + switch (AdditionalSenseCodeQual) + { + + case SCSI_SESNEQ_COMM_CRC_ERROR: + { + needFurtherInterpret = FALSE; + + *Status = STATUS_IO_DEVICE_ERROR; + *Retry = TRUE; + *RetryIntervalInSeconds = 1; + LogContext->LogError = TRUE; + LogContext->UniqueErrorValue = 257; + LogContext->ErrorCode = IO_ERR_CONTROLLER_ERROR; + break; + } + + default: + { + needFurtherInterpret = TRUE; + break; + } + } + + break; + } // end case SCSI_ADSENSE_LUN_COMMUNICATION + + case SCSI_ADSENSE_ILLEGAL_BLOCK: + { + needFurtherInterpret = FALSE; + + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, + "SenseInfoInterpretByAdditionalSenseCode: Illegal block address\n")); + *Status = STATUS_NONEXISTENT_SECTOR; + *Retry = FALSE; + break; + } + + case SCSI_ADSENSE_INVALID_LUN: + { + needFurtherInterpret = FALSE; + + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, + "SenseInfoInterpretByAdditionalSenseCode: Invalid LUN\n")); + *Status = STATUS_NO_SUCH_DEVICE; + *Retry = FALSE; + break; + } + + case SCSI_ADSENSE_COPY_PROTECTION_FAILURE: + { + needFurtherInterpret = FALSE; + + *Retry = FALSE; + + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, + "SenseInfoInterpretByAdditionalSenseCode: Key - Copy protection failure\n")); + + switch (AdditionalSenseCodeQual) + { + case SCSI_SENSEQ_AUTHENTICATION_FAILURE: + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, + "SenseInfoInterpretByAdditionalSenseCode: Authentication failure\n")); + *Status = STATUS_CSS_AUTHENTICATION_FAILURE; + break; + case SCSI_SENSEQ_KEY_NOT_PRESENT: + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, + "SenseInfoInterpretByAdditionalSenseCode: Key not present\n")); + *Status = STATUS_CSS_KEY_NOT_PRESENT; + break; + case SCSI_SENSEQ_KEY_NOT_ESTABLISHED: + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, + "SenseInfoInterpretByAdditionalSenseCode: Key not established\n")); + *Status = STATUS_CSS_KEY_NOT_ESTABLISHED; + break; + case SCSI_SENSEQ_READ_OF_SCRAMBLED_SECTOR_WITHOUT_AUTHENTICATION: + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, + "SenseInfoInterpretByAdditionalSenseCode: Read of scrambled sector w/o authentication\n")); + *Status = STATUS_CSS_SCRAMBLED_SECTOR; + break; + case SCSI_SENSEQ_MEDIA_CODE_MISMATCHED_TO_LOGICAL_UNIT: + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, + "SenseInfoInterpretByAdditionalSenseCode: Media region does not logical unit region\n")); + *Status = STATUS_CSS_REGION_MISMATCH; + break; + case SCSI_SENSEQ_LOGICAL_UNIT_RESET_COUNT_ERROR: + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, + "SenseInfoInterpretByAdditionalSenseCode: Region set error -- region may be permanent\n")); + *Status = STATUS_CSS_RESETS_EXHAUSTED; + break; + + default: + *Status = STATUS_COPY_PROTECTION_FAILURE; + break; + } // end switch of ASCQ for COPY_PROTECTION_FAILURE + + break; + } + + case SCSI_ADSENSE_INVALID_CDB: + { + needFurtherInterpret = FALSE; + + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, + "SenseInfoInterpretByAdditionalSenseCode: Key - Invalid CDB\n")); + + *Status = STATUS_INVALID_DEVICE_REQUEST; + *Retry = FALSE; + + // Note: the retry interval is not typically used. + // it is set here only because a ClassErrorHandler + // cannot set the RetryIntervalInSeconds, and the error may + // require a few commands to be sent to clear whatever + // caused this condition (i.e. disk clears the write + // cache, requiring at least two commands) + // + // hopefully, this shortcoming can be changed for blackcomb. + *RetryIntervalInSeconds = 3; + + break; + } + + case SCSI_ADSENSE_MEDIUM_CHANGED: + { + needFurtherInterpret = FALSE; + *RetryIntervalInSeconds = 0; + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, + "SenseInfoInterpretByAdditionalSenseCode: Media changed\n")); + + DeviceSetMediaChangeStateEx(DeviceExtension, MediaPresent, NULL); + + // special process for Media Change + if (IsVolumeMounted(DeviceExtension->DeviceObject)) + { + // Set bit to indicate that media may have changed and volume needs verification. + SET_FLAG(DeviceExtension->DeviceObject->Flags, DO_VERIFY_VOLUME); + + *Status = STATUS_VERIFY_REQUIRED; + *Retry = FALSE; + } + else + { + *Status = STATUS_IO_DEVICE_ERROR; + *Retry = TRUE; + } + break; + } + + case SCSI_ADSENSE_OPERATOR_REQUEST: + { + switch (AdditionalSenseCodeQual) + { + case SCSI_SENSEQ_MEDIUM_REMOVAL: + { + needFurtherInterpret = FALSE; + *RetryIntervalInSeconds = 0; + + InterlockedIncrement((PLONG)&DeviceExtension->MediaChangeCount); + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, + "SenseInfoInterpretByAdditionalSenseCode: Ejection request received!\n")); + //Send eject notification. + DeviceSendNotification(DeviceExtension, + &GUID_IO_MEDIA_EJECT_REQUEST, + 0, + NULL); + // special process for Media Change + if (IsVolumeMounted(DeviceExtension->DeviceObject)) + { + // Set bit to indicate that media may have changed and volume needs verification. + SET_FLAG(DeviceExtension->DeviceObject->Flags, DO_VERIFY_VOLUME); + + *Status = STATUS_VERIFY_REQUIRED; + *Retry = FALSE; + } + else + { + *Status = STATUS_IO_DEVICE_ERROR; + *Retry = TRUE; + } + break; + } + default: + { + needFurtherInterpret = TRUE; + break; + } + } + break; + } + + case SCSI_ADSENSE_OPERATING_CONDITIONS_CHANGED: + { + needFurtherInterpret = FALSE; + *RetryIntervalInSeconds = 5; + + InterlockedIncrement((PLONG)&DeviceExtension->MediaChangeCount); + + // Device information has changed, we need to rescan the + // bus for changed information such as the capacity. + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, + "SenseInfoInterpretByAdditionalSenseCode: Device information changed. Invalidate the bus\n")); + + IoInvalidateDeviceRelations(DeviceExtension->LowerPdo, BusRelations); + + // special process for Media Change + if (IsVolumeMounted(DeviceExtension->DeviceObject)) + { + // Set bit to indicate that media may have changed and volume needs verification. + SET_FLAG(DeviceExtension->DeviceObject->Flags, DO_VERIFY_VOLUME); + + *Status = STATUS_VERIFY_REQUIRED; + *Retry = FALSE; + } + else + { + *Status = STATUS_IO_DEVICE_ERROR; + *Retry = TRUE; + } + break; + } //end Case SCSI_ADSENSE_OPERATING_CONDITIONS_CHANGED + + + case SCSI_ADSENSE_REC_DATA_NOECC: + case SCSI_ADSENSE_REC_DATA_ECC: + { + needFurtherInterpret = FALSE; + + *Status = STATUS_SUCCESS; + *Retry = FALSE; + LogContext->LogError = TRUE; + LogContext->UniqueErrorValue = 258; + LogContext->ErrorCode = IO_RECOVERED_VIA_ECC; + + if (senseBuffer->IncorrectLength) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, + "SenseInfoInterpretByAdditionalSenseCode: Incorrect length detected.\n")); + *Status = STATUS_INVALID_BLOCK_LENGTH ; + } + break; + } + + case SCSI_ADSENSE_FAILURE_PREDICTION_THRESHOLD_EXCEEDED: + { + UCHAR wmiEventData[sizeof(ULONG)+sizeof(UCHAR)] = {0}; + + *((PULONG)wmiEventData) = sizeof(UCHAR); + wmiEventData[sizeof(ULONG)] = AdditionalSenseCodeQual; + + needFurtherInterpret = FALSE; + + // Don't log another eventlog if we have already logged once + // NOTE: this should have been interlocked, but the structure + // was publicly defined to use a BOOLEAN (char). Since + // media only reports these errors once per X minutes, + // the potential race condition is nearly non-existant. + // the worst case is duplicate log entries, so ignore. + + *Status = STATUS_SUCCESS; + *Retry = FALSE; + LogContext->UniqueErrorValue = 258; + LogContext->LogError = TRUE; + LogContext->ErrorCode = IO_WRN_FAILURE_PREDICTED; + + if (senseBuffer->IncorrectLength) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, + "SenseInfoInterpretByAdditionalSenseCode: Incorrect length detected.\n")); + *Status = STATUS_INVALID_BLOCK_LENGTH ; + } + break; + } + + case 0x57: + { + // UNABLE_TO_RECOVER_TABLE_OF_CONTENTS + // the Matshita CR-585 returns this for all read commands + // on blank CD-R and CD-RW media, and we need to handle + // this for READ_CD detection ability. + switch (AdditionalSenseCodeQual) + { + case 0x00: + { + needFurtherInterpret = FALSE; + + *Status = STATUS_UNRECOGNIZED_MEDIA; + *Retry = FALSE; + break; + } + default: + { + needFurtherInterpret = TRUE; + break; + } + } + break; + } //end case Matshita specific error 0x57 + + default: + { + needFurtherInterpret = TRUE; + break; + } + } + + return needFurtherInterpret; +} + +VOID +SenseInfoInterpretBySenseKey( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ PSENSE_DATA SenseData, + _In_ UCHAR SenseKey, + _Inout_ NTSTATUS* Status, + _Inout_ BOOLEAN* Retry, + _Out_ _Deref_out_range_(0,100) ULONG* RetryIntervalInSeconds, + _Inout_ PERROR_LOG_CONTEXT LogContext + ) +{ + // set default values for retry fields. + *Status = STATUS_IO_DEVICE_ERROR; + *Retry = TRUE; + *RetryIntervalInSeconds = 0; + + switch (SenseKey) + { + case SCSI_SENSE_NOT_READY: + { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, + "SenseInfoInterpretBySenseKey: Key - Not Ready (bad block)\n")); + + *Status = STATUS_DEVICE_NOT_READY; + *Retry = TRUE; + + // for unprocessed "not ready" codes, retry the command immediately. + *RetryIntervalInSeconds = 0; + break; + } + + case SCSI_SENSE_DATA_PROTECT: + { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, + "SenseInfoInterpretBySenseKey: Key - Media write protected\n")); + *Status = STATUS_MEDIA_WRITE_PROTECTED; + *Retry = FALSE; + break; + } + + case SCSI_SENSE_MEDIUM_ERROR: + { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, + "SenseInfoInterpretBySenseKey: Key - Medium Error (bad block)\n")); + + *Status = STATUS_DEVICE_DATA_ERROR; + *Retry = FALSE; + LogContext->LogError = TRUE; + LogContext->UniqueErrorValue = 256; + LogContext->ErrorCode = IO_ERR_BAD_BLOCK; + + break; + } // end SCSI_SENSE_MEDIUM_ERROR + + case SCSI_SENSE_HARDWARE_ERROR: + { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, + "SenseInfoInterpretBySenseKey: Key - Hardware error\n")); + + *Status = STATUS_IO_DEVICE_ERROR; + *Retry = TRUE; + LogContext->LogError = TRUE; + LogContext->UniqueErrorValue = 257; + LogContext->ErrorCode = IO_ERR_CONTROLLER_ERROR; + + break; + } // end SCSI_SENSE_HARDWARE_ERROR + + case SCSI_SENSE_ILLEGAL_REQUEST: + { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, + "SenseInfoInterpretBySenseKey: Key - Illegal SCSI request\n")); + *Status = STATUS_INVALID_DEVICE_REQUEST; + *Retry = FALSE; + + break; + } // end SCSI_SENSE_ILLEGAL_REQUEST + + case SCSI_SENSE_UNIT_ATTENTION: + { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, + "SenseInfoInterpretBySenseKey: Key - Unit Attention\n")); + + // A media change may have occured so increment the change + // count for the physical device + InterlockedIncrement((PLONG)&DeviceExtension->MediaChangeCount); + + if (IsVolumeMounted(DeviceExtension->DeviceObject)) + { + // Set bit to indicate that media may have changed + // and volume needs verification. + SET_FLAG(DeviceExtension->DeviceObject->Flags, DO_VERIFY_VOLUME); + + *Status = STATUS_VERIFY_REQUIRED; + *Retry = FALSE; + } + else + { + *Status = STATUS_IO_DEVICE_ERROR; + *Retry = TRUE; + } + + break; + + } // end SCSI_SENSE_UNIT_ATTENTION + + case SCSI_SENSE_ABORTED_COMMAND: + { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, + "SenseInfoInterpretBySenseKey: Command aborted\n")); + *Status = STATUS_IO_DEVICE_ERROR; + *Retry = TRUE; + *RetryIntervalInSeconds = 1; + break; + } // end SCSI_SENSE_ABORTED_COMMAND + + case SCSI_SENSE_BLANK_CHECK: + { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, + "SenseInfoInterpretBySenseKey: Media blank check\n")); + *Retry = FALSE; + *Status = STATUS_NO_DATA_DETECTED; + break; + } // end SCSI_SENSE_BLANK_CHECK + + case SCSI_SENSE_RECOVERED_ERROR: + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, + "SenseInfoInterpretBySenseKey: Recovered error\n")); + *Status = STATUS_SUCCESS; + *Retry = FALSE; + LogContext->LogError = TRUE; + LogContext->UniqueErrorValue = 258; + LogContext->ErrorCode = IO_ERR_CONTROLLER_ERROR; + + if (SenseData->IncorrectLength) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, + "SenseInfoInterpretBySenseKey: Incorrect length detected.\n")); + *Status = STATUS_INVALID_BLOCK_LENGTH ; + } + + break; + } // end SCSI_SENSE_RECOVERED_ERROR + + case SCSI_SENSE_NO_SENSE: + { + // Check other indicators. + if (SenseData->IncorrectLength) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, + "SenseInfoInterpretBySenseKey: Incorrect length detected.\n")); + *Status = STATUS_INVALID_BLOCK_LENGTH ; + *Retry = FALSE; + } + else + { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, + "SenseInfoInterpretBySenseKey: No specific sense key\n")); + *Status = STATUS_IO_DEVICE_ERROR; + *Retry = TRUE; + } + + break; + } // end SCSI_SENSE_NO_SENSE + + default: + { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, + "SenseInfoInterpretBySenseKey: Unrecognized sense code\n")); + *Status = STATUS_IO_DEVICE_ERROR; + *Retry = TRUE; + *RetryIntervalInSeconds = 0; + + break; + } + + } // end switch (SenseKey) + + return; +} + +VOID +SenseInfoInterpretBySrbStatus( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ PSCSI_REQUEST_BLOCK Srb, + _In_ ULONG RetriedCount, + _Inout_ NTSTATUS* Status, + _Inout_ BOOLEAN* Retry, + _Out_ _Deref_out_range_(0,100) ULONG* RetryIntervalInSeconds, + _Inout_ PERROR_LOG_CONTEXT LogContext + ) +{ + BOOLEAN incrementErrorCount = FALSE; + + // set default values for retry fields. + *Status = STATUS_IO_DEVICE_ERROR; + *Retry = TRUE; + *RetryIntervalInSeconds = 0; + + switch (SRB_STATUS(Srb->SrbStatus)) + { + case SRB_STATUS_INVALID_LUN: + case SRB_STATUS_INVALID_TARGET_ID: + case SRB_STATUS_NO_DEVICE: + case SRB_STATUS_NO_HBA: + case SRB_STATUS_INVALID_PATH_ID: + { + *Status = STATUS_NO_SUCH_DEVICE; + *Retry = FALSE; + break; + } + + case SRB_STATUS_COMMAND_TIMEOUT: + case SRB_STATUS_TIMEOUT: + { + // Update the error count for the device. + *Status = STATUS_IO_TIMEOUT; + *Retry = TRUE; + *RetryIntervalInSeconds = 0; + incrementErrorCount = TRUE; + break; + } + + case SRB_STATUS_ABORTED: + { + // Update the error count for the device. + *Status = STATUS_IO_TIMEOUT; + *Retry = TRUE; + *RetryIntervalInSeconds = 1; + incrementErrorCount = TRUE; + break; + } + + case SRB_STATUS_SELECTION_TIMEOUT: + { + *Status = STATUS_DEVICE_NOT_CONNECTED; + *Retry = FALSE; + *RetryIntervalInSeconds = 2; + LogContext->LogError = TRUE; + LogContext->ErrorCode = IO_ERR_NOT_READY; + LogContext->UniqueErrorValue = 260; + break; + } + + case SRB_STATUS_DATA_OVERRUN: + { + *Status = STATUS_DATA_OVERRUN; + *Retry = FALSE; + break; + } + + case SRB_STATUS_PHASE_SEQUENCE_FAILURE: + { + // Update the error count for the device. + incrementErrorCount = TRUE; + *Status = STATUS_IO_DEVICE_ERROR; + + // If there was phase sequence error then limit the number of retries. + *Retry = (RetriedCount <= 1); + + break; + } + + case SRB_STATUS_REQUEST_FLUSHED: + { + // If the status needs verification bit is set. Then set + // the status to need verification and no retry; otherwise, + // just retry the request. + if (TEST_FLAG(DeviceExtension->DeviceObject->Flags, DO_VERIFY_VOLUME)) + { + *Status = STATUS_VERIFY_REQUIRED; + *Retry = FALSE; + } + else + { + *Status = STATUS_IO_DEVICE_ERROR; + *Retry = TRUE; + } + + break; + } + + case SRB_STATUS_INVALID_REQUEST: + { + *Status = STATUS_INVALID_DEVICE_REQUEST; + *Retry = FALSE; + break; + } + + case SRB_STATUS_UNEXPECTED_BUS_FREE: + case SRB_STATUS_PARITY_ERROR: + // Update the error count for the device and fall through to below + incrementErrorCount = TRUE; + + case SRB_STATUS_BUS_RESET: + { + *Status = STATUS_IO_DEVICE_ERROR; + *Retry = TRUE; + break; + } + + case SRB_STATUS_ERROR: + { + *Status = STATUS_IO_DEVICE_ERROR; + *Retry = TRUE; + + if (Srb->ScsiStatus == 0) + { + // This is some strange return code. Update the error + // count for the device. + incrementErrorCount = TRUE; + } + + if (Srb->ScsiStatus == SCSISTAT_BUSY) + { + *Status = STATUS_DEVICE_NOT_READY; + } + + break; + } + + default: + { + *Status = STATUS_IO_DEVICE_ERROR; + *Retry = TRUE; + LogContext->LogError = TRUE; + LogContext->ErrorCode = IO_ERR_CONTROLLER_ERROR; + LogContext->UniqueErrorValue = 259; + LogContext->ErrorUnhandled = TRUE; + break; + } + + } //end of (SRB_STATUS(Srb->SrbStatus)) + + if (incrementErrorCount) + { + // if any error count occurred, delay the retry of this io by + // at least one second, if caller supports it. + if (*RetryIntervalInSeconds == 0) + { + *RetryIntervalInSeconds = 1; + } + + DevicePerfIncrementErrorCount(DeviceExtension); + } + + return; +} + +VOID +SenseInfoLogError( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ PSCSI_REQUEST_BLOCK Srb, + _In_ UCHAR MajorFunctionCode, + _In_ ULONG IoControlCode, + _In_ ULONG RetriedCount, + _In_ NTSTATUS* Status, + _In_ BOOLEAN* Retry, + _Inout_ PERROR_LOG_CONTEXT LogContext + ) +{ + // Always log the error in our internal log. + // If logError is set, also log the error in the system log. + PSENSE_DATA senseBuffer = (PSENSE_DATA)Srb->SenseInfoBuffer; + ULONG totalSize = 0; + ULONG senseBufferSize = 0; + IO_ERROR_LOG_PACKET staticErrLogEntry = {0}; + CDROM_ERROR_LOG_DATA staticErrLogData = {0}; + + // Calculate the total size of the error log entry. + // add to totalSize in the order that they are used. + // the advantage to calculating all the sizes here is + // that we don't have to do a bunch of extraneous checks + // later on in this code path. + totalSize = sizeof(IO_ERROR_LOG_PACKET) // required + + sizeof(CDROM_ERROR_LOG_DATA); // struct for ease + + // also save any available extra sense data, up to the maximum errlog + // packet size . WMI should be used for real-time analysis. + // the event log should only be used for post-mortem debugging. + if (TEST_FLAG(Srb->SrbStatus, SRB_STATUS_AUTOSENSE_VALID)) + { + ULONG validSenseBytes; + BOOLEAN validSense; + + // make sure we can at least access the AdditionalSenseLength field + validSense = RTL_CONTAINS_FIELD(senseBuffer, + Srb->SenseInfoBufferLength, + AdditionalSenseLength); + if (validSense) + { + // if extra info exists, copy the maximum amount of available + // sense data that is safe into the the errlog. + validSenseBytes = senseBuffer->AdditionalSenseLength + + offsetof(SENSE_DATA, AdditionalSenseLength); + + // this is invalid because it causes overflow! + // whoever sent this type of request would cause + // a system crash. + NT_ASSERT(validSenseBytes < MAX_ADDITIONAL_SENSE_BYTES); + + // set to save the most sense buffer possible + senseBufferSize = max(validSenseBytes, sizeof(SENSE_DATA)); + senseBufferSize = min(senseBufferSize, Srb->SenseInfoBufferLength); + } + else + { + // it's smaller than required to read the total number of + // valid bytes, so just use the SenseInfoBufferLength field. + senseBufferSize = Srb->SenseInfoBufferLength; + } + + // Bump totalSize by the number of extra senseBuffer bytes + // (beyond the default sense buffer within CDROM_ERROR_LOG_DATA). + // Make sure to never allocate more than ERROR_LOG_MAXIMUM_SIZE. + if (senseBufferSize > sizeof(SENSE_DATA)) + { + totalSize += senseBufferSize-sizeof(SENSE_DATA); + if (totalSize > ERROR_LOG_MAXIMUM_SIZE) + { + senseBufferSize -= totalSize-ERROR_LOG_MAXIMUM_SIZE; + totalSize = ERROR_LOG_MAXIMUM_SIZE; + } + } + } + + // If we've used up all of our retry attempts, set the final status to + // reflect the appropriate result. + // + // ISSUE: the test below should also check RetriedCount to determine if we will actually retry, + // but there is no easy test because we'd have to consider the original retry count + // for the op; besides, InterpretTransferPacketError sometimes ignores the retry + // decision returned by this function. So just ErrorRetried to be true in the majority case. + // + if (*Retry) + { + staticErrLogEntry.FinalStatus = STATUS_SUCCESS; + staticErrLogData.ErrorRetried = TRUE; + } + else + { + staticErrLogEntry.FinalStatus = *Status; + } + + // Don't log generic IO_WARNING_PAGING_FAILURE message if either the + // I/O is retried, or it completed successfully. + if ((LogContext->ErrorCode == IO_WARNING_PAGING_FAILURE) && + (*Retry || NT_SUCCESS(*Status)) ) + { + LogContext->LogError = FALSE; + } + + if (TEST_FLAG(Srb->SrbFlags, SRB_CLASS_FLAGS_PAGING)) + { + staticErrLogData.ErrorPaging = TRUE; + } + + staticErrLogData.ErrorUnhandled = LogContext->ErrorUnhandled; + + // Calculate the device offset if there is a geometry. + staticErrLogEntry.DeviceOffset.QuadPart = (LONGLONG)LogContext->BadSector; + staticErrLogEntry.DeviceOffset.QuadPart *= (LONGLONG)DeviceExtension->DiskGeometry.BytesPerSector; + + if (LogContext->ErrorCode == -1) + { + staticErrLogEntry.ErrorCode = STATUS_IO_DEVICE_ERROR; + } + else + { + staticErrLogEntry.ErrorCode = LogContext->ErrorCode; + } + + // The dump data follows the IO_ERROR_LOG_PACKET + staticErrLogEntry.DumpDataSize = (USHORT)totalSize - sizeof(IO_ERROR_LOG_PACKET); + + staticErrLogEntry.SequenceNumber = 0; + staticErrLogEntry.MajorFunctionCode = MajorFunctionCode; + staticErrLogEntry.IoControlCode = IoControlCode; + staticErrLogEntry.RetryCount = (UCHAR)RetriedCount; + staticErrLogEntry.UniqueErrorValue = LogContext->UniqueErrorValue; + + KeQueryTickCount(&staticErrLogData.TickCount); + staticErrLogData.PortNumber = (ULONG)-1; + + // Save the entire contents of the SRB. + staticErrLogData.Srb = *Srb; + + // For our private log, save just the default length of the SENSE_DATA. + if (senseBufferSize != 0) + { + RtlCopyMemory(&staticErrLogData.SenseData, senseBuffer, min(senseBufferSize, sizeof(SENSE_DATA))); + } + + // Save the error log in our context. + // We only save the default sense buffer length. + { + KIRQL oldIrql; + KeAcquireSpinLock(&DeviceExtension->PrivateFdoData->SpinLock, &oldIrql); + DeviceExtension->PrivateFdoData->ErrorLogs[DeviceExtension->PrivateFdoData->ErrorLogNextIndex] = staticErrLogData; + DeviceExtension->PrivateFdoData->ErrorLogNextIndex++; + DeviceExtension->PrivateFdoData->ErrorLogNextIndex %= NUM_ERROR_LOG_ENTRIES; + KeReleaseSpinLock(&DeviceExtension->PrivateFdoData->SpinLock, oldIrql); + } + + // If logError is set, also save this log in the system's error log. + // But make sure we don't log TUR failures over and over + // (e.g. if an external drive was switched off and we're still sending TUR's to it every second). + if (LogContext->LogError) + { + // We do not want to log certain system events repetitively + switch (((PCDB)Srb->Cdb)->CDB10.OperationCode) + { + case SCSIOP_TEST_UNIT_READY: + { + if (DeviceExtension->PrivateFdoData->LoggedTURFailureSinceLastIO) + { + LogContext->LogError = FALSE; + } + else + { + DeviceExtension->PrivateFdoData->LoggedTURFailureSinceLastIO = TRUE; + } + + break; + } + + case SCSIOP_SYNCHRONIZE_CACHE: + { + if (DeviceExtension->PrivateFdoData->LoggedSYNCFailure) + { + LogContext->LogError = FALSE; + } + else + { + DeviceExtension->PrivateFdoData->LoggedSYNCFailure = TRUE; + } + + break; + } + } + + // Do not log 5/21/00 LOGICAL BLOCK ADDRESS OUT OF RANGE if the disc is blank, + // it is known to litter the Event Log with repetitive errors + // Do not log this error for READ, as it's known that File System mount process reads different sectors from media. + if (senseBufferSize > RTL_SIZEOF_THROUGH_FIELD(SENSE_DATA, AdditionalSenseCodeQualifier) && + senseBuffer->SenseKey == SCSI_SENSE_ILLEGAL_REQUEST && + senseBuffer->AdditionalSenseCode == SCSI_ADSENSE_ILLEGAL_BLOCK && + senseBuffer->AdditionalSenseCodeQualifier == 0 && + IS_SCSIOP_READ(((PCDB)Srb->Cdb)->CDB10.OperationCode)) + { + LogContext->LogError = FALSE; + } + } + + // Write the error log packet to the system error logging thread. + if (LogContext->LogError) + { + PIO_ERROR_LOG_PACKET errorLogEntry; + PCDROM_ERROR_LOG_DATA errlogData; + + errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(DeviceExtension->DeviceObject, (UCHAR)totalSize); + if (errorLogEntry) + { + errlogData = (PCDROM_ERROR_LOG_DATA)errorLogEntry->DumpData; + + *errorLogEntry = staticErrLogEntry; + *errlogData = staticErrLogData; + + // For the system log, copy as much of the sense buffer as possible. + if (senseBufferSize != 0) + { + RtlCopyMemory(&errlogData->SenseData, senseBuffer, senseBufferSize); + } + + // errorLogEntry - It will be freed by the kernel. + IoWriteErrorLogEntry(errorLogEntry); + } + } + + return; +} + +VOID +SenseInfoInterpretRefineByScsiCommand( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ PSCSI_REQUEST_BLOCK Srb, + _In_ ULONG RetriedCount, + _In_ LONGLONG Total100nsSinceFirstSend, + _In_ BOOLEAN OverrideVerifyVolume, + _Inout_ BOOLEAN* Retry, + _Inout_ NTSTATUS* Status, + _Inout_ _Deref_out_range_(0, MAXIMUM_RETRY_FOR_SINGLE_IO_IN_100NS_UNITS) + LONGLONG* RetryIntervalIn100ns + ) +/*++ + +Routine Description: + + Based on SCSI command, modify the interpretion result. + +Arguments: + + DeviceExtension - device extension. + Srb - Supplies the scsi request block which failed. + RetriedCount - retried count. + Total100nsUnitsSinceFirstSend - time spent after the request was sent down first time. + OverrideVerifyVolume - should override verify volume request. + +Return Value: + + Retry - the reques should be retried or not. + Status - Returns the status for the request. + RetryInterval - waiting time (in 100ns) before the request should be retried. + Zero indicates the request should be immediately retried. + +--*/ +{ + UCHAR const opCode = Srb->Cdb[0]; + CDB const* cdb = (CDB const*)(Srb->Cdb); + PSENSE_DATA senseBuffer = (PSENSE_DATA)Srb->SenseInfoBuffer; + + if (opCode == SCSIOP_MEDIUM_REMOVAL) + { + if (( cdb->AsByte[1] == 0) && + ( cdb->AsByte[2] == 0) && + ( cdb->AsByte[3] == 0) && + ((cdb->AsByte[4] & 0xFC) == 0) + ) + { + // byte[4] == 0x3 or byte[4] == 0x1 == UNLOCK OF MEDIA + if ((cdb->AsByte[4] & 0x01) == 0) + { + if (RetriedCount < TOTAL_COUNT_RETRY_DEFAULT) + { + // keep retrying unlock operation for several times + *Retry = TRUE; + } + } + else // LOCK REQUEST + { + // do not retry LOCK requests more than once (per CLASSPNP code) + if (RetriedCount > TOTAL_COUNT_RETRY_LOCK_MEDIA) + { + *Retry = FALSE; + } + } + } + + // want a minimum time to retry of 2 seconds + if ((*Status == STATUS_DEVICE_NOT_READY) && + (senseBuffer->AdditionalSenseCode == SCSI_ADSENSE_LUN_NOT_READY)) + { + *RetryIntervalIn100ns = max(*RetryIntervalIn100ns, SECONDS_TO_100NS_UNITS(2)); + } + else if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SELECTION_TIMEOUT) + { + *RetryIntervalIn100ns = max(*RetryIntervalIn100ns, SECONDS_TO_100NS_UNITS(2)); + } + } + else if ((opCode == SCSIOP_MODE_SENSE) || (opCode == SCSIOP_MODE_SENSE10)) + { + // want a minimum time to retry of 2 seconds + if ((*Status == STATUS_DEVICE_NOT_READY) && + (senseBuffer->AdditionalSenseCode == SCSI_ADSENSE_LUN_NOT_READY)) + { + *RetryIntervalIn100ns = max(*RetryIntervalIn100ns, SECONDS_TO_100NS_UNITS(2)); + } + else if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SELECTION_TIMEOUT) + { + *RetryIntervalIn100ns = max(*RetryIntervalIn100ns, SECONDS_TO_100NS_UNITS(2)); + } + + // Want to ignore a STATUS_VERIFY_REQUIRED error because it either + // doesn't make sense or is required to satisfy the VERIFY. + if (*Status == STATUS_VERIFY_REQUIRED) + { + *Retry = TRUE; + } + else if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_DATA_OVERRUN) + { + /* + * This is a HACK. + * Atapi returns SRB_STATUS_DATA_OVERRUN when it really means + * underrun (i.e. success, and the buffer is longer than needed). + * So treat this as a success. + * When the caller of this function sees that the status was changed to success, + * it will add the transferred length to the original irp. + */ + *Status = STATUS_SUCCESS; + *Retry = FALSE; + } + + // limit the count of retries + if (RetriedCount > TOTAL_COUNT_RETRY_MODESENSE) + { + *Retry = FALSE; + } + } + else if ((opCode == SCSIOP_READ_CAPACITY) || (opCode == SCSIOP_READ_CAPACITY16)) + { + // Want to ignore a STATUS_VERIFY_REQUIRED error because it either + // doesn't make sense or is required to satisfy the VERIFY. + if (*Status == STATUS_VERIFY_REQUIRED) + { + *Retry = TRUE; + } + + if (RetriedCount > TOTAL_COUNT_RETRY_READ_CAPACITY) + { + *Retry = FALSE; + } + } + else if ((opCode == SCSIOP_RESERVE_UNIT) || (opCode == SCSIOP_RELEASE_UNIT)) + { + // The RESERVE(6) / RELEASE(6) commands are optional. + // So if they aren't supported, try the 10-byte equivalents + if (*Status == STATUS_INVALID_DEVICE_REQUEST) + { + PCDB tempCdb = (PCDB)Srb->Cdb; + + Srb->CdbLength = 10; + tempCdb->CDB10.OperationCode = (tempCdb->CDB6GENERIC.OperationCode == SCSIOP_RESERVE_UNIT) + ? SCSIOP_RESERVE_UNIT10 + : SCSIOP_RELEASE_UNIT10; + + SET_FLAG(DeviceExtension->PrivateFdoData->HackFlags, FDO_HACK_NO_RESERVE6); + *Retry = TRUE; + } + } + else if (IS_SCSIOP_READWRITE(opCode)) + { + // Retry if still verifying a (possibly) reloaded disk/cdrom. + if (OverrideVerifyVolume && (*Status == STATUS_VERIFY_REQUIRED)) + { + *Status = STATUS_IO_DEVICE_ERROR; + *Retry = TRUE; + } + + // Special case for streaming READ/WRITE commands + if (((opCode == SCSIOP_READ12) && (cdb->READ12.Streaming == 1)) || + ((opCode == SCSIOP_WRITE12) && (cdb->WRITE12.Streaming == 1))) + { + // We've got a failure while performing a streaming operation and now need to guess if + // it's likely to be a permanent error because the drive does not support streaming at all + // (in which case we're going to fall back to normal reads/writes), or a transient error + // (in which case we quickly fail the request but contrinue to use streaming). + // + // We analyze the sense information to make that decision. Bus resets and device timeouts + // are treated as permanent errors, because some non-compliant devices may even hang when + // they get a command that they do not expect. + + BOOLEAN disableStreaming = FALSE; + + if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_TIMEOUT || + SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_COMMAND_TIMEOUT || + SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SELECTION_TIMEOUT || + SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_BUS_RESET) + { + disableStreaming = TRUE; + } + else if ((senseBuffer->SenseKey &0xf) == SCSI_SENSE_UNIT_ATTENTION) + { + if (senseBuffer->AdditionalSenseCode == SCSI_ADSENSE_BUS_RESET || + senseBuffer->AdditionalSenseCode == SCSI_ADSENSE_INSUFFICIENT_TIME_FOR_OPERATION) + { + disableStreaming = TRUE; + } + } + else if ((senseBuffer->SenseKey &0xf) == SCSI_SENSE_ILLEGAL_REQUEST) + { + // LBA Out of Range is an exception, as it's more likely to be caused by + // upper layers attempting to read/write a wrong LBA. + if (senseBuffer->AdditionalSenseCode != SCSI_ADSENSE_ILLEGAL_BLOCK) + { + disableStreaming = TRUE; + } + } + + if (disableStreaming) + { + // if the failure looks permanent, we disable streaming for all future reads/writes + // and retry the command immediately + SET_FLAG(DeviceExtension->PrivateFdoData->HackFlags, FDO_HACK_NO_STREAMING); + *Retry = TRUE; + *RetryIntervalIn100ns = 0; + } + else + { + // if the failure looks transient, we simply fail the current request without retries + // to minimize the time of processing + *Retry = FALSE; + } + } + + // Special-case handling of READ/WRITE commands. These commands now have a 120 second timeout, + // but the preferred behavior (and that taken by many drives) is to immediately report 2/4/x + // on OPC and similar commands. Thus, retries must occur for at least 160 seconds + // (120 seconds + four 10 second retries) as a conservative guess. + // Note: 160s retry time is also a result of discussion with OEMs for case of 2/4/7 and 2/4/8. + if (*Retry) + { + if ((Total100nsSinceFirstSend < 0) || + (((senseBuffer->SenseKey &0xf) == SCSI_SENSE_HARDWARE_ERROR) && (senseBuffer->AdditionalSenseCode == 0x09))) + { + // time information is not valid. use default retry count. + // or if it's SERVO FAILURE, use retry count instead of 160s retry. + *Retry = (RetriedCount <= TOTAL_COUNT_RETRY_DEFAULT); + } + else if (Total100nsSinceFirstSend > SECONDS_TO_100NS_UNITS(TOTAL_SECONDS_RETRY_TIME_WRITE)) + { + *Retry = FALSE; + } + + // How long should we request a delay for during writing? This depends entirely on + // the current write speed of the drive. If we request retries too quickly, + // we can overload the processor on the drive (resulting in garbage being written), + // but too slowly results in lesser performance. + // + *RetryIntervalIn100ns = DeviceExtension->DeviceAdditionalData.ReadWriteRetryDelay100nsUnits; + + } // end retry for 160 seconds modification + } + else if (opCode == SCSIOP_GET_PERFORMANCE) + { + if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_DATA_OVERRUN) + { + // This is a HACK. + // Atapi returns SRB_STATUS_DATA_OVERRUN when it really means + // underrun (i.e. success, and the buffer is longer than needed). + // So treat this as a success. + // When the caller of this function sees that the status was changed to success, + // it will add the transferred length to the original irp. + *Status = STATUS_SUCCESS; + *Retry = FALSE; + } + + if ((Srb->SenseInfoBufferLength < RTL_SIZEOF_THROUGH_FIELD(SENSE_DATA,AdditionalSenseCodeQualifier)) || + !TEST_FLAG(Srb->SrbStatus, SRB_STATUS_AUTOSENSE_VALID)) + { + // If get configuration command is failing and if the request type is TYPE ONE + // then most likely the device does not support this request type. Set the + // flag so that the TYPE ONE requests will be tried as TYPE ALL requets. + if ((SRB_STATUS(Srb->SrbStatus) != SRB_STATUS_SUCCESS) && + (SRB_STATUS(Srb->SrbStatus) != SRB_STATUS_DATA_OVERRUN) && + (((PCDB)Srb->Cdb)->GET_CONFIGURATION.RequestType == SCSI_GET_CONFIGURATION_REQUEST_TYPE_ONE)) + { + + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, + "TYPE ONE GetConfiguration failed. Set hack flag and retry.\n")); + SET_FLAG(DeviceExtension->DeviceAdditionalData.HackFlags, CDROM_HACK_BAD_TYPE_ONE_GET_CONFIG); + *Retry = TRUE; + } + } + + // limit retries to GET_PERFORMANCE commands to default retry count + if (RetriedCount > TOTAL_COUNT_RETRY_DEFAULT) + { + *Retry = FALSE; + } + } + else // default handler -- checks for retry count only. + { + if (RetriedCount > TOTAL_COUNT_RETRY_DEFAULT) + { + *Retry = FALSE; + } + } + + return; +} + + +VOID +SenseInfoInterpretRefineByIoControl( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ ULONG IoControlCode, + _In_ BOOLEAN OverrideVerifyVolume, + _Inout_ BOOLEAN* Retry, + _Inout_ NTSTATUS* Status + ) +/*++ + +Routine Description: + + Based on IOCTL code, modify the interpretion result. + +Arguments: + + Device - Supplies the device object associated with this request. + OriginalRequest - the irp that error occurs on. + Srb - Supplies the scsi request block which failed. + MajorFunctionCode - Supplies the function code to be used for logging. + IoDeviceCode - Supplies the device code to be used for logging. + PreviousRetryCount - retried count. + RequestHistory_DoNotUse - the history list + +Return Value: + + BOOLEAN TRUE: Drivers should retry this request. + FALSE: Drivers should not retry this request. + Status - Returns the status for the request. + RetryInterval - Number of seconds before the request should be retried. + Zero indicates the request should be immediately retried. + +--*/ +{ + PAGED_CODE(); + + if ((IoControlCode == IOCTL_CDROM_GET_LAST_SESSION) || + (IoControlCode == IOCTL_CDROM_READ_TOC) || + (IoControlCode == IOCTL_CDROM_READ_TOC_EX) || + (IoControlCode == IOCTL_CDROM_GET_CONFIGURATION)|| + (IoControlCode == IOCTL_CDROM_GET_VOLUME)) + { + if (*Status == STATUS_DATA_OVERRUN) + { + *Status = STATUS_SUCCESS; + *Retry = FALSE; + } + } + + if (IoControlCode == IOCTL_CDROM_READ_Q_CHANNEL) + { + PLAY_ACTIVE(DeviceExtension) = FALSE; + } + + // If the status is verified required and the this request + // should bypass verify required then retry the request. + if (OverrideVerifyVolume && (*Status == STATUS_VERIFY_REQUIRED)) + { + // note: status gets overwritten here + *Status = STATUS_IO_DEVICE_ERROR; + *Retry = TRUE; + + if ((IoControlCode == IOCTL_CDROM_CHECK_VERIFY) || + (IoControlCode == IOCTL_STORAGE_CHECK_VERIFY) || + (IoControlCode == IOCTL_STORAGE_CHECK_VERIFY2) || + (IoControlCode == IOCTL_DISK_CHECK_VERIFY) + ) + { + // Update the geometry information, as the media could have changed. + (VOID) MediaReadCapacity(DeviceExtension->Device); + } // end of ioctls to update capacity + } + + if (!NT_SUCCESS(*Status) && (IoControlCode == IOCTL_CDROM_SET_SPEED)) + { + // If set speed request fails then we should disable the restore speed option. + // Otherwise we will try to restore to default speed on next media change, + // if requested by the caller. + DeviceExtension->DeviceAdditionalData.RestoreDefaults = FALSE; + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "Disable restore default\n")); + } + + return; +} + +BOOLEAN +SenseInfoInterpret( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ PSCSI_REQUEST_BLOCK Srb, + _In_ ULONG RetriedCount, + _Out_ NTSTATUS* Status, + _Out_ _Deref_out_range_(0, MAXIMUM_RETRY_FOR_SINGLE_IO_IN_100NS_UNITS) + LONGLONG* RetryIntervalIn100ns + ) +/*++ + +SenseInfoInterpret() + +Routine Description: + + This routine interprets the data returned from the SCSI request sense. + It determines the status to return in the IRP + and whether this request can be retried. + +Arguments: + + Device - Supplies the device object associated with this request. + Srb - Supplies the scsi request block which failed. + MajorFunctionCode - Supplies the function code to be used for logging. + IoDeviceCode - Supplies the device code to be used for logging. + +Return Value: + + BOOLEAN TRUE: Drivers should retry this request. + FALSE: Drivers should not retry this request. + Status - Returns the status for the request. + RetryInterval - Number of seconds before the request should be retried. + Zero indicates the request should be immediately retried. + +--*/ +{ + ULONG retryIntervalInSeconds = 0; + BOOLEAN retry = TRUE; + PSENSE_DATA senseBuffer = Srb->SenseInfoBuffer; + ULONG readSector = 0; + ERROR_LOG_CONTEXT logContext; + + UCHAR majorFunctionCode = 0; + ULONG ioControlCode = 0; + BOOLEAN overrideVerifyVolume = FALSE; + ULONGLONG total100nsSinceFirstSend = 0; + PZERO_POWER_ODD_INFO zpoddInfo = DeviceExtension->ZeroPowerODDInfo; + + // + *Status = STATUS_IO_DEVICE_ERROR; + + RtlZeroMemory(&logContext, sizeof(ERROR_LOG_CONTEXT)); + logContext.ErrorCode = -1; + + // Get Original Request related information + SenseInfoRequestGetInformation(Request, + &majorFunctionCode, + &ioControlCode, + &overrideVerifyVolume, + &total100nsSinceFirstSend); + + if(TEST_FLAG(Srb->SrbFlags, SRB_CLASS_FLAGS_PAGING)) + { + // Log anything remotely incorrect about paging i/o + logContext.LogError = TRUE; + logContext.UniqueErrorValue = 301; + logContext.ErrorCode = IO_WARNING_PAGING_FAILURE; + } + + // must handle the SRB_STATUS_INTERNAL_ERROR case first, + // as it has all the flags set. + if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_INTERNAL_ERROR) + { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, + "SenseInfoInterpret: Internal Error code is %x\n", + Srb->InternalStatus)); + + retry = FALSE; + *Status = Srb->InternalStatus; + } + else if (Srb->ScsiStatus == SCSISTAT_RESERVATION_CONFLICT) + { + retry = FALSE; + *Status = STATUS_DEVICE_BUSY; + logContext.LogError = FALSE; + } + else if ((Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) && + (Srb->SenseInfoBufferLength >= RTL_SIZEOF_THROUGH_FIELD(SENSE_DATA, AdditionalSenseLength))) + { + UCHAR senseKey = (UCHAR)(senseBuffer->SenseKey & 0x0f); + UCHAR additionalSenseCode = 0; + UCHAR additionalSenseCodeQual = 0; + + // Zero the additional sense code and additional sense code qualifier + // if they were not returned by the device. + readSector = senseBuffer->AdditionalSenseLength + offsetof(SENSE_DATA, AdditionalSenseLength); + if (readSector > Srb->SenseInfoBufferLength) + { + readSector = Srb->SenseInfoBufferLength; + } + + additionalSenseCode = (readSector >= RTL_SIZEOF_THROUGH_FIELD(SENSE_DATA, AdditionalSenseCode)) ? + senseBuffer->AdditionalSenseCode : 0; + additionalSenseCodeQual = (readSector >= RTL_SIZEOF_THROUGH_FIELD(SENSE_DATA, AdditionalSenseCodeQualifier)) ? + senseBuffer->AdditionalSenseCodeQualifier : 0; + + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, + "SCSI Error - \n" + "\tcdb: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n" + "\tsrb status: %X; sense: %02X/%02X/%02X; Retried count: %d\n\n", + Srb->Cdb[0], Srb->Cdb[1], Srb->Cdb[2], Srb->Cdb[3], Srb->Cdb[4], Srb->Cdb[5], + Srb->Cdb[6], Srb->Cdb[7], Srb->Cdb[8], Srb->Cdb[9], Srb->Cdb[10], Srb->Cdb[11], + Srb->Cdb[12], Srb->Cdb[13], Srb->Cdb[14], Srb->Cdb[15], + SRB_STATUS(Srb->SrbStatus), + senseKey, + additionalSenseCode, + additionalSenseCodeQual, + RetriedCount)); + + if (senseKey == SCSI_SENSE_UNIT_ATTENTION) + { + ULONG mediaChangeCount; + + // A media change may have occured so increment the change count for the physical device + mediaChangeCount = InterlockedIncrement((PLONG)&DeviceExtension->MediaChangeCount); + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, + "SenseInfoInterpret: Media change count for device %d incremented to %#lx\n", + DeviceExtension->DeviceNumber, mediaChangeCount)); + } + + if ((zpoddInfo != NULL) && + (((PCDB)Srb->Cdb)->CDB6GENERIC.OperationCode == SCSIOP_TEST_UNIT_READY)) + { + // This sense code is in response to the Test Unit Ready sent during delayed power down + // request. Copy the sense data into the zpoddInfo structure for later processing. + zpoddInfo->SenseKey = senseKey; + zpoddInfo->AdditionalSenseCode = additionalSenseCode; + zpoddInfo->AdditionalSenseCodeQualifier = additionalSenseCodeQual; + } + + // Interpret error by specific ASC & ASCQ first, + // If the error is not handled, interpret using f + { + BOOLEAN notHandled = FALSE; + notHandled = SenseInfoInterpretByAdditionalSenseCode(DeviceExtension, + Srb, + additionalSenseCode, + additionalSenseCodeQual, + Status, + &retry, + &retryIntervalInSeconds, + &logContext); + + if (notHandled) + { + SenseInfoInterpretBySenseKey(DeviceExtension, + senseBuffer, + senseKey, + Status, + &retry, + &retryIntervalInSeconds, + &logContext); + } + } + + // Try to determine the bad sector from the inquiry data. + if ((IS_SCSIOP_READWRITE(((PCDB)Srb->Cdb)->CDB10.OperationCode)) || + (((PCDB)Srb->Cdb)->CDB10.OperationCode == SCSIOP_VERIFY) || + (((PCDB)Srb->Cdb)->CDB10.OperationCode == SCSIOP_VERIFY16)) + { + ULONG index; + readSector = 0; + + for (index = 0; index < 4; index++) + { + logContext.BadSector = (logContext.BadSector << 8) | senseBuffer->Information[index]; + } + + for (index = 0; index < 4; index++) + { + readSector = (readSector << 8) | Srb->Cdb[index+2]; + } + + index = (((PCDB)Srb->Cdb)->CDB10.TransferBlocksMsb << 8) | + ((PCDB)Srb->Cdb)->CDB10.TransferBlocksLsb; + + // Make sure the bad sector is within the read sectors. + if (!(logContext.BadSector >= readSector && logContext.BadSector < (readSector + index))) + { + logContext.BadSector = readSector; + } + } + } + else + { + // Request sense buffer not valid. No sense information + // to pinpoint the error. Return general request fail. + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, + "SCSI Error - \n" + "\tcdb: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n" + "\tsrb status: %X; sense info not valid; Retried count: %d\n\n", + Srb->Cdb[0], Srb->Cdb[1], Srb->Cdb[2], Srb->Cdb[3], Srb->Cdb[4], Srb->Cdb[5], + Srb->Cdb[6], Srb->Cdb[7], Srb->Cdb[8], Srb->Cdb[9], Srb->Cdb[10], Srb->Cdb[11], + Srb->Cdb[12], Srb->Cdb[13], Srb->Cdb[14], Srb->Cdb[15], + SRB_STATUS(Srb->SrbStatus), + RetriedCount)); + + SenseInfoInterpretBySrbStatus(DeviceExtension, + Srb, + RetriedCount, + Status, + &retry, + &retryIntervalInSeconds, + &logContext); + } + + // all functions using unit - seconds for retry Interval already be called. + *RetryIntervalIn100ns = SECONDS_TO_100NS_UNITS(retryIntervalInSeconds); + + // call the device specific error handler if it has one. + // DeviceErrorHandlerForMmmc() for all MMC devices + // or DeviceErrorHandlerForHitachiGD2000() for HITACHI GD-2000, HITACHI DVD-ROM GD-2000 + if (DeviceExtension->DeviceAdditionalData.ErrorHandler) + { + DeviceExtension->DeviceAdditionalData.ErrorHandler(DeviceExtension, Srb, Status, &retry); + } + + // Refine retry based on SCSI command + SenseInfoInterpretRefineByScsiCommand(DeviceExtension, + Srb, + RetriedCount, + total100nsSinceFirstSend, + overrideVerifyVolume, + &retry, + Status, + RetryIntervalIn100ns); + + // Refine retry based on IOCTL code. + if (majorFunctionCode == IRP_MJ_DEVICE_CONTROL) + { + SenseInfoInterpretRefineByIoControl(DeviceExtension, + ioControlCode, + overrideVerifyVolume, + &retry, + Status); + } + + // LOG the error: + // Always log the error in our internal log. + // If logError is set, also log the error in the system log. + SenseInfoLogError(DeviceExtension, + Srb, + majorFunctionCode, + ioControlCode, + RetriedCount, + Status, + &retry, + &logContext); + + // all process about the error done. check if the irp was cancelled. + if ((!NT_SUCCESS(*Status)) && retry) + { + PCDROM_REQUEST_CONTEXT requestContext = RequestGetContext(Request); + + if ((requestContext->OriginalRequest != NULL) && + WdfRequestIsCanceled(requestContext->OriginalRequest) + ) + { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, + "Request %p was cancelled when it would have been retried\n", + requestContext->OriginalRequest)); + + *Status = STATUS_CANCELLED; + retry = FALSE; + *RetryIntervalIn100ns = 0; + } + } + + // now, all decisions are made. display trace information. + if (retry) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, + "Command shall be retried in %2I64d.%03I64d seconds\n", + (*RetryIntervalIn100ns / UNIT_100NS_PER_SECOND), + (*RetryIntervalIn100ns / 10000) % 1000 + )); + } + else + { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, + "Will not retry; Sense/ASC/ASCQ of %02x/%02x/%02x\n", + senseBuffer->SenseKey, + senseBuffer->AdditionalSenseCode, + senseBuffer->AdditionalSenseCodeQualifier + )); + } + + return retry; + +} // end SenseInfoInterpret() + + +BOOLEAN +SenseInfoInterpretForZPODD( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ PSCSI_REQUEST_BLOCK Srb, + _Out_ NTSTATUS* Status, + _Out_ _Out_range_(0, MAXIMUM_RETRY_FOR_SINGLE_IO_IN_100NS_UNITS) + LONGLONG* RetryIntervalIn100ns + ) +/*++ + +SenseInfoInterpretForZPODD() + +Routine Description: + + This routine interprets the data returned from the SCSI request sense. + It determines the status to return in the IRP + and whether this request can be retried. + +Arguments: + + Device - Supplies the device object associated with this request. + Srb - Supplies the scsi request block which failed. + +Return Value: + + BOOLEAN TRUE: Drivers should retry this request. + FALSE: Drivers should not retry this request. + Status - Returns the status for the request. + RetryInterval - Number of seconds before the request should be retried. + Zero indicates the request should be immediately retried. + +--*/ +{ + BOOLEAN retry = FALSE; + PSENSE_DATA senseBuffer = Srb->SenseInfoBuffer; + ULONG readSector = 0; + PZERO_POWER_ODD_INFO zpoddInfo = DeviceExtension->ZeroPowerODDInfo; + + *Status = STATUS_IO_DEVICE_ERROR; + *RetryIntervalIn100ns = 0; + + if (zpoddInfo->RetryFirstCommand != FALSE) + { + // The first command to the logical unit after power resumed will be terminated + // with CHECK CONDITION Status, 6/29/00 POWER ON, RESET, OR BUS DEVICE RESET OCCURRED + + // We have observed some devices return a different sense code, and thus as long as + // the first command after power resume fails, we just retry one more time. + zpoddInfo->RetryFirstCommand = FALSE; + + retry = TRUE; + } + else if ((Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) && + (Srb->SenseInfoBufferLength >= RTL_SIZEOF_THROUGH_FIELD(SENSE_DATA, AdditionalSenseLength))) + { + UCHAR senseKey = (UCHAR)(senseBuffer->SenseKey & 0x0f); + UCHAR additionalSenseCode = 0; + UCHAR additionalSenseCodeQual = 0; + + // Zero the additional sense code and additional sense code qualifier + // if they were not returned by the device. + readSector = senseBuffer->AdditionalSenseLength + offsetof(SENSE_DATA, AdditionalSenseLength); + if (readSector > Srb->SenseInfoBufferLength) + { + readSector = Srb->SenseInfoBufferLength; + } + + additionalSenseCode = (readSector >= RTL_SIZEOF_THROUGH_FIELD(SENSE_DATA, AdditionalSenseCode)) ? + senseBuffer->AdditionalSenseCode : 0; + additionalSenseCodeQual = (readSector >= RTL_SIZEOF_THROUGH_FIELD(SENSE_DATA, AdditionalSenseCodeQualifier)) ? + senseBuffer->AdditionalSenseCodeQualifier : 0; + + // If sense code is 2/4/1, device is becoming ready from ZPODD mode. According to Mt Fuji, device + // could take up to 800msec to be fully operational. + if ((senseKey == SCSI_SENSE_NOT_READY) && + (additionalSenseCode == SCSI_ADSENSE_LUN_NOT_READY) && + (additionalSenseCodeQual == SCSI_SENSEQ_BECOMING_READY)) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, + "SenseInfoInterpretForZPODD: In process of becoming ready\n")); + + zpoddInfo->BecomingReadyRetryCount--; + + if (zpoddInfo->BecomingReadyRetryCount > 0) + { + DEVICE_EVENT_BECOMING_READY notReady = {0}; + + retry = TRUE; + *Status = STATUS_DEVICE_NOT_READY; + *RetryIntervalIn100ns = BECOMING_READY_RETRY_INTERNVAL_IN_100NS; + + notReady.Version = 1; + notReady.Reason = 1; + notReady.Estimated100msToReady = (ULONG) *RetryIntervalIn100ns / (1000 * 1000); + DeviceSendNotification(DeviceExtension, + &GUID_IO_DEVICE_BECOMING_READY, + sizeof(DEVICE_EVENT_BECOMING_READY), + ¬Ready); + } + } + } + + // now, all decisions are made. display trace information. + if (retry) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, + "Command shall be retried in %2I64d.%03I64d seconds\n", + (*RetryIntervalIn100ns / UNIT_100NS_PER_SECOND), + (*RetryIntervalIn100ns / 10000) % 1000 + )); + } + else + { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, + "Will not retry; Sense/ASC/ASCQ of %02x/%02x/%02x\n", + senseBuffer->SenseKey, + senseBuffer->AdditionalSenseCode, + senseBuffer->AdditionalSenseCodeQualifier + )); + } + + return retry; + +} // end SenseInfoInterpret() + + +BOOLEAN +RequestSenseInfoInterpret( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ WDFREQUEST Request, + _In_ PSCSI_REQUEST_BLOCK Srb, + _In_ ULONG RetriedCount, + _Out_ NTSTATUS* Status, + _Out_opt_ _Deref_out_range_(0, MAXIMUM_RETRY_FOR_SINGLE_IO_IN_100NS_UNITS) + LONGLONG* RetryIntervalIn100ns + ) +/*++ + +Routine Description: + +Interpret the error, process it. + 1. Release device queue if it's frozen. + 2. Interpret and process the error. + +Arguments: + + DeviceExtension - Supplies the device object associated with this request. + Request - the Request that error occurs on. + Srb - Supplies the scsi request block which failed. + RetriedCount - retried count. + +Return Value: + + BOOLEAN TRUE: Drivers should retry this request. + FALSE: Drivers should not retry this request. + Status - Returns the status for the request. + RetryIntervalIn100nsUnits - Number of 100ns before the request should be retried. + Zero indicates the request should be immediately retried. + +--*/ +{ + BOOLEAN retry = FALSE; + LONGLONG retryIntervalIn100ns = 0; + PZERO_POWER_ODD_INFO zpoddInfo = DeviceExtension->ZeroPowerODDInfo; + + if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SUCCESS) + { + // request succeeded. + if ((zpoddInfo != NULL) && + (zpoddInfo->BecomingReadyRetryCount > 0)) + { + zpoddInfo->BecomingReadyRetryCount = 0; + } + + *Status = STATUS_SUCCESS; + retry = FALSE; + } + else + { + // request failed. We need to process the error. + + // 1. Release the queue if it is frozen. + if (Srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) + { + DeviceReleaseQueue(DeviceExtension->Device); + } + + if ((zpoddInfo != NULL) && + ((zpoddInfo->RetryFirstCommand != FALSE) || (zpoddInfo->BecomingReadyRetryCount > 0))) + { + retry = SenseInfoInterpretForZPODD(DeviceExtension, + Srb, + Status, + &retryIntervalIn100ns); + } + + if (retry == FALSE) + { + // 2. Error Processing + if ((zpoddInfo != NULL) && + (zpoddInfo->BecomingReadyRetryCount > 0)) + { + zpoddInfo->BecomingReadyRetryCount = 0; + } + + retry = SenseInfoInterpret(DeviceExtension, + Request, + Srb, + RetriedCount, + Status, + &retryIntervalIn100ns); + } + } + + if (RetryIntervalIn100ns != NULL) + { + *RetryIntervalIn100ns = retryIntervalIn100ns; + } + + return retry; +} + + +BOOLEAN +RequestSenseInfoInterpretForScratchBuffer( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ ULONG RetriedCount, + _Out_ NTSTATUS* Status, + _Out_ _Deref_out_range_(0, MAXIMUM_RETRY_FOR_SINGLE_IO_IN_100NS_UNITS) + LONGLONG* RetryIntervalIn100ns + ) +/*++ + +Routine Description: + + to analyze the error occurred and set the status, retry interval and decide to retry or not. + +Arguments: + + DeviceExtension - device extension + RetriedCount - already retried count. + +Return Value: + + BOOLEAN - TRUE (should retry) + Status - NTSTATUS + RetryIntervalIn100nsUnits - retry interval + +--*/ +{ + NT_ASSERT(DeviceExtension->ScratchContext.ScratchInUse != 0); + + return RequestSenseInfoInterpret(DeviceExtension, + DeviceExtension->ScratchContext.ScratchRequest, + DeviceExtension->ScratchContext.ScratchSrb, + RetriedCount, + Status, + RetryIntervalIn100ns); +} + + diff --git a/storage/class/cdrom/src/zpodd.c b/storage/class/cdrom/src/zpodd.c new file mode 100644 index 00000000..59434896 --- /dev/null +++ b/storage/class/cdrom/src/zpodd.c @@ -0,0 +1,825 @@ +/*++ + +Copyright (C) Microsoft Corporation. All rights reserved. + +Module Name: + + zpodd.c + +Abstract: + + Code for Zero Power ODD support. + +Environment: + + kernel mode only + +Notes: + + +Revision History: + +--*/ + +#include "ntddk.h" +#include "ntddstor.h" +#include "wdmguid.h" +#include "cdrom.h" +#include "mmc.h" +#include "ioctl.h" +#include "scratch.h" + +#ifdef DEBUG_USE_WPP +#include "zpodd.tmh" +#endif + +_IRQL_requires_max_(PASSIVE_LEVEL) +ULONG +DeviceGetZPODDEnabledFromRegistry(); + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +DeviceQueryD3ColdInterface( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _Out_ PD3COLD_SUPPORT_INTERFACE D3ColdInterface + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +DeviceSendEnableIdlePowerIoctl( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ BOOLEAN WakeCapable, + _In_ BOOLEAN Enable, + _In_ ULONG D3IdleTimeout + ); + +#if ALLOC_PRAGMA + +#pragma alloc_text(PAGE, DeviceInitializeZPODD) +#pragma alloc_text(PAGE, DeviceGetZPODDEnabledFromRegistry) +#pragma alloc_text(PAGE, DeviceQueryD3ColdInterface) +#pragma alloc_text(PAGE, DeviceSendEnableIdlePowerIoctl) +#pragma alloc_text(PAGE, DeviceReleaseZPODDResources) +#pragma alloc_text(PAGE, DeviceZPODDIsInHomePosition) +#pragma alloc_text(PAGE, DeviceMarkActive) + +#endif + +#pragma warning(push) +#pragma warning(disable:4152) // nonstandard extension, function/data pointer conversion in expression +#pragma warning(disable:26000) // read overflow reported because of pointer type conversion + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +DeviceInitializeZPODD( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension + ) +/*++ + +Routine Description: + + This routine initialize the contents of ZPODD structure. + +Arguments: + + DeviceExtension - the device extension + +Return Value: + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + NTSTATUS tempStatus = STATUS_SUCCESS; + PZERO_POWER_ODD_INFO zpoddInfo = NULL; + PFEATURE_DATA_REMOVABLE_MEDIUM removableMediumHeader = NULL; + ULONG ZPODDEnabledInRegistry = 0; + PD3COLD_SUPPORT_INTERFACE d3ColdInterface = NULL; + DEVICE_WAKE_DEPTH deepestWakeableDstate = DeviceWakeDepthNotWakeable; + BOOLEAN inHomePosition = FALSE; + + PAGED_CODE(); + + if (DeviceExtension->ZeroPowerODDInfo != NULL) + { + // + // Already initialized. + // + + goto Cleanup; + } + + ZPODDEnabledInRegistry = DeviceGetZPODDEnabledFromRegistry(); + + if (ZPODDEnabledInRegistry == 0) + { + // + // User has explicitly disabled Zero Power ODD. + // + + status = STATUS_NOT_SUPPORTED; + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, + "DeviceInitializeZPODD: ZPODD not enabled due to registry settings.\n" + )); + + goto Cleanup; + } + + zpoddInfo = ExAllocatePoolWithTag(NonPagedPoolNx, + sizeof(ZERO_POWER_ODD_INFO), + CDROM_TAG_ZERO_POWER_ODD); + + if (zpoddInfo == NULL) + { + status = STATUS_INSUFFICIENT_RESOURCES; + + goto Cleanup; + } + + RtlZeroMemory(zpoddInfo, sizeof (ZERO_POWER_ODD_INFO)); + + // + // Check the system for the following prerequisites: + // + // 1. SATA: Device Attention line + // 2. SATA: Asynchronous Notification + // 3. ODD: LoChange / MediaRemoval + // 4. ACPI: Wake capable + // + // Only drawer and slot loading types have well defined behaviors in the spec, so only these two + // types are supported. + // + + // + // Check for DA & AN + // + + if ((DeviceExtension->PowerDescriptor == NULL) || + (DeviceExtension->PowerDescriptor->DeviceAttentionSupported == FALSE) || + (DeviceExtension->PowerDescriptor->AsynchronousNotificationSupported == FALSE)) + { + status = STATUS_NOT_SUPPORTED; + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, + "DeviceInitializeZPODD: ZPODD not enabled due to SATA features not present.\n" + )); + + goto Cleanup; + } + + // + // Check for LoChange / MediaRemoval + // + + removableMediumHeader = (PFEATURE_DATA_REMOVABLE_MEDIUM) + DeviceFindFeaturePage(DeviceExtension->DeviceAdditionalData.Mmc.CapabilitiesBuffer, + DeviceExtension->DeviceAdditionalData.Mmc.CapabilitiesBufferSize, + FeatureRemovableMedium); + + if ((removableMediumHeader == NULL) || + !((removableMediumHeader->LoadingMechanism == LOADING_MECHANISM_TRAY) && (removableMediumHeader->Load == 0) && // Drawer ... + (removableMediumHeader->DBML != FALSE)) && // requires LoChange/NotBusy + !((removableMediumHeader->LoadingMechanism == LOADING_MECHANISM_CADDY) && (removableMediumHeader->Load == 0) && // Slot ... + (DeviceExtension->MediaChangeDetectionInfo->Gesn.Supported != FALSE))) // requires MediaRemoval + { + status = STATUS_NOT_SUPPORTED; + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, + "DeviceInitializeZPODD: ZPODD not enabled due to ODD features not present.\n" + )); + + goto Cleanup; + } + + zpoddInfo->LoadingMechanism = removableMediumHeader->LoadingMechanism; + zpoddInfo->Load = removableMediumHeader->Load; + + // + // Check for ACPI + // + + status = DeviceQueryD3ColdInterface(DeviceExtension, &zpoddInfo->D3ColdInterface); + + if (!NT_SUCCESS(status)) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, + "DeviceInitializeZPODD: Query D3Cold support interface failed.\n" + )); + + goto Cleanup; + } + + // + // If the platform supports Zero Power ODD, the following conditions must be met: + // + // 1. The deepest wakeable D-state for the device is D3Cold; + // 2. The platform supports D3Cold for the device. + // + + d3ColdInterface = &zpoddInfo->D3ColdInterface; + + status = d3ColdInterface->GetIdleWakeInfo(d3ColdInterface->Context, + PowerSystemWorking, + &deepestWakeableDstate); + + if (!NT_SUCCESS(status)) + { + goto Cleanup; + } + + // + // DeviceExtension->PowerDescriptor->D3ColdSupported is retrieved from lower layer. + // It has more accurate supportive information than just uses d3ColdInterface->GetD3ColdCapability + // + if ((deepestWakeableDstate != DeviceWakeDepthD3cold) || + (DeviceExtension->PowerDescriptor->D3ColdSupported == FALSE)) + { + status = STATUS_NOT_SUPPORTED; + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, + "DeviceInitializeZPODD: ZPODD not enabled due to ACPI support not present.\n" + )); + + goto Cleanup; + } + + // + // The system meets all requirements. Go ahead and enable ZPODD. + // + + // + // Register with the runtime power framework. + // Note that no un-registration is needed during tear-down. + // D3Cold will be enabled (success case of following call) or disabled by port driver during processing Enable Idle Power IOCTL. + // + + status = DeviceSendEnableIdlePowerIoctl(DeviceExtension, TRUE, TRUE, DELAY_TIME_TO_ENTER_ZERO_POWER_IN_MS); + + if (!NT_SUCCESS(status)) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, + "DeviceInitializeZPODD: ZPODD not enabled due to runtime power framework.\n" + )); + + goto Cleanup; + } + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, + "DeviceInitializeZPODD: ZPODD is enabled.\n" + )); + + DeviceExtension->ZeroPowerODDInfo = zpoddInfo; + + // + // If device is not in home position, then we should take an active reference here + // to prevent it from being powered off. + // + + inHomePosition = DeviceZPODDIsInHomePosition(DeviceExtension); + + if (inHomePosition == FALSE) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, + "DeviceInitializeZPODD: not ready to power off, device marked as active\n")); + + DeviceMarkActive(DeviceExtension, TRUE, FALSE); + } + else + { + // + // cache get configuration response. + // failing is not critical, so we don't want to check for status here. + // + + if (zpoddInfo->GetConfigurationBuffer == NULL) + { + tempStatus = DeviceGetConfigurationWithAlloc(DeviceExtension->Device, + &zpoddInfo->GetConfigurationBuffer, + &zpoddInfo->GetConfigurationBufferSize, + FeatureProfileList, + SCSI_GET_CONFIGURATION_REQUEST_TYPE_ALL); + + UNREFERENCED_PARAMETER(tempStatus); // Avoid PREFAST warning. + } + } + +Cleanup: + + if (!NT_SUCCESS(status)) + { + // + // We register always even in non-ZPODD case, per request from storport. + // + + tempStatus = DeviceSendEnableIdlePowerIoctl(DeviceExtension, FALSE, FALSE, DELAY_TIME_TO_ENTER_ZERO_POWER_IN_MS); + + if (NT_SUCCESS(tempStatus)) + { + // + // Mark the device active; this reference will never be released unless the system enters a + // low power state. + // + + DeviceMarkActive(DeviceExtension, TRUE, FALSE); + } + + FREE_POOL(zpoddInfo); + } + + // + // If Zero Power ODD is not supported, we should not block the device init sequence. + // + + return STATUS_SUCCESS; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +ULONG +DeviceGetZPODDEnabledFromRegistry() +/*++ + +Routine Description: + + Get the ZeroPowerODDEnabled value from registry, which dictates if Zero Power ODD + should be enabled or not. If the value is not in registry, by default Zero + Power ODD is enabled. + +Arguments: + + None + +Return Value: + + ULONG + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + WDFKEY registryKey = NULL; + ULONG ZPODDEnabled = 0; + + DECLARE_CONST_UNICODE_STRING(registryValueName, L"ZeroPowerODDEnabled"); + + PAGED_CODE(); + + // + // open the Parameters key under the service key. + // + + status = WdfDriverOpenParametersRegistryKey(WdfGetDriver(), + KEY_READ, + WDF_NO_OBJECT_ATTRIBUTES, + ®istryKey); + + if (NT_SUCCESS(status)) + { + status = WdfRegistryQueryULong(registryKey, + ®istryValueName, + &ZPODDEnabled); + + WdfRegistryClose(registryKey); + } + + if (!NT_SUCCESS(status)) + { + // + // By default, Zero Power ODD is enabled + // + + ZPODDEnabled = 1; + } + + return ZPODDEnabled; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +DeviceQueryD3ColdInterface( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _Out_ PD3COLD_SUPPORT_INTERFACE D3ColdInterface + ) +/*++ + +Routine Description: + + Queries ACPI for the D3Cold support interface. + +Arguments: + + DeviceExtension - the device extension + D3ColdInterface - output buffer receiving the interface + +Return Value: + + NTSTATUS + +--*/ +{ + PIRP irp = NULL; + KEVENT event; + NTSTATUS status = STATUS_SUCCESS; + PDEVICE_OBJECT targetDevice = NULL; + IO_STATUS_BLOCK ioStatus = {0}; + PIO_STACK_LOCATION irpStack = NULL; + + PAGED_CODE(); + + RtlZeroMemory(D3ColdInterface, sizeof(D3COLD_SUPPORT_INTERFACE)); + + // + // Query D3COLD support interface synchronously + // + + KeInitializeEvent(&event, NotificationEvent, FALSE); + + targetDevice = IoGetAttachedDeviceReference(DeviceExtension->DeviceObject); + + irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP, + targetDevice, + NULL, + 0, + 0, + &event, + &ioStatus); + + if (irp == NULL) + { + status = STATUS_INSUFFICIENT_RESOURCES; + + goto Cleanup; + } + + irp->IoStatus.Status = STATUS_NOT_SUPPORTED; + irp->IoStatus.Information = 0; + + irpStack = IoGetNextIrpStackLocation(irp); + irpStack->MinorFunction = IRP_MN_QUERY_INTERFACE; + irpStack->Parameters.QueryInterface.InterfaceType = (LPGUID) &GUID_D3COLD_SUPPORT_INTERFACE; + irpStack->Parameters.QueryInterface.Size = sizeof (D3COLD_SUPPORT_INTERFACE); + irpStack->Parameters.QueryInterface.Version = D3COLD_SUPPORT_INTERFACE_VERSION; + irpStack->Parameters.QueryInterface.Interface = (PINTERFACE) D3ColdInterface; + irpStack->Parameters.QueryInterface.InterfaceSpecificData = NULL; + + status = IoCallDriver(targetDevice, irp); + + if (status == STATUS_PENDING) + { + KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL); + + status = ioStatus.Status; + } + + if (!NT_SUCCESS(status)) + { + goto Cleanup; + } + + NT_ASSERT(D3ColdInterface->SetD3ColdSupport != NULL); + NT_ASSERT(D3ColdInterface->GetIdleWakeInfo != NULL); + NT_ASSERT(D3ColdInterface->GetD3ColdCapability != NULL); + +Cleanup: + + ObDereferenceObject(targetDevice); + + return status; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +DeviceSendEnableIdlePowerIoctl( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ BOOLEAN WakeCapable, + _In_ BOOLEAN Enable, + _In_ ULONG D3IdleTimeout + ) +/*++ + +Routine Description: + + Enables idle power support. + +Arguments: + + DeviceExtension - the device extension + WakeCapable - whether the device is wake capable + Enable - enable / disable idle power management + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + STORAGE_IDLE_POWER idlePower = {0}; + IO_STATUS_BLOCK ioStatus = {0}; + PIRP irp = NULL; + KEVENT event; + + PAGED_CODE(); + + idlePower.Version = 1; + idlePower.Size = sizeof (STORAGE_IDLE_POWER); + idlePower.WakeCapableHint = WakeCapable; + idlePower.D3ColdSupported = Enable; + idlePower.D3IdleTimeout = D3IdleTimeout; + + KeInitializeEvent(&event, NotificationEvent, FALSE); + + irp = IoBuildDeviceIoControlRequest(IOCTL_STORAGE_ENABLE_IDLE_POWER, + DeviceExtension->LowerPdo, + &idlePower, + sizeof(STORAGE_IDLE_POWER), + NULL, + 0, + FALSE, + &event, + &ioStatus); + + if (irp == NULL) + { + status = STATUS_INSUFFICIENT_RESOURCES; + } + else + { + // + // Send the synchronous request to port driver. + // + + status = IoCallDriver(DeviceExtension->LowerPdo, irp); + + if (status == STATUS_PENDING) + { + KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL); + + status = ioStatus.Status; + } + } + + TracePrint((TRACE_LEVEL_INFORMATION, + TRACE_FLAG_POWER, + "DeviceSendEnableIdlePowerIoctl: Port driver returned status (%x) for FDO (%p)\n" + "\tD3ColdSupported: %u\n" + "\tD3IdleTimeout: %u (ms)", + status, + DeviceExtension->DeviceObject, + Enable, + DELAY_TIME_TO_ENTER_ZERO_POWER_IN_MS)); + + return status; +} + +_IRQL_requires_max_(APC_LEVEL) +VOID +DeviceReleaseZPODDResources( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension + ) +/*++ + +Routine Description: + + This routine will cleanup any resources allocated for ZPODD. + +Arguments: + + DeviceExtension - the device context + +Return Value: + None. + +--*/ +{ + PZERO_POWER_ODD_INFO zpoddInfo = DeviceExtension->ZeroPowerODDInfo; + + PAGED_CODE() + + if (zpoddInfo != NULL) + { + FREE_POOL(zpoddInfo->GetConfigurationBuffer); + FREE_POOL(zpoddInfo); + } + + return; +} + +NTSTATUS +DeviceZPODDGetPowerupReason( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _Out_ PSTORAGE_IDLE_POWERUP_REASON PowerupReason + ) +/*++ + +Routine Description: + + This routine queries the port driver for what caused the power up. + +Arguments: + + DeviceExtension - device extension. + PowerupReason - what caused the power up. + +Return Value: + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PIRP irp = NULL; + IO_STATUS_BLOCK ioStatus = {0}; + KEVENT event; + + RtlZeroMemory(PowerupReason, sizeof (STORAGE_IDLE_POWERUP_REASON)); + + PowerupReason->Size = sizeof (STORAGE_IDLE_POWERUP_REASON); + PowerupReason->Version = STORAGE_IDLE_POWERUP_REASON_VERSION_V1; + + // + // Setup a synchronous irp. + // + + KeInitializeEvent(&event, NotificationEvent, FALSE); + + irp = IoBuildDeviceIoControlRequest(IOCTL_STORAGE_GET_IDLE_POWERUP_REASON, + DeviceExtension->LowerPdo, + PowerupReason, + sizeof (STORAGE_IDLE_POWERUP_REASON), + PowerupReason, + sizeof (STORAGE_IDLE_POWERUP_REASON), + FALSE, + &event, + &ioStatus); + + if (irp == NULL) + { + status = STATUS_INSUFFICIENT_RESOURCES; + } + else + { + // + // Send the synchronous request to port driver. + // + + status = IoCallDriver(DeviceExtension->LowerPdo, irp); + + if (status == STATUS_PENDING) + { + KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL); + + status = ioStatus.Status; + } + } + + return status; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +BOOLEAN +DeviceZPODDIsInHomePosition( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension + ) +/*++ + +Routine Description: + + Checks to see if the device is ready to be powered off. + Requirements are: 1. tray closed 2. no media present. + +Arguments: + + DeviceExtension - device extension. + +Return Value: + BOOLEAN + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PZERO_POWER_ODD_INFO zpoddInfo = DeviceExtension->ZeroPowerODDInfo; + SCSI_REQUEST_BLOCK srb = {0}; + PCDB cdb = (PCDB) srb.Cdb; + BOOLEAN inHomePosition = FALSE; + + PAGED_CODE(); + + if (zpoddInfo != NULL) + { + // + // Clear sense data. + // + + zpoddInfo->SenseKey = 0; + zpoddInfo->AdditionalSenseCode = 0; + zpoddInfo->AdditionalSenseCodeQualifier = 0; + + // + // Send a Test Unit Ready to check media & tray status. + // + + RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK)); + + srb.CdbLength = 6; + cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY; + + srb.TimeOutValue = CDROM_TEST_UNIT_READY_TIMEOUT; + + status = DeviceSendSrbSynchronously(DeviceExtension->Device, + &srb, + NULL, + 0, + FALSE, + NULL); + + // + // At this time, sense data, if available, is already copied into zpoddInfo. + // + // We don't check for status because we expect it to fail in case there is no media in device. + // + // Should enter Zero Power state if: + // + // Drawer: 02/3A/01 + // Slot: 02/3A/xx + // + + if (((zpoddInfo->LoadingMechanism == LOADING_MECHANISM_TRAY) && (zpoddInfo->Load == 0) && // Drawer + (zpoddInfo->SenseKey == SCSI_SENSE_NOT_READY) && + (zpoddInfo->AdditionalSenseCode == SCSI_ADSENSE_NO_MEDIA_IN_DEVICE) && + (zpoddInfo->AdditionalSenseCodeQualifier == 0x01)) || + ((zpoddInfo->LoadingMechanism == LOADING_MECHANISM_CADDY) && (zpoddInfo->Load == 0) && // Slot + (zpoddInfo->SenseKey == SCSI_SENSE_NOT_READY) && + (zpoddInfo->AdditionalSenseCode == SCSI_ADSENSE_NO_MEDIA_IN_DEVICE))) + { + inHomePosition = TRUE; + } + } + + return inHomePosition; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +VOID +DeviceMarkActive( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ BOOLEAN IsActive, + _In_ BOOLEAN SetIdleTimeout + ) +/*++ + +Routine Description: + + This routine will mark the device as active / idle. + +Arguments: + + DeviceExtension - the device context + IsActive - if the device should be marked as active + +Return Value: + None. + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PZERO_POWER_ODD_INFO zpoddInfo = DeviceExtension->ZeroPowerODDInfo; + + PAGED_CODE() + + if (DeviceExtension->IsActive != IsActive) + { + if ((IsActive == FALSE) && (zpoddInfo != NULL)) + { + // cache get configuration response. + // failing is not critical, so we don't want to check for status here. + if (zpoddInfo->GetConfigurationBuffer == NULL) + { + (VOID)DeviceGetConfigurationWithAlloc(DeviceExtension->Device, + &zpoddInfo->GetConfigurationBuffer, + &zpoddInfo->GetConfigurationBufferSize, + FeatureProfileList, + SCSI_GET_CONFIGURATION_REQUEST_TYPE_ALL); + } + } + + if (SetIdleTimeout) + { + status = DeviceSendEnableIdlePowerIoctl(DeviceExtension, + FALSE, + FALSE, + IsActive ? DELAY_TIME_TO_ENTER_ZERO_POWER_IN_MS : DELAY_TIME_TO_ENTER_AOAC_IDLE_POWER_IN_MS); + } + + if (NT_SUCCESS(status)) + { + DeviceSendIoctlAsynchronously(DeviceExtension, + IsActive ? IOCTL_STORAGE_POWER_ACTIVE : IOCTL_STORAGE_POWER_IDLE, + DeviceExtension->LowerPdo); + } + + DeviceExtension->IsActive = IsActive; + } +} + +#pragma warning(pop) // un-sets any local warning changes + + diff --git a/storage/class/classpnp/classpnp.sln b/storage/class/classpnp/classpnp.sln index 34e3421f..3be88814 100644 --- a/storage/class/classpnp/classpnp.sln +++ b/storage/class/classpnp/classpnp.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "classpnp", "src\classpnp.vcxproj", "{6AEA931E-5110-494C-A1DB-9FDE40CE7133}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "classpnp", "src\classpnp.vcxproj", "{A5AC0FD0-F93F-4FAD-940A-704DF40D9283}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +13,14 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {6AEA931E-5110-494C-A1DB-9FDE40CE7133}.Debug|Win32.ActiveCfg = Debug|Win32 - {6AEA931E-5110-494C-A1DB-9FDE40CE7133}.Debug|Win32.Build.0 = Debug|Win32 - {6AEA931E-5110-494C-A1DB-9FDE40CE7133}.Release|Win32.ActiveCfg = Release|Win32 - {6AEA931E-5110-494C-A1DB-9FDE40CE7133}.Release|Win32.Build.0 = Release|Win32 - {6AEA931E-5110-494C-A1DB-9FDE40CE7133}.Debug|x64.ActiveCfg = Debug|x64 - {6AEA931E-5110-494C-A1DB-9FDE40CE7133}.Debug|x64.Build.0 = Debug|x64 - {6AEA931E-5110-494C-A1DB-9FDE40CE7133}.Release|x64.ActiveCfg = Release|x64 - {6AEA931E-5110-494C-A1DB-9FDE40CE7133}.Release|x64.Build.0 = Release|x64 + {A5AC0FD0-F93F-4FAD-940A-704DF40D9283}.Debug|Win32.ActiveCfg = Debug|Win32 + {A5AC0FD0-F93F-4FAD-940A-704DF40D9283}.Debug|Win32.Build.0 = Debug|Win32 + {A5AC0FD0-F93F-4FAD-940A-704DF40D9283}.Release|Win32.ActiveCfg = Release|Win32 + {A5AC0FD0-F93F-4FAD-940A-704DF40D9283}.Release|Win32.Build.0 = Release|Win32 + {A5AC0FD0-F93F-4FAD-940A-704DF40D9283}.Debug|x64.ActiveCfg = Debug|x64 + {A5AC0FD0-F93F-4FAD-940A-704DF40D9283}.Debug|x64.Build.0 = Debug|x64 + {A5AC0FD0-F93F-4FAD-940A-704DF40D9283}.Release|x64.ActiveCfg = Release|x64 + {A5AC0FD0-F93F-4FAD-940A-704DF40D9283}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/storage/class/classpnp/src/classp.h b/storage/class/classpnp/src/classp.h index 3c32c25d..b46b2d8b 100644 --- a/storage/class/classpnp/src/classp.h +++ b/storage/class/classpnp/src/classp.h @@ -355,7 +355,7 @@ typedef struct _MEDIA_CHANGE_DETECTION_INFO { // UCHAR SenseBufferLength; -}; +} MEDIA_CHANGE_DETECTION_INFO, *PMEDIA_CHANGE_DETECTION_INFO; typedef enum { SimpleMediaLock, diff --git a/storage/class/classpnp/src/classpnp.vcxproj b/storage/class/classpnp/src/classpnp.vcxproj index 1a18fbc8..ca387b67 100644 --- a/storage/class/classpnp/src/classpnp.vcxproj +++ b/storage/class/classpnp/src/classpnp.vcxproj @@ -19,12 +19,12 @@ - {6AEA931E-5110-494C-A1DB-9FDE40CE7133} + {A5AC0FD0-F93F-4FAD-940A-704DF40D9283} $(MSBuildProjectName) false Debug Win32 - {FDD23D45-9A28-4A9B-8C8A-3B388DEAC852} + {36EE04FE-C8BB-410A-90C6-DD06D6865FAF} diff --git a/storage/class/classpnp/src/classpnp.vcxproj.Filters b/storage/class/classpnp/src/classpnp.vcxproj.Filters index 4ee10b9f..a0c56993 100644 --- a/storage/class/classpnp/src/classpnp.vcxproj.Filters +++ b/storage/class/classpnp/src/classpnp.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {30C77614-BC54-48A1-B49D-DA6B50452C12} + {1400A9A1-2ED5-462A-A94C-FCE810F5566E} h;hpp;hxx;hm;inl;inc;xsd - {289E064C-1506-47AC-86D9-854F5A784947} + {5BE1D83C-D225-42F8-AA81-E3E4C5A7200D} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {7085ABD8-FCBB-43B4-993A-2B3187FFA33E} + {29F75A8E-F140-40BB-A154-FCC5F6584668} inf;inv;inx;mof;mc; - {26B13FCD-BE1B-4A53-B538-39878886CB7C} + {EA1725C9-0F85-48DD-8BB8-7234C2DDF3FA} diff --git a/storage/class/classpnp/src/utils.c b/storage/class/classpnp/src/utils.c index f8236c68..b503f890 100644 --- a/storage/class/classpnp/src/utils.c +++ b/storage/class/classpnp/src/utils.c @@ -8128,8 +8128,6 @@ retry: if ((firmwareInfo->Version < sizeof(STORAGE_HW_FIRMWARE_INFO)) || (firmwareInfo->Size < sizeof(STORAGE_HW_FIRMWARE_INFO)) || (firmwareInfo->SlotCount == 0) || - (firmwareInfo->ActiveSlot >= firmwareInfo->SlotCount) || - ((firmwareInfo->PendingActivateSlot >= firmwareInfo->SlotCount) && (firmwareInfo->PendingActivateSlot != STORAGE_HW_FIRMWARE_INVALID_SLOT)) || (firmwareInfo->ImagePayloadMaxSize > fdoExtension->AdapterDescriptor->MaximumTransferLength)) { oldState = InterlockedCompareExchange((PLONG)(&fdoExtension->FunctionSupportInfo->HwFirmwareGetInfoSupport), (LONG)NotSupported, (ULONG)SupportUnknown); @@ -8493,7 +8491,8 @@ ClassDeviceHwFirmwareDownloadProcess( // // Validate the device support // - if (fdoExtension->FunctionSupportInfo->HwFirmwareInfo->SupportUpgrade == FALSE) { + if ((fdoExtension->FunctionSupportInfo->HwFirmwareInfo->SupportUpgrade == FALSE) || + (fdoExtension->FunctionSupportInfo->HwFirmwareInfo->ImagePayloadAlignment == 0)) { status = STATUS_NOT_SUPPORTED; goto Exit_Firmware_Download; } @@ -8538,9 +8537,9 @@ ClassDeviceHwFirmwareDownloadProcess( // if (((ULONG_PTR)firmwareDownload->ImageBuffer % fdoExtension->FunctionSupportInfo->HwFirmwareInfo->ImagePayloadAlignment) != 0) { // - // Allocate buffer aligns to PAGE_SIZE to accommodate any alignment requirement. + // Allocate buffer aligns to ImagePayloadAlignment to accommodate the alignment requirement. // - bufferSize = ALIGN_UP_BY(firmwareDownload->BufferSize, PAGE_SIZE); + bufferSize = ALIGN_UP_BY(firmwareDownload->BufferSize, fdoExtension->FunctionSupportInfo->HwFirmwareInfo->ImagePayloadAlignment); #pragma prefast(suppress:6014, "The allocated memory that firmwareImageBuffer points to will be freed in ClassHwFirmwareDownloadComplete().") firmwareImageBuffer = ExAllocatePoolWithTag(NonPagedPoolNx, bufferSize, CLASSPNP_POOL_TAG_FIRMWARE); @@ -8631,9 +8630,9 @@ ClassDeviceHwFirmwareDownloadProcess( cdb->WRITE_BUFFER.BufferOffset[1] = *((PCHAR)&firmwareDownload->Offset + 1); cdb->WRITE_BUFFER.BufferOffset[2] = *((PCHAR)&firmwareDownload->Offset); - cdb->WRITE_BUFFER.ParameterListLength[0] = *((PCHAR)&firmwareDownload->BufferSize + 2); - cdb->WRITE_BUFFER.ParameterListLength[1] = *((PCHAR)&firmwareDownload->BufferSize + 1); - cdb->WRITE_BUFFER.ParameterListLength[2] = *((PCHAR)&firmwareDownload->BufferSize); + cdb->WRITE_BUFFER.ParameterListLength[0] = *((PCHAR)&bufferSize + 2); + cdb->WRITE_BUFFER.ParameterListLength[1] = *((PCHAR)&bufferSize + 1); + cdb->WRITE_BUFFER.ParameterListLength[2] = *((PCHAR)&bufferSize); // // Send as a tagged command. @@ -8902,5 +8901,3 @@ Exit_Firmware_Activate: FREE_POOL(Srb); return status; } - - diff --git a/storage/class/classpnp/src/xferpkt.c b/storage/class/classpnp/src/xferpkt.c index e4a051ed..159a59b3 100644 --- a/storage/class/classpnp/src/xferpkt.c +++ b/storage/class/classpnp/src/xferpkt.c @@ -144,12 +144,12 @@ NTSTATUS InitializeTransferPackets(PDEVICE_OBJECT Fdo) minWorkingSetTransferPackets = MIN_WORKINGSET_TRANSFER_PACKETS_Client; - // Note: the reason we use max here is to guarantee a reasonable large max number + // Note: the reason we use max here is to guarantee a reasonable large max number // in the case where the port driver may return a very small supported outstanding // IOs. For example, even EMMC drive only reports 1 outstanding IO supported, we - // may still want to set this value to be at least + // may still want to set this value to be at least // MAX_WORKINGSET_TRANSFER_PACKETS_Client. - maxWorkingSetTransferPackets = max(MAX_WORKINGSET_TRANSFER_PACKETS_Client, + maxWorkingSetTransferPackets = max(MAX_WORKINGSET_TRANSFER_PACKETS_Client, 2 * maxOutstandingIOPerLUN); } else { @@ -161,12 +161,12 @@ NTSTATUS InitializeTransferPackets(PDEVICE_OBJECT Fdo) // In other words, the minWorkingSetTransferPackets for server will always between // MIN_WORKINGSET_TRANSFER_PACKETS_Server_LowerBound and MIN_WORKINGSET_TRANSFER_PACKETS_Server_UpperBound - minWorkingSetTransferPackets = - max(MIN_WORKINGSET_TRANSFER_PACKETS_Server_LowerBound, - min(MIN_WORKINGSET_TRANSFER_PACKETS_Server_UpperBound, + minWorkingSetTransferPackets = + max(MIN_WORKINGSET_TRANSFER_PACKETS_Server_LowerBound, + min(MIN_WORKINGSET_TRANSFER_PACKETS_Server_UpperBound, maxOutstandingIOPerLUN)); - maxWorkingSetTransferPackets = max(MAX_WORKINGSET_TRANSFER_PACKETS_Server, + maxWorkingSetTransferPackets = max(MAX_WORKINGSET_TRANSFER_PACKETS_Server, 2 * maxOutstandingIOPerLUN); } diff --git a/storage/class/disk/ReadMe.md b/storage/class/disk/ReadMe.md new file mode 100644 index 00000000..4945350a --- /dev/null +++ b/storage/class/disk/ReadMe.md @@ -0,0 +1,44 @@ +Disk Class Driver +================= + +The disk class driver sample is used for managing disk devices + +Build the sample +---------------- + +You can build the sample in two ways: using Microsoft Visual Studio or the command line (*MSBuild*). + +Building a Driver Using Visual Studio +------------------------------------- + +You build a driver the same way you build any project or solution in Visual Studio. When you create a new driver project using a Windows driver template, the template defines a default (active) project configuration and a default (active) solution build configuration. When you create a project from existing driver sources or convert existing driver code that was built with previous versions of the WDK, the conversion process preserves the target version information (operating systems and platform). + +The default Solution build configuration is Windows 8.1 Debug and Win32. + +### To select a configuration and build a driver or an application + +1. Open the driver project or solution in Visual Studio (find *samplename*.sln or *samplename*.vcxproj). +2. Right-click the solution in the **Solutions Explorer** and select **Configuration Manager**. +3. From the **Configuration Manager**, select the **Active Solution Configuration** (for example, Windows 8.1 Debug or Windows 8.1 Release) and the **Active Solution Platform** (for example, Win32) that correspond to the type of build you are interested in. +4. From the Build menu, click **Build Solution** (Ctrl+Shift+B). + +Building a Driver Using the Command Line (MSBuild) +-------------------------------------------------- + +You can build a driver from the command line using the Visual Studio Command Prompt window and the Microsoft Build Engine (MSBuild.exe) Previous versions of the WDK used the Windows Build utility (Build.exe) and provided separate build environment windows for each of the supported build configurations. You can now use the Visual Studio Command Prompt window for all build configurations. + +### To select a configuration and build a driver or an application + +1. Open a Visual Studio Command Prompt window at the **Start** screen. From this window you can use MsBuild.exe to build any Visual Studio project by specifying the project (.VcxProj) or solutions (.Sln) file. +2. Navigate to the project directory and enter the **MSbuild** command for your target. For example, to perform a clean build of a Visual Studio driver project called *filtername*.vcxproj, navigate to the project directory and enter the following MSBuild command: **msbuild /t:clean /t:build .\\***samplename***.vcxproj**. + +Run the sample +-------------- + +Installation and Operation +-------------------------- + +The disk class driver is used to interact with disk devices along with the appropriate port driver. The disk class driver is layered above the port driver and manages disk devices regardless of their bus type. This driver attaches to the disk devices that are enumerated by all of the storage port drivers. This driver exposes the required functionality to the file system drivers to access the disk devices. + +For more information, see [Introduction to Storage Class Drivers](http://msdn.microsoft.com/en-us/library/windows/hardware/ff559215) in the storage technologies design guide. + diff --git a/storage/class/disk/disk.sln b/storage/class/disk/disk.sln new file mode 100644 index 00000000..ad08d643 --- /dev/null +++ b/storage/class/disk/disk.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0 +MinimumVisualStudioVersion = 12.0 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "disk", "src\disk.vcxproj", "{627F8680-3389-4050-A0E1-9EA14F615498}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {627F8680-3389-4050-A0E1-9EA14F615498}.Debug|Win32.ActiveCfg = Debug|Win32 + {627F8680-3389-4050-A0E1-9EA14F615498}.Debug|Win32.Build.0 = Debug|Win32 + {627F8680-3389-4050-A0E1-9EA14F615498}.Release|Win32.ActiveCfg = Release|Win32 + {627F8680-3389-4050-A0E1-9EA14F615498}.Release|Win32.Build.0 = Release|Win32 + {627F8680-3389-4050-A0E1-9EA14F615498}.Debug|x64.ActiveCfg = Debug|x64 + {627F8680-3389-4050-A0E1-9EA14F615498}.Debug|x64.Build.0 = Debug|x64 + {627F8680-3389-4050-A0E1-9EA14F615498}.Release|x64.ActiveCfg = Release|x64 + {627F8680-3389-4050-A0E1-9EA14F615498}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/storage/class/disk/src/data.c b/storage/class/disk/src/data.c new file mode 100644 index 00000000..52f273ab --- /dev/null +++ b/storage/class/disk/src/data.c @@ -0,0 +1,85 @@ +/*++ + +Copyright (C) Microsoft Corporation, 1991 - 1999 + +Module Name: + + disk.c + +Abstract: + + SCSI disk class driver + +Environment: + + kernel mode only + +Notes: + +Revision History: + +--*/ + +#include "disk.h" + +#ifdef ALLOC_DATA_PRAGMA +#pragma data_seg("PAGEDATA") +#endif + +/* +#define HackDisableTaggedQueuing (0x01) +#define HackDisableSynchronousTransfers (0x02) +#define HackDisableSpinDown (0x04) +#define HackDisableWriteCache (0x08) +#define HackCauseNotReportableHack (0x10) +#define HackRequiresStartUnitCommand (0x20) +*/ + +CLASSPNP_SCAN_FOR_SPECIAL_INFO DiskBadControllers[] = { + { "COMPAQ" , "PD-1" , NULL, 0x02 }, + { "CONNER" , "CP3500" , NULL, 0x02 }, + { "FUJITSU" , "M2652S-512" , NULL, 0x01 }, + { "HP ", "C1113F " , NULL, 0x20 }, + // iomegas require START_UNIT commands so be sure to match all of them. + { "iomega" , "jaz" , NULL, 0x30 }, + { "iomega" , NULL , NULL, 0x20 }, + { "IOMEGA" , "ZIP" , NULL, 0x27 }, + { "IOMEGA" , NULL , NULL, 0x20 }, + { "MAXTOR" , "MXT-540SL" , "I1.2", 0x01 }, + { "MICROP" , "1936-21MW1002002" , NULL, 0x03 }, + { "OLIVETTI", "CP3500" , NULL, 0x02 }, + { "SEAGATE" , "ST41601N" , "0102", 0x02 }, + { "SEAGATE" , "ST3655N" , NULL, 0x08 }, + { "SEAGATE" , "ST3390N" , NULL, 0x08 }, + { "SEAGATE" , "ST12550N" , NULL, 0x08 }, + { "SEAGATE" , "ST32430N" , NULL, 0x08 }, + { "SEAGATE" , "ST31230N" , NULL, 0x08 }, + { "SEAGATE" , "ST15230N" , NULL, 0x08 }, + { "SyQuest" , "SQ5110" , "CHC", 0x03 }, + { "TOSHIBA" , "MK538FB" , "60", 0x01 }, + { NULL , NULL , NULL, 0x0 } +}; + +DISK_MEDIA_TYPES_LIST const DiskMediaTypesExclude[] = { + { "HP" , "RDX" , NULL, 0, 0, 0 , 0 , 0 , 0 }, + { NULL , NULL , NULL, 0, 0, 0 , 0 , 0 , 0 } +}; + + +DISK_MEDIA_TYPES_LIST const DiskMediaTypes[] = { + { "COMPAQ" , "PD-1 LF-1094" , NULL, 1, 1, PC_5_RW , 0 , 0 , 0 }, + { "HP" , NULL , NULL, 2, 2, MO_5_WO , MO_5_RW, 0 , 0 }, + { "iomega" , "jaz" , NULL, 1, 1, IOMEGA_JAZ , 0 , 0 , 0 }, + { "IOMEGA" , "ZIP" , NULL, 1, 1, IOMEGA_ZIP , 0 , 0 , 0 }, + { "PINNACLE", "Apex 4.6GB" , NULL, 3, 2, PINNACLE_APEX_5_RW, MO_5_RW, MO_5_WO, 0 }, + { "SONY" , "SMO-F541" , NULL, 2, 2, MO_5_WO , MO_5_RW, 0 , 0 }, + { "SONY" , "SMO-F551" , NULL, 2, 2, MO_5_WO , MO_5_RW, 0 , 0 }, + { "SONY" , "SMO-F561" , NULL, 2, 2, MO_5_WO , MO_5_RW, 0 , 0 }, + { "Maxoptix", "T5-2600" , NULL, 2, 2, MO_5_WO , MO_5_RW, 0 , 0 }, + { "Maxoptix", "T6-5200" , NULL, 2, 2, MO_5_WO , MO_5_RW, 0 , 0 }, + { NULL , NULL , NULL, 0, 0, 0 , 0 , 0 , 0 } +}; + +#ifdef ALLOC_DATA_PRAGMA +#pragma data_seg() +#endif diff --git a/storage/class/disk/src/disk.c b/storage/class/disk/src/disk.c new file mode 100644 index 00000000..3d4d19b4 --- /dev/null +++ b/storage/class/disk/src/disk.c @@ -0,0 +1,6166 @@ +/*++ + +Copyright (C) Microsoft Corporation, 1991 - 2010 + +Module Name: + + disk.c + +Abstract: + + SCSI disk class driver + +Environment: + + kernel mode only + +Notes: + +Revision History: + +--*/ + +#define DEBUG_MAIN_SOURCE 1 +#include "disk.h" + + +// +// Now instantiate the GUIDs +// + +#include "initguid.h" +#include "ntddstor.h" +#include "ntddvol.h" +#include "ioevent.h" + +#ifdef DEBUG_USE_WPP +#include "disk.tmh" +#endif + +#ifdef ALLOC_PRAGMA + +#pragma alloc_text(INIT, DriverEntry) +#pragma alloc_text(PAGE, DiskUnload) +#pragma alloc_text(PAGE, DiskCreateFdo) +#pragma alloc_text(PAGE, DiskDetermineMediaTypes) +#pragma alloc_text(PAGE, DiskModeSelect) +#pragma alloc_text(PAGE, DisableWriteCache) +#pragma alloc_text(PAGE, DiskSetSpecialHacks) +#pragma alloc_text(PAGE, DiskGetCacheInformation) +#pragma alloc_text(PAGE, DiskSetCacheInformation) +#pragma alloc_text(PAGE, DiskLogCacheInformation) +#pragma alloc_text(PAGE, DiskSetInfoExceptionInformation) +#pragma alloc_text(PAGE, DiskGetInfoExceptionInformation) +#pragma alloc_text(PAGE, DiskIoctlGetCacheSetting) +#pragma alloc_text(PAGE, DiskIoctlSetCacheSetting) +#pragma alloc_text(PAGE, DiskIoctlGetLengthInfo) +#pragma alloc_text(PAGE, DiskIoctlGetDriveGeometry) +#pragma alloc_text(PAGE, DiskIoctlGetDriveGeometryEx) +#pragma alloc_text(PAGE, DiskIoctlGetCacheInformation) +#pragma alloc_text(PAGE, DiskIoctlSetCacheInformation) +#pragma alloc_text(PAGE, DiskIoctlGetMediaTypesEx) +#pragma alloc_text(PAGE, DiskIoctlPredictFailure) +#pragma alloc_text(PAGE, DiskIoctlEnableFailurePrediction) +#pragma alloc_text(PAGE, DiskIoctlReassignBlocks) +#pragma alloc_text(PAGE, DiskIoctlReassignBlocksEx) +#pragma alloc_text(PAGE, DiskIoctlIsWritable) +#pragma alloc_text(PAGE, DiskIoctlUpdateDriveSize) +#pragma alloc_text(PAGE, DiskIoctlGetVolumeDiskExtents) +#pragma alloc_text(PAGE, DiskIoctlSmartGetVersion) +#pragma alloc_text(PAGE, DiskIoctlSmartReceiveDriveData) +#pragma alloc_text(PAGE, DiskIoctlSmartSendDriveCommand) +#pragma alloc_text(PAGE, DiskIoctlVerifyThread) + +#endif + +// +// ETW related globals +// +BOOLEAN DiskETWEnabled = FALSE; + +BOOLEAN DiskIsPastReinit = FALSE; + +const GUID GUID_NULL = { 0 }; +#define DiskCompareGuid(_First,_Second) \ + (memcmp ((_First),(_Second), sizeof (GUID))) + +// +// This macro is used to work around a bug in the definition of +// DISK_CACHE_RETENTION_PRIORITY. The value KeepReadData should be +// assigned 0xf rather than 0x2. Since the interface was already published +// when this was discovered the disk driver has been modified to translate +// between the interface value and the correct scsi value. +// +// 0x2 is turned into 0xf +// 0xf is turned into 0x2 - this ensures that future SCSI defintions can be +// accomodated. +// + +#define TRANSLATE_RETENTION_PRIORITY(_x)\ + ((_x) == 0xf ? 0x2 : \ + ((_x) == 0x2 ? 0xf : _x) \ + ) + +#define IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS_ADMIN CTL_CODE(IOCTL_VOLUME_BASE, 0, METHOD_BUFFERED, FILE_READ_ACCESS) + +VOID +DiskDriverReinit( + IN PDRIVER_OBJECT DriverObject, + IN PVOID Nothing, + IN ULONG Count + ) +{ + UNREFERENCED_PARAMETER(DriverObject); + UNREFERENCED_PARAMETER(Nothing); + UNREFERENCED_PARAMETER(Count); + + DiskIsPastReinit = TRUE; +} + +VOID +DiskBootDriverReinit( + IN PDRIVER_OBJECT DriverObject, + IN PVOID Nothing, + IN ULONG Count + ) +{ + IoRegisterDriverReinitialization(DriverObject, DiskDriverReinit, NULL); + +#if defined(_X86_) || defined(_AMD64_) + + DiskDriverReinitialization(DriverObject, Nothing, Count); + +#else + + UNREFERENCED_PARAMETER(Nothing); + UNREFERENCED_PARAMETER(Count); + +#endif + +} + +NTSTATUS +DriverEntry( + IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegistryPath + ) + +/*++ + +Routine Description: + + This routine initializes the SCSI hard disk class driver. + +Arguments: + + DriverObject - Pointer to driver object created by system. + + RegistryPath - Pointer to the name of the services node for this driver. + +Return Value: + + The function value is the final status from the initialization operation. + +--*/ + +{ + CLASS_INIT_DATA InitializationData = { 0 }; + CLASS_QUERY_WMI_REGINFO_EX_LIST classQueryWmiRegInfoExList = { 0 }; + GUID guidQueryRegInfoEx = GUID_CLASSPNP_QUERY_REGINFOEX; + GUID guidSrbSupport = GUID_CLASSPNP_SRB_SUPPORT; + ULONG srbSupport; + + NTSTATUS status; + + // + // Initializes tracing + // + WPP_INIT_TRACING(DriverObject, RegistryPath); + +#if defined(_X86_) || defined(_AMD64_) + + // + // Read the information NtDetect squirreled away about the disks in this + // system. + // + + DiskSaveDetectInfo(DriverObject); + +#endif + + InitializationData.InitializationDataSize = sizeof(CLASS_INIT_DATA); + + // + // Setup sizes and entry points for functional device objects + // + + InitializationData.FdoData.DeviceExtensionSize = FUNCTIONAL_EXTENSION_SIZE; + InitializationData.FdoData.DeviceType = FILE_DEVICE_DISK; + InitializationData.FdoData.DeviceCharacteristics = FILE_DEVICE_SECURE_OPEN; + + InitializationData.FdoData.ClassInitDevice = DiskInitFdo; + InitializationData.FdoData.ClassStartDevice = DiskStartFdo; + InitializationData.FdoData.ClassStopDevice = DiskStopDevice; + InitializationData.FdoData.ClassRemoveDevice = DiskRemoveDevice; + InitializationData.FdoData.ClassPowerDevice = ClassSpinDownPowerHandler; + + InitializationData.FdoData.ClassError = DiskFdoProcessError; + InitializationData.FdoData.ClassReadWriteVerification = DiskReadWriteVerification; + InitializationData.FdoData.ClassDeviceControl = DiskDeviceControl; + InitializationData.FdoData.ClassShutdownFlush = DiskShutdownFlush; + InitializationData.FdoData.ClassCreateClose = NULL; + + + InitializationData.FdoData.ClassWmiInfo.GuidCount = 7; + InitializationData.FdoData.ClassWmiInfo.GuidRegInfo = DiskWmiFdoGuidList; + InitializationData.FdoData.ClassWmiInfo.ClassQueryWmiRegInfo = DiskFdoQueryWmiRegInfo; + InitializationData.FdoData.ClassWmiInfo.ClassQueryWmiDataBlock = DiskFdoQueryWmiDataBlock; + InitializationData.FdoData.ClassWmiInfo.ClassSetWmiDataBlock = DiskFdoSetWmiDataBlock; + InitializationData.FdoData.ClassWmiInfo.ClassSetWmiDataItem = DiskFdoSetWmiDataItem; + InitializationData.FdoData.ClassWmiInfo.ClassExecuteWmiMethod = DiskFdoExecuteWmiMethod; + InitializationData.FdoData.ClassWmiInfo.ClassWmiFunctionControl = DiskWmiFunctionControl; + + InitializationData.ClassAddDevice = DiskAddDevice; + InitializationData.ClassUnload = DiskUnload; + + // + // Initialize regregistration data structures + // + + DiskInitializeReregistration(); + + // + // Call the class init routine + // + + status = ClassInitialize(DriverObject, RegistryPath, &InitializationData); + + if (NT_SUCCESS(status)) { + + IoRegisterBootDriverReinitialization(DriverObject, + DiskBootDriverReinit, + NULL); + } + + // + // Call class init Ex routine to register a + // PCLASS_QUERY_WMI_REGINFO_EX routine + // + + classQueryWmiRegInfoExList.Size = sizeof(CLASS_QUERY_WMI_REGINFO_EX_LIST); + classQueryWmiRegInfoExList.ClassFdoQueryWmiRegInfoEx = DiskFdoQueryWmiRegInfoEx; + + (VOID)ClassInitializeEx(DriverObject, + &guidQueryRegInfoEx, + &classQueryWmiRegInfoExList); + + // + // Call class init Ex routine to register SRB support + // + srbSupport = CLASS_SRB_SCSI_REQUEST_BLOCK | CLASS_SRB_STORAGE_REQUEST_BLOCK; + if (!NT_SUCCESS(ClassInitializeEx(DriverObject, + &guidSrbSupport, + &srbSupport))) { + // + // Should not fail + // + NT_ASSERT(FALSE); + } + + + return status; + +} // end DriverEntry() + + +VOID +DiskUnload( + IN PDRIVER_OBJECT DriverObject + ) +{ + PAGED_CODE(); + +#if defined(_X86_) || defined(_AMD64_) + DiskCleanupDetectInfo(DriverObject); +#else + // NB: Need to use UNREFERENCED_PARAMETER to prevent build error + // DriverObject is not referenced below in WPP_CLEANUP. + // WPP_CLEANUP is currently an "NOOP" marco. + UNREFERENCED_PARAMETER(DriverObject); +#endif + + + // + // Cleans up tracing + // + WPP_CLEANUP(DriverObject); + + return; +} + + +NTSTATUS +DiskCreateFdo( + IN PDRIVER_OBJECT DriverObject, + IN PDEVICE_OBJECT PhysicalDeviceObject, + IN PULONG DeviceCount, + IN BOOLEAN DasdAccessOnly + ) + +/*++ + +Routine Description: + + This routine creates an object for the functional device + +Arguments: + + DriverObject - Pointer to driver object created by system. + + PhysicalDeviceObject - Lower level driver we should attach to + + DeviceCount - Number of previously installed devices. + + DasdAccessOnly - indicates whether or not a file system is allowed to mount + on this device object. Used to avoid double-mounting of + file systems on super-floppies (which can unfortunately be + fixed disks). If set the i/o system will only allow rawfs + to be mounted. + +Return Value: + + NTSTATUS + +--*/ + +{ + PCCHAR deviceName = NULL; + HANDLE handle = NULL; + PDEVICE_OBJECT lowerDevice = NULL; + PDEVICE_OBJECT deviceObject = NULL; + PFUNCTIONAL_DEVICE_EXTENSION fdoExtension; + NTSTATUS status; + + PAGED_CODE(); + + *DeviceCount = 0; + + // + // Set up an object directory to contain the objects for this + // device and all its partitions. + // + + do { + + WCHAR dirBuffer[64] = { 0 }; + UNICODE_STRING dirName; + OBJECT_ATTRIBUTES objectAttribs; + + status = RtlStringCchPrintfW(dirBuffer, sizeof(dirBuffer) / sizeof(dirBuffer[0]) - 1, L"\\Device\\Harddisk%d", *DeviceCount); + if (!NT_SUCCESS(status)) { + TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_PNP, "DiskCreateFdo: Format symbolic link failed with error: 0x%X\n", status)); + return status; + } + + RtlInitUnicodeString(&dirName, dirBuffer); + + InitializeObjectAttributes(&objectAttribs, + &dirName, + OBJ_CASE_INSENSITIVE | OBJ_PERMANENT | OBJ_KERNEL_HANDLE, + NULL, + NULL); + + status = ZwCreateDirectoryObject(&handle, + DIRECTORY_ALL_ACCESS, + &objectAttribs); + + (*DeviceCount)++; + + } while((status == STATUS_OBJECT_NAME_COLLISION) || + (status == STATUS_OBJECT_NAME_EXISTS)); + + if (!NT_SUCCESS(status)) { + + TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_PNP, "DiskCreateFdo: Could not create directory - %lx\n", status)); + + return(status); + } + + // + // When this loop exits the count is inflated by one - fix that. + // + + (*DeviceCount)--; + + // + // Claim the device. + // + + lowerDevice = IoGetAttachedDeviceReference(PhysicalDeviceObject); + + status = ClassClaimDevice(lowerDevice, FALSE); + + if (!NT_SUCCESS(status)) { + ZwMakeTemporaryObject(handle); + ZwClose(handle); + ObDereferenceObject(lowerDevice); + return status; + } + + // + // Create a device object for this device. Each physical disk will + // have at least one device object. The required device object + // describes the entire device. Its directory path is + // \Device\HarddiskN\Partition0, where N = device number. + // + + status = DiskGenerateDeviceName(*DeviceCount, &deviceName); + + if(!NT_SUCCESS(status)) { + TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_PNP, "DiskCreateFdo - couldn't create name %lx\n", status)); + + goto DiskCreateFdoExit; + + } + + status = ClassCreateDeviceObject(DriverObject, + deviceName, + PhysicalDeviceObject, + TRUE, + &deviceObject); + + if (!NT_SUCCESS(status)) { + TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_PNP, "DiskCreateFdo: Can not create device object %s\n", deviceName)); + goto DiskCreateFdoExit; + } + + FREE_POOL(deviceName); + + // + // Indicate that IRPs should include MDLs for data transfers. + // + + SET_FLAG(deviceObject->Flags, DO_DIRECT_IO); + + fdoExtension = deviceObject->DeviceExtension; + + if(DasdAccessOnly) { + + // + // Inidicate that only RAW should be allowed to mount on the root + // partition object. This ensures that a file system can't doubly + // mount on a super-floppy by mounting once on P0 and once on P1. + // + +#pragma prefast(suppress:28175); + SET_FLAG(deviceObject->Vpb->Flags, VPB_RAW_MOUNT); + } + + // + // Initialize lock count to zero. The lock count is used to + // disable the ejection mechanism on devices that support + // removable media. Only the lock count in the physical + // device extension is used. + // + + fdoExtension->LockCount = 0; + + // + // Save system disk number. + // + + fdoExtension->DeviceNumber = *DeviceCount; + + // + // Set the alignment requirements for the device based on the + // host adapter requirements + // + + if (lowerDevice->AlignmentRequirement > deviceObject->AlignmentRequirement) { + deviceObject->AlignmentRequirement = lowerDevice->AlignmentRequirement; + } + + // + // Finally, attach to the pdo + // + + fdoExtension->LowerPdo = PhysicalDeviceObject; + + fdoExtension->CommonExtension.LowerDeviceObject = + IoAttachDeviceToDeviceStack(deviceObject, PhysicalDeviceObject); + + + if(fdoExtension->CommonExtension.LowerDeviceObject == NULL) { + + // + // Uh - oh, we couldn't attach + // cleanup and return + // + + status = STATUS_UNSUCCESSFUL; + goto DiskCreateFdoExit; + } + + // + // Clear the init flag. + // + + CLEAR_FLAG(deviceObject->Flags, DO_DEVICE_INITIALIZING); + + // + // Store a handle to the device object directory for this disk + // + + fdoExtension->DeviceDirectory = handle; + + ObDereferenceObject(lowerDevice); + + return STATUS_SUCCESS; + +DiskCreateFdoExit: + + if (deviceObject != NULL) + { + IoDeleteDevice(deviceObject); + } + + FREE_POOL(deviceName); + + ObDereferenceObject(lowerDevice); + + ZwMakeTemporaryObject(handle); + ZwClose(handle); + + return status; +} + + +NTSTATUS +DiskReadWriteVerification( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp + ) + +/*++ + +Routine Description: + + I/O System entry for read and write requests to SCSI disks. + +Arguments: + + DeviceObject - Pointer to driver object created by system. + Irp - IRP involved. + +Return Value: + + NT Status + +--*/ + +{ + PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; + PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp); + ULONG residualBytes; + ULONG residualOffset; + NTSTATUS status = STATUS_SUCCESS; + + // + // Make sure that the request is within the bounds of the partition, + // the number of bytes to transfer and the byte offset are a + // multiple of the sector size. + // + + residualBytes = irpSp->Parameters.Read.Length & (commonExtension->PartitionZeroExtension->DiskGeometry.BytesPerSector - 1); + residualOffset = irpSp->Parameters.Read.ByteOffset.LowPart & (commonExtension->PartitionZeroExtension->DiskGeometry.BytesPerSector - 1); + + if ((irpSp->Parameters.Read.ByteOffset.QuadPart > commonExtension->PartitionLength.QuadPart) || + (irpSp->Parameters.Read.ByteOffset.QuadPart < 0) || + (residualBytes != 0) || + (residualOffset != 0)) + { + NT_ASSERT(residualOffset == 0); + status = STATUS_INVALID_PARAMETER; + } + else + { + ULONGLONG bytesRemaining = commonExtension->PartitionLength.QuadPart - irpSp->Parameters.Read.ByteOffset.QuadPart; + + if ((ULONGLONG)irpSp->Parameters.Read.Length > bytesRemaining) + { + status = STATUS_INVALID_PARAMETER; + } + } + + if (!NT_SUCCESS(status)) + { + // + // This error may be caused by the fact that the drive is not ready. + // + + status = ((PDISK_DATA) commonExtension->DriverData)->ReadyStatus; + + if (!NT_SUCCESS(status)) { + + // + // Flag this as a user error so that a popup is generated. + // + + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_RW, "DiskReadWriteVerification: ReadyStatus is %lx\n", status)); + + if (IoIsErrorUserInduced(status) && Irp->Tail.Overlay.Thread != NULL) { + IoSetHardErrorOrVerifyDevice(Irp, DeviceObject); + } + + // + // status will keep the current error + // + + } else if ((residualBytes == 0) && (residualOffset == 0)) { + + // + // This failed because we think the physical disk is too small. + // Send it down to the drive and let the hardware decide for + // itself. + // + + status = STATUS_SUCCESS; + + } else { + + // + // Note fastfat depends on this parameter to determine when to + // remount due to a sector size change. + // + + status = STATUS_INVALID_PARAMETER; + } + } + + Irp->IoStatus.Status = status; + + return status; + +} // end DiskReadWrite() + + +NTSTATUS +DiskDetermineMediaTypes( + IN PDEVICE_OBJECT Fdo, + IN PIRP Irp, + IN UCHAR MediumType, + IN UCHAR DensityCode, + IN BOOLEAN MediaPresent, + IN BOOLEAN IsWritable + ) + +/*++ + +Routine Description: + + Determines number of types based on the physical device, validates the user buffer + and builds the MEDIA_TYPE information. + +Arguments: + + DeviceObject - Pointer to functional device object created by system. + Irp - IOCTL_STORAGE_GET_MEDIA_TYPES_EX Irp. + MediumType - byte returned in mode data header. + DensityCode - byte returned in mode data block descriptor. + NumberOfTypes - pointer to be updated based on actual device. + +Return Value: + + Status is returned. + +--*/ + +{ + PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension; + PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); + + PGET_MEDIA_TYPES mediaTypes = Irp->AssociatedIrp.SystemBuffer; + PDEVICE_MEDIA_INFO mediaInfo = &mediaTypes->MediaInfo[0]; + BOOLEAN deviceMatched = FALSE; + + PAGED_CODE(); + + // + // this should be checked prior to calling into this routine + // as we use the buffer as mediaTypes + // + + NT_ASSERT(irpStack->Parameters.DeviceIoControl.OutputBufferLength >= + sizeof(GET_MEDIA_TYPES)); + + // + // Determine if this device is removable or fixed. + // + + if (!TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)) { + + // + // Fixed disk. + // + + mediaTypes->DeviceType = FILE_DEVICE_DISK; + mediaTypes->MediaInfoCount = 1; + + mediaInfo->DeviceSpecific.DiskInfo.Cylinders.QuadPart = fdoExtension->DiskGeometry.Cylinders.QuadPart; + mediaInfo->DeviceSpecific.DiskInfo.MediaType = FixedMedia; + mediaInfo->DeviceSpecific.DiskInfo.TracksPerCylinder = fdoExtension->DiskGeometry.TracksPerCylinder; + mediaInfo->DeviceSpecific.DiskInfo.SectorsPerTrack = fdoExtension->DiskGeometry.SectorsPerTrack; + mediaInfo->DeviceSpecific.DiskInfo.BytesPerSector = fdoExtension->DiskGeometry.BytesPerSector; + mediaInfo->DeviceSpecific.DiskInfo.NumberMediaSides = 1; + mediaInfo->DeviceSpecific.DiskInfo.MediaCharacteristics = (MEDIA_CURRENTLY_MOUNTED | MEDIA_READ_WRITE); + + if (!IsWritable) { + + SET_FLAG(mediaInfo->DeviceSpecific.DiskInfo.MediaCharacteristics, + MEDIA_WRITE_PROTECTED); + } + + } else { + + PCCHAR vendorId = (PCCHAR) fdoExtension->DeviceDescriptor + fdoExtension->DeviceDescriptor->VendorIdOffset; + PCCHAR productId = (PCCHAR) fdoExtension->DeviceDescriptor + fdoExtension->DeviceDescriptor->ProductIdOffset; + PCCHAR productRevision = (PCCHAR) fdoExtension->DeviceDescriptor + fdoExtension->DeviceDescriptor->ProductRevisionOffset; + DISK_MEDIA_TYPES_LIST const *mediaListEntry; + ULONG currentMedia; + ULONG i; + ULONG j; + ULONG sizeNeeded; + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, + "DiskDetermineMediaTypes: Vendor %s, Product %s\n", + vendorId, + productId)); + + + // + // If there's an entry with such vendorId & ProductId in the DiskMediaTypesExclude list, + // this device shouldn't be looked up in the DiskMediaTypes list to determine a medium type. + // The exclude table allows to narrow down the set of devices described by the DiskMediaTypes + // list (e.g.: DiskMediaTypes says "all HP devices" and DiskMediaTypesExlclude says + // "except for HP RDX") + // + + for (i = 0; DiskMediaTypesExclude[i].VendorId != NULL; i++) { + mediaListEntry = &DiskMediaTypesExclude[i]; + + if (strncmp(mediaListEntry->VendorId,vendorId,strlen(mediaListEntry->VendorId))) { + continue; + } + + if ((mediaListEntry->ProductId != NULL) && + strncmp(mediaListEntry->ProductId, productId, strlen(mediaListEntry->ProductId))) { + continue; + } + + goto SkipTable; + } + + // + // Run through the list until we find the entry with a NULL Vendor Id. + // + + for (i = 0; DiskMediaTypes[i].VendorId != NULL; i++) { + + mediaListEntry = &DiskMediaTypes[i]; + + if (strncmp(mediaListEntry->VendorId,vendorId,strlen(mediaListEntry->VendorId))) { + continue; + } + + if ((mediaListEntry->ProductId != NULL) && + strncmp(mediaListEntry->ProductId, productId, strlen(mediaListEntry->ProductId))) { + continue; + } + + if ((mediaListEntry->Revision != NULL) && + strncmp(mediaListEntry->Revision, productRevision, strlen(mediaListEntry->Revision))) { + continue; + } + + deviceMatched = TRUE; + + mediaTypes->DeviceType = FILE_DEVICE_DISK; + mediaTypes->MediaInfoCount = mediaListEntry->NumberOfTypes; + + // + // Ensure that buffer is large enough. + // + + sizeNeeded = FIELD_OFFSET(GET_MEDIA_TYPES, MediaInfo[0]) + + (mediaListEntry->NumberOfTypes * + sizeof(DEVICE_MEDIA_INFO) + ); + + if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < + sizeNeeded) { + + // + // Buffer too small + // + + Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL; + return STATUS_BUFFER_TOO_SMALL; + } + + for (j = 0; j < mediaListEntry->NumberOfTypes; j++) { + + mediaInfo->DeviceSpecific.RemovableDiskInfo.Cylinders.QuadPart = fdoExtension->DiskGeometry.Cylinders.QuadPart; + mediaInfo->DeviceSpecific.RemovableDiskInfo.TracksPerCylinder = fdoExtension->DiskGeometry.TracksPerCylinder; + mediaInfo->DeviceSpecific.RemovableDiskInfo.SectorsPerTrack = fdoExtension->DiskGeometry.SectorsPerTrack; + mediaInfo->DeviceSpecific.RemovableDiskInfo.BytesPerSector = fdoExtension->DiskGeometry.BytesPerSector; + mediaInfo->DeviceSpecific.RemovableDiskInfo.NumberMediaSides = mediaListEntry->NumberOfSides; + + // + // Set the type. + // + + mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaType = mediaListEntry->MediaTypes[j]; + + if (mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaType == MO_5_WO) { + mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics = MEDIA_WRITE_ONCE; + } else { + mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics = MEDIA_READ_WRITE; + } + + // + // Status will either be success, if media is present, or no media. + // It would be optimal to base from density code and medium type, but not all devices + // have values for these fields. + // + + if (MediaPresent) { + + // + // The usage of MediumType and DensityCode is device specific, so this may need + // to be extended to further key off of product/vendor ids. + // Currently, the MO units are the only devices that return this information. + // + + if (MediumType == 2) { + currentMedia = MO_5_WO; + } else if (MediumType == 3) { + currentMedia = MO_5_RW; + + if (DensityCode == 0x87) { + + // + // Indicate that the pinnacle 4.6 G media + // is present. Other density codes will default to normal + // RW MO media. + // + + currentMedia = PINNACLE_APEX_5_RW; + } + } else { + currentMedia = 0; + } + + if (currentMedia) { + if (mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaType == (STORAGE_MEDIA_TYPE)currentMedia) { + SET_FLAG(mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics, MEDIA_CURRENTLY_MOUNTED); + } + + } else { + SET_FLAG(mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics, MEDIA_CURRENTLY_MOUNTED); + } + } + + if (!IsWritable) { + SET_FLAG(mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics, MEDIA_WRITE_PROTECTED); + } + + // + // Advance to next entry. + // + + mediaInfo++; + } + } + +SkipTable: + + if (!deviceMatched) { + + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, + "DiskDetermineMediaTypes: Unknown device. Vendor: %s Product: %s Revision: %s\n", + vendorId, + productId, + productRevision)); + // + // Build an entry for unknown. + // + + mediaTypes->DeviceType = FILE_DEVICE_DISK; + mediaTypes->MediaInfoCount = 1; + + mediaInfo->DeviceSpecific.RemovableDiskInfo.Cylinders.QuadPart = fdoExtension->DiskGeometry.Cylinders.QuadPart; + mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaType = RemovableMedia; + mediaInfo->DeviceSpecific.RemovableDiskInfo.TracksPerCylinder = fdoExtension->DiskGeometry.TracksPerCylinder; + mediaInfo->DeviceSpecific.RemovableDiskInfo.SectorsPerTrack = fdoExtension->DiskGeometry.SectorsPerTrack; + mediaInfo->DeviceSpecific.RemovableDiskInfo.BytesPerSector = fdoExtension->DiskGeometry.BytesPerSector; + mediaInfo->DeviceSpecific.RemovableDiskInfo.NumberMediaSides = 1; + mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics = MEDIA_READ_WRITE; + + if (MediaPresent) { + + SET_FLAG(mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics, MEDIA_CURRENTLY_MOUNTED); + } + + if (!IsWritable) { + + SET_FLAG(mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics, MEDIA_WRITE_PROTECTED); + } + } + } + + Irp->IoStatus.Information = + FIELD_OFFSET(GET_MEDIA_TYPES, MediaInfo[0]) + + (mediaTypes->MediaInfoCount * sizeof(DEVICE_MEDIA_INFO)); + + return STATUS_SUCCESS; +} + + +NTSTATUS +DiskDeviceControl( + PDEVICE_OBJECT DeviceObject, + PIRP Irp + ) + +/*++ + +Routine Description: + + I/O system entry for device controls to SCSI disks. + +Arguments: + + Fdo - Pointer to functional device object created by system. + Irp - IRP involved. + +Return Value: + + Status is returned. + +--*/ + +{ + PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); + NTSTATUS status = STATUS_SUCCESS; + ULONG ioctlCode; + + NT_ASSERT(DeviceObject != NULL); + + Irp->IoStatus.Information = 0; + ioctlCode = irpStack->Parameters.DeviceIoControl.IoControlCode; + + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL, "DiskDeviceControl: Received IOCTL 0x%X for device %p through IRP %p\n", + ioctlCode, DeviceObject, Irp)); + + + switch (ioctlCode) { + + case IOCTL_DISK_GET_CACHE_INFORMATION: { + status = DiskIoctlGetCacheInformation(DeviceObject, Irp); + break; + } + + case IOCTL_DISK_SET_CACHE_INFORMATION: { + status = DiskIoctlSetCacheInformation(DeviceObject, Irp); + break; + } + + case IOCTL_DISK_GET_CACHE_SETTING: { + status = DiskIoctlGetCacheSetting(DeviceObject, Irp); + break; + } + + case IOCTL_DISK_SET_CACHE_SETTING: { + status = DiskIoctlSetCacheSetting(DeviceObject, Irp); + break; + } + + case IOCTL_DISK_GET_DRIVE_GEOMETRY: { + status = DiskIoctlGetDriveGeometry(DeviceObject, Irp); + break; + } + + case IOCTL_DISK_GET_DRIVE_GEOMETRY_EX: { + status = DiskIoctlGetDriveGeometryEx( DeviceObject, Irp ); + break; + } + + case IOCTL_DISK_VERIFY: { + status = DiskIoctlVerify(DeviceObject, Irp); + break; + } + + case IOCTL_DISK_GET_LENGTH_INFO: { + status = DiskIoctlGetLengthInfo(DeviceObject, Irp); + break; + } + + case IOCTL_DISK_IS_WRITABLE: { + status = DiskIoctlIsWritable(DeviceObject, Irp); + break; + } + + case IOCTL_DISK_UPDATE_DRIVE_SIZE: { + status = DiskIoctlUpdateDriveSize(DeviceObject, Irp); + break; + } + + case IOCTL_DISK_REASSIGN_BLOCKS: { + status = DiskIoctlReassignBlocks(DeviceObject, Irp); + break; + } + + case IOCTL_DISK_REASSIGN_BLOCKS_EX: { + status = DiskIoctlReassignBlocksEx(DeviceObject, Irp); + break; + } + + case IOCTL_DISK_INTERNAL_SET_VERIFY: { + status = DiskIoctlSetVerify(DeviceObject, Irp); + break; + } + + case IOCTL_DISK_INTERNAL_CLEAR_VERIFY: { + status = DiskIoctlClearVerify(DeviceObject, Irp); + break; + } + + case IOCTL_STORAGE_GET_MEDIA_TYPES_EX: { + status = DiskIoctlGetMediaTypesEx(DeviceObject, Irp); + break; + } + + case IOCTL_STORAGE_PREDICT_FAILURE : { + status = DiskIoctlPredictFailure(DeviceObject, Irp); + break; + } + + #if (NTDDI_VERSION >= NTDDI_WINBLUE) + case IOCTL_STORAGE_FAILURE_PREDICTION_CONFIG : { + status = DiskIoctlEnableFailurePrediction(DeviceObject, Irp); + break; + } + #endif + + case SMART_GET_VERSION: { + status = DiskIoctlSmartGetVersion(DeviceObject, Irp); + break; + } + + case SMART_RCV_DRIVE_DATA: { + status = DiskIoctlSmartReceiveDriveData(DeviceObject, Irp); + break; + } + + case SMART_SEND_DRIVE_COMMAND: { + status = DiskIoctlSmartSendDriveCommand(DeviceObject, Irp); + break; + } + + case IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS: + case IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS_ADMIN: { + status = DiskIoctlGetVolumeDiskExtents(DeviceObject, Irp); + break; + } + + default: { + + // + // Pass the request to the common device control routine. + // + return(ClassDeviceControl(DeviceObject, Irp)); + break; + } + } // end switch + + if (!NT_SUCCESS(status)) { + + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskDeviceControl: IOCTL 0x%X to device %p failed with error 0x%X\n", + ioctlCode, DeviceObject, status)); + if (IoIsErrorUserInduced(status) && + (Irp->Tail.Overlay.Thread != NULL)) { + IoSetHardErrorOrVerifyDevice(Irp, DeviceObject); + } + } + + // + // DiskIoctlVerify() (IOCTL_DISK_VERIFY) function returns STATUS_PENDING + // and completes the IRP in the work item. Do not touch or complete + // the IRP if STATUS_PENDING is returned. + // + + if (status != STATUS_PENDING) { + + + Irp->IoStatus.Status = status; + ClassReleaseRemoveLock(DeviceObject, Irp); + ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); + } + + return(status); +} // end DiskDeviceControl() + +NTSTATUS +DiskShutdownFlush( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp + ) + +/*++ + +Routine Description: + + This routine is the handler for shutdown and flush requests. It sends + down a synch cache command to the device if its cache is enabled. If + the request is a shutdown and the media is removable, it sends down + an unlock request + + Finally, an SRB_FUNCTION_SHUTDOWN or SRB_FUNCTION_FLUSH is sent down + the stack + +Arguments: + + DeviceObject - The device object processing the request + Irp - The shutdown | flush request being serviced + +Return Value: + + STATUS_PENDING if successful, an error code otherwise + +--*/ + +{ + PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; + PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = commonExtension->PartitionZeroExtension; + PDISK_DATA diskData = (PDISK_DATA) commonExtension->DriverData; + PIO_STACK_LOCATION irpStack; + NTSTATUS status = STATUS_SUCCESS; + ULONG srbSize; + PSCSI_REQUEST_BLOCK srb; + PSTORAGE_REQUEST_BLOCK srbEx = NULL; + PSTOR_ADDR_BTL8 storAddrBtl8 = NULL; + PSRBEX_DATA_SCSI_CDB16 srbExDataCdb16 = NULL; + PCDB cdb; + KIRQL irql; + + // + // Flush requests are combined and need to be handled in a special manner + // + + irpStack = IoGetCurrentIrpStackLocation(Irp); + + if (irpStack->MajorFunction == IRP_MJ_FLUSH_BUFFERS) { + + if (TEST_FLAG(fdoExtension->DeviceFlags, DEV_POWER_PROTECTED)) { + + // + // We've been assured that both the disk + // and adapter caches are battery-backed + // + + Irp->IoStatus.Status = STATUS_SUCCESS; + ClassReleaseRemoveLock(DeviceObject, Irp); + ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); + return STATUS_SUCCESS; + } + + KeAcquireSpinLock(&diskData->FlushContext.Spinlock, &irql); + + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_SCSI, "DiskShutdownFlush: IRP %p flags = 0x%x\n", Irp, irpStack->Flags)); + + // + // This request will most likely be completed asynchronously + // + IoMarkIrpPending(Irp); + + // + // Look to see if a flush is in progress + // + + if (diskData->FlushContext.CurrIrp != NULL) { + + // + // There is an outstanding flush. Queue this + // request to the group that is next in line + // + + if (diskData->FlushContext.NextIrp != NULL) { + + #if DBG + diskData->FlushContext.DbgTagCount++; + #endif + + InsertTailList(&diskData->FlushContext.NextList, &Irp->Tail.Overlay.ListEntry); + + KeReleaseSpinLock(&diskData->FlushContext.Spinlock, irql); + + // + // This request will be completed by its representative + // + + } else { + + #if DBG + if (diskData->FlushContext.DbgTagCount < 64) { + + diskData->FlushContext.DbgRefCount[diskData->FlushContext.DbgTagCount]++; + } + + diskData->FlushContext.DbgSavCount += diskData->FlushContext.DbgTagCount; + diskData->FlushContext.DbgTagCount = 0; + #endif + + diskData->FlushContext.NextIrp = Irp; + NT_ASSERT(IsListEmpty(&diskData->FlushContext.NextList)); + + + KeReleaseSpinLock(&diskData->FlushContext.Spinlock, irql); + + + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_SCSI, "DiskShutdownFlush: waiting for event\n")); + + // + // Wait for the outstanding flush to complete + // + KeWaitForSingleObject(&diskData->FlushContext.Event, Executive, KernelMode, FALSE, NULL); + + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_SCSI, "DiskShutdownFlush: event signal\n")); + + // + // Make this group the outstanding one and free up the next slot + // + + KeAcquireSpinLock(&diskData->FlushContext.Spinlock, &irql); + + NT_ASSERT(IsListEmpty(&diskData->FlushContext.CurrList)); + + while (!IsListEmpty(&diskData->FlushContext.NextList)) { + + PLIST_ENTRY listEntry = RemoveHeadList(&diskData->FlushContext.NextList); + InsertTailList(&diskData->FlushContext.CurrList, listEntry); + } + + NT_ASSERT(diskData->FlushContext.CurrIrp != diskData->FlushContext.NextIrp); + diskData->FlushContext.CurrIrp = diskData->FlushContext.NextIrp; + diskData->FlushContext.NextIrp = NULL; + + KeReleaseSpinLock(&diskData->FlushContext.Spinlock, irql); + + // + // Send this request down to the device + // + DiskFlushDispatch(DeviceObject, &diskData->FlushContext); + } + + } else { + + diskData->FlushContext.CurrIrp = Irp; + NT_ASSERT(IsListEmpty(&diskData->FlushContext.CurrList)); + + NT_ASSERT(diskData->FlushContext.NextIrp == NULL); + NT_ASSERT(IsListEmpty(&diskData->FlushContext.NextList)); + + + KeReleaseSpinLock(&diskData->FlushContext.Spinlock, irql); + + DiskFlushDispatch(DeviceObject, &diskData->FlushContext); + } + + } else { + + // + // Allocate SCSI request block. + // + + if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { + srbSize = CLASS_SRBEX_SCSI_CDB16_BUFFER_SIZE; + } else { + srbSize = sizeof(SCSI_REQUEST_BLOCK); + } + + srb = ExAllocatePoolWithTag(NonPagedPoolNx, + srbSize, + DISK_TAG_SRB); + if (srb == NULL) { + + // + // Set the status and complete the request. + // + + Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; + ClassReleaseRemoveLock(DeviceObject, Irp); + ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); + return(STATUS_INSUFFICIENT_RESOURCES); + } + + RtlZeroMemory(srb, srbSize); + if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { + + srbEx = (PSTORAGE_REQUEST_BLOCK)srb; + + // + // Set up STORAGE_REQUEST_BLOCK fields + // + + srbEx->Length = FIELD_OFFSET(STORAGE_REQUEST_BLOCK, Signature); + srbEx->Function = SRB_FUNCTION_STORAGE_REQUEST_BLOCK; + srbEx->Signature = SRB_SIGNATURE; + srbEx->Version = STORAGE_REQUEST_BLOCK_VERSION_1; + srbEx->SrbLength = srbSize; + srbEx->SrbFunction = SRB_FUNCTION_EXECUTE_SCSI; + srbEx->RequestPriority = IoGetIoPriorityHint(Irp); + srbEx->AddressOffset = sizeof(STORAGE_REQUEST_BLOCK); + srbEx->NumSrbExData = 1; + + // Set timeout value and mark the request as not being a tagged request. + srbEx->TimeOutValue = fdoExtension->TimeOutValue * 4; + srbEx->RequestTag = SP_UNTAGGED; + srbEx->RequestAttribute = SRB_SIMPLE_TAG_REQUEST; + srbEx->SrbFlags = fdoExtension->SrbFlags; + + // + // Set up address fields + // + + storAddrBtl8 = (PSTOR_ADDR_BTL8) ((PUCHAR)srbEx + srbEx->AddressOffset); + storAddrBtl8->Type = STOR_ADDRESS_TYPE_BTL8; + storAddrBtl8->AddressLength = STOR_ADDR_BTL8_ADDRESS_LENGTH; + + // + // Set up SCSI SRB extended data fields + // + + srbEx->SrbExDataOffset[0] = sizeof(STORAGE_REQUEST_BLOCK) + + sizeof(STOR_ADDR_BTL8); + if ((srbEx->SrbExDataOffset[0] + sizeof(SRBEX_DATA_SCSI_CDB16)) <= srbEx->SrbLength) { + srbExDataCdb16 = (PSRBEX_DATA_SCSI_CDB16)((PUCHAR)srbEx + srbEx->SrbExDataOffset[0]); + srbExDataCdb16->Type = SrbExDataTypeScsiCdb16; + srbExDataCdb16->Length = SRBEX_DATA_SCSI_CDB16_LENGTH; + + cdb = (PCDB)srbExDataCdb16->Cdb; + } else { + // Should not happen + NT_ASSERT(FALSE); + + // + // Set the status and complete the request. + // + + Irp->IoStatus.Status = STATUS_INTERNAL_ERROR; + ClassReleaseRemoveLock(DeviceObject, Irp); + ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); + return(STATUS_INTERNAL_ERROR); + } + + } else { + + // + // Write length to SRB. + // + + srb->Length = SCSI_REQUEST_BLOCK_SIZE; + + // + // Set timeout value and mark the request as not being a tagged request. + // + + srb->TimeOutValue = fdoExtension->TimeOutValue * 4; + srb->QueueTag = SP_UNTAGGED; + srb->QueueAction = SRB_SIMPLE_TAG_REQUEST; + srb->SrbFlags = fdoExtension->SrbFlags; + srb->Function = SRB_FUNCTION_EXECUTE_SCSI; + + cdb = (PCDB)srb->Cdb; + } + + // + // If the write cache is enabled then send a synchronize cache request. + // + + if (TEST_FLAG(fdoExtension->DeviceFlags, DEV_WRITE_CACHE)) { + + if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { + srbExDataCdb16->CdbLength = 10; + } else { + srb->CdbLength = 10; + } + + cdb->CDB10.OperationCode = SCSIOP_SYNCHRONIZE_CACHE; + + status = ClassSendSrbSynchronous(DeviceObject, + srb, + NULL, + 0, + TRUE); + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskShutdownFlush: Synchonize cache sent. Status = %lx\n", status)); + } + + // + // Unlock the device if it contains removable media + // + + if (TEST_FLAG(DeviceObject->Characteristics, FILE_REMOVABLE_MEDIA)) + { + + if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { + + // + // Reinitialize status fields to 0 in case there was a previous request + // + + srbEx->SrbStatus = 0; + srbExDataCdb16->ScsiStatus = 0; + + srbExDataCdb16->CdbLength = 6; + + // + // Set timeout value + // + + srbEx->TimeOutValue = fdoExtension->TimeOutValue; + + } else { + + // + // Reinitialize status fields to 0 in case there was a previous request + // + + srb->SrbStatus = 0; + srb->ScsiStatus = 0; + + srb->CdbLength = 6; + + // + // Set timeout value. + // + + srb->TimeOutValue = fdoExtension->TimeOutValue; + } + + cdb->MEDIA_REMOVAL.OperationCode = SCSIOP_MEDIUM_REMOVAL; + cdb->MEDIA_REMOVAL.Prevent = FALSE; + + status = ClassSendSrbSynchronous(DeviceObject, + srb, + NULL, + 0, + TRUE); + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskShutdownFlush: Unlock device request sent. Status = %lx\n", status)); + } + + // + // Set up a SHUTDOWN SRB + // + + if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { + srbEx->NumSrbExData = 0; + srbEx->SrbExDataOffset[0] = 0; + srbEx->SrbFunction = SRB_FUNCTION_SHUTDOWN; + srbEx->OriginalRequest = Irp; + srbEx->SrbLength = CLASS_SRBEX_NO_SRBEX_DATA_BUFFER_SIZE; + srbEx->SrbStatus = 0; + } else { + srb->CdbLength = 0; + srb->Function = SRB_FUNCTION_SHUTDOWN; + srb->SrbStatus = 0; + srb->OriginalRequest = Irp; + } + + // + // Set the retry count to zero. + // + + irpStack->Parameters.Others.Argument4 = (PVOID) 0; + + // + // Set up IoCompletion routine address. + // + + IoSetCompletionRoutine(Irp, ClassIoComplete, srb, TRUE, TRUE, TRUE); + + // + // Get next stack location and + // set major function code. + // + + irpStack = IoGetNextIrpStackLocation(Irp); + + irpStack->MajorFunction = IRP_MJ_SCSI; + + // + // Set up SRB for execute scsi request. + // Save SRB address in next stack for port driver. + // + + irpStack->Parameters.Scsi.Srb = srb; + + // + // Call the port driver to process the request. + // + + IoMarkIrpPending(Irp); + IoCallDriver(commonExtension->LowerDeviceObject, Irp); + } + + return STATUS_PENDING; +} + + +VOID +DiskFlushDispatch( + IN PDEVICE_OBJECT Fdo, + IN PDISK_GROUP_CONTEXT FlushContext + ) + +/*++ + +Routine Description: + + This routine is the handler for flush requests. It sends down a synch + cache command to the device if its cache is enabled. This is followed + by an SRB_FUNCTION_FLUSH + +Arguments: + + Fdo - The device object processing the flush request + FlushContext - The flush group context + +Return Value: + + None + +--*/ + +{ + PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Fdo->DeviceExtension; + PSCSI_REQUEST_BLOCK srb = &FlushContext->Srb.Srb; + PSTORAGE_REQUEST_BLOCK srbEx = &FlushContext->Srb.SrbEx; + PIO_STACK_LOCATION irpSp = NULL; + PSTOR_ADDR_BTL8 storAddrBtl8; + PSRBEX_DATA_SCSI_CDB16 srbExDataCdb16; + + // + // Fill in the srb fields appropriately + // + if (fdoExt->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { + RtlZeroMemory(srbEx, sizeof(FlushContext->Srb.SrbExBuffer)); + + srbEx->Length = FIELD_OFFSET(STORAGE_REQUEST_BLOCK, Signature); + srbEx->Function = SRB_FUNCTION_STORAGE_REQUEST_BLOCK; + srbEx->Signature = SRB_SIGNATURE; + srbEx->Version = STORAGE_REQUEST_BLOCK_VERSION_1; + srbEx->SrbLength = sizeof(FlushContext->Srb.SrbExBuffer); + srbEx->RequestPriority = IoGetIoPriorityHint(FlushContext->CurrIrp); + srbEx->AddressOffset = sizeof(STORAGE_REQUEST_BLOCK); + srbEx->TimeOutValue = fdoExt->TimeOutValue * 4; + srbEx->RequestTag = SP_UNTAGGED; + srbEx->RequestAttribute = SRB_SIMPLE_TAG_REQUEST; + srbEx->SrbFlags = fdoExt->SrbFlags; + + // + // Set up address fields + // + + storAddrBtl8 = (PSTOR_ADDR_BTL8) ((PUCHAR)srbEx + srbEx->AddressOffset); + storAddrBtl8->Type = STOR_ADDRESS_TYPE_BTL8; + storAddrBtl8->AddressLength = STOR_ADDR_BTL8_ADDRESS_LENGTH; + + } else { + RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE); + + srb->Length = SCSI_REQUEST_BLOCK_SIZE; + srb->TimeOutValue = fdoExt->TimeOutValue * 4; + srb->QueueTag = SP_UNTAGGED; + srb->QueueAction = SRB_SIMPLE_TAG_REQUEST; + srb->SrbFlags = fdoExt->SrbFlags; + } + + // + // If write caching is enabled then send down a synchronize cache request + // + if (TEST_FLAG(fdoExt->DeviceFlags, DEV_WRITE_CACHE)) + { + + if (fdoExt->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { + srbEx->SrbFunction = SRB_FUNCTION_EXECUTE_SCSI; + srbEx->NumSrbExData = 1; + + // + // Set up SCSI SRB extended data fields + // + + srbEx->SrbExDataOffset[0] = sizeof(STORAGE_REQUEST_BLOCK) + + sizeof(STOR_ADDR_BTL8); + if ((srbEx->SrbExDataOffset[0] + sizeof(SRBEX_DATA_SCSI_CDB16)) <= srbEx->SrbLength) { + srbExDataCdb16 = (PSRBEX_DATA_SCSI_CDB16)((PUCHAR)srbEx + srbEx->SrbExDataOffset[0]); + srbExDataCdb16->Type = SrbExDataTypeScsiCdb16; + srbExDataCdb16->Length = SRBEX_DATA_SCSI_CDB16_LENGTH; + srbExDataCdb16->CdbLength = 10; + srbExDataCdb16->Cdb[0] = SCSIOP_SYNCHRONIZE_CACHE; + } else { + // Should not happen + NT_ASSERT(FALSE); + return; + } + + } else { + srb->Function = SRB_FUNCTION_EXECUTE_SCSI; + srb->CdbLength = 10; + srb->Cdb[0] = SCSIOP_SYNCHRONIZE_CACHE; + } + + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_SCSI, "DiskFlushDispatch: sending sync cache\n")); + + ClassSendSrbSynchronous(Fdo, srb, NULL, 0, TRUE); + } + + // + // Set up a FLUSH SRB + // + if (fdoExt->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { + srbEx->SrbFunction = SRB_FUNCTION_FLUSH; + srbEx->NumSrbExData = 0; + srbEx->SrbExDataOffset[0] = 0; + srbEx->OriginalRequest = FlushContext->CurrIrp; + srbEx->SrbStatus = 0; + + // + // Make sure that this srb does not get freed + // + SET_FLAG(srbEx->SrbFlags, SRB_CLASS_FLAGS_PERSISTANT); + + } else { + srb->Function = SRB_FUNCTION_FLUSH; + srb->CdbLength = 0; + srb->OriginalRequest = FlushContext->CurrIrp; + srb->SrbStatus = 0; + srb->ScsiStatus = 0; + + // + // Make sure that this srb does not get freed + // + SET_FLAG(srb->SrbFlags, SRB_CLASS_FLAGS_PERSISTANT); + } + + // + // Make sure that this request does not get retried + // + irpSp = IoGetCurrentIrpStackLocation(FlushContext->CurrIrp); + + irpSp->Parameters.Others.Argument4 = (PVOID) 0; + + // + // Fill in the irp fields appropriately + // + irpSp = IoGetNextIrpStackLocation(FlushContext->CurrIrp); + + irpSp->MajorFunction = IRP_MJ_SCSI; + irpSp->Parameters.Scsi.Srb = srb; + + IoSetCompletionRoutine(FlushContext->CurrIrp, DiskFlushComplete, NULL, TRUE, TRUE, TRUE); + + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_SCSI, "DiskFlushDispatch: sending srb flush on irp %p\n", FlushContext->CurrIrp)); + + // + // Send down the flush request + // + IoCallDriver(((PCOMMON_DEVICE_EXTENSION)fdoExt)->LowerDeviceObject, FlushContext->CurrIrp); +} + + + +NTSTATUS +DiskFlushComplete( + IN PDEVICE_OBJECT Fdo, + IN PIRP Irp, + IN PVOID Context + ) + +/*++ + +Routine Description: + + This completion routine is a wrapper around ClassIoComplete. It + will complete all the flush requests that are tagged to it, set + an event to signal the next group to proceed and return + +Arguments: + + Fdo - The device object which requested the completion routine + Irp - The irp that is being completed + Context - The flush group context + +Return Value: + + STATUS_SUCCESS if successful, an error code otherwise + +--*/ + +{ + PDISK_GROUP_CONTEXT FlushContext; + NTSTATUS status; + PFUNCTIONAL_DEVICE_EXTENSION fdoExt; + PDISK_DATA diskData; + + UNREFERENCED_PARAMETER(Context); + + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "DiskFlushComplete: %p %p\n", Fdo, Irp)); + + // + // Get the flush context from the device extension + // + fdoExt = (PFUNCTIONAL_DEVICE_EXTENSION)Fdo->DeviceExtension; + diskData = (PDISK_DATA)fdoExt->CommonExtension.DriverData; + NT_ASSERT(diskData != NULL); + _Analysis_assume_(diskData != NULL); + + FlushContext = &diskData->FlushContext; + + // + // Make sure everything is in order + // + NT_ASSERT(Irp == FlushContext->CurrIrp); + + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_SCSI, "DiskFlushComplete: completing irp %p\n", Irp)); + status = ClassIoComplete(Fdo, Irp, &FlushContext->Srb.Srb); + + // + // Make sure that ClassIoComplete did not decide to retry this request + // + NT_ASSERT(status != STATUS_MORE_PROCESSING_REQUIRED); + + // + // Complete the flush requests tagged to this one + // + + while (!IsListEmpty(&FlushContext->CurrList)) { + + PLIST_ENTRY listEntry = RemoveHeadList(&FlushContext->CurrList); + PIRP tempIrp = CONTAINING_RECORD(listEntry, IRP, Tail.Overlay.ListEntry); + + InitializeListHead(&tempIrp->Tail.Overlay.ListEntry); + tempIrp->IoStatus = Irp->IoStatus; + + ClassReleaseRemoveLock(Fdo, tempIrp); + ClassCompleteRequest(Fdo, tempIrp, IO_NO_INCREMENT); + } + + + // + // Notify the next group's representative that it may go ahead now + // + KeSetEvent(&FlushContext->Event, IO_NO_INCREMENT, FALSE); + + + TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_SCSI, "DiskFlushComplete: irp %p status = 0x%x\n", Irp, status)); + + return status; +} + + + +NTSTATUS +DiskModeSelect( + IN PDEVICE_OBJECT Fdo, + _In_reads_bytes_(Length) PCHAR ModeSelectBuffer, + IN ULONG Length, + IN BOOLEAN SavePage + ) + +/*++ + +Routine Description: + + This routine sends a mode select command. + +Arguments: + + DeviceObject - Supplies the device object associated with this request. + + ModeSelectBuffer - Supplies a buffer containing the page data. + + Length - Supplies the length in bytes of the mode select buffer. + + SavePage - Indicates that parameters should be written to disk. + +Return Value: + + Length of the transferred data is returned. + +--*/ + +{ + PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension; + PCDB cdb; + SCSI_REQUEST_BLOCK srb = {0}; + ULONG retries = 1; + ULONG length2; + NTSTATUS status; + PULONG buffer; + PMODE_PARAMETER_BLOCK blockDescriptor; + UCHAR srbExBuffer[CLASS_SRBEX_SCSI_CDB16_BUFFER_SIZE] = {0}; + PSTORAGE_REQUEST_BLOCK srbEx = (PSTORAGE_REQUEST_BLOCK)srbExBuffer; + PSTOR_ADDR_BTL8 storAddrBtl8; + PSRBEX_DATA_SCSI_CDB16 srbExDataCdb16; + PSCSI_REQUEST_BLOCK srbPtr; + + PAGED_CODE(); + + // + // Check whether block length is available + // + + if (fdoExtension->DiskGeometry.BytesPerSector == 0) { + + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskModeSelect: Block length is not available. Unable to send mode select\n")); + NT_ASSERT(fdoExtension->DiskGeometry.BytesPerSector != 0); + return STATUS_INVALID_PARAMETER; + } + + + + length2 = Length + sizeof(MODE_PARAMETER_HEADER) + sizeof(MODE_PARAMETER_BLOCK); + + // + // Allocate buffer for mode select header, block descriptor, and mode page. + // + + buffer = ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned, + length2, + DISK_TAG_MODE_DATA); + + if (buffer == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlZeroMemory(buffer, length2); + + // + // Set length in header to size of mode page. + // + + ((PMODE_PARAMETER_HEADER)buffer)->BlockDescriptorLength = sizeof(MODE_PARAMETER_BLOCK); + + blockDescriptor = (PMODE_PARAMETER_BLOCK)(buffer + 1); + + // + // Set block length from the cached disk geometry + // + + blockDescriptor->BlockLength[2] = (UCHAR) (fdoExtension->DiskGeometry.BytesPerSector >> 16); + blockDescriptor->BlockLength[1] = (UCHAR) (fdoExtension->DiskGeometry.BytesPerSector >> 8); + blockDescriptor->BlockLength[0] = (UCHAR) (fdoExtension->DiskGeometry.BytesPerSector); + + // + // Copy mode page to buffer. + // + + RtlCopyMemory(buffer + 3, ModeSelectBuffer, Length); + + // + // Build the MODE SELECT CDB. + // + + if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { + + // + // Set up STORAGE_REQUEST_BLOCK fields + // + + srbEx->Length = FIELD_OFFSET(STORAGE_REQUEST_BLOCK, Signature); + srbEx->Function = SRB_FUNCTION_STORAGE_REQUEST_BLOCK; + srbEx->Signature = SRB_SIGNATURE; + srbEx->Version = STORAGE_REQUEST_BLOCK_VERSION_1; + srbEx->SrbLength = sizeof(srbExBuffer); + srbEx->SrbFunction = SRB_FUNCTION_EXECUTE_SCSI; + srbEx->RequestPriority = IoPriorityNormal; + srbEx->AddressOffset = sizeof(STORAGE_REQUEST_BLOCK); + srbEx->NumSrbExData = 1; + + // Set timeout value from device extension. + srbEx->TimeOutValue = fdoExtension->TimeOutValue * 2; + + // + // Set up address fields + // + + storAddrBtl8 = (PSTOR_ADDR_BTL8) ((PUCHAR)srbEx + srbEx->AddressOffset); + storAddrBtl8->Type = STOR_ADDRESS_TYPE_BTL8; + storAddrBtl8->AddressLength = STOR_ADDR_BTL8_ADDRESS_LENGTH; + + // + // Set up SCSI SRB extended data fields + // + + srbEx->SrbExDataOffset[0] = sizeof(STORAGE_REQUEST_BLOCK) + + sizeof(STOR_ADDR_BTL8); + if ((srbEx->SrbExDataOffset[0] + sizeof(SRBEX_DATA_SCSI_CDB16)) <= srbEx->SrbLength) { + srbExDataCdb16 = (PSRBEX_DATA_SCSI_CDB16)((PUCHAR)srbEx + srbEx->SrbExDataOffset[0]); + srbExDataCdb16->Type = SrbExDataTypeScsiCdb16; + srbExDataCdb16->Length = SRBEX_DATA_SCSI_CDB16_LENGTH; + srbExDataCdb16->CdbLength = 6; + + cdb = (PCDB)srbExDataCdb16->Cdb; + } else { + // Should not happen + NT_ASSERT(FALSE); + + FREE_POOL(buffer); + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskModeSelect: Insufficient extended SRB size\n")); + return STATUS_INTERNAL_ERROR; + } + + srbPtr = (PSCSI_REQUEST_BLOCK)srbEx; + + } else { + + srb.CdbLength = 6; + cdb = (PCDB)srb.Cdb; + + // + // Set timeout value from device extension. + // + + srb.TimeOutValue = fdoExtension->TimeOutValue * 2; + + srbPtr = &srb; + } + + cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT; + cdb->MODE_SELECT.SPBit = SavePage; + cdb->MODE_SELECT.PFBit = 1; + cdb->MODE_SELECT.ParameterListLength = (UCHAR)(length2); + +Retry: + + status = ClassSendSrbSynchronous(Fdo, + srbPtr, + buffer, + length2, + TRUE); + + if (status == STATUS_VERIFY_REQUIRED) { + + // + // Routine ClassSendSrbSynchronous does not retry requests returned with + // this status. + // + + if (retries--) { + + // + // Retry request. + // + + goto Retry; + } + + } else if (SRB_STATUS(srbPtr->SrbStatus) == SRB_STATUS_DATA_OVERRUN) { + status = STATUS_SUCCESS; + } + + FREE_POOL(buffer); + + return status; +} // end DiskModeSelect() + + +// +// This routine is structured as a work-item routine +// +VOID +DisableWriteCache( + IN PDEVICE_OBJECT Fdo, + IN PVOID Context + ) + +{ + PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = (PFUNCTIONAL_DEVICE_EXTENSION)Fdo->DeviceExtension; + DISK_CACHE_INFORMATION cacheInfo = { 0 }; + NTSTATUS status; + PIO_WORKITEM WorkItem = (PIO_WORKITEM)Context; + + PAGED_CODE(); + + NT_ASSERT(WorkItem != NULL); + _Analysis_assume_(WorkItem != NULL); + + status = DiskGetCacheInformation(fdoExtension, &cacheInfo); + + if (NT_SUCCESS(status) && (cacheInfo.WriteCacheEnabled == TRUE)) { + + cacheInfo.WriteCacheEnabled = FALSE; + + DiskSetCacheInformation(fdoExtension, &cacheInfo); + } + + IoFreeWorkItem(WorkItem); +} + + +// +// This routine is structured as a work-item routine +// +VOID +DiskIoctlVerifyThread( + IN PDEVICE_OBJECT Fdo, + IN PVOID Context + ) +{ + PDISK_VERIFY_WORKITEM_CONTEXT WorkContext = (PDISK_VERIFY_WORKITEM_CONTEXT)Context; + PIRP Irp = NULL; + PFUNCTIONAL_DEVICE_EXTENSION FdoExtension = (PFUNCTIONAL_DEVICE_EXTENSION)Fdo->DeviceExtension; + PDISK_DATA DiskData = (PDISK_DATA)FdoExtension->CommonExtension.DriverData; + PVERIFY_INFORMATION verifyInfo = NULL; + PSCSI_REQUEST_BLOCK Srb = NULL; + PCDB Cdb = NULL; + LARGE_INTEGER byteOffset; + LARGE_INTEGER sectorOffset; + ULONG sectorCount; + NTSTATUS status = STATUS_SUCCESS; + PSTORAGE_REQUEST_BLOCK srbEx = NULL; + PSTOR_ADDR_BTL8 storAddrBtl8 = NULL; + PSRBEX_DATA_SCSI_CDB16 srbExDataCdb16 = NULL; + + PAGED_CODE(); + + NT_ASSERT(WorkContext != NULL); + _Analysis_assume_(WorkContext != NULL); + + Srb = WorkContext->Srb; + Irp = WorkContext->Irp; + verifyInfo = (PVERIFY_INFORMATION)Irp->AssociatedIrp.SystemBuffer; + + // + // We don't need to hold on to this memory as + // the following operation may take some time + // + + IoFreeWorkItem(WorkContext->WorkItem); + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlVerifyThread: Spliting up the request\n")); + + // + // Add disk offset to starting the sector + // + + byteOffset.QuadPart = FdoExtension->CommonExtension.StartingOffset.QuadPart + + verifyInfo->StartingOffset.QuadPart; + + // + // Convert byte offset to the sector offset + // + + sectorOffset.QuadPart = byteOffset.QuadPart >> FdoExtension->SectorShift; + + // + // Convert byte count to sector count. + // + + sectorCount = verifyInfo->Length >> FdoExtension->SectorShift; + + // + // Make sure that all previous verify requests have indeed completed + // This greatly reduces the possibility of a Denial-of-Service attack + // + + KeWaitForMutexObject(&DiskData->VerifyMutex, + Executive, + KernelMode, + FALSE, + NULL); + + // + // Initialize SCSI SRB for a verify CDB + // + if (FdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { + RtlZeroMemory(Srb, CLASS_SRBEX_SCSI_CDB16_BUFFER_SIZE); + srbEx = (PSTORAGE_REQUEST_BLOCK)Srb; + + // + // Set up STORAGE_REQUEST_BLOCK fields + // + + srbEx->Length = FIELD_OFFSET(STORAGE_REQUEST_BLOCK, Signature); + srbEx->Function = SRB_FUNCTION_STORAGE_REQUEST_BLOCK; + srbEx->Signature = SRB_SIGNATURE; + srbEx->Version = STORAGE_REQUEST_BLOCK_VERSION_1; + srbEx->SrbLength = CLASS_SRBEX_SCSI_CDB16_BUFFER_SIZE; + srbEx->SrbFunction = SRB_FUNCTION_EXECUTE_SCSI; + srbEx->RequestPriority = IoGetIoPriorityHint(Irp); + srbEx->AddressOffset = sizeof(STORAGE_REQUEST_BLOCK); + srbEx->NumSrbExData = 1; + + // + // Set up address fields + // + + storAddrBtl8 = (PSTOR_ADDR_BTL8) ((PUCHAR)srbEx + srbEx->AddressOffset); + storAddrBtl8->Type = STOR_ADDRESS_TYPE_BTL8; + storAddrBtl8->AddressLength = STOR_ADDR_BTL8_ADDRESS_LENGTH; + + // + // Set up SCSI SRB extended data fields + // + + srbEx->SrbExDataOffset[0] = sizeof(STORAGE_REQUEST_BLOCK) + + sizeof(STOR_ADDR_BTL8); + if ((srbEx->SrbExDataOffset[0] + sizeof(SRBEX_DATA_SCSI_CDB16)) <= srbEx->SrbLength) { + srbExDataCdb16 = (PSRBEX_DATA_SCSI_CDB16)((PUCHAR)srbEx + srbEx->SrbExDataOffset[0]); + srbExDataCdb16->Type = SrbExDataTypeScsiCdb16; + srbExDataCdb16->Length = SRBEX_DATA_SCSI_CDB16_LENGTH; + + Cdb = (PCDB)srbExDataCdb16->Cdb; + if (TEST_FLAG(FdoExtension->DeviceFlags, DEV_USE_16BYTE_CDB)) { + srbExDataCdb16->CdbLength = 16; + Cdb->CDB16.OperationCode = SCSIOP_VERIFY16; + } else { + srbExDataCdb16->CdbLength = 10; + Cdb->CDB10.OperationCode = SCSIOP_VERIFY; + } + } else { + // Should not happen + NT_ASSERT(FALSE); + + FREE_POOL(Srb); + FREE_POOL(WorkContext); + status = STATUS_INTERNAL_ERROR; + } + + } else { + RtlZeroMemory(Srb, SCSI_REQUEST_BLOCK_SIZE); + + Srb->Length = sizeof(SCSI_REQUEST_BLOCK); + Srb->Function = SRB_FUNCTION_EXECUTE_SCSI; + + Cdb = (PCDB)Srb->Cdb; + if (TEST_FLAG(FdoExtension->DeviceFlags, DEV_USE_16BYTE_CDB)) { + Srb->CdbLength = 16; + Cdb->CDB16.OperationCode = SCSIOP_VERIFY16; + } else { + Srb->CdbLength = 10; + Cdb->CDB10.OperationCode = SCSIOP_VERIFY; + } + + } + + while (NT_SUCCESS(status) && (sectorCount != 0)) { + + USHORT numSectors = (USHORT) min(sectorCount, MAX_SECTORS_PER_VERIFY); + + if (FdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { + + // + // Reset status fields + // + + srbEx->SrbStatus = 0; + srbExDataCdb16->ScsiStatus = 0; + + // + // Calculate the request timeout value based + // on the number of sectors being verified + // + + srbEx->TimeOutValue = ((numSectors + 0x7F) >> 7) * FdoExtension->TimeOutValue; + } else { + + // + // Reset status fields + // + + Srb->SrbStatus = 0; + Srb->ScsiStatus = 0; + + // + // Calculate the request timeout value based + // on the number of sectors being verified + // + + Srb->TimeOutValue = ((numSectors + 0x7F) >> 7) * FdoExtension->TimeOutValue; + } + + // + // Update verify CDB info. + // NOTE - CDB opcode and length has been initialized prior to entering + // the while loop + // + + if (TEST_FLAG(FdoExtension->DeviceFlags, DEV_USE_16BYTE_CDB)) { + + REVERSE_BYTES_QUAD(&Cdb->CDB16.LogicalBlock, §orOffset); + REVERSE_BYTES_SHORT(&Cdb->CDB16.TransferLength[2], &numSectors); + } else { + + // + // Move little endian values into CDB in big endian format + // + + Cdb->CDB10.LogicalBlockByte0 = ((PFOUR_BYTE)§orOffset)->Byte3; + Cdb->CDB10.LogicalBlockByte1 = ((PFOUR_BYTE)§orOffset)->Byte2; + Cdb->CDB10.LogicalBlockByte2 = ((PFOUR_BYTE)§orOffset)->Byte1; + Cdb->CDB10.LogicalBlockByte3 = ((PFOUR_BYTE)§orOffset)->Byte0; + + Cdb->CDB10.TransferBlocksMsb = ((PFOUR_BYTE)&numSectors)->Byte1; + Cdb->CDB10.TransferBlocksLsb = ((PFOUR_BYTE)&numSectors)->Byte0; + } + + status = ClassSendSrbSynchronous(Fdo, + Srb, + NULL, + 0, + FALSE); + + NT_ASSERT(status != STATUS_NONEXISTENT_SECTOR); + + sectorCount -= numSectors; + sectorOffset.QuadPart += numSectors; + } + + KeReleaseMutex(&DiskData->VerifyMutex, FALSE); + + Irp->IoStatus.Status = status; + Irp->IoStatus.Information = 0; + + ClassReleaseRemoveLock(Fdo, Irp); + ClassCompleteRequest(Fdo, Irp, IO_NO_INCREMENT); + + FREE_POOL(Srb); + FREE_POOL(WorkContext); +} + + +VOID +DiskFdoProcessError( + PDEVICE_OBJECT Fdo, + PSCSI_REQUEST_BLOCK Srb, + NTSTATUS *Status, + BOOLEAN *Retry + ) + +/*++ + +Routine Description: + + This routine checks the type of error. If the error indicates an underrun + then indicate the request should be retried. + +Arguments: + + Fdo - Supplies a pointer to the functional device object. + + Srb - Supplies a pointer to the failing Srb. + + Status - Status with which the IRP will be completed. + + Retry - Indication of whether the request will be retried. + +Return Value: + + None. + +--*/ + +{ + PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension; + PSTORAGE_REQUEST_BLOCK srbEx; + PCDB cdb = NULL; + UCHAR scsiStatus = 0; + UCHAR senseBufferLength = 0; + PVOID senseBuffer = NULL; + CDB noOp = {0}; + + // + // Get relevant fields from SRB + // + if (Srb->Function == SRB_FUNCTION_STORAGE_REQUEST_BLOCK) { + + srbEx = (PSTORAGE_REQUEST_BLOCK)Srb; + + // + // Look for SCSI SRB specific fields + // + if ((srbEx->SrbFunction == SRB_FUNCTION_EXECUTE_SCSI) && + (srbEx->NumSrbExData > 0)) { + cdb = GetSrbScsiData(srbEx, NULL, NULL, &scsiStatus, &senseBuffer, &senseBufferLength); + + // + // cdb and sense buffer should not be NULL + // + NT_ASSERT(cdb != NULL); + NT_ASSERT(senseBuffer != NULL); + + } + + if (cdb == NULL) { + + // + // Use a cdb that is all 0s + // + cdb = &noOp; + } + + } else { + + cdb = (PCDB)(Srb->Cdb); + scsiStatus = Srb->ScsiStatus; + senseBufferLength = Srb->SenseInfoBufferLength; + senseBuffer = Srb->SenseInfoBuffer; + } + + if (*Status == STATUS_DATA_OVERRUN && + (cdb != NULL) && + (IS_SCSIOP_READWRITE(cdb->CDB10.OperationCode))) { + + *Retry = TRUE; + + // + // Update the error count for the device. + // + + fdoExtension->ErrorCount++; + + } else if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_ERROR && + scsiStatus == SCSISTAT_BUSY) { + + // + // a disk drive should never be busy this long. Reset the scsi bus + // maybe this will clear the condition. + // + + ResetBus(Fdo); + + // + // Update the error count for the device. + // + + fdoExtension->ErrorCount++; + + } else { + + BOOLEAN invalidatePartitionTable = FALSE; + + // + // See if this might indicate that something on the drive has changed. + // + + if ((Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) && + (senseBuffer != NULL) && (cdb != NULL)) { + + BOOLEAN validSense = FALSE; + UCHAR senseKey = 0; + UCHAR asc = 0; + UCHAR ascq = 0; + + validSense = ScsiGetSenseKeyAndCodes(senseBuffer, + senseBufferLength, + SCSI_SENSE_OPTIONS_FIXED_FORMAT_IF_UNKNOWN_FORMAT_INDICATED, + &senseKey, + &asc, + &ascq); + + if (validSense) { + + switch (senseKey) { + + case SCSI_SENSE_ILLEGAL_REQUEST: { + + switch (asc) { + + case SCSI_ADSENSE_INVALID_CDB: + { + // + // Look to see if this is an Io request with the ForceUnitAccess flag set + // + if (((cdb->CDB10.OperationCode == SCSIOP_WRITE) || + (cdb->CDB10.OperationCode == SCSIOP_WRITE16)) && + (cdb->CDB10.ForceUnitAccess)) + { + PDISK_DATA diskData = (PDISK_DATA)fdoExtension->CommonExtension.DriverData; + + if (diskData->WriteCacheOverride == DiskWriteCacheEnable) + { + PIO_ERROR_LOG_PACKET logEntry = NULL; + + // + // The user has explicitly requested that write caching be turned on. + // Warn the user that writes with FUA enabled are not working and that + // they should disable write cache. + // + + logEntry = IoAllocateErrorLogEntry(fdoExtension->DeviceObject, + sizeof(IO_ERROR_LOG_PACKET) + (4 * sizeof(ULONG))); + + if (logEntry != NULL) + { + logEntry->FinalStatus = *Status; + logEntry->ErrorCode = IO_WARNING_WRITE_FUA_PROBLEM; + logEntry->SequenceNumber = 0; + logEntry->MajorFunctionCode = IRP_MJ_SCSI; + logEntry->IoControlCode = 0; + logEntry->RetryCount = 0; + logEntry->UniqueErrorValue = 0; + logEntry->DumpDataSize = 4 * sizeof(ULONG); + + logEntry->DumpData[0] = diskData->ScsiAddress.PortNumber; + logEntry->DumpData[1] = diskData->ScsiAddress.PathId; + logEntry->DumpData[2] = diskData->ScsiAddress.TargetId; + logEntry->DumpData[3] = diskData->ScsiAddress.Lun; + + // + // Write the error log packet. + // + + IoWriteErrorLogEntry(logEntry); + } + } + else + { + // + // Turn off write caching on this device. This is so that future + // critical requests need not be sent down with ForceUnitAccess + // + PIO_WORKITEM workItem = IoAllocateWorkItem(Fdo); + + if (workItem) + { + IoQueueWorkItem(workItem, DisableWriteCache, CriticalWorkQueue, workItem); + } + } + + SET_FLAG(fdoExtension->ScanForSpecialFlags, CLASS_SPECIAL_FUA_NOT_SUPPORTED); + ADJUST_FUA_FLAG(fdoExtension); + + + cdb->CDB10.ForceUnitAccess = FALSE; + *Retry = TRUE; + + } else if ((cdb->CDB6FORMAT.OperationCode == SCSIOP_MODE_SENSE) && + (cdb->MODE_SENSE.PageCode == MODE_SENSE_RETURN_ALL)) { + + // + // Mode sense for all pages failed. This command could fail with + // SCSI_SENSE_ILLEGAL_REQUEST / SCSI_ADSENSE_INVALID_CDB if the data + // to be returned is more than 256 bytes. In which case, try to get + // only MODE_PAGE_CACHING since we only need the block descriptor. + // + // Simply change the page code and retry the request + // + + cdb->MODE_SENSE.PageCode = MODE_PAGE_CACHING; + *Retry = TRUE; + } + + break; + } + } // end switch(asc) + break; + } + + case SCSI_SENSE_NOT_READY: { + + switch (asc) { + case SCSI_ADSENSE_LUN_NOT_READY: { + switch (ascq) { + case SCSI_SENSEQ_BECOMING_READY: + case SCSI_SENSEQ_MANUAL_INTERVENTION_REQUIRED: + case SCSI_SENSEQ_CAUSE_NOT_REPORTABLE: { + invalidatePartitionTable = TRUE; + break; + } + } // end switch(ascq) + break; + } + + case SCSI_ADSENSE_NO_MEDIA_IN_DEVICE: { + invalidatePartitionTable = TRUE; + break; + } + } // end switch(asc) + break; + } + + case SCSI_SENSE_MEDIUM_ERROR: { + invalidatePartitionTable = TRUE; + break; + } + + case SCSI_SENSE_HARDWARE_ERROR: { + invalidatePartitionTable = TRUE; + break; + } + + case SCSI_SENSE_UNIT_ATTENTION: + { + invalidatePartitionTable = TRUE; + break; + } + + case SCSI_SENSE_RECOVERED_ERROR: { + invalidatePartitionTable = TRUE; + break; + } + + } // end switch(senseKey) + } // end if (validSense) + } else { + + // + // On any exceptional scsi condition which might indicate that the + // device was changed we will flush out the state of the partition + // table. + // + + switch (SRB_STATUS(Srb->SrbStatus)) { + case SRB_STATUS_INVALID_LUN: + case SRB_STATUS_INVALID_TARGET_ID: + case SRB_STATUS_NO_DEVICE: + case SRB_STATUS_NO_HBA: + case SRB_STATUS_INVALID_PATH_ID: + case SRB_STATUS_COMMAND_TIMEOUT: + case SRB_STATUS_TIMEOUT: + case SRB_STATUS_SELECTION_TIMEOUT: + case SRB_STATUS_REQUEST_FLUSHED: + case SRB_STATUS_UNEXPECTED_BUS_FREE: + case SRB_STATUS_PARITY_ERROR: + { + invalidatePartitionTable = TRUE; + break; + } + + case SRB_STATUS_ERROR: + { + if (scsiStatus == SCSISTAT_RESERVATION_CONFLICT) + { + invalidatePartitionTable = TRUE; + } + + break; + } + } // end switch(Srb->SrbStatus) + } + + if (invalidatePartitionTable && TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)) { + + // + // Inform the upper layers that the volume + // on this disk is in need of verification + // + + SET_FLAG(Fdo->Flags, DO_VERIFY_VOLUME); + } + } + + return; +} + + +VOID +DiskSetSpecialHacks( + IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, + IN ULONG_PTR Data + ) + +/*++ + +Routine Description: + + This function checks to see if an SCSI logical unit requires speical + flags to be set. + +Arguments: + + Fdo - Supplies the device object to be tested. + + InquiryData - Supplies the inquiry data returned by the device of interest. + + AdapterDescriptor - Supplies the capabilities of the device object. + +Return Value: + + None. + +--*/ + +{ + PDEVICE_OBJECT fdo = FdoExtension->DeviceObject; + + PAGED_CODE(); + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, "Disk SetSpecialHacks, Setting Hacks %p\n", (void*) Data)); + + // + // Found a listed controller. Determine what must be done. + // + + if (TEST_FLAG(Data, HackDisableTaggedQueuing)) { + + // + // Disable tagged queuing. + // + + CLEAR_FLAG(FdoExtension->SrbFlags, SRB_FLAGS_QUEUE_ACTION_ENABLE); + } + + if (TEST_FLAG(Data, HackDisableSynchronousTransfers)) { + + // + // Disable synchronous data transfers. + // + + SET_FLAG(FdoExtension->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER); + + } + + if (TEST_FLAG(Data, HackDisableSpinDown)) { + + // + // Disable spinning down of drives. + // + + SET_FLAG(FdoExtension->ScanForSpecialFlags, + CLASS_SPECIAL_DISABLE_SPIN_DOWN); + + } + + if (TEST_FLAG(Data, HackDisableWriteCache)) { + + // + // Disable the drive's write cache + // + + SET_FLAG(FdoExtension->ScanForSpecialFlags, + CLASS_SPECIAL_DISABLE_WRITE_CACHE); + + } + + if (TEST_FLAG(Data, HackCauseNotReportableHack)) { + + SET_FLAG(FdoExtension->ScanForSpecialFlags, + CLASS_SPECIAL_CAUSE_NOT_REPORTABLE_HACK); + } + + if (TEST_FLAG(fdo->Characteristics, FILE_REMOVABLE_MEDIA) && + TEST_FLAG(Data, HackRequiresStartUnitCommand) + ) { + + // + // this is a list of vendors who require the START_UNIT command + // + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, "DiskScanForSpecial (%p) => This unit requires " + " START_UNITS\n", fdo)); + SET_FLAG(FdoExtension->DeviceFlags, DEV_SAFE_START_UNIT); + + } + + return; +} + + +VOID +ResetBus( + IN PDEVICE_OBJECT Fdo + ) + +/*++ + +Routine Description: + + This command sends a reset bus command to the SCSI port driver. + +Arguments: + + Fdo - The functional device object for the logical unit with hardware problem. + +Return Value: + + None. + +--*/ + +{ + PIO_STACK_LOCATION irpStack; + PIRP irp; + + PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension; + PSCSI_REQUEST_BLOCK srb; + PCOMPLETION_CONTEXT context; + PSTORAGE_REQUEST_BLOCK srbEx = NULL; + PSTOR_ADDR_BTL8 storAddrBtl8 = NULL; + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "Disk ResetBus: Sending reset bus request to port driver.\n")); + + // + // Allocate Srb from nonpaged pool. + // + + context = ExAllocatePoolWithTag(NonPagedPoolNx, + sizeof(COMPLETION_CONTEXT), + DISK_TAG_CCONTEXT); + + if(context == NULL) { + return; + } + + // + // Save the device object in the context for use by the completion + // routine. + // + + context->DeviceObject = Fdo; + srb = &context->Srb.Srb; + + if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { + srbEx = &context->Srb.SrbEx; + + // + // Zero out srb + // + + RtlZeroMemory(srbEx, sizeof(context->Srb.SrbExBuffer)); + + // + // Set up STORAGE_REQUEST_BLOCK fields + // + + srbEx->Length = FIELD_OFFSET(STORAGE_REQUEST_BLOCK, Signature); + srbEx->Function = SRB_FUNCTION_STORAGE_REQUEST_BLOCK; + srbEx->Signature = SRB_SIGNATURE; + srbEx->Version = STORAGE_REQUEST_BLOCK_VERSION_1; + srbEx->SrbLength = sizeof(context->Srb.SrbExBuffer); + srbEx->SrbFunction = SRB_FUNCTION_RESET_BUS; + srbEx->AddressOffset = sizeof(STORAGE_REQUEST_BLOCK); + + // + // Set up address fields + // + + storAddrBtl8 = (PSTOR_ADDR_BTL8) ((PUCHAR)srbEx + srbEx->AddressOffset); + storAddrBtl8->Type = STOR_ADDRESS_TYPE_BTL8; + storAddrBtl8->AddressLength = STOR_ADDR_BTL8_ADDRESS_LENGTH; + + } else { + + // + // Zero out srb. + // + + RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE); + + // + // Write length to SRB. + // + + srb->Length = SCSI_REQUEST_BLOCK_SIZE; + + srb->Function = SRB_FUNCTION_RESET_BUS; + + } + + // + // Build the asynchronous request to be sent to the port driver. + // Since this routine is called from a DPC the IRP should always be + // available. + // + + irp = IoAllocateIrp(Fdo->StackSize, FALSE); + + if (irp == NULL) { + FREE_POOL(context); + return; + } + + ClassAcquireRemoveLock(Fdo, irp); + + IoSetCompletionRoutine(irp, + (PIO_COMPLETION_ROUTINE)ClassAsynchronousCompletion, + context, + TRUE, + TRUE, + TRUE); + + irpStack = IoGetNextIrpStackLocation(irp); + + irpStack->MajorFunction = IRP_MJ_SCSI; + + if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { + srbEx->RequestPriority = IoGetIoPriorityHint(irp); + srbEx->OriginalRequest = irp; + } else { + srb->OriginalRequest = irp; + } + + // + // Store the SRB address in next stack for port driver. + // + + irpStack->Parameters.Scsi.Srb = srb; + + // + // Call the port driver with the IRP. + // + + IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp); + + return; + +} // end ResetBus() + + + +VOID +DiskLogCacheInformation( + IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, + IN PDISK_CACHE_INFORMATION CacheInfo, + IN NTSTATUS Status + ) +{ + PIO_ERROR_LOG_PACKET logEntry = NULL; + + PAGED_CODE(); + + logEntry = IoAllocateErrorLogEntry(FdoExtension->DeviceObject, sizeof(IO_ERROR_LOG_PACKET) + (4 * sizeof(ULONG))); + + if (logEntry != NULL) + { + PDISK_DATA diskData = FdoExtension->CommonExtension.DriverData; + BOOLEAN bIsEnabled = TEST_FLAG(FdoExtension->DeviceFlags, DEV_WRITE_CACHE); + + logEntry->FinalStatus = Status; + logEntry->ErrorCode = (bIsEnabled) ? IO_WRITE_CACHE_ENABLED : IO_WRITE_CACHE_DISABLED; + logEntry->SequenceNumber = 0; + logEntry->MajorFunctionCode = IRP_MJ_SCSI; + logEntry->IoControlCode = 0; + logEntry->RetryCount = 0; + logEntry->UniqueErrorValue = 0x1; + logEntry->DumpDataSize = 4 * sizeof(ULONG); + + logEntry->DumpData[0] = diskData->ScsiAddress.PathId; + logEntry->DumpData[1] = diskData->ScsiAddress.TargetId; + logEntry->DumpData[2] = diskData->ScsiAddress.Lun; + logEntry->DumpData[3] = CacheInfo->WriteCacheEnabled; + + // + // Write the error log packet. + // + + IoWriteErrorLogEntry(logEntry); + } +} + +NTSTATUS +DiskGetInfoExceptionInformation( + IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, + IN PMODE_INFO_EXCEPTIONS ReturnPageData + ) +{ + PMODE_PARAMETER_HEADER modeData; + PMODE_INFO_EXCEPTIONS pageData; + ULONG length; + + NTSTATUS status; + + PAGED_CODE(); + + // + // ReturnPageData is allocated by the caller + // + + modeData = ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned, + MODE_DATA_SIZE, + DISK_TAG_INFO_EXCEPTION); + + if (modeData == NULL) { + + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DiskGetInfoExceptionInformation: Unable to allocate mode " + "data buffer\n")); + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlZeroMemory(modeData, MODE_DATA_SIZE); + + length = ClassModeSense(FdoExtension->DeviceObject, + (PCHAR) modeData, + MODE_DATA_SIZE, + MODE_PAGE_FAULT_REPORTING); + + if (length < sizeof(MODE_PARAMETER_HEADER)) { + + // + // Retry the request in case of a check condition. + // + + length = ClassModeSense(FdoExtension->DeviceObject, + (PCHAR) modeData, + MODE_DATA_SIZE, + MODE_PAGE_FAULT_REPORTING); + + if (length < sizeof(MODE_PARAMETER_HEADER)) { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DiskGetInfoExceptionInformation: Mode Sense failed\n")); + FREE_POOL(modeData); + return STATUS_IO_DEVICE_ERROR; + } + } + + // + // If the length is greater than length indicated by the mode data reset + // the data to the mode data. + // + + if (length > (ULONG) (modeData->ModeDataLength + 1)) { + length = modeData->ModeDataLength + 1; + } + + // + // Find the mode page for info exceptions + // + + pageData = ClassFindModePage((PCHAR) modeData, + length, + MODE_PAGE_FAULT_REPORTING, + TRUE); + + if (pageData != NULL) { + RtlCopyMemory(ReturnPageData, pageData, sizeof(MODE_INFO_EXCEPTIONS)); + status = STATUS_SUCCESS; + } else { + status = STATUS_NOT_SUPPORTED; + } + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_WMI, "DiskGetInfoExceptionInformation: %s support SMART for device %p\n", + NT_SUCCESS(status) ? "does" : "does not", + FdoExtension->DeviceObject)); + + FREE_POOL(modeData); + + return(status); +} + + +NTSTATUS +DiskSetInfoExceptionInformation( + IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, + IN PMODE_INFO_EXCEPTIONS PageData + ) + +{ + ULONG i; + NTSTATUS status = STATUS_SUCCESS; + + PAGED_CODE(); + + // + // We will attempt (twice) to issue the mode select with the page. + // Make the setting persistant so that we don't have to turn it back + // on after a bus reset. + // + + for (i = 0; i < 2; i++) + { + status = DiskModeSelect(FdoExtension->DeviceObject, + (PCHAR) PageData, + sizeof(MODE_INFO_EXCEPTIONS), + TRUE); + } + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_WMI, "DiskSetInfoExceptionInformation: %s for device %p\n", + NT_SUCCESS(status) ? "succeeded" : "failed", + FdoExtension->DeviceObject)); + + return status; +} + +NTSTATUS +DiskGetCacheInformation( + IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, + IN PDISK_CACHE_INFORMATION CacheInfo + ) +/*++ + +Routine Description: + + This function gets the caching mode page from the drive. This function + is called from DiskIoctlGetCacheInformation() in response to the IOCTL + IOCTL_DISK_GET_CACHE_INFORMATION. This is also called from the + DisableWriteCache() worker thread to disable caching when write commands fail. + +Arguments: + + FdoExtension - The device extension for this device. + + CacheInfo - Buffer to receive the Cache Information. + +Return Value: + + NTSTATUS code + +--*/ + +{ + PMODE_PARAMETER_HEADER modeData; + PMODE_CACHING_PAGE pageData; + + ULONG length; + + PAGED_CODE(); + + + + modeData = ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned, + MODE_DATA_SIZE, + DISK_TAG_DISABLE_CACHE); + + if (modeData == NULL) { + + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskGetSetCacheInformation: Unable to allocate mode " + "data buffer\n")); + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlZeroMemory(modeData, MODE_DATA_SIZE); + + length = ClassModeSense(FdoExtension->DeviceObject, + (PCHAR) modeData, + MODE_DATA_SIZE, + MODE_PAGE_CACHING); + + if (length < sizeof(MODE_PARAMETER_HEADER)) { + + // + // Retry the request in case of a check condition. + // + + length = ClassModeSense(FdoExtension->DeviceObject, + (PCHAR) modeData, + MODE_DATA_SIZE, + MODE_PAGE_CACHING); + + if (length < sizeof(MODE_PARAMETER_HEADER)) { + + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskGetCacheInformation: Mode Sense failed\n")); + + FREE_POOL(modeData); + return STATUS_IO_DEVICE_ERROR; + } + } + + // + // If the length is greater than length indicated by the mode data reset + // the data to the mode data. + // + + if (length > (ULONG) (modeData->ModeDataLength + 1)) { + length = modeData->ModeDataLength + 1; + } + + // + // Check to see if the write cache is enabled. + // + + pageData = ClassFindModePage((PCHAR) modeData, + length, + MODE_PAGE_CACHING, + TRUE); + + // + // Check if valid caching page exists. + // + + if (pageData == NULL) { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskGetCacheInformation: Unable to find caching mode page.\n")); + FREE_POOL(modeData); + return STATUS_NOT_SUPPORTED; + } + + // + // Copy the parameters over. + // + + RtlZeroMemory(CacheInfo, sizeof(DISK_CACHE_INFORMATION)); + + CacheInfo->ParametersSavable = pageData->PageSavable; + + CacheInfo->ReadCacheEnabled = !(pageData->ReadDisableCache); + CacheInfo->WriteCacheEnabled = pageData->WriteCacheEnable; + + + // + // Translate the values in the mode page into the ones defined in + // ntdddisk.h. + // + + CacheInfo->ReadRetentionPriority = + TRANSLATE_RETENTION_PRIORITY(pageData->ReadRetensionPriority); + CacheInfo->WriteRetentionPriority = + TRANSLATE_RETENTION_PRIORITY(pageData->WriteRetensionPriority); + + CacheInfo->DisablePrefetchTransferLength = + ((pageData->DisablePrefetchTransfer[0] << 8) + + pageData->DisablePrefetchTransfer[1]); + + CacheInfo->ScalarPrefetch.Minimum = + ((pageData->MinimumPrefetch[0] << 8) + pageData->MinimumPrefetch[1]); + + CacheInfo->ScalarPrefetch.Maximum = + ((pageData->MaximumPrefetch[0] << 8) + pageData->MaximumPrefetch[1]); + + if(pageData->MultiplicationFactor) { + CacheInfo->PrefetchScalar = TRUE; + CacheInfo->ScalarPrefetch.MaximumBlocks = + ((pageData->MaximumPrefetchCeiling[0] << 8) + + pageData->MaximumPrefetchCeiling[1]); + } + + + FREE_POOL(modeData); + return STATUS_SUCCESS; +} + + +NTSTATUS +DiskSetCacheInformation( + IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, + IN PDISK_CACHE_INFORMATION CacheInfo + ) +/*++ + +Routine Description: + + This function sets the caching mode page in the drive. This function + is also called from the DisableWriteCache() worker thread to disable + caching when write commands fail. + +Arguments: + + FdoExtension - The device extension for this device. + + CacheInfo - Buffer the contains the Cache Information to be set on the drive. + +Return Value: + + NTSTATUS code + +--*/ +{ + PMODE_PARAMETER_HEADER modeData; + ULONG length; + PMODE_CACHING_PAGE pageData; + ULONG i; + NTSTATUS status = STATUS_SUCCESS; + + PAGED_CODE(); + + modeData = ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned, + MODE_DATA_SIZE, + DISK_TAG_DISABLE_CACHE); + + if (modeData == NULL) { + + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskSetCacheInformation: Unable to allocate mode " + "data buffer\n")); + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlZeroMemory(modeData, MODE_DATA_SIZE); + + length = ClassModeSense(FdoExtension->DeviceObject, + (PCHAR) modeData, + MODE_DATA_SIZE, + MODE_PAGE_CACHING); + + if (length < sizeof(MODE_PARAMETER_HEADER)) { + + // + // Retry the request in case of a check condition. + // + + length = ClassModeSense(FdoExtension->DeviceObject, + (PCHAR) modeData, + MODE_DATA_SIZE, + MODE_PAGE_CACHING); + + if (length < sizeof(MODE_PARAMETER_HEADER)) { + + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskSetCacheInformation: Mode Sense failed\n")); + + FREE_POOL(modeData); + return STATUS_IO_DEVICE_ERROR; + } + } + + // + // If the length is greater than length indicated by the mode data reset + // the data to the mode data. + // + + if (length > (ULONG) (modeData->ModeDataLength + 1)) { + length = modeData->ModeDataLength + 1; + } + + // + // Check to see if the write cache is enabled. + // + + pageData = ClassFindModePage((PCHAR) modeData, + length, + MODE_PAGE_CACHING, + TRUE); + + // + // Check if valid caching page exists. + // + + if (pageData == NULL) { + FREE_POOL(modeData); + return STATUS_NOT_SUPPORTED; + } + + // + // Don't touch any of the normal parameters - not all drives actually + // use the correct size of caching mode page. Just change the things + // which the user could have modified. + // + + pageData->PageSavable = FALSE; + + pageData->ReadDisableCache = !(CacheInfo->ReadCacheEnabled); + pageData->MultiplicationFactor = CacheInfo->PrefetchScalar; + pageData->WriteCacheEnable = CacheInfo->WriteCacheEnabled; + + pageData->WriteRetensionPriority = (UCHAR) + TRANSLATE_RETENTION_PRIORITY(CacheInfo->WriteRetentionPriority); + pageData->ReadRetensionPriority = (UCHAR) + TRANSLATE_RETENTION_PRIORITY(CacheInfo->ReadRetentionPriority); + + pageData->DisablePrefetchTransfer[0] = + (UCHAR) (CacheInfo->DisablePrefetchTransferLength >> 8); + pageData->DisablePrefetchTransfer[1] = + (UCHAR) (CacheInfo->DisablePrefetchTransferLength & 0x00ff); + + pageData->MinimumPrefetch[0] = + (UCHAR) (CacheInfo->ScalarPrefetch.Minimum >> 8); + pageData->MinimumPrefetch[1] = + (UCHAR) (CacheInfo->ScalarPrefetch.Minimum & 0x00ff); + + pageData->MaximumPrefetch[0] = + (UCHAR) (CacheInfo->ScalarPrefetch.Maximum >> 8); + pageData->MaximumPrefetch[1] = + (UCHAR) (CacheInfo->ScalarPrefetch.Maximum & 0x00ff); + + if(pageData->MultiplicationFactor) { + + pageData->MaximumPrefetchCeiling[0] = + (UCHAR) (CacheInfo->ScalarPrefetch.MaximumBlocks >> 8); + pageData->MaximumPrefetchCeiling[1] = + (UCHAR) (CacheInfo->ScalarPrefetch.MaximumBlocks & 0x00ff); + } + + // + // We will attempt (twice) to issue the mode select with the page. + // + + for (i = 0; i < 2; i++) { + + status = DiskModeSelect(FdoExtension->DeviceObject, + (PCHAR) pageData, + (pageData->PageLength + 2), + CacheInfo->ParametersSavable); + + if (NT_SUCCESS(status)) { + + if (CacheInfo->WriteCacheEnabled) + { + SET_FLAG(FdoExtension->DeviceFlags, DEV_WRITE_CACHE); + } + else + { + CLEAR_FLAG(FdoExtension->DeviceFlags, DEV_WRITE_CACHE); + } + ADJUST_FUA_FLAG(FdoExtension); + + break; + } + } + + if (NT_SUCCESS(status)) + { + } else { + + // + // We were unable to modify the disk write cache setting + // + + SET_FLAG(FdoExtension->ScanForSpecialFlags, CLASS_SPECIAL_MODIFY_CACHE_UNSUCCESSFUL); + } + + FREE_POOL(modeData); + return status; +} + +NTSTATUS +DiskIoctlGetCacheSetting( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp + ) + +/*++ + +Routine description: + + This routine services IOCTL_DISK_GET_CACHE_SETTING. It looks to + see if there are any issues with the disk cache and whether the + user had previously indicated that the cache is power-protected + +Arguments: + + Fdo - The functional device object processing the request + Irp - The ioctl to be processed + +Return Value: + + STATUS_SUCCESS if successful, an error code otherwise + +--*/ + +{ + PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension; + PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp); + NTSTATUS status = STATUS_SUCCESS; + + PAGED_CODE(); + + if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(DISK_CACHE_SETTING)) + { + status = STATUS_BUFFER_TOO_SMALL; + } + else + { + PDISK_CACHE_SETTING cacheSetting = (PDISK_CACHE_SETTING)Irp->AssociatedIrp.SystemBuffer; + + cacheSetting->Version = sizeof(DISK_CACHE_SETTING); + cacheSetting->State = DiskCacheNormal; + + // + // Determine whether it is safe to turn on the cache + // + if (TEST_FLAG(fdoExtension->ScanForSpecialFlags, CLASS_SPECIAL_FUA_NOT_SUPPORTED)) + { + cacheSetting->State = DiskCacheWriteThroughNotSupported; + } + + // + // Determine whether it is possible to modify the cache setting + // + if (TEST_FLAG(fdoExtension->ScanForSpecialFlags, CLASS_SPECIAL_MODIFY_CACHE_UNSUCCESSFUL)) + { + cacheSetting->State = DiskCacheModifyUnsuccessful; + } + + cacheSetting->IsPowerProtected = TEST_FLAG(fdoExtension->DeviceFlags, DEV_POWER_PROTECTED); + + Irp->IoStatus.Information = sizeof(DISK_CACHE_SETTING); + } + + return status; +} + + +NTSTATUS +DiskIoctlSetCacheSetting( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp + ) + +/*++ + +Routine description: + + This routine services IOCTL_DISK_SET_CACHE_SETTING. It allows + the user to specify whether the disk cache is power-protected + or not + + This function must be called at IRQL < DISPATCH_LEVEL. + +Arguments: + + Fdo - The functional device object processing the request + Irp - The ioctl to be processed + +Return Value: + + STATUS_SUCCESS if successful, an error code otherwise + +--*/ + +{ + PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension; + PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp); + NTSTATUS status = STATUS_SUCCESS; + + // + // This function must be called at less than dispatch level. + // Fail if IRQL >= DISPATCH_LEVEL. + // + PAGED_CODE(); + CHECK_IRQL(); + + if (irpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(DISK_CACHE_SETTING)) + { + status = STATUS_INFO_LENGTH_MISMATCH; + } + else + { + PDISK_CACHE_SETTING cacheSetting = (PDISK_CACHE_SETTING)Irp->AssociatedIrp.SystemBuffer; + + if (cacheSetting->Version == sizeof(DISK_CACHE_SETTING)) + { + ULONG isPowerProtected; + + // + // Save away the user-defined override in our extension and the registry + // + if (cacheSetting->IsPowerProtected) + { + SET_FLAG(fdoExtension->DeviceFlags, DEV_POWER_PROTECTED); + isPowerProtected = 1; + } + else + { + CLEAR_FLAG(fdoExtension->DeviceFlags, DEV_POWER_PROTECTED); + isPowerProtected = 0; + } + ADJUST_FUA_FLAG(fdoExtension); + + ClassSetDeviceParameter(fdoExtension, DiskDeviceParameterSubkey, DiskDeviceCacheIsPowerProtected, isPowerProtected); + } + else + { + status = STATUS_INVALID_PARAMETER; + } + } + + return status; +} + +NTSTATUS +DiskIoctlGetLengthInfo( + IN OUT PDEVICE_OBJECT DeviceObject, + IN OUT PIRP Irp + ) + +/*++ + +Routine Description: + + This routine services IOCTL_DISK_GET_LENGTH_INFO. It returns + the disk geometry to the caller. + + This function must be called at IRQL < DISPATCH_LEVEL. + +Arguments: + + DeviceObject - Supplies the device object associated with this request. + + Irp - The IRP to be processed + +Return Value: + + NTSTATUS code + +--*/ + +{ + NTSTATUS status; + PIO_STACK_LOCATION irpStack; + PGET_LENGTH_INFORMATION lengthInfo; + PFUNCTIONAL_DEVICE_EXTENSION p0Extension; + PCOMMON_DEVICE_EXTENSION commonExtension; + PDISK_DATA partitionZeroData; + NTSTATUS oldReadyStatus; + + // + // This function must be called at less than dispatch level. + // Fail if IRQL >= DISPATCH_LEVEL. + // + PAGED_CODE(); + CHECK_IRQL(); + + // + // Initialization + // + + commonExtension = DeviceObject->DeviceExtension; + irpStack = IoGetCurrentIrpStackLocation(Irp); + p0Extension = commonExtension->PartitionZeroExtension; + partitionZeroData = ((PDISK_DATA) p0Extension->CommonExtension.DriverData); + + // + // Check that the buffer is large enough. + // + + if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(GET_LENGTH_INFORMATION)) { + return STATUS_BUFFER_TOO_SMALL; + } + + // + // Update the geometry in case it has changed + // + + status = DiskReadDriveCapacity(p0Extension->DeviceObject); + + // + // Note whether the drive is ready. If the status has changed then + // notify pnp. + // + + oldReadyStatus = InterlockedExchange(&(partitionZeroData->ReadyStatus), status); + + if(partitionZeroData->ReadyStatus != oldReadyStatus) { + IoInvalidateDeviceRelations(p0Extension->LowerPdo, BusRelations); + } + + if(!NT_SUCCESS(status)) { + return status; + } + lengthInfo = (PGET_LENGTH_INFORMATION) Irp->AssociatedIrp.SystemBuffer; + + lengthInfo->Length = commonExtension->PartitionLength; + + status = STATUS_SUCCESS; + Irp->IoStatus.Information = sizeof(GET_LENGTH_INFORMATION); + + return status; +} + +NTSTATUS +DiskIoctlGetDriveGeometry( + IN PDEVICE_OBJECT DeviceObject, + IN OUT PIRP Irp + ) + +/*++ + +Routine Description: + + This routine services IOCTL_DISK_GET_DRIVE_GEOMETRY. It returns + the disk geometry to the caller. + + This function must be called at IRQL < DISPATCH_LEVEL. + +Arguments: + + DeviceObject - Supplies the device object associated with this request. + + Irp - IRP with a return buffer large enough to receive the + extended geometry information. + +Return Value: + + NTSTATUS code + +--*/ + +{ + PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; + PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension; + PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData); + PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation (Irp); + NTSTATUS status; + + // + // This function must be called at less than dispatch level. + // Fail if IRQL >= DISPATCH_LEVEL. + // + PAGED_CODE(); + CHECK_IRQL(); + + if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(DISK_GEOMETRY)) { + + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlGetDriveGeometry: Output buffer too small.\n")); + return STATUS_BUFFER_TOO_SMALL; + } + + if (TEST_FLAG(DeviceObject->Characteristics, FILE_REMOVABLE_MEDIA)) { + + // + // Issue ReadCapacity to update device extension + // with information for current media. + // + + status = DiskReadDriveCapacity(commonExtension->PartitionZeroExtension->DeviceObject); + + // + // Note whether the drive is ready. + // + + diskData->ReadyStatus = status; + + if (!NT_SUCCESS(status)) { + return status; + } + } + + // + // Copy drive geometry information from device extension. + // + + RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer, + &(fdoExtension->DiskGeometry), + sizeof(DISK_GEOMETRY)); + + if (((PDISK_GEOMETRY)Irp->AssociatedIrp.SystemBuffer)->BytesPerSector == 0) { + ((PDISK_GEOMETRY)Irp->AssociatedIrp.SystemBuffer)->BytesPerSector = 512; + } + Irp->IoStatus.Information = sizeof(DISK_GEOMETRY); + return STATUS_SUCCESS; +} + +typedef struct _DISK_GEOMETRY_EX_INTERNAL { + DISK_GEOMETRY Geometry; + LARGE_INTEGER DiskSize; + DISK_PARTITION_INFO Partition; + DISK_DETECTION_INFO Detection; +} DISK_GEOMETRY_EX_INTERNAL, *PDISK_GEOMETRY_EX_INTERNAL; + +NTSTATUS +DiskIoctlGetDriveGeometryEx( + IN PDEVICE_OBJECT DeviceObject, + IN OUT PIRP Irp + ) + +/*++ + +Routine Description: + + This routine services IOCTL_DISK_GET_DRIVE_GEOMETRY_EX. It returns + the extended disk geometry to the caller. + + This function must be called at IRQL < DISPATCH_LEVEL. + +Arguments: + + DeviceObject - The device object to obtain the geometry for. + + Irp - IRP with a return buffer large enough to receive the + extended geometry information. + +Return Value: + + NTSTATUS code + +--*/ + +{ + NTSTATUS status; + PIO_STACK_LOCATION irpStack; + PCOMMON_DEVICE_EXTENSION commonExtension; + PFUNCTIONAL_DEVICE_EXTENSION fdoExtension; + PDISK_DATA diskData; + PDISK_GEOMETRY_EX_INTERNAL geometryEx; + ULONG OutputBufferLength; + + // + // This function must be called at less than dispatch level. + // Fail if IRQL >= DISPATCH_LEVEL. + // + PAGED_CODE(); + CHECK_IRQL(); + + // + // Setup parameters + // + + commonExtension = DeviceObject->DeviceExtension; + fdoExtension = DeviceObject->DeviceExtension; + diskData = (PDISK_DATA)(commonExtension->DriverData); + irpStack = IoGetCurrentIrpStackLocation ( Irp ); + geometryEx = NULL; + OutputBufferLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength; + + // + // Check that the buffer is large enough. It must be large enough + // to hold at lest the Geometry and DiskSize fields of of the + // DISK_GEOMETRY_EX structure. + // + + if ( (LONG)OutputBufferLength < FIELD_OFFSET (DISK_GEOMETRY_EX, Data) ) { + + // + // Buffer too small. Bail out, telling the caller the required + // size. + // + + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlGetDriveGeometryEx: Output buffer too small.\n")); + status = STATUS_BUFFER_TOO_SMALL; + return status; + } + + if (TEST_FLAG (DeviceObject->Characteristics, FILE_REMOVABLE_MEDIA)) { + + // + // Issue a ReadCapacity to update device extension + // with information for the current media. + // + + status = DiskReadDriveCapacity(commonExtension->PartitionZeroExtension->DeviceObject); + + diskData->ReadyStatus = status; + + if (!NT_SUCCESS (status)) { + return status; + } + } + + // + // Copy drive geometry. + // + + geometryEx = (PDISK_GEOMETRY_EX_INTERNAL)Irp->AssociatedIrp.SystemBuffer; + geometryEx->Geometry = fdoExtension->DiskGeometry; + if (geometryEx->Geometry.BytesPerSector == 0) { + geometryEx->Geometry.BytesPerSector = 512; + } + geometryEx->DiskSize = commonExtension->PartitionZeroExtension->CommonExtension.PartitionLength; + + // + // If the user buffer is large enough to hold the partition information + // then add that as well. + // + + if ((LONG)OutputBufferLength >= FIELD_OFFSET (DISK_GEOMETRY_EX_INTERNAL, Detection)) { + + geometryEx->Partition.SizeOfPartitionInfo = sizeof (geometryEx->Partition); + geometryEx->Partition.PartitionStyle = diskData->PartitionStyle; + + switch ( diskData->PartitionStyle ) { + + case PARTITION_STYLE_GPT: + + // + // Copy GPT signature. + // + + geometryEx->Partition.Gpt.DiskId = diskData->Efi.DiskId; + break; + + case PARTITION_STYLE_MBR: + + // + // Copy MBR signature and checksum. + // + + geometryEx->Partition.Mbr.Signature = diskData->Mbr.Signature; + geometryEx->Partition.Mbr.CheckSum = diskData->Mbr.MbrCheckSum; + break; + + default: + + // + // This is a raw disk. Zero out the signature area so + // nobody gets confused. + // + + RtlZeroMemory(&geometryEx->Partition, sizeof (geometryEx->Partition)); + } + } + + // + // If the buffer is large enough to hold the detection information, + // then also add that. + // + + if (OutputBufferLength >= sizeof (DISK_GEOMETRY_EX_INTERNAL)) { + + geometryEx->Detection.SizeOfDetectInfo = sizeof (geometryEx->Detection); + + status = DiskGetDetectInfo(fdoExtension, &geometryEx->Detection); + + // + // Failed to obtain detection information, set to none. + // + + if (!NT_SUCCESS (status)) { + geometryEx->Detection.DetectionType = DetectNone; + } + } + + status = STATUS_SUCCESS; + Irp->IoStatus.Information = min (OutputBufferLength, sizeof (DISK_GEOMETRY_EX_INTERNAL)); + + return status; +} + +NTSTATUS +DiskIoctlGetCacheInformation( + IN PDEVICE_OBJECT DeviceObject, + IN OUT PIRP Irp + ) + +/*++ + +Routine Description: + + This routine services IOCTL_DISK_GET_CACHE_INFORMATION. It reads + the caching mode page from the device and returns information to + the caller. After validating the user parameter it calls the + DiskGetCacheInformation() function to get the mode page. + + This function must be called at IRQL < DISPATCH_LEVEL. + +Arguments: + + DeviceObject - Supplies the device object associated with this request. + + Irp - The IRP to be processed + +Return Value: + + NTSTATUS code + +--*/ + +{ + PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension; + PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation (Irp); + PDISK_CACHE_INFORMATION cacheInfo = Irp->AssociatedIrp.SystemBuffer; + NTSTATUS status; + + // + // This function must be called at less than dispatch level. + // Fail if IRQL >= DISPATCH_LEVEL. + // + PAGED_CODE(); + CHECK_IRQL(); + + // + // Validate the request. + // + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlGetCacheInformation: DeviceObject %p Irp %p\n", DeviceObject, Irp)); + + if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(DISK_CACHE_INFORMATION)) { + + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlGetCacheInformation: Output buffer too small.\n")); + return STATUS_BUFFER_TOO_SMALL; + } + + status = DiskGetCacheInformation(fdoExtension, cacheInfo); + + if (NT_SUCCESS(status)) { + Irp->IoStatus.Information = sizeof(DISK_CACHE_INFORMATION); + + // + // Make sure write cache setting is reflected in device extension + // + if (cacheInfo->WriteCacheEnabled) + { + SET_FLAG(fdoExtension->DeviceFlags, DEV_WRITE_CACHE); + } + else + { + CLEAR_FLAG(fdoExtension->DeviceFlags, DEV_WRITE_CACHE); + } + ADJUST_FUA_FLAG(fdoExtension); + + } + return status; +} + + +NTSTATUS +DiskIoctlSetCacheInformation( + IN PDEVICE_OBJECT DeviceObject, + IN OUT PIRP Irp + ) + +/*++ + +Routine Description: + + This routine services IOCTL_DISK_SET_CACHE_INFORMATION. It allows + the caller to set the caching mode page on the device. This function + validates the user parameter and calls the DiskSetCacheInformation() + function to set the mode page. It also stores the cache value in the + device extension and registry. + + This function must be called at IRQL < DISPATCH_LEVEL. + +Arguments: + + DeviceObject - Supplies the device object associated with this request. + + Irp - The IRP to be processed + +Return Value: + + NTSTATUS code + +--*/ + +{ + PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; + PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension; + PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData); + PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation (Irp); + PDISK_CACHE_INFORMATION cacheInfo = Irp->AssociatedIrp.SystemBuffer; + NTSTATUS status; + + // + // This function must be called at less than dispatch level. + // Fail if IRQL is equal or above DISPATCH_LEVEL. + // + + PAGED_CODE(); + CHECK_IRQL(); + + // + // Validate the request. + // + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlSetCacheInformation: DeviceObject %p Irp %p\n", DeviceObject, Irp)); + + if (irpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(DISK_CACHE_INFORMATION)) { + + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlSetCacheInformation: Input buffer length mismatch.\n")); + return STATUS_INFO_LENGTH_MISMATCH; + } + + status = DiskSetCacheInformation(fdoExtension, cacheInfo); + + // + // Save away the user-defined override in our extension and the registry + // + if (cacheInfo->WriteCacheEnabled) { + diskData->WriteCacheOverride = DiskWriteCacheEnable; + } else { + diskData->WriteCacheOverride = DiskWriteCacheDisable; + } + + ClassSetDeviceParameter(fdoExtension, DiskDeviceParameterSubkey, + DiskDeviceUserWriteCacheSetting, diskData->WriteCacheOverride); + + DiskLogCacheInformation(fdoExtension, cacheInfo, status); + + return status; +} + +NTSTATUS +DiskIoctlGetMediaTypesEx( + IN PDEVICE_OBJECT DeviceObject, + IN OUT PIRP Irp + ) + +/*++ + +Routine Description: + + This routine services IOCTL_STORAGE_GET_MEDIA_TYPES_EX. It returns + the media type information to the caller. After validating the user + parameter it calls DiskDetermineMediaTypes() to get the media type. + + This function must be called at IRQL < DISPATCH_LEVEL. + +Arguments: + + DeviceObject - Supplies the device object associated with this request. + + Irp - The IRP to be processed + +Return Value: + + NTSTATUS code + +--*/ + +{ + PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension; + PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation (Irp); + NTSTATUS status; + + PMODE_PARAMETER_HEADER modeData; + PMODE_PARAMETER_BLOCK blockDescriptor; + PSCSI_REQUEST_BLOCK srb; + PCDB cdb; + ULONG modeLength; + ULONG retries = 4; + UCHAR densityCode = 0; + BOOLEAN writable = TRUE; + BOOLEAN mediaPresent = FALSE; + ULONG srbSize; + PSTORAGE_REQUEST_BLOCK srbEx = NULL; + PSTOR_ADDR_BTL8 storAddrBtl8 = NULL; + PSRBEX_DATA_SCSI_CDB16 srbExDataCdb16 = NULL; + + // + // This function must be called at less than dispatch level. + // Fail if IRQL >= DISPATCH_LEVEL. + // + PAGED_CODE(); + CHECK_IRQL(); + + // + // Validate the request. + // + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlGetMediaTypesEx: DeviceObject %p Irp %p\n", DeviceObject, Irp)); + + if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(GET_MEDIA_TYPES)) { + + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlGetMediaTypesEx: Output buffer too small.\n")); + return STATUS_BUFFER_TOO_SMALL; + } + + if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { + srbSize = CLASS_SRBEX_SCSI_CDB16_BUFFER_SIZE; + } else { + srbSize = SCSI_REQUEST_BLOCK_SIZE; + } + + srb = ExAllocatePoolWithTag(NonPagedPoolNx, + srbSize, + DISK_TAG_SRB); + + if (srb == NULL) { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlGetMediaTypesEx: Unable to allocate memory.\n")); + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlZeroMemory(srb, srbSize); + + // + // Send a TUR to determine if media is present. + // + + if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { + srbEx = (PSTORAGE_REQUEST_BLOCK)srb; + + // + // Set up STORAGE_REQUEST_BLOCK fields + // + + srbEx->Length = FIELD_OFFSET(STORAGE_REQUEST_BLOCK, Signature); + srbEx->Function = SRB_FUNCTION_STORAGE_REQUEST_BLOCK; + srbEx->Signature = SRB_SIGNATURE; + srbEx->Version = STORAGE_REQUEST_BLOCK_VERSION_1; + srbEx->SrbLength = srbSize; + srbEx->SrbFunction = SRB_FUNCTION_EXECUTE_SCSI; + srbEx->RequestPriority = IoGetIoPriorityHint(Irp); + srbEx->AddressOffset = sizeof(STORAGE_REQUEST_BLOCK); + srbEx->NumSrbExData = 1; + + // Set timeout value. + srbEx->TimeOutValue = fdoExtension->TimeOutValue; + + // + // Set up address fields + // + + storAddrBtl8 = (PSTOR_ADDR_BTL8) ((PUCHAR)srbEx + srbEx->AddressOffset); + storAddrBtl8->Type = STOR_ADDRESS_TYPE_BTL8; + storAddrBtl8->AddressLength = STOR_ADDR_BTL8_ADDRESS_LENGTH; + + // + // Set up SCSI SRB extended data fields + // + + srbEx->SrbExDataOffset[0] = sizeof(STORAGE_REQUEST_BLOCK) + + sizeof(STOR_ADDR_BTL8); + if ((srbEx->SrbExDataOffset[0] + sizeof(SRBEX_DATA_SCSI_CDB16)) <= srbEx->SrbLength) { + srbExDataCdb16 = (PSRBEX_DATA_SCSI_CDB16)((PUCHAR)srbEx + srbEx->SrbExDataOffset[0]); + srbExDataCdb16->Type = SrbExDataTypeScsiCdb16; + srbExDataCdb16->Length = SRBEX_DATA_SCSI_CDB16_LENGTH; + srbExDataCdb16->CdbLength = 6; + + cdb = (PCDB)srbExDataCdb16->Cdb; + } else { + // Should not happen + NT_ASSERT(FALSE); + + FREE_POOL(srb); + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlGetMediaTypesEx: Insufficient extended SRB size.\n")); + return STATUS_INTERNAL_ERROR; + } + + } else { + + srb->Length = SCSI_REQUEST_BLOCK_SIZE; + srb->Function = SRB_FUNCTION_EXECUTE_SCSI; + srb->CdbLength = 6; + cdb = (PCDB)srb->Cdb; + + // + // Set timeout value. + // + + srb->TimeOutValue = fdoExtension->TimeOutValue; + + } + cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY; + + status = ClassSendSrbSynchronous(DeviceObject, + srb, + NULL, + 0, + FALSE); + + if (NT_SUCCESS(status)) { + mediaPresent = TRUE; + } + + modeLength = MODE_DATA_SIZE; + modeData = ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned, + modeLength, + DISK_TAG_MODE_DATA); + + if (modeData == NULL) { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlGetMediaTypesEx: Unable to allocate memory.\n")); + FREE_POOL(srb); + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlZeroMemory(modeData, modeLength); + + // + // Build the MODE SENSE CDB using previous SRB. + // + + if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { + srbEx->SrbStatus = 0; + srbExDataCdb16->ScsiStatus = 0; + srbExDataCdb16->CdbLength = 6; + + // + // Set timeout value from device extension. + // + + srbEx->TimeOutValue = fdoExtension->TimeOutValue; + } else { + srb->SrbStatus = 0; + srb->ScsiStatus = 0; + srb->CdbLength = 6; + + // + // Set timeout value from device extension. + // + + srb->TimeOutValue = fdoExtension->TimeOutValue; + } + + // + // Page code of 0x3F will return all pages. + // This command could fail if the data to be returned is + // more than 256 bytes. In which case, we should get only + // the caching page since we only need the block descriptor. + // DiskFdoProcessError will change the page code to + // MODE_PAGE_CACHING if there is an error. + // + + cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE; + cdb->MODE_SENSE.PageCode = MODE_SENSE_RETURN_ALL; + cdb->MODE_SENSE.AllocationLength = (UCHAR)modeLength; + +Retry: + status = ClassSendSrbSynchronous(DeviceObject, + srb, + modeData, + modeLength, + FALSE); + + if (status == STATUS_VERIFY_REQUIRED) { + + if (retries--) { + + // + // Retry request. + // + + goto Retry; + } + } else if (SRB_STATUS(srb->SrbStatus) == SRB_STATUS_DATA_OVERRUN) { + status = STATUS_SUCCESS; + } + + if (NT_SUCCESS(status) || (status == STATUS_NO_MEDIA_IN_DEVICE)) { + + // + // Get the block descriptor. + // + + if (modeData->BlockDescriptorLength != 0) { + + blockDescriptor = (PMODE_PARAMETER_BLOCK)((ULONG_PTR)modeData + sizeof(MODE_PARAMETER_HEADER)); + densityCode = blockDescriptor->DensityCode; + } + + if (TEST_FLAG(modeData->DeviceSpecificParameter, + MODE_DSP_WRITE_PROTECT)) { + + writable = FALSE; + } + + status = DiskDetermineMediaTypes(DeviceObject, + Irp, + modeData->MediumType, + densityCode, + mediaPresent, + writable); + // + // If the buffer was too small, DetermineMediaTypes updated the status and information and the request will fail. + // + + } else { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlGetMediaTypesEx: Mode sense for header/bd failed. %lx\n", status)); + } + + FREE_POOL(srb); + FREE_POOL(modeData); + + return status; +} + +NTSTATUS +DiskIoctlPredictFailure( + IN PDEVICE_OBJECT DeviceObject, + IN OUT PIRP Irp + ) + +/*++ + +Routine Description: + + This routine services IOCTL_STORAGE_PREDICT_FAILURE. If the device + supports SMART then it returns any available failure data. + + This function must be called at IRQL < DISPATCH_LEVEL. + +Arguments: + + DeviceObject - Supplies the device object associated with this request. + + Irp - The IRP to be processed + +Return Value: + + NTSTATUS code + +--*/ + +{ + PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; + PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension; + PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData); + PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation (Irp); + NTSTATUS status = STATUS_SUCCESS; + + PSTORAGE_PREDICT_FAILURE checkFailure; + STORAGE_FAILURE_PREDICT_STATUS diskSmartStatus; + IO_STATUS_BLOCK ioStatus = { 0 }; + KEVENT event; + + // + // This function must be called at less than dispatch level. + // Fail if IRQL >= DISPATCH_LEVEL. + // + PAGED_CODE(); + CHECK_IRQL(); + + // + // Validate the request. + // + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlPredictFailure: DeviceObject %p Irp %p\n", DeviceObject, Irp)); + + if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(STORAGE_PREDICT_FAILURE)) { + + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlPredictFailure: Output buffer too small.\n")); + return STATUS_BUFFER_TOO_SMALL; + } + + // + // See if the disk is predicting failure + // + + checkFailure = (PSTORAGE_PREDICT_FAILURE)Irp->AssociatedIrp.SystemBuffer; + + if (diskData->FailurePredictionCapability == FailurePredictionSense) { + ULONG readBufferSize; + PUCHAR readBuffer; + PIRP readIrp; + PDEVICE_OBJECT topOfStack; + + checkFailure->PredictFailure = 0; + + KeInitializeEvent(&event, SynchronizationEvent, FALSE); + + topOfStack = IoGetAttachedDeviceReference(DeviceObject); + + // + // SCSI disks need to have a read sent down to provoke any + // failures to be reported. + // + // Issue a normal read operation. The error-handling code in + // classpnp will take care of a failure prediction by logging the + // correct event. + // + + readBufferSize = fdoExtension->DiskGeometry.BytesPerSector; + readBuffer = ExAllocatePoolWithTag(NonPagedPoolNx, + readBufferSize, + DISK_TAG_SMART); + + if (readBuffer != NULL) { + LARGE_INTEGER offset; + + offset.QuadPart = 0; + readIrp = IoBuildSynchronousFsdRequest(IRP_MJ_READ, + topOfStack, + readBuffer, + readBufferSize, + &offset, + &event, + &ioStatus); + + if (readIrp != NULL) { + + status = IoCallDriver(topOfStack, readIrp); + if (status == STATUS_PENDING) { + KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL); + status = ioStatus.Status; + } + + + } else { + status = STATUS_INSUFFICIENT_RESOURCES; + } + + FREE_POOL(readBuffer); + } else { + status = STATUS_INSUFFICIENT_RESOURCES; + } + + ObDereferenceObject(topOfStack); + } + + if (status != STATUS_INSUFFICIENT_RESOURCES) + { + if ((diskData->FailurePredictionCapability == FailurePredictionSmart) || + (diskData->FailurePredictionCapability == FailurePredictionSense)) { + + status = DiskReadFailurePredictStatus(fdoExtension, &diskSmartStatus); + + if (NT_SUCCESS(status)) { + + status = DiskReadFailurePredictData(fdoExtension, + Irp->AssociatedIrp.SystemBuffer); + + if (diskSmartStatus.PredictFailure) { + checkFailure->PredictFailure = 1; + } else { + checkFailure->PredictFailure = 0; + } + + Irp->IoStatus.Information = sizeof(STORAGE_PREDICT_FAILURE); + } + } else { + status = STATUS_INVALID_DEVICE_REQUEST; + } + } + return status; +} + +#if (NTDDI_VERSION >= NTDDI_WINBLUE) +NTSTATUS +DiskIoctlEnableFailurePrediction( + IN PDEVICE_OBJECT DeviceObject, + IN OUT PIRP Irp + ) + +/*++ + +Routine Description: + + This routine services IOCTL_STORAGE_FAILURE_PREDICTION_CONFIG. If the device + supports SMART then it returns any available failure data. + + This function must be called at IRQL < DISPATCH_LEVEL. + +Arguments: + + DeviceObject - Supplies the device object associated with this request. + + Irp - The IRP to be processed + +Return Value: + + NTSTATUS code + +--*/ + +{ + PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; + PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension; + PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData); + PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation (Irp); + NTSTATUS status = STATUS_SUCCESS; + PSTORAGE_FAILURE_PREDICTION_CONFIG enablePrediction; + + // + // This function must be called at less than dispatch level. + // Fail if IRQL >= DISPATCH_LEVEL. + // + PAGED_CODE(); + CHECK_IRQL(); + + // + // Validate the request. + // + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlEnableFailurePrediction: DeviceObject %p Irp %p\n", DeviceObject, Irp)); + + if (irpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(STORAGE_FAILURE_PREDICTION_CONFIG) || + irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(STORAGE_FAILURE_PREDICTION_CONFIG)) { + + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlEnableFailurePrediction: Buffer too small.\n")); + return STATUS_BUFFER_TOO_SMALL; + } + + enablePrediction = (PSTORAGE_FAILURE_PREDICTION_CONFIG)Irp->AssociatedIrp.SystemBuffer; + + if (enablePrediction->Version != STORAGE_FAILURE_PREDICTION_CONFIG_V1 || + enablePrediction->Size < sizeof(STORAGE_FAILURE_PREDICTION_CONFIG)) { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlEnableFailurePrediction: Buffer version or size is incorrect.\n")); + status = STATUS_INVALID_PARAMETER; + } + + if (enablePrediction->Reserved != 0) { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlEnableFailurePrediction: Reserved bytes are not zero!\n")); + status = STATUS_INVALID_PARAMETER; + } + + // + // Default to success. This might get overwritten on failure below. + // + status = STATUS_SUCCESS; + + // + // If this is a "set" and the current state (enabled/disabled) is + // different from the sender's desired state, + // + if (enablePrediction->Set && enablePrediction->Enabled != diskData->FailurePredictionEnabled) { + if (diskData->FailurePredictionCapability == FailurePredictionSmart || + diskData->FailurePredictionCapability == FailurePredictionIoctl) { + // + // SMART or IOCTL based failure prediction is being used so call + // the generic function that is normally called in the WMI path. + // + status = DiskEnableDisableFailurePrediction(fdoExtension, enablePrediction->Enabled); + } else if (diskData->ScsiInfoExceptionsSupported) { + // + // If we know that the device supports the Informational Exceptions + // mode page, try to enable/disable failure prediction that way. + // + status = DiskEnableInfoExceptions(fdoExtension, enablePrediction->Enabled); + } + } + + // + // Return the current state regardless if this was a "set" or a "get". + // + enablePrediction->Enabled = diskData->FailurePredictionEnabled; + + if (NT_SUCCESS(status)) { + Irp->IoStatus.Information = sizeof(STORAGE_FAILURE_PREDICTION_CONFIG); + } + + return status; +} +#endif //(NTDDI_VERSION >= NTDDI_WINBLUE) + +NTSTATUS +DiskIoctlVerify( + IN PDEVICE_OBJECT DeviceObject, + IN OUT PIRP Irp + ) + +/*++ + +Routine Description: + + This routine services IOCTL_DISK_VERIFY. After verifying + user input, it starts the worker thread DiskIoctlVerifyThread() + to verify the device. + +Arguments: + + DeviceObject - Supplies the device object associated with this request. + + Irp - The IRP to be processed + +Return Value: + + NTSTATUS code + +--*/ + +{ + PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; + PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension; + PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation (Irp); + PVERIFY_INFORMATION verifyInfo = Irp->AssociatedIrp.SystemBuffer; + PDISK_VERIFY_WORKITEM_CONTEXT Context = NULL; + PSCSI_REQUEST_BLOCK srb; + LARGE_INTEGER byteOffset; + ULONG srbSize; + + // + // Validate the request. + // + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlVerify: DeviceObject %p Irp %p\n", DeviceObject, Irp)); + + if (irpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(VERIFY_INFORMATION)) { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlVerify: Input buffer length mismatch.\n")); + return STATUS_INFO_LENGTH_MISMATCH; + } + + if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { + srbSize = CLASS_SRBEX_SCSI_CDB16_BUFFER_SIZE; + } else { + srbSize = SCSI_REQUEST_BLOCK_SIZE; + } + srb = ExAllocatePoolWithTag(NonPagedPoolNx, + srbSize, + DISK_TAG_SRB); + + if (srb == NULL) { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlVerify: Unable to allocate memory.\n")); + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlZeroMemory(srb, srbSize); + + // + // Add disk offset to starting sector. + // + + byteOffset.QuadPart = commonExtension->StartingOffset.QuadPart + + verifyInfo->StartingOffset.QuadPart; + + // + // Perform a bounds check on the sector range + // + + if ((verifyInfo->StartingOffset.QuadPart > commonExtension->PartitionLength.QuadPart) || + (verifyInfo->StartingOffset.QuadPart < 0)) { + + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlVerify: Verify request to invalid sector.\n")); + FREE_POOL(srb) + return STATUS_NONEXISTENT_SECTOR; + } else { + + ULONGLONG bytesRemaining = commonExtension->PartitionLength.QuadPart - verifyInfo->StartingOffset.QuadPart; + + if ((ULONGLONG)verifyInfo->Length > bytesRemaining) { + + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlVerify: Verify request to invalid sector.\n")); + FREE_POOL(srb) + return STATUS_NONEXISTENT_SECTOR; + } + } + + Context = ExAllocatePoolWithTag(NonPagedPoolNx, + sizeof(DISK_VERIFY_WORKITEM_CONTEXT), + DISK_TAG_WI_CONTEXT); + if (Context) { + + Context->Irp = Irp; + Context->Srb = srb; + Context->WorkItem = IoAllocateWorkItem(DeviceObject); + + if (Context->WorkItem) { + + // + // Queue the work item and return. + // + + IoMarkIrpPending(Irp); + + IoQueueWorkItem(Context->WorkItem, + DiskIoctlVerifyThread, + DelayedWorkQueue, + Context); + + return STATUS_PENDING; + } + FREE_POOL(Context); + } + FREE_POOL(srb) + return STATUS_INSUFFICIENT_RESOURCES; +} + +NTSTATUS +DiskIoctlReassignBlocks( + IN PDEVICE_OBJECT DeviceObject, + IN OUT PIRP Irp + ) + +/*++ + +Routine Description: + + This routine services IOCTL_DISK_REASSIGN_BLOCKS. This IOCTL + allows the caller to remap the defective blocks to a new + location on the disk. + + This function must be called at IRQL < DISPATCH_LEVEL. + +Arguments: + + DeviceObject - Supplies the device object associated with this request. + + Irp - The IRP to be processed + +Return Value: + + NTSTATUS code + +--*/ + +{ + PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension; + PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation (Irp); + NTSTATUS status; + PREASSIGN_BLOCKS badBlocks = Irp->AssociatedIrp.SystemBuffer; + PSCSI_REQUEST_BLOCK srb; + PCDB cdb; + ULONG bufferSize; + ULONG blockNumber; + ULONG blockCount; + ULONG srbSize; + PSTORAGE_REQUEST_BLOCK srbEx; + PSTOR_ADDR_BTL8 storAddrBtl8; + PSRBEX_DATA_SCSI_CDB16 srbExDataCdb16; + + // + // This function must be called at less than dispatch level. + // Fail if IRQL >= DISPATCH_LEVEL. + // + PAGED_CODE(); + CHECK_IRQL(); + + // + // Validate the request. + // + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlReassignBlocks: DeviceObject %p Irp %p\n", DeviceObject, Irp)); + + if (irpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(REASSIGN_BLOCKS)) { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlReassignBlocks: Input buffer length mismatch.\n")); + return STATUS_INFO_LENGTH_MISMATCH; + } + + // + // Make sure we have some data in the input buffer. + // + + if (badBlocks->Count == 0) { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlReassignBlocks: Invalid block count\n")); + return STATUS_INVALID_PARAMETER; + } + + bufferSize = sizeof(REASSIGN_BLOCKS) + ((badBlocks->Count - 1) * sizeof(ULONG)); + + if (irpStack->Parameters.DeviceIoControl.InputBufferLength < bufferSize) { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlReassignBlocks: Input buffer length mismatch for bad blocks.\n")); + return STATUS_INFO_LENGTH_MISMATCH; + } + + if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { + srbSize = CLASS_SRBEX_SCSI_CDB16_BUFFER_SIZE; + } else { + srbSize = SCSI_REQUEST_BLOCK_SIZE; + } + srb = ExAllocatePoolWithTag(NonPagedPoolNx, + srbSize, + DISK_TAG_SRB); + + if (srb == NULL) { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlReassignBlocks: Unable to allocate memory.\n")); + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlZeroMemory(srb, srbSize); + + // + // Build the data buffer to be transferred in the input buffer. + // The format of the data to the device is: + // + // 2 bytes Reserved + // 2 bytes Length + // x * 4 btyes Block Address + // + // All values are big endian. + // + + badBlocks->Reserved = 0; + blockCount = badBlocks->Count; + + // + // Convert # of entries to # of bytes. + // + + blockCount *= 4; + badBlocks->Count = (USHORT) ((blockCount >> 8) & 0XFF); + badBlocks->Count |= (USHORT) ((blockCount << 8) & 0XFF00); + + // + // Convert back to number of entries. + // + + blockCount /= 4; + + for (; blockCount > 0; blockCount--) { + + blockNumber = badBlocks->BlockNumber[blockCount-1]; + REVERSE_BYTES((PFOUR_BYTE) &badBlocks->BlockNumber[blockCount-1], (PFOUR_BYTE) &blockNumber); + } + + // + // Build a SCSI SRB containing a SCSIOP_REASSIGN_BLOCKS cdb + // + + if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { + srbEx = (PSTORAGE_REQUEST_BLOCK)srb; + + // + // Set up STORAGE_REQUEST_BLOCK fields + // + + srbEx->Length = FIELD_OFFSET(STORAGE_REQUEST_BLOCK, Signature); + srbEx->Function = SRB_FUNCTION_STORAGE_REQUEST_BLOCK; + srbEx->Signature = SRB_SIGNATURE; + srbEx->Version = STORAGE_REQUEST_BLOCK_VERSION_1; + srbEx->SrbLength = srbSize; + srbEx->SrbFunction = SRB_FUNCTION_EXECUTE_SCSI; + srbEx->RequestPriority = IoGetIoPriorityHint(Irp); + srbEx->AddressOffset = sizeof(STORAGE_REQUEST_BLOCK); + srbEx->NumSrbExData = 1; + + // Set timeout value. + srbEx->TimeOutValue = fdoExtension->TimeOutValue; + + // + // Set up address fields + // + + storAddrBtl8 = (PSTOR_ADDR_BTL8) ((PUCHAR)srbEx + srbEx->AddressOffset); + storAddrBtl8->Type = STOR_ADDRESS_TYPE_BTL8; + storAddrBtl8->AddressLength = STOR_ADDR_BTL8_ADDRESS_LENGTH; + + // + // Set up SCSI SRB extended data fields + // + + srbEx->SrbExDataOffset[0] = sizeof(STORAGE_REQUEST_BLOCK) + + sizeof(STOR_ADDR_BTL8); + if ((srbEx->SrbExDataOffset[0] + sizeof(SRBEX_DATA_SCSI_CDB16)) <= srbEx->SrbLength) { + srbExDataCdb16 = (PSRBEX_DATA_SCSI_CDB16)((PUCHAR)srbEx + srbEx->SrbExDataOffset[0]); + srbExDataCdb16->Type = SrbExDataTypeScsiCdb16; + srbExDataCdb16->Length = SRBEX_DATA_SCSI_CDB16_LENGTH; + srbExDataCdb16->CdbLength = 6; + + cdb = (PCDB)srbExDataCdb16->Cdb; + } else { + // Should not happen + NT_ASSERT(FALSE); + + FREE_POOL(srb); + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlReassignBlocks: Insufficient extended SRB size.\n")); + return STATUS_INTERNAL_ERROR; + } + + } else { + srb->Length = SCSI_REQUEST_BLOCK_SIZE; + srb->Function = SRB_FUNCTION_EXECUTE_SCSI; + srb->CdbLength = 6; + + // + // Set timeout value. + // + + srb->TimeOutValue = fdoExtension->TimeOutValue; + + cdb = (PCDB)srb->Cdb; + } + + cdb->CDB6GENERIC.OperationCode = SCSIOP_REASSIGN_BLOCKS; + + status = ClassSendSrbSynchronous(DeviceObject, + srb, + badBlocks, + bufferSize, + TRUE); + + FREE_POOL(srb); + return status; +} + +NTSTATUS +DiskIoctlReassignBlocksEx( + IN PDEVICE_OBJECT DeviceObject, + IN OUT PIRP Irp + ) + +/*++ + +Routine Description: + + This routine services IOCTL_DISK_REASSIGN_BLOCKS_EX. This IOCTL + allows the caller to remap the defective blocks to a new + location on the disk. The input buffer contains 8-byte LBAs. + + This function must be called at IRQL < DISPATCH_LEVEL. + +Arguments: + + DeviceObject - Supplies the device object associated with this request. + + Irp - The IRP to be processed + +Return Value: + + NTSTATUS code + +--*/ + +{ + PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension; + PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation (Irp); + NTSTATUS status; + PREASSIGN_BLOCKS_EX badBlocks = Irp->AssociatedIrp.SystemBuffer; + PSCSI_REQUEST_BLOCK srb; + PCDB cdb; + LARGE_INTEGER blockNumber; + ULONG bufferSize; + ULONG blockCount; + ULONG srbSize; + PSTORAGE_REQUEST_BLOCK srbEx; + PSTOR_ADDR_BTL8 storAddrBtl8; + PSRBEX_DATA_SCSI_CDB16 srbExDataCdb16; + + // + // This function must be called at less than dispatch level. + // Fail if IRQL >= DISPATCH_LEVEL. + // + PAGED_CODE(); + CHECK_IRQL(); + + // + // Validate the request. + // + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlReassignBlocksEx: DeviceObject %p Irp %p\n", DeviceObject, Irp)); + + if (irpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(REASSIGN_BLOCKS_EX)) { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlReassignBlocksEx: Input buffer length mismatch.\n")); + return STATUS_INFO_LENGTH_MISMATCH; + } + + // + // Make sure we have some data in the input buffer. + // + + if (badBlocks->Count == 0) { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlReassignBlocksEx: Invalid block count\n")); + return STATUS_INVALID_PARAMETER; + } + + bufferSize = sizeof(REASSIGN_BLOCKS_EX) + ((badBlocks->Count - 1) * sizeof(LARGE_INTEGER)); + + if (irpStack->Parameters.DeviceIoControl.InputBufferLength < bufferSize) { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlReassignBlocksEx: Input buffer length mismatch for bad blocks.\n")); + return STATUS_INFO_LENGTH_MISMATCH; + } + + if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { + srbSize = CLASS_SRBEX_SCSI_CDB16_BUFFER_SIZE; + } else { + srbSize = SCSI_REQUEST_BLOCK_SIZE; + } + srb = ExAllocatePoolWithTag(NonPagedPoolNx, + srbSize, + DISK_TAG_SRB); + + if (srb == NULL) { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlReassignBlocks: Unable to allocate memory.\n")); + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlZeroMemory(srb, srbSize); + + // + // Build the data buffer to be transferred in the input buffer. + // The format of the data to the device is: + // + // 2 bytes Reserved + // 2 bytes Length + // x * 8 btyes Block Address + // + // All values are big endian. + // + + badBlocks->Reserved = 0; + blockCount = badBlocks->Count; + + // + // Convert # of entries to # of bytes. + // + + blockCount *= 8; + badBlocks->Count = (USHORT) ((blockCount >> 8) & 0XFF); + badBlocks->Count |= (USHORT) ((blockCount << 8) & 0XFF00); + + // + // Convert back to number of entries. + // + + blockCount /= 8; + + for (; blockCount > 0; blockCount--) { + + blockNumber = badBlocks->BlockNumber[blockCount-1]; + REVERSE_BYTES_QUAD(&badBlocks->BlockNumber[blockCount-1], &blockNumber); + } + + // + // Build a SCSI SRB containing a SCSIOP_REASSIGN_BLOCKS cdb + // + + if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { + srbEx = (PSTORAGE_REQUEST_BLOCK)srb; + + // + // Set up STORAGE_REQUEST_BLOCK fields + // + + srbEx->Length = FIELD_OFFSET(STORAGE_REQUEST_BLOCK, Signature); + srbEx->Function = SRB_FUNCTION_STORAGE_REQUEST_BLOCK; + srbEx->Signature = SRB_SIGNATURE; + srbEx->Version = STORAGE_REQUEST_BLOCK_VERSION_1; + srbEx->SrbLength = srbSize; + srbEx->SrbFunction = SRB_FUNCTION_EXECUTE_SCSI; + srbEx->RequestPriority = IoGetIoPriorityHint(Irp); + srbEx->AddressOffset = sizeof(STORAGE_REQUEST_BLOCK); + srbEx->NumSrbExData = 1; + + // Set timeout value. + srbEx->TimeOutValue = fdoExtension->TimeOutValue; + + // + // Set up address fields + // + + storAddrBtl8 = (PSTOR_ADDR_BTL8) ((PUCHAR)srbEx + srbEx->AddressOffset); + storAddrBtl8->Type = STOR_ADDRESS_TYPE_BTL8; + storAddrBtl8->AddressLength = STOR_ADDR_BTL8_ADDRESS_LENGTH; + + // + // Set up SCSI SRB extended data fields + // + + srbEx->SrbExDataOffset[0] = sizeof(STORAGE_REQUEST_BLOCK) + + sizeof(STOR_ADDR_BTL8); + if ((srbEx->SrbExDataOffset[0] + sizeof(SRBEX_DATA_SCSI_CDB16)) <= srbEx->SrbLength) { + srbExDataCdb16 = (PSRBEX_DATA_SCSI_CDB16)((PUCHAR)srbEx + srbEx->SrbExDataOffset[0]); + srbExDataCdb16->Type = SrbExDataTypeScsiCdb16; + srbExDataCdb16->Length = SRBEX_DATA_SCSI_CDB16_LENGTH; + srbExDataCdb16->CdbLength = 6; + + cdb = (PCDB)srbExDataCdb16->Cdb; + } else { + // Should not happen + NT_ASSERT(FALSE); + + FREE_POOL(srb); + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlReassignBlocks: Insufficient extended SRB size.\n")); + return STATUS_INTERNAL_ERROR; + } + + } else { + srb->Length = SCSI_REQUEST_BLOCK_SIZE; + srb->Function = SRB_FUNCTION_EXECUTE_SCSI; + srb->CdbLength = 6; + + // + // Set timeout value. + // + + srb->TimeOutValue = fdoExtension->TimeOutValue; + + cdb = (PCDB)srb->Cdb; + } + + cdb->CDB6GENERIC.OperationCode = SCSIOP_REASSIGN_BLOCKS; + cdb->CDB6GENERIC.CommandUniqueBits = 1; // LONGLBA + + status = ClassSendSrbSynchronous(DeviceObject, + srb, + badBlocks, + bufferSize, + TRUE); + + FREE_POOL(srb); + return status; +} + +NTSTATUS +DiskIoctlIsWritable( + IN PDEVICE_OBJECT DeviceObject, + IN OUT PIRP Irp + ) + +/*++ + +Routine Description: + + This routine services IOCTL_DISK_IS_WRITABLE. This function + returns whether the disk is writable. If the device is not + writable then STATUS_MEDIA_WRITE_PROTECTED will be returned. + + This function must be called at IRQL < DISPATCH_LEVEL. + +Arguments: + + DeviceObject - Supplies the device object associated with this request. + + Irp - The IRP to be processed + +Return Value: + + NTSTATUS code + +--*/ + +{ + PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension; + NTSTATUS status = STATUS_SUCCESS; + + PMODE_PARAMETER_HEADER modeData; + PSCSI_REQUEST_BLOCK srb; + PCDB cdb = NULL; + ULONG modeLength; + ULONG retries = 4; + ULONG srbSize; + PSTORAGE_REQUEST_BLOCK srbEx; + PSTOR_ADDR_BTL8 storAddrBtl8; + PSRBEX_DATA_SCSI_CDB16 srbExDataCdb16; + + // + // This function must be called at less than dispatch level. + // Fail if IRQL >= DISPATCH_LEVEL. + // + PAGED_CODE(); + CHECK_IRQL(); + + // + // Validate the request. + // + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlIsWritable: DeviceObject %p Irp %p\n", DeviceObject, Irp)); + + if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { + srbSize = CLASS_SRBEX_SCSI_CDB16_BUFFER_SIZE; + } else { + srbSize = SCSI_REQUEST_BLOCK_SIZE; + } + srb = ExAllocatePoolWithTag(NonPagedPoolNx, + srbSize, + DISK_TAG_SRB); + + if (srb == NULL) { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlIsWritable: Unable to allocate memory.\n")); + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlZeroMemory(srb, srbSize); + + // + // Allocate memory for a mode header and then some + // for port drivers that need to convert to MODE10 + // or always return the MODE_PARAMETER_BLOCK (even + // when memory was not allocated for this purpose) + // + + modeLength = MODE_DATA_SIZE; + modeData = ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned, + modeLength, + DISK_TAG_MODE_DATA); + + if (modeData == NULL) { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlIsWritable: Unable to allocate memory.\n")); + FREE_POOL(srb); + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlZeroMemory(modeData, modeLength); + + // + // Build the MODE SENSE CDB + // + + if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { + srbEx = (PSTORAGE_REQUEST_BLOCK)srb; + + // + // Set up STORAGE_REQUEST_BLOCK fields + // + + srbEx->Length = FIELD_OFFSET(STORAGE_REQUEST_BLOCK, Signature); + srbEx->Function = SRB_FUNCTION_STORAGE_REQUEST_BLOCK; + srbEx->Signature = SRB_SIGNATURE; + srbEx->Version = STORAGE_REQUEST_BLOCK_VERSION_1; + srbEx->SrbLength = srbSize; + srbEx->SrbFunction = SRB_FUNCTION_EXECUTE_SCSI; + srbEx->RequestPriority = IoGetIoPriorityHint(Irp); + srbEx->AddressOffset = sizeof(STORAGE_REQUEST_BLOCK); + srbEx->NumSrbExData = 1; + + // Set timeout value. + srbEx->TimeOutValue = fdoExtension->TimeOutValue; + + // + // Set up address fields + // + + storAddrBtl8 = (PSTOR_ADDR_BTL8) ((PUCHAR)srbEx + srbEx->AddressOffset); + storAddrBtl8->Type = STOR_ADDRESS_TYPE_BTL8; + storAddrBtl8->AddressLength = STOR_ADDR_BTL8_ADDRESS_LENGTH; + + // + // Set up SCSI SRB extended data fields + // + + srbEx->SrbExDataOffset[0] = sizeof(STORAGE_REQUEST_BLOCK) + + sizeof(STOR_ADDR_BTL8); + if ((srbEx->SrbExDataOffset[0] + sizeof(SRBEX_DATA_SCSI_CDB16)) <= srbEx->SrbLength) { + srbExDataCdb16 = (PSRBEX_DATA_SCSI_CDB16)((PUCHAR)srbEx + srbEx->SrbExDataOffset[0]); + srbExDataCdb16->Type = SrbExDataTypeScsiCdb16; + srbExDataCdb16->Length = SRBEX_DATA_SCSI_CDB16_LENGTH; + srbExDataCdb16->CdbLength = 6; + + cdb = (PCDB)srbExDataCdb16->Cdb; + } else { + // Should not happen + NT_ASSERT(FALSE); + + FREE_POOL(srb); + FREE_POOL(modeData); + return STATUS_INTERNAL_ERROR; + } + + } else { + srb->Length = SCSI_REQUEST_BLOCK_SIZE; + srb->Function = SRB_FUNCTION_EXECUTE_SCSI; + srb->CdbLength = 6; + + // + // Set timeout value. + // + + srb->TimeOutValue = fdoExtension->TimeOutValue; + + cdb = (PCDB)srb->Cdb; + } + + // + // Page code of 0x3F will return all pages. + // This command could fail if the data to be returned is + // more than 256 bytes. In which case, we should get only + // the caching page since we only need the block descriptor. + // DiskFdoProcessError will change the page code to + // MODE_PAGE_CACHING if there is an error. + // + + cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE; + cdb->MODE_SENSE.PageCode = MODE_SENSE_RETURN_ALL; + cdb->MODE_SENSE.AllocationLength = (UCHAR)modeLength; + + while (retries != 0) { + + status = ClassSendSrbSynchronous(DeviceObject, + srb, + modeData, + modeLength, + FALSE); + + if (status != STATUS_VERIFY_REQUIRED) { + if (SRB_STATUS(srb->SrbStatus) == SRB_STATUS_DATA_OVERRUN) { + status = STATUS_SUCCESS; + } + break; + } + retries--; + } + + if (NT_SUCCESS(status)) { + + if (TEST_FLAG(modeData->DeviceSpecificParameter, MODE_DSP_WRITE_PROTECT)) { + status = STATUS_MEDIA_WRITE_PROTECTED; + } + } + + FREE_POOL(srb); + FREE_POOL(modeData); + return status; +} + +NTSTATUS +DiskIoctlSetVerify( + IN PDEVICE_OBJECT DeviceObject, + IN OUT PIRP Irp + ) + +/*++ + +Routine Description: + + This routine services IOCTL_DISK_INTERNAL_SET_VERIFY. + This is an internal function used to set the DO_VERIFY_VOLUME + device object flag. Only a kernel mode component can send this + IOCTL. + +Arguments: + + DeviceObject - Supplies the device object associated with this request. + + Irp - The IRP to be processed + +Return Value: + + NTSTATUS code + +--*/ + +{ + NTSTATUS status = STATUS_NOT_SUPPORTED; + + // + // Validate the request. + // + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlSetVerify: DeviceObject %p Irp %p\n", DeviceObject, Irp)); + + // + // If the caller is kernel mode, set the verify bit. + // + + if (Irp->RequestorMode == KernelMode) { + + SET_FLAG(DeviceObject->Flags, DO_VERIFY_VOLUME); + status = STATUS_SUCCESS; + + } + return status; +} + +NTSTATUS +DiskIoctlClearVerify( + IN PDEVICE_OBJECT DeviceObject, + IN OUT PIRP Irp + ) + +/*++ + +Routine Description: + + This routine services IOCTL_DISK_INTERNAL_CLEAR_VERIFY. + This is an internal function used to clear the DO_VERIFY_VOLUME + device object flag. Only a kernel mode component can send this + IOCTL. + +Arguments: + + DeviceObject - Supplies the device object associated with this request. + + Irp - The IRP to be processed + +Return Value: + + NTSTATUS code + +--*/ + +{ + NTSTATUS status = STATUS_NOT_SUPPORTED; + + // + // Validate the request. + // + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlClearVerify: DeviceObject %p Irp %p\n", DeviceObject, Irp)); + + // + // If the caller is kernel mode, set the verify bit. + // + + if (Irp->RequestorMode == KernelMode) { + + CLEAR_FLAG(DeviceObject->Flags, DO_VERIFY_VOLUME); + status = STATUS_SUCCESS; + + } + return status; +} + +NTSTATUS +DiskIoctlUpdateDriveSize( + IN PDEVICE_OBJECT DeviceObject, + IN OUT PIRP Irp + ) + +/*++ + +Routine Description: + + This routine services IOCTL_DISK_UPDATE_DRIVE_SIZE. + This function is used to inform the disk driver to update + the device geometry information cached in the device extension + This is normally initiated from the drivers layers above disk + driver. + + This function must be called at IRQL < DISPATCH_LEVEL. + +Arguments: + + DeviceObject - Supplies the device object associated with this request. + + Irp - The IRP to be processed + +Return Value: + + NTSTATUS code + +--*/ + +{ + PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; + PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension; + PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData); + PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation (Irp); + TARGET_DEVICE_CUSTOM_NOTIFICATION Notification = {0}; + NTSTATUS status; + + // + // This function must be called at less than dispatch level. + // Fail if IRQL >= DISPATCH_LEVEL. + // + PAGED_CODE(); + CHECK_IRQL(); + + // + // Validate the request. + // + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlUpdateDriveSize: DeviceObject %p Irp %p\n", DeviceObject, Irp)); + + if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(DISK_GEOMETRY)) { + + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlUpdateDriveSize: Output buffer too small.\n")); + return STATUS_BUFFER_TOO_SMALL; + } + + status = DiskReadDriveCapacity(DeviceObject); + + // + // Note whether the drive is ready. + // + + diskData->ReadyStatus = status; + + if (NT_SUCCESS(status)) { + + // + // Copy drive geometry information from the device extension. + // + + RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer, + &(fdoExtension->DiskGeometry), + sizeof(DISK_GEOMETRY)); + + if (((PDISK_GEOMETRY)Irp->AssociatedIrp.SystemBuffer)->BytesPerSector == 0) { + ((PDISK_GEOMETRY)Irp->AssociatedIrp.SystemBuffer)->BytesPerSector = 512; + } + Irp->IoStatus.Information = sizeof(DISK_GEOMETRY); + status = STATUS_SUCCESS; + + // + // Notify everyone that the disk layout may have changed + // + + Notification.Event = GUID_IO_DISK_LAYOUT_CHANGE; + Notification.Version = 1; + Notification.Size = (USHORT)FIELD_OFFSET(TARGET_DEVICE_CUSTOM_NOTIFICATION, CustomDataBuffer); + Notification.FileObject = NULL; + Notification.NameBufferOffset = -1; + + IoReportTargetDeviceChangeAsynchronous(fdoExtension->LowerPdo, + &Notification, + NULL, + NULL); + } + return status; +} + +NTSTATUS +DiskIoctlGetVolumeDiskExtents( + IN PDEVICE_OBJECT DeviceObject, + IN OUT PIRP Irp + ) + +/*++ + +Routine Description: + + This routine services IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS + and IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS_ADMIN. This function + returns the physical location of a volume. + + This function must be called at IRQL < DISPATCH_LEVEL. + +Arguments: + + DeviceObject - Supplies the device object associated with this request. + + Irp - The IRP to be processed + +Return Value: + + NTSTATUS code + +--*/ + +{ + PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; + PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData); + PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation (Irp); + NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST; + + // + // This function must be called at less than dispatch level. + // Fail if IRQL >= DISPATCH_LEVEL. + // + PAGED_CODE(); + CHECK_IRQL(); + + // + // Validate the request. + // + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlGetVolumeDiskExtents: DeviceObject %p Irp %p\n", DeviceObject, Irp)); + + + if (TEST_FLAG(DeviceObject->Characteristics, FILE_REMOVABLE_MEDIA)) { + + if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(VOLUME_DISK_EXTENTS)) { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlGetVolumeDiskExtents: Output buffer too small.\n")); + return STATUS_BUFFER_TOO_SMALL; + } + + status = DiskReadDriveCapacity(commonExtension->PartitionZeroExtension->DeviceObject); + + // + // Note whether the drive is ready. + // + + diskData->ReadyStatus = status; + + if (NT_SUCCESS(status)) { + + PVOLUME_DISK_EXTENTS pVolExt = (PVOLUME_DISK_EXTENTS)Irp->AssociatedIrp.SystemBuffer; + + pVolExt->NumberOfDiskExtents = 1; + pVolExt->Extents[0].DiskNumber = commonExtension->PartitionZeroExtension->DeviceNumber; + pVolExt->Extents[0].StartingOffset = commonExtension->StartingOffset; + pVolExt->Extents[0].ExtentLength = commonExtension->PartitionLength; + + Irp->IoStatus.Information = sizeof(VOLUME_DISK_EXTENTS); + } + } + + return status; +} + +NTSTATUS +DiskIoctlSmartGetVersion( + IN PDEVICE_OBJECT DeviceObject, + IN OUT PIRP Irp + ) + +/*++ + +Routine Description: + + This routine services SMART_GET_VERSION. It returns the + SMART version information. + + This function must be called at IRQL < DISPATCH_LEVEL. + +Arguments: + + DeviceObject - Supplies the device object associated with this request. + + Irp - The IRP to be processed + +Return Value: + + NTSTATUS code + +--*/ + +{ + PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; + PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension; + PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData); + PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation (Irp); + NTSTATUS status; + + PGETVERSIONINPARAMS versionParams; + PSRB_IO_CONTROL srbControl; + IO_STATUS_BLOCK ioStatus = { 0 }; + PUCHAR buffer; + + // + // This function must be called at less than dispatch level. + // Fail if IRQL >= DISPATCH_LEVEL. + // + PAGED_CODE(); + CHECK_IRQL(); + + // + // Validate the request. + // + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlSmartGetVersion: DeviceObject %p Irp %p\n", DeviceObject, Irp)); + + + if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(GETVERSIONINPARAMS)) { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlSmartGetVersion: Output buffer too small.\n")); + return STATUS_BUFFER_TOO_SMALL; + } + + srbControl = ExAllocatePoolWithTag(NonPagedPoolNx, + sizeof(SRB_IO_CONTROL) + + sizeof(GETVERSIONINPARAMS), + DISK_TAG_SMART); + + if (srbControl == NULL) { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlSmartGetVersion: Unable to allocate memory.\n")); + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlZeroMemory(srbControl, sizeof(SRB_IO_CONTROL) + sizeof(GETVERSIONINPARAMS)); + + // + // fill in srbControl fields + // + + srbControl->HeaderLength = sizeof(SRB_IO_CONTROL); + RtlMoveMemory (srbControl->Signature, "SCSIDISK", 8); + srbControl->Timeout = fdoExtension->TimeOutValue; + srbControl->Length = sizeof(GETVERSIONINPARAMS); + srbControl->ControlCode = IOCTL_SCSI_MINIPORT_SMART_VERSION; + + // + // Point to the 'buffer' portion of the SRB_CONTROL + // + + buffer = (PUCHAR)srbControl + srbControl->HeaderLength; + + // + // Ensure correct target is set in the cmd parameters. + // + + versionParams = (PGETVERSIONINPARAMS)buffer; + versionParams->bIDEDeviceMap = diskData->ScsiAddress.TargetId; + + ClassSendDeviceIoControlSynchronous( + IOCTL_SCSI_MINIPORT, + commonExtension->LowerDeviceObject, + srbControl, + sizeof(SRB_IO_CONTROL) + sizeof(GETVERSIONINPARAMS), + sizeof(SRB_IO_CONTROL) + sizeof(GETVERSIONINPARAMS), + FALSE, + &ioStatus); + + status = ioStatus.Status; + + // + // If successful, copy the data received into the output buffer. + // This should only fail in the event that the IDE driver is older + // than this driver. + // + + if (NT_SUCCESS(status)) { + + buffer = (PUCHAR)srbControl + srbControl->HeaderLength; + + RtlMoveMemory (Irp->AssociatedIrp.SystemBuffer, buffer, sizeof(GETVERSIONINPARAMS)); + Irp->IoStatus.Information = sizeof(GETVERSIONINPARAMS); + } + + FREE_POOL(srbControl); + + return status; +} + +NTSTATUS +DiskIoctlSmartReceiveDriveData( + IN PDEVICE_OBJECT DeviceObject, + IN OUT PIRP Irp + ) + +/*++ + +Routine Description: + + This routine services SMART_RCV_DRIVE_DATA. This function + allows the caller to read SMART information from the device. + + This function must be called at IRQL < DISPATCH_LEVEL. + +Arguments: + + DeviceObject - Supplies the device object associated with this request. + + Irp - The IRP to be processed + +Return Value: + + NTSTATUS code + +--*/ + +{ + PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; + PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension; + PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData); + PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation (Irp); + NTSTATUS status = STATUS_INVALID_PARAMETER; + + PSENDCMDINPARAMS cmdInParameters = ((PSENDCMDINPARAMS)Irp->AssociatedIrp.SystemBuffer); + PSRB_IO_CONTROL srbControl; + IO_STATUS_BLOCK ioStatus = { 0 }; + ULONG controlCode = 0; + PUCHAR buffer; + PIRP irp2; + KEVENT event; + ULONG length = 0; + + // + // This function must be called at less than dispatch level. + // Fail if IRQL >= DISPATCH_LEVEL. + // + PAGED_CODE(); + CHECK_IRQL(); + + // + // Validate the request. + // + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlSmartReceiveDriveData: DeviceObject %p Irp %p\n", DeviceObject, Irp)); + + if (irpStack->Parameters.DeviceIoControl.InputBufferLength < (sizeof(SENDCMDINPARAMS) - 1)) { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlSmartReceiveDriveData: Input buffer length invalid.\n")); + return STATUS_INVALID_PARAMETER; + } + + if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < (sizeof(SENDCMDOUTPARAMS) + 512 - 1)) { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlSmartReceiveDriveData: Output buffer too small.\n")); + return STATUS_BUFFER_TOO_SMALL; + } + + // + // Create notification event object to be used to signal the + // request completion. + // + + KeInitializeEvent(&event, NotificationEvent, FALSE); + + // + // use controlCode as a sort of 'STATUS_SUCCESS' to see if it's + // a valid request type + // + + if (cmdInParameters->irDriveRegs.bCommandReg == ID_CMD) { + + length = IDENTIFY_BUFFER_SIZE + sizeof(SENDCMDOUTPARAMS); + controlCode = IOCTL_SCSI_MINIPORT_IDENTIFY; + + } else if (cmdInParameters->irDriveRegs.bCommandReg == SMART_CMD) { + + switch (cmdInParameters->irDriveRegs.bFeaturesReg) { + + case READ_ATTRIBUTES: + controlCode = IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS; + length = READ_ATTRIBUTE_BUFFER_SIZE + sizeof(SENDCMDOUTPARAMS); + break; + + case READ_THRESHOLDS: + controlCode = IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS; + length = READ_THRESHOLD_BUFFER_SIZE + sizeof(SENDCMDOUTPARAMS); + break; + + case SMART_READ_LOG: { + + if (diskData->FailurePredictionCapability != FailurePredictionSmart) { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlSmartReceiveDriveData: SMART failure prediction not supported.\n")); + return STATUS_INVALID_DEVICE_REQUEST; + } + + // + // Calculate additional length based on number of sectors to be read. + // Then verify the output buffer is large enough. + // + + length = cmdInParameters->irDriveRegs.bSectorCountReg * SMART_LOG_SECTOR_SIZE; + + // + // Ensure at least 1 sector is going to be read + // + if (length == 0) { + return STATUS_INVALID_PARAMETER; + } + + length += max(sizeof(SENDCMDOUTPARAMS), sizeof(SENDCMDINPARAMS)); + + if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < length - 1) { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlSmartReceiveDriveData: Output buffer too small for SMART_READ_LOG.\n")); + return STATUS_BUFFER_TOO_SMALL; + } + + controlCode = IOCTL_SCSI_MINIPORT_READ_SMART_LOG; + break; + } + } + } + + if (controlCode == 0) { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlSmartReceiveDriveData: Invalid request.\n")); + return STATUS_INVALID_PARAMETER; + } + + srbControl = ExAllocatePoolWithTag(NonPagedPoolNx, + sizeof(SRB_IO_CONTROL) + length, + DISK_TAG_SMART); + + if (srbControl == NULL) { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlSmartReceiveDriveData: Unable to allocate memory.\n")); + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // fill in srbControl fields + // + + srbControl->HeaderLength = sizeof(SRB_IO_CONTROL); + RtlMoveMemory (srbControl->Signature, "SCSIDISK", 8); + srbControl->Timeout = fdoExtension->TimeOutValue; + srbControl->Length = length; + srbControl->ControlCode = controlCode; + + // + // Point to the 'buffer' portion of the SRB_CONTROL + // + + buffer = (PUCHAR)srbControl + srbControl->HeaderLength; + + // + // Ensure correct target is set in the cmd parameters. + // + + cmdInParameters->bDriveNumber = diskData->ScsiAddress.TargetId; + + // + // Copy the IOCTL parameters to the srb control buffer area. + // + + RtlMoveMemory(buffer, + Irp->AssociatedIrp.SystemBuffer, + sizeof(SENDCMDINPARAMS) - 1); + + irp2 = IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT, + commonExtension->LowerDeviceObject, + srbControl, + sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS) - 1, + srbControl, + sizeof(SRB_IO_CONTROL) + length, + FALSE, + &event, + &ioStatus); + + if (irp2 == NULL) { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlSmartReceiveDriveData: Unable to allocate IRP.\n")); + FREE_POOL(srbControl); + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // Call the port driver with the request and wait for it to complete. + // + + status = IoCallDriver(commonExtension->LowerDeviceObject, irp2); + + if (status == STATUS_PENDING) { + KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL); + status = ioStatus.Status; + } + + // + // Copy the data received into the output buffer. Since the status buffer + // contains error information also, always perform this copy. IO will + // either pass this back to the app, or zero it, in case of error. + // + + buffer = (PUCHAR)srbControl + srbControl->HeaderLength; + + if (NT_SUCCESS(status)) { + + RtlMoveMemory ( Irp->AssociatedIrp.SystemBuffer, buffer, length - 1); + Irp->IoStatus.Information = length - 1; + + } else { + + RtlMoveMemory ( Irp->AssociatedIrp.SystemBuffer, buffer, (sizeof(SENDCMDOUTPARAMS) - 1)); + Irp->IoStatus.Information = sizeof(SENDCMDOUTPARAMS) - 1; + + } + + FREE_POOL(srbControl); + + return status; +} + +NTSTATUS +DiskIoctlSmartSendDriveCommand( + IN PDEVICE_OBJECT DeviceObject, + IN OUT PIRP Irp + ) + +/*++ + +Routine Description: + + This routine services SMART_SEND_DRIVE_COMMAND. This function + allows the caller to send SMART commands to the device. + + This function must be called at IRQL < DISPATCH_LEVEL. + +Arguments: + + DeviceObject - Supplies the device object associated with this request. + + Irp - The IRP to be processed + +Return Value: + + NTSTATUS code + +--*/ + +{ + PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; + PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension; + PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData); + PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation (Irp); + NTSTATUS status = STATUS_INVALID_PARAMETER; + + PSENDCMDINPARAMS cmdInParameters = ((PSENDCMDINPARAMS)Irp->AssociatedIrp.SystemBuffer); + PSRB_IO_CONTROL srbControl; + IO_STATUS_BLOCK ioStatus = { 0 }; + ULONG controlCode = 0; + PUCHAR buffer; + PIRP irp2; + KEVENT event; + ULONG length = 0; + + // + // This function must be called at less than dispatch level. + // Fail if IRQL >= DISPATCH_LEVEL. + // + PAGED_CODE(); + CHECK_IRQL(); + + // + // Validate the request. + // + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlSmartSendDriveCommand: DeviceObject %p Irp %p\n", DeviceObject, Irp)); + + if (irpStack->Parameters.DeviceIoControl.InputBufferLength < (sizeof(SENDCMDINPARAMS) - 1)) { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlSmartSendDriveCommand: Input buffer size invalid.\n")); + return STATUS_INVALID_PARAMETER; + } + + if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < (sizeof(SENDCMDOUTPARAMS) - 1)) { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlSmartSendDriveCommand: Output buffer too small.\n")); + return STATUS_BUFFER_TOO_SMALL; + } + + // + // Create notification event object to be used to signal the + // request completion. + // + + KeInitializeEvent(&event, NotificationEvent, FALSE); + + if (cmdInParameters->irDriveRegs.bCommandReg == SMART_CMD) { + + switch (cmdInParameters->irDriveRegs.bFeaturesReg) { + + case SMART_WRITE_LOG: { + + if (diskData->FailurePredictionCapability != FailurePredictionSmart) { + + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlSmartSendDriveCommand: SMART failure prediction not supported.\n")); + return STATUS_INVALID_DEVICE_REQUEST; + } + + // + // Calculate additional length based on number of sectors to be written. + // Then verify the input buffer is large enough. + // + + length = cmdInParameters->irDriveRegs.bSectorCountReg * SMART_LOG_SECTOR_SIZE; + + // + // Ensure at least 1 sector is going to be written + // + + if (length == 0) { + return STATUS_INVALID_PARAMETER; + } + + if (irpStack->Parameters.DeviceIoControl.InputBufferLength < + (sizeof(SENDCMDINPARAMS) - 1) + length) { + + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlSmartSendDriveCommand: Input buffer too small for SMART_WRITE_LOG.\n")); + return STATUS_BUFFER_TOO_SMALL; + } + + controlCode = IOCTL_SCSI_MINIPORT_WRITE_SMART_LOG; + break; + } + + case ENABLE_SMART: + controlCode = IOCTL_SCSI_MINIPORT_ENABLE_SMART; + break; + + case DISABLE_SMART: + controlCode = IOCTL_SCSI_MINIPORT_DISABLE_SMART; + break; + + case RETURN_SMART_STATUS: + + // + // Ensure bBuffer is at least 2 bytes (to hold the values of + // cylinderLow and cylinderHigh). + // + + if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < + (sizeof(SENDCMDOUTPARAMS) - 1 + sizeof(IDEREGS))) { + + return STATUS_BUFFER_TOO_SMALL; + break; + } + + controlCode = IOCTL_SCSI_MINIPORT_RETURN_STATUS; + length = sizeof(IDEREGS); + break; + + case ENABLE_DISABLE_AUTOSAVE: + controlCode = IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE; + break; + + case SAVE_ATTRIBUTE_VALUES: + controlCode = IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES; + break; + + case EXECUTE_OFFLINE_DIAGS: + // + // Validate that this is an ok self test command + // + if (DiskIsValidSmartSelfTest(cmdInParameters->irDriveRegs.bSectorNumberReg)) { + + controlCode = IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS; + } + break; + + case ENABLE_DISABLE_AUTO_OFFLINE: + controlCode = IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTO_OFFLINE; + break; + } + } + + if (controlCode == 0) { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlSmartSendDriveCommand: Invalid request.\n")); + return STATUS_INVALID_PARAMETER; + } + + length += max(sizeof(SENDCMDOUTPARAMS), sizeof(SENDCMDINPARAMS)); + srbControl = ExAllocatePoolWithTag(NonPagedPoolNx, + sizeof(SRB_IO_CONTROL) + length, + DISK_TAG_SMART); + + if (srbControl == NULL) { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlSmartSendDriveCommand: Unable to allocate memory.\n")); + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // fill in srbControl fields + // + + srbControl->HeaderLength = sizeof(SRB_IO_CONTROL); + RtlMoveMemory (srbControl->Signature, "SCSIDISK", 8); + srbControl->Timeout = fdoExtension->TimeOutValue; + srbControl->Length = length; + srbControl->ControlCode = controlCode; + + // + // Point to the 'buffer' portion of the SRB_CONTROL + // + + buffer = (PUCHAR)srbControl + srbControl->HeaderLength; + + // + // Ensure correct target is set in the cmd parameters. + // + + cmdInParameters->bDriveNumber = diskData->ScsiAddress.TargetId; + + // + // Copy the IOCTL parameters to the srb control buffer area. + // + + if (cmdInParameters->irDriveRegs.bFeaturesReg == SMART_WRITE_LOG) { + RtlMoveMemory(buffer, + Irp->AssociatedIrp.SystemBuffer, + sizeof(SENDCMDINPARAMS) - 1 + + cmdInParameters->irDriveRegs.bSectorCountReg * SMART_LOG_SECTOR_SIZE); + } else { + RtlMoveMemory(buffer, Irp->AssociatedIrp.SystemBuffer, sizeof(SENDCMDINPARAMS) - 1); + } + + irp2 = IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT, + commonExtension->LowerDeviceObject, + srbControl, + sizeof(SRB_IO_CONTROL) + length, + srbControl, + sizeof(SRB_IO_CONTROL) + length, + FALSE, + &event, + &ioStatus); + + if (irp2 == NULL) { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlSmartSendDriveCommand: Unable to allocate IRP.\n")); + FREE_POOL(srbControl); + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // Call the port driver with the request and wait for it to complete. + // + + status = IoCallDriver(commonExtension->LowerDeviceObject, irp2); + + if (status == STATUS_PENDING) { + KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL); + status = ioStatus.Status; + } + + // + // Copy the data received into the output buffer. Since the status buffer + // contains error information also, always perform this copy. IO will + // either pass this back to the app, or zero it, in case of error. + // + + buffer = (PUCHAR)srbControl + srbControl->HeaderLength; + + // + // Update the return buffer size based on the sub-command. + // + + if (cmdInParameters->irDriveRegs.bFeaturesReg == RETURN_SMART_STATUS) { + length = sizeof(SENDCMDOUTPARAMS) - 1 + sizeof(IDEREGS); + } else { + length = sizeof(SENDCMDOUTPARAMS) - 1; + } + + RtlMoveMemory ( Irp->AssociatedIrp.SystemBuffer, buffer, length); + Irp->IoStatus.Information = length; + + FREE_POOL(srbControl); + + return status; +} + + +VOID +DiskEtwEnableCallback ( + _In_ LPCGUID SourceId, + _In_ ULONG IsEnabled, + _In_ UCHAR Level, + _In_ ULONGLONG MatchAnyKeyword, + _In_ ULONGLONG MatchAllKeyword, + _In_opt_ PEVENT_FILTER_DESCRIPTOR FilterData, + _In_opt_ PVOID CallbackContext + ) +/*+++ + +Routine Description: + + This routine is the enable callback routine for ETW. It gets called when + tracing is enabled or disabled for our provider. + +Arguments: + + As per the ETW callback. + +Return Value: + + None. +--*/ + +{ + // + // Initialize locals. + // + UNREFERENCED_PARAMETER(SourceId); + UNREFERENCED_PARAMETER(Level); + UNREFERENCED_PARAMETER(MatchAnyKeyword); + UNREFERENCED_PARAMETER(MatchAllKeyword); + UNREFERENCED_PARAMETER(FilterData); + UNREFERENCED_PARAMETER(CallbackContext); + + // + // Set the ETW tracing enable state. + // + DiskETWEnabled = IsEnabled ? TRUE : FALSE; + + return; +} + + diff --git a/storage/class/disk/src/disk.h b/storage/class/disk/src/disk.h new file mode 100644 index 00000000..91427ba3 --- /dev/null +++ b/storage/class/disk/src/disk.h @@ -0,0 +1,1257 @@ +/*++ + +Copyright (C) Microsoft Corporation, 1991 - 2010 + +Module Name: + + disk.c + +Abstract: + + SCSI disk class driver + +Environment: + + kernel mode only + +Notes: + +Revision History: + +--*/ + +#include "ntddk.h" +#include "scsi.h" +#include +#include "classpnp.h" + +#include +#include "ntstrsafe.h" + +// +// Set component ID for DbgPrintEx calls +// +#ifndef DEBUG_COMP_ID +#define DEBUG_COMP_ID DPFLTR_DISK_ID +#endif + +// +// Include header file and setup GUID for tracing +// +#include +#define WPP_GUID_DISK (945186BF, 3DD6, 4f3f, 9C8E, 9EDD3FC9D558) +#ifndef WPP_CONTROL_GUIDS +#define WPP_CONTROL_GUIDS WPP_CONTROL_GUIDS_NORMAL_FLAGS(WPP_GUID_DISK) +#endif + + +#ifdef ExAllocatePool +#undef ExAllocatePool +#define ExAllocatePool #NT_ASSERT(FALSE) +#endif + +#define DISK_TAG_GENERAL ' DcS' // "ScD " - generic tag +#define DISK_TAG_SMART 'aDcS' // "ScDa" - SMART allocations +#define DISK_TAG_INFO_EXCEPTION 'ADcS' // "ScDA" - Info Exceptions +#define DISK_TAG_DISABLE_CACHE 'CDcS' // "ScDC" - disable cache paths +#define DISK_TAG_CCONTEXT 'cDcS' // "ScDc" - disk allocated completion context +#define DISK_TAG_DISK_GEOM 'GDcS' // "ScDG" - disk geometry buffer +#define DISK_TAG_UPDATE_GEOM 'gDcS' // "ScDg" - update disk geometry paths +#define DISK_TAG_SENSE_INFO 'IDcS' // "ScDI" - sense info buffers +#define DISK_TAG_PNP_ID 'iDcS' // "ScDp" - pnp ids +#define DISK_TAG_MODE_DATA 'MDcS' // "ScDM" - mode data buffer +#define DISK_CACHE_MBR_CHECK 'mDcS' // "ScDM" - mbr checksum code +#define DISK_TAG_NAME 'NDcS' // "ScDN" - disk name code +#define DISK_TAG_READ_CAP 'PDcS' // "ScDP" - read capacity buffer +#define DISK_TAG_PART_LIST 'pDcS' // "ScDp" - disk partition lists +#define DISK_TAG_SRB 'SDcS' // "ScDS" - srb allocation +#define DISK_TAG_START 'sDcS' // "ScDs" - start device paths +#define DISK_TAG_UPDATE_CAP 'UDcS' // "ScDU" - update capacity path +#define DISK_TAG_WI_CONTEXT 'WDcS' // "ScDW" - work-item context + + +#if defined(_X86_) || defined(_AMD64_) + +// +// Disk device data +// + +typedef enum _DISK_GEOMETRY_SOURCE { + DiskGeometryUnknown, + DiskGeometryFromBios, + DiskGeometryFromPort, + DiskGeometryFromNec98, + DiskGeometryGuessedFromBios, + DiskGeometryFromDefault, + DiskGeometryFromNT4 +} DISK_GEOMETRY_SOURCE, *PDISK_GEOMETRY_SOURCE; +#endif + +// +// Context for requests that can be combined and sent down +// + +typedef struct _DISK_GROUP_CONTEXT +{ + // + // Queue of requests whose representative is currently outstanding at the port driver + // + LIST_ENTRY CurrList; + + // + // The representative for the above queue + // + PIRP CurrIrp; + + // + // Queue of requests whose representative is waiting to go down + // + LIST_ENTRY NextList; + + // + // The representative for the above queue + // + PIRP NextIrp; + + // + // The srb associated with this group + // +#if (NTDDI_VERSION >= NTDDI_WIN8) + + union { + SCSI_REQUEST_BLOCK Srb; + STORAGE_REQUEST_BLOCK SrbEx; + UCHAR SrbExBuffer[CLASS_SRBEX_SCSI_CDB16_BUFFER_SIZE]; + } Srb; + +#else + SCSI_REQUEST_BLOCK Srb; +#endif + + // + // The spinlock that will synchronize access to this context + // + KSPIN_LOCK Spinlock; + + // + // This event will allow for the requests to be sent down synchronously + // + KEVENT Event; + + +#if DBG + + // + // This counter maintains the number of requests currently tagged + // to the request that is waiting to go down + // + ULONG DbgTagCount; + + // + // This counter maintains the number of requests that were avoided + // + ULONG DbgSavCount; + + // + // This counter maintains the total number of times that we combined + // requests and the respective number of requests that were tagged + // + ULONG DbgRefCount[64]; + +#endif + +} DISK_GROUP_CONTEXT, *PDISK_GROUP_CONTEXT; + +// +// Write cache setting as defined by the user +// +typedef enum _DISK_USER_WRITE_CACHE_SETTING +{ + DiskWriteCacheDisable = 0, + DiskWriteCacheEnable = 1, + DiskWriteCacheDefault = -1 + +} DISK_USER_WRITE_CACHE_SETTING, *PDISK_USER_WRITE_CACHE_SETTING; + +typedef struct _DISK_DATA { + + // + // This field is the ordinal of a partition as it appears on a disk. + // + + ULONG PartitionOrdinal; + + // + // How has this disk been partitioned? Either EFI or MBR. + // + + PARTITION_STYLE PartitionStyle; + + union { + + struct { + + // + // Disk signature (from MBR) + // + + ULONG Signature; + + // + // MBR checksum + // + + ULONG MbrCheckSum; + + // + // Number of hidden sectors for BPB. + // + + ULONG HiddenSectors; + + // + // Partition type of this device object + // + // This field is set by: + // + // 1. Initially set according to the partition list entry + // partition type returned by IoReadPartitionTable. + // + // 2. Subsequently set by the + // IOCTL_DISK_SET_PARTITION_INFORMATION I/O control + // function when IoSetPartitionInformation function + // successfully updates the partition type on the disk. + // + + UCHAR PartitionType; + + // + // Boot indicator - indicates whether this partition is a + // bootable (active) partition for this device + // + // This field is set according to the partition list entry boot + // indicator returned by IoReadPartitionTable. + // + + BOOLEAN BootIndicator; + + } Mbr; + + struct { + + // + // The DiskGUID field from the EFI partition header. + // + + GUID DiskId; + + // + // Partition type of this device object. + // + + GUID PartitionType; + + // + // Unique partition identifier for this partition. + // + + GUID PartitionId; + + // + // EFI partition attributes for this partition. + // + + ULONG64 Attributes; + + // + // EFI partition name of this partition. + // + + WCHAR PartitionName[36]; + + } Efi; + +#pragma warning(suppress: 4201) //this is intended to be an unnamed union + }; + + struct { + // + // This flag is set when the well known name is created (through + // DiskCreateSymbolicLinks) and cleared when destroying it + // (by calling DiskDeleteSymbolicLinks). + // + + unsigned int WellKnownNameCreated : 1; + + // + // This flag is set when the PhysicalDriveN link is created (through + // DiskCreateSymbolicLinks) and is cleared when destroying it (through + // DiskDeleteSymbolicLinks) + // + + unsigned int PhysicalDriveLinkCreated : 1; + + } LinkStatus; + + // + // ReadyStatus - STATUS_SUCCESS indicates that the drive is ready for + // use. Any error status is to be returned as an explaination for why + // a request is failed. + // + // This was done solely for the zero-length partition case of having no + // media in a removable disk drive. When that occurs, and a read is sent + // to the zero-length non-partition-zero PDO that was created, we had to + // be able to fail the request with a reasonable value. This may not have + // been the best way to do this, but it works. + // + + NTSTATUS ReadyStatus; + + // + // SCSI address used for SMART operations. + // + + SCSI_ADDRESS ScsiAddress; + + // + // What type of failure prediction mechanism is available + // + + FAILURE_PREDICTION_METHOD FailurePredictionCapability; + BOOLEAN AllowFPPerfHit; + + // + // Indicates that the SCSI Informational Exceptions mode page is supported. + // Note that this only indicates *support* and does not necessarily + // indicate that Informational Exception reporting via sense code is + // actually enabled. + // + BOOLEAN ScsiInfoExceptionsSupported; + + // + // Indicates if failure prediction is actually enabled (via whatever) + // method is applicable as indicated by FailurePredictionCapability. + // + BOOLEAN FailurePredictionEnabled; + +#if defined(_X86_) || defined(_AMD64_) + // + // This flag indiciates that a non-default geometry for this drive has + // already been determined by the disk driver. This field is ignored + // for removable media drives. + // + + DISK_GEOMETRY_SOURCE GeometrySource; + + // + // If GeometryDetermined is TRUE this will contain the geometry which was + // reported by the firmware or by the BIOS. For removable media drives + // this will contain the last geometry used when media was present. + // + + DISK_GEOMETRY RealGeometry; +#endif + + // + // This mutex prevents more than one IOCTL_DISK_VERIFY from being + // sent down to the disk. This greatly reduces the possibility of + // a Denial-of-Service attack + // + + KMUTEX VerifyMutex; + + // + // This allows for parallel flush requests to be combined into one so as to + // reduce the number of outstanding requests that are sent down to the disk + // + + DISK_GROUP_CONTEXT FlushContext; + + // + // The user-specified disk write cache setting + // + + DISK_USER_WRITE_CACHE_SETTING WriteCacheOverride; + + +} DISK_DATA, *PDISK_DATA; + +// +// Define a general structure of identfing disk controllers with bad +// hardware. +// + +#define HackDisableTaggedQueuing (0x01) +#define HackDisableSynchronousTransfers (0x02) +#define HackDisableSpinDown (0x04) +#define HackDisableWriteCache (0x08) +#define HackCauseNotReportableHack (0x10) +#define HackRequiresStartUnitCommand (0x20) + + +#define DiskDeviceParameterSubkey L"Disk" +#define DiskDeviceUserWriteCacheSetting L"UserWriteCacheSetting" +#define DiskDeviceCacheIsPowerProtected L"CacheIsPowerProtected" + + +#define FUNCTIONAL_EXTENSION_SIZE sizeof(FUNCTIONAL_DEVICE_EXTENSION) + sizeof(DISK_DATA) + +#define MODE_DATA_SIZE 192 +#define VALUE_BUFFER_SIZE 2048 +#define SCSI_DISK_TIMEOUT 10 +#define PARTITION0_LIST_SIZE 4 + +#define MAX_MEDIA_TYPES 4 +typedef struct _DISK_MEDIA_TYPES_LIST { + PCCHAR VendorId; + PCCHAR ProductId; + PCCHAR Revision; + const ULONG NumberOfTypes; + const ULONG NumberOfSides; + const STORAGE_MEDIA_TYPE MediaTypes[MAX_MEDIA_TYPES]; +} DISK_MEDIA_TYPES_LIST, *PDISK_MEDIA_TYPES_LIST; + +// +// WMI reregistration structures used for reregister work item +// +typedef struct +{ + SINGLE_LIST_ENTRY Next; + PDEVICE_OBJECT DeviceObject; + PIRP Irp; +} DISKREREGREQUEST, *PDISKREREGREQUEST; + +#define MAX_SECTORS_PER_VERIFY 0x100 + +// +// This is based off 100ns units +// +#define ONE_MILLI_SECOND ((ULONGLONG)10 * 1000) + +// +// Context for the work-item +// +typedef struct _DISK_VERIFY_WORKITEM_CONTEXT +{ + PIRP Irp; + PSCSI_REQUEST_BLOCK Srb; + PIO_WORKITEM WorkItem; + +} DISK_VERIFY_WORKITEM_CONTEXT, *PDISK_VERIFY_WORKITEM_CONTEXT; + +// +// Poll for Failure Prediction every hour +// +#define DISK_DEFAULT_FAILURE_POLLING_PERIOD 1 * 60 * 60 + +#define CHECK_IRQL() \ + if (KeGetCurrentIrql() >= DISPATCH_LEVEL) { \ + NT_ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL); \ + return STATUS_INVALID_LEVEL; \ + } + +// +// Static global lookup tables. +// + +extern CLASSPNP_SCAN_FOR_SPECIAL_INFO DiskBadControllers[]; +extern const DISK_MEDIA_TYPES_LIST DiskMediaTypes[]; +extern const DISK_MEDIA_TYPES_LIST DiskMediaTypesExclude[]; + +// +// Macros +// + +// +// Routine prototypes. +// + + +DRIVER_INITIALIZE DriverEntry; + +VOID +DiskUnload( + IN PDRIVER_OBJECT DriverObject + ); + +NTSTATUS +DiskAddDevice( + IN PDRIVER_OBJECT DriverObject, + IN PDEVICE_OBJECT Pdo + ); + +NTSTATUS +DiskInitFdo( + IN PDEVICE_OBJECT Fdo + ); + +NTSTATUS +DiskStartFdo( + IN PDEVICE_OBJECT Fdo + ); + +NTSTATUS +DiskStopDevice( + IN PDEVICE_OBJECT DeviceObject, + IN UCHAR Type + ); + +NTSTATUS +DiskRemoveDevice( + IN PDEVICE_OBJECT DeviceObject, + IN UCHAR Type + ); + +NTSTATUS +DiskReadWriteVerification( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp + ); + +NTSTATUS +DiskDeviceControl( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp + ); + +VOID +DiskFdoProcessError( + PDEVICE_OBJECT DeviceObject, + PSCSI_REQUEST_BLOCK Srb, + NTSTATUS *Status, + BOOLEAN *Retry + ); + +NTSTATUS +DiskShutdownFlush( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp + ); + +NTSTATUS +DiskGetCacheInformation( + IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, + IN PDISK_CACHE_INFORMATION CacheInfo + ); + +NTSTATUS +DiskSetCacheInformation( + IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, + IN PDISK_CACHE_INFORMATION CacheInfo + ); + +VOID +DiskLogCacheInformation( + IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, + IN PDISK_CACHE_INFORMATION CacheInfo, + IN NTSTATUS Status + ); + +NTSTATUS +DiskIoctlGetCacheSetting( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp + ); + +NTSTATUS +DiskIoctlSetCacheSetting( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp + ); + +IO_WORKITEM_ROUTINE DisableWriteCache; + +IO_WORKITEM_ROUTINE DiskIoctlVerifyThread; + +VOID +DiskFlushDispatch( + IN PDEVICE_OBJECT Fdo, + IN PDISK_GROUP_CONTEXT FlushContext + ); + +IO_COMPLETION_ROUTINE DiskFlushComplete; + + +NTSTATUS +DiskModeSelect( + IN PDEVICE_OBJECT DeviceObject, + _In_reads_bytes_(Length) PCHAR ModeSelectBuffer, + IN ULONG Length, + IN BOOLEAN SavePage + ); + +// +// We need to validate that the self test subcommand is valid and +// appropriate. Right now we allow subcommands 0, 1 and 2 which are non +// captive mode tests. Once we figure out a way to know if it is safe to +// run a captive test then we can allow captive mode tests. Also if the +// atapi 5 spec is ever updated to denote that bit 7 is the captive +// mode bit, we can allow any request that does not have bit 7 set. Until +// that is done we want to be sure +// +#define DiskIsValidSmartSelfTest(Subcommand) \ + ( ((Subcommand) == SMART_OFFLINE_ROUTINE_OFFLINE) || \ + ((Subcommand) == SMART_SHORT_SELFTEST_OFFLINE) || \ + ((Subcommand) == SMART_EXTENDED_SELFTEST_OFFLINE) ) + + +NTSTATUS +DiskPerformSmartCommand( + IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, + IN ULONG SrbControlCode, + IN UCHAR Command, + IN UCHAR Feature, + IN UCHAR SectorCount, + IN UCHAR SectorNumber, + IN OUT PSRB_IO_CONTROL SrbControl, + OUT PULONG BufferSize + ); + +NTSTATUS +DiskGetInfoExceptionInformation( + IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, + OUT PMODE_INFO_EXCEPTIONS ReturnPageData + ); + +NTSTATUS +DiskSetInfoExceptionInformation( + IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, + IN PMODE_INFO_EXCEPTIONS PageData + ); + +#if (NTDDI_VERSION >= NTDDI_WINBLUE) +NTSTATUS +DiskGetModePage( + _In_ PDEVICE_OBJECT Fdo, + _In_ UCHAR PageMode, + _In_ UCHAR PageControl, + _In_ PMODE_PARAMETER_HEADER ModeData, + _Inout_ PULONG ModeDataSize, + _Out_ PVOID* PageData + ); + +NTSTATUS +DiskEnableInfoExceptions( + _In_ PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, + _In_ BOOLEAN Enable + ); +#endif // (NTDDI_VERSION >= NTDDI_WINBLUE) + +NTSTATUS +DiskDetectFailurePrediction( + PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, + PFAILURE_PREDICTION_METHOD FailurePredictCapability, + BOOLEAN ScsiAddressAvailable + ); + +NTSTATUS +DiskCreateFdo( + IN PDRIVER_OBJECT DriverObject, + IN PDEVICE_OBJECT LowerDeviceObject, + IN PULONG DeviceCount, + IN BOOLEAN DasdAccessOnly + ); + +VOID +DiskSetSpecialHacks( + IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, + IN ULONG_PTR Data + ); + +VOID +ResetBus( + IN PDEVICE_OBJECT DeviceObject + ); + +NTSTATUS +DiskGenerateDeviceName( + IN ULONG DeviceNumber, + OUT PCCHAR *RawName + ); + +VOID +DiskCreateSymbolicLinks( + IN PDEVICE_OBJECT DeviceObject + ); + +VOID +DiskDeleteSymbolicLinks( + IN PDEVICE_OBJECT DeviceObject + ); + + +NTSTATUS +DiskFdoQueryWmiRegInfo( + IN PDEVICE_OBJECT DeviceObject, + OUT ULONG *RegFlags, + OUT PUNICODE_STRING InstanceName + ); + +NTSTATUS +DiskFdoQueryWmiRegInfoEx( + IN PDEVICE_OBJECT DeviceObject, + OUT ULONG *RegFlags, + OUT PUNICODE_STRING InstanceName, + OUT PUNICODE_STRING MofName + ); + +NTSTATUS +DiskFdoQueryWmiDataBlock( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN ULONG GuidIndex, + IN ULONG BufferAvail, + OUT PUCHAR Buffer + ); + +NTSTATUS +DiskFdoSetWmiDataBlock( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN ULONG GuidIndex, + IN ULONG BufferSize, + IN PUCHAR Buffer + ); + +NTSTATUS +DiskFdoSetWmiDataItem( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN ULONG GuidIndex, + IN ULONG DataItemId, + IN ULONG BufferSize, + IN PUCHAR Buffer + ); + +NTSTATUS +DiskFdoExecuteWmiMethod( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN ULONG GuidIndex, + IN ULONG MethodId, + IN ULONG InBufferSize, + IN ULONG OutBufferSize, + IN PUCHAR Buffer + ); + +NTSTATUS +DiskWmiFunctionControl( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN ULONG GuidIndex, + IN CLASSENABLEDISABLEFUNCTION Function, + IN BOOLEAN Enable + ); + +NTSTATUS +DiskReadFailurePredictStatus( + PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, + PSTORAGE_FAILURE_PREDICT_STATUS DiskSmartStatus + ); + +NTSTATUS +DiskReadFailurePredictData( + PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, + PSTORAGE_FAILURE_PREDICT_DATA DiskSmartData + ); + +NTSTATUS +DiskEnableDisableFailurePrediction( + PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, + BOOLEAN Enable + ); + +NTSTATUS +DiskEnableDisableFailurePredictPolling( + PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, + BOOLEAN Enable, + ULONG PollTimeInSeconds + ); + +NTSTATUS DiskInitializeReregistration( + VOID + ); + +extern GUIDREGINFO DiskWmiFdoGuidList[]; + +#if defined(_X86_) || defined(_AMD64_) +NTSTATUS +DiskReadDriveCapacity( + IN PDEVICE_OBJECT Fdo + ); +#else +#define DiskReadDriveCapacity(Fdo) ClassReadDriveCapacity(Fdo) +#endif + + +#if defined(_X86_) || defined(_AMD64_) + +NTSTATUS +DiskSaveDetectInfo( + PDRIVER_OBJECT DriverObject + ); + +VOID +DiskCleanupDetectInfo( + IN PDRIVER_OBJECT DriverObject + ); + +VOID +DiskDriverReinitialization ( + IN PDRIVER_OBJECT DriverObject, + IN PVOID Nothing, + IN ULONG Count + ); + +#endif + +#if defined(_X86_) || defined(_AMD64_) +NTSTATUS +DiskGetDetectInfo( + IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, + OUT PDISK_DETECTION_INFO DetectInfo + ); + +NTSTATUS +DiskReadSignature( + IN PDEVICE_OBJECT Fdo + ); + +BOOLEAN +DiskIsNT4Geometry( + IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension + ); + +#else +#define DiskGetDetectInfo(FdoExtension, DetectInfo) (STATUS_UNSUCCESSFUL) +#endif + + +#define DiskHashGuid(Guid) (((PULONG) &Guid)[0] ^ ((PULONG) &Guid)[0] ^ ((PULONG) &Guid)[0] ^ ((PULONG) &Guid)[0]) + + +NTSTATUS +DiskDetermineMediaTypes( + IN PDEVICE_OBJECT Fdo, + IN PIRP Irp, + IN UCHAR MediumType, + IN UCHAR DensityCode, + IN BOOLEAN MediaPresent, + IN BOOLEAN IsWritable + ); + +NTSTATUS +DiskIoctlGetLengthInfo( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp + ); + +NTSTATUS +DiskIoctlGetDriveGeometry( + IN PDEVICE_OBJECT DeviceObject, + IN OUT PIRP Irp + ); + +NTSTATUS +DiskIoctlGetDriveGeometryEx( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp + ); + +NTSTATUS +DiskIoctlGetCacheInformation( + IN PDEVICE_OBJECT DeviceObject, + IN OUT PIRP Irp + ); + +NTSTATUS +DiskIoctlSetCacheInformation( + IN PDEVICE_OBJECT DeviceObject, + IN OUT PIRP Irp + ); + +NTSTATUS +DiskIoctlGetMediaTypesEx( + IN PDEVICE_OBJECT DeviceObject, + IN OUT PIRP Irp + ); + +NTSTATUS +DiskIoctlPredictFailure( + IN PDEVICE_OBJECT DeviceObject, + IN OUT PIRP Irp + ); + +NTSTATUS +DiskIoctlEnableFailurePrediction( + IN PDEVICE_OBJECT DeviceObject, + IN OUT PIRP Irp + ); + +NTSTATUS +DiskIoctlVerify( + IN PDEVICE_OBJECT DeviceObject, + IN OUT PIRP Irp + ); + +NTSTATUS +DiskIoctlReassignBlocks( + IN PDEVICE_OBJECT DeviceObject, + IN OUT PIRP Irp + ); + +NTSTATUS +DiskIoctlReassignBlocksEx( + IN PDEVICE_OBJECT DeviceObject, + IN OUT PIRP Irp + ); + +NTSTATUS +DiskIoctlIsWritable( + IN PDEVICE_OBJECT DeviceObject, + IN OUT PIRP Irp + ); + +NTSTATUS +DiskIoctlSetVerify( + IN PDEVICE_OBJECT DeviceObject, + IN OUT PIRP Irp + ); + +NTSTATUS +DiskIoctlClearVerify( + IN PDEVICE_OBJECT DeviceObject, + IN OUT PIRP Irp + ); + +NTSTATUS +DiskIoctlUpdateDriveSize( + IN PDEVICE_OBJECT DeviceObject, + IN OUT PIRP Irp + ); + +NTSTATUS +DiskIoctlGetVolumeDiskExtents( + IN PDEVICE_OBJECT DeviceObject, + IN OUT PIRP Irp + ); + +NTSTATUS +DiskIoctlSmartGetVersion( + IN PDEVICE_OBJECT DeviceObject, + IN OUT PIRP Irp + ); + +NTSTATUS +DiskIoctlSmartReceiveDriveData( + IN PDEVICE_OBJECT DeviceObject, + IN OUT PIRP Irp + ); + +NTSTATUS +DiskIoctlSmartSendDriveCommand( + IN PDEVICE_OBJECT DeviceObject, + IN OUT PIRP Irp + ); + +__inline +PCDB +GetSrbScsiData( + _In_ PSTORAGE_REQUEST_BLOCK SrbEx, + _In_opt_ PUCHAR CdbLength8, + _In_opt_ PULONG CdbLength32, + _In_opt_ PUCHAR ScsiStatus, + _In_opt_ PVOID *SenseInfoBuffer, + _In_opt_ PUCHAR SenseInfoBufferLength + ) +/*++ + +Routine Description: + + Helper function to retrieve SCSI related fields from an extended SRB. If SRB is + not a SRB_FUNCTION_EXECUTE_SCSI or not an extended SRB, default values will be returned. + +Arguments: + + SrbEx - Pointer to extended SRB. + + CdbLength8 - Pointer to buffer to hold CdbLength field value for + SRBEX_DATA_SCSI_CDB16 or SRBEX_DATA_SCSI_CDB32 + + CdbLength32 - Pointer to buffer to hold CdbLength field value for + SRBEX_DATA_SCSI_CDB_VAR + + ScsiStatus - Pointer to buffer to hold ScsiStatus field value. + + SenseInfoBuffer - Pointer to buffer to hold SenseInfoBuffer value. + + SenseInfoBufferLength - Pointer to buffer to hold SenseInfoBufferLength value. + +Return Value: + + Pointer to Cdb field or NULL if SRB is not a SRB_FUNCTION_EXECUTE_SCSI. + +--*/ +{ + PCDB Cdb = NULL; + ULONG i; + PSRBEX_DATA SrbExData = NULL; + BOOLEAN FoundEntry = FALSE; + + if ((SrbEx->Function == SRB_FUNCTION_STORAGE_REQUEST_BLOCK) && + (SrbEx->SrbFunction == SRB_FUNCTION_EXECUTE_SCSI)) { + NT_ASSERT(SrbEx->NumSrbExData > 0); + + for (i = 0; i < SrbEx->NumSrbExData; i++) { + + // Skip any invalid offsets + if ((SrbEx->SrbExDataOffset[i] < sizeof(STORAGE_REQUEST_BLOCK)) || + (SrbEx->SrbExDataOffset[i] > SrbEx->SrbLength)){ + // Catch any invalid offsets + NT_ASSERT(FALSE); + continue; + } + + SrbExData = (PSRBEX_DATA)((PUCHAR)SrbEx + SrbEx->SrbExDataOffset[i]); + + switch (SrbExData->Type) { + + case SrbExDataTypeScsiCdb16: + if (SrbEx->SrbExDataOffset[i] + sizeof(SRBEX_DATA_SCSI_CDB16) <= SrbEx->SrbLength) { + FoundEntry = TRUE; + if (CdbLength8) { + *CdbLength8 = ((PSRBEX_DATA_SCSI_CDB16) SrbExData)->CdbLength; + } + + if (((PSRBEX_DATA_SCSI_CDB16) SrbExData)->CdbLength > 0) { + Cdb = (PCDB)((PSRBEX_DATA_SCSI_CDB16) SrbExData)->Cdb; + } + + if (ScsiStatus) { + *ScsiStatus = + ((PSRBEX_DATA_SCSI_CDB16) SrbExData)->ScsiStatus; + } + + if (SenseInfoBuffer) { + *SenseInfoBuffer = + ((PSRBEX_DATA_SCSI_CDB16) SrbExData)->SenseInfoBuffer; + } + + if (SenseInfoBufferLength) { + *SenseInfoBufferLength = + ((PSRBEX_DATA_SCSI_CDB16) SrbExData)->SenseInfoBufferLength; + } + + } else { + // Catch invalid offset + NT_ASSERT(FALSE); + } + break; + + case SrbExDataTypeScsiCdb32: + if (SrbEx->SrbExDataOffset[i] + sizeof(SRBEX_DATA_SCSI_CDB32) <= SrbEx->SrbLength) { + FoundEntry = TRUE; + if (CdbLength8) { + *CdbLength8 = ((PSRBEX_DATA_SCSI_CDB32) SrbExData)->CdbLength; + } + + if (((PSRBEX_DATA_SCSI_CDB32) SrbExData)->CdbLength > 0) { + Cdb = (PCDB)((PSRBEX_DATA_SCSI_CDB32) SrbExData)->Cdb; + } + + if (ScsiStatus) { + *ScsiStatus = + ((PSRBEX_DATA_SCSI_CDB32) SrbExData)->ScsiStatus; + } + + if (SenseInfoBuffer) { + *SenseInfoBuffer = + ((PSRBEX_DATA_SCSI_CDB32) SrbExData)->SenseInfoBuffer; + } + + if (SenseInfoBufferLength) { + *SenseInfoBufferLength = + ((PSRBEX_DATA_SCSI_CDB32) SrbExData)->SenseInfoBufferLength; + } + + } else { + // Catch invalid offset + NT_ASSERT(FALSE); + } + break; + + case SrbExDataTypeScsiCdbVar: + if (SrbEx->SrbExDataOffset[i] + sizeof(SRBEX_DATA_SCSI_CDB_VAR) <= SrbEx->SrbLength) { + FoundEntry = TRUE; + if (CdbLength32) { + *CdbLength32 = ((PSRBEX_DATA_SCSI_CDB_VAR) SrbExData)->CdbLength; + } + + if (((PSRBEX_DATA_SCSI_CDB_VAR) SrbExData)->CdbLength > 0) { + Cdb = (PCDB)((PSRBEX_DATA_SCSI_CDB_VAR) SrbExData)->Cdb; + } + + if (ScsiStatus) { + *ScsiStatus = + ((PSRBEX_DATA_SCSI_CDB_VAR) SrbExData)->ScsiStatus; + } + + if (SenseInfoBuffer) { + *SenseInfoBuffer = + ((PSRBEX_DATA_SCSI_CDB_VAR) SrbExData)->SenseInfoBuffer; + } + + if (SenseInfoBufferLength) { + *SenseInfoBufferLength = + ((PSRBEX_DATA_SCSI_CDB_VAR) SrbExData)->SenseInfoBufferLength; + } + + } else { + // Catch invalid offset + NT_ASSERT(FALSE); + } + break; + } + + if (FoundEntry) { + break; + } + } + + } else { + + if (CdbLength8) { + *CdbLength8 = 0; + } + + if (CdbLength32) { + *CdbLength32 = 0; + } + + if (ScsiStatus) { + *ScsiStatus = 0; + } + + if (SenseInfoBuffer) { + *SenseInfoBuffer = NULL; + } + + if (SenseInfoBufferLength) { + *SenseInfoBufferLength = 0; + } + } + + return Cdb; +} + +__inline +VOID +SetSrbScsiData( + _In_ PSTORAGE_REQUEST_BLOCK SrbEx, + _In_ UCHAR CdbLength8, + _In_ ULONG CdbLength32, + _In_ UCHAR ScsiStatus, + _In_opt_ PVOID SenseInfoBuffer, + _In_ UCHAR SenseInfoBufferLength + ) +/*++ + +Routine Description: + + Helper function to set SCSI related fields from an extended SRB. If SRB is + not a SRB_FUNCTION_EXECUTE_SCSI or not an extended SRB, no modifications will + be made + +Arguments: + + SrbEx - Pointer to extended SRB. + + CdbLength8 - CdbLength field value for SRBEX_DATA_SCSI_CDB16 + or SRBEX_DATA_SCSI_CDB32 + + CdbLength32 - CdbLength field value for SRBEX_DATA_SCSI_CDB_VAR + + ScsiStatus - ScsiStatus field value. + + SenseInfoBuffer - SenseInfoBuffer value. + + SenseInfoBufferLength - SenseInfoBufferLength value. + +Return Value: + + None + +--*/ +{ + ULONG i; + PSRBEX_DATA SrbExData = NULL; + BOOLEAN FoundEntry = FALSE; + + if ((SrbEx->Function == SRB_FUNCTION_STORAGE_REQUEST_BLOCK) && + (SrbEx->SrbFunction == SRB_FUNCTION_EXECUTE_SCSI)) { + NT_ASSERT(SrbEx->NumSrbExData > 0); + + for (i = 0; i < SrbEx->NumSrbExData; i++) { + + // Skip any invalid offsets + if ((SrbEx->SrbExDataOffset[i] < sizeof(STORAGE_REQUEST_BLOCK)) || + (SrbEx->SrbExDataOffset[i] > SrbEx->SrbLength)){ + // Catch any invalid offsets + NT_ASSERT(FALSE); + continue; + } + + SrbExData = (PSRBEX_DATA)((PUCHAR)SrbEx + SrbEx->SrbExDataOffset[i]); + + switch (SrbExData->Type) { + + case SrbExDataTypeScsiCdb16: + if (SrbEx->SrbExDataOffset[i] + sizeof(SRBEX_DATA_SCSI_CDB16) <= SrbEx->SrbLength) { + FoundEntry = TRUE; + ((PSRBEX_DATA_SCSI_CDB16) SrbExData)->CdbLength = CdbLength8; + ((PSRBEX_DATA_SCSI_CDB16) SrbExData)->ScsiStatus = ScsiStatus; + ((PSRBEX_DATA_SCSI_CDB16) SrbExData)->SenseInfoBuffer = SenseInfoBuffer; + ((PSRBEX_DATA_SCSI_CDB16) SrbExData)->SenseInfoBufferLength = SenseInfoBufferLength; + } else { + // Catch invalid offset + NT_ASSERT(FALSE); + } + break; + + case SrbExDataTypeScsiCdb32: + if (SrbEx->SrbExDataOffset[i] + sizeof(SRBEX_DATA_SCSI_CDB32) <= SrbEx->SrbLength) { + FoundEntry = TRUE; + ((PSRBEX_DATA_SCSI_CDB32) SrbExData)->CdbLength = CdbLength8; + ((PSRBEX_DATA_SCSI_CDB32) SrbExData)->ScsiStatus = ScsiStatus; + ((PSRBEX_DATA_SCSI_CDB32) SrbExData)->SenseInfoBuffer = SenseInfoBuffer; + ((PSRBEX_DATA_SCSI_CDB32) SrbExData)->SenseInfoBufferLength = SenseInfoBufferLength; + } else { + // Catch invalid offset + NT_ASSERT(FALSE); + } + break; + + case SrbExDataTypeScsiCdbVar: + if (SrbEx->SrbExDataOffset[i] + sizeof(SRBEX_DATA_SCSI_CDB_VAR) <= SrbEx->SrbLength) { + FoundEntry = TRUE; + ((PSRBEX_DATA_SCSI_CDB_VAR) SrbExData)->CdbLength = CdbLength32; + ((PSRBEX_DATA_SCSI_CDB_VAR) SrbExData)->ScsiStatus = ScsiStatus; + ((PSRBEX_DATA_SCSI_CDB_VAR) SrbExData)->SenseInfoBuffer = SenseInfoBuffer; + ((PSRBEX_DATA_SCSI_CDB_VAR) SrbExData)->SenseInfoBufferLength = SenseInfoBufferLength; + } else { + // Catch invalid offset + NT_ASSERT(FALSE); + } + break; + } + + if (FoundEntry) { + break; + } + } + + } + + return; +} + diff --git a/storage/class/disk/src/disk.htm b/storage/class/disk/src/disk.htm new file mode 100644 index 00000000..bb77f1fd --- /dev/null +++ b/storage/class/disk/src/disk.htm @@ -0,0 +1,42 @@ + + + + +Disk + + + +

Disk

+ +

Summary

+The Disk sample is used with Classpnp.sys as disk driver. The sample supports Plug and Play, Power Management, WMI, and failure prediction (S.M.A.R.T.), and it is 64-bit compliant. + +

Building the Sample

+To build the sample, run the build command. Once built, this sample will create one binary: Disk.sys. + +

CODE TOUR

+

File Manifest

+
File			Description
+
+Data.c		List of workarounds for some drives (no code)
+Disk.c		Main code base
+Disk.h		Private header files
+Disk.rc		Resource file
+Diskwmi.c		S.M.A.R.T. WMI implementation
+Drivesup.c		No longer used
+Drivesup.h		No longer used
+Enum.c		Enumeration routines for disk drives
+Makefile		Makefile
+Pnp.c		Start/add/pnp code
+Sources		Sources
+
+
+

Top of page

+ + + +
+

+ +

© 1999 Microsoft Corporation

+ diff --git a/storage/class/disk/src/disk.rc b/storage/class/disk/src/disk.rc new file mode 100644 index 00000000..b697f15b --- /dev/null +++ b/storage/class/disk/src/disk.rc @@ -0,0 +1,23 @@ +/* ------------------------------------------------------------------------- * + * * + * Copyright (c) Microsoft Corporation * + * * + * Module Name : disk.rc * + * * + * Abstract : Resource script for disk.sys * + * * + * ------------------------------------------------------------------------- */ + +#include + +#include + +#define VER_FILETYPE VFT_DRV +#define VER_FILESUBTYPE VFT2_DRV_SYSTEM +#define VER_FILEDESCRIPTION_STR "PnP Disk Driver" +#define VER_INTERNALNAME_STR "disk.sys" +#define VER_ORIGINALFILENAME_STR "disk.sys" +#define VER_LANGNEUTRAL + +#include "common.ver" + diff --git a/storage/class/disk/src/disk.vcxproj b/storage/class/disk/src/disk.vcxproj new file mode 100644 index 00000000..7d749d1c --- /dev/null +++ b/storage/class/disk/src/disk.vcxproj @@ -0,0 +1,195 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {627F8680-3389-4050-A0E1-9EA14F615498} + $(MSBuildProjectName) + false + Debug + Win32 + {0AA04C84-504B-44EC-90C4-BDC48593BE4F} + + + + Windows10 + False + Universal + WDM + WindowsKernelModeDriver10.0 + Driver + + + Windows10 + True + Universal + WDM + WindowsKernelModeDriver10.0 + Driver + + + Windows10 + False + Universal + WDM + WindowsKernelModeDriver10.0 + Driver + + + Windows10 + True + Universal + WDM + WindowsKernelModeDriver10.0 + Driver + + + + $(IntDir) + + + + + + + + + + + + + + + + true + true + TracePrint((LEVEL,FLAGS,MSG,...)) + + + true + true + TracePrint((LEVEL,FLAGS,MSG,...)) + + + + disk + + + disk + + + disk + + + disk + + + + %(AdditionalDependencies);$(DDK_LIB_PATH)\classpnp.lib + + + %(AdditionalIncludeDirectories);..\inc;..\..\inc;..\..\..\inc + %(PreprocessorDefinitions);DEBUG_USE_KDPRINT + + + %(AdditionalIncludeDirectories);..\inc;..\..\inc;..\..\..\inc + %(PreprocessorDefinitions);DEBUG_USE_KDPRINT + + + + + %(AdditionalIncludeDirectories);..\inc;..\..\inc;..\..\..\inc + %(PreprocessorDefinitions);DEBUG_USE_KDPRINT + + + + + %(AdditionalDependencies);$(DDK_LIB_PATH)\classpnp.lib + + + %(AdditionalIncludeDirectories);..\inc;..\..\inc;..\..\..\inc + %(PreprocessorDefinitions);DEBUG_USE_KDPRINT + + + %(AdditionalIncludeDirectories);..\inc;..\..\inc;..\..\..\inc + %(PreprocessorDefinitions);DEBUG_USE_KDPRINT + + + + + %(AdditionalIncludeDirectories);..\inc;..\..\inc;..\..\..\inc + %(PreprocessorDefinitions);DEBUG_USE_KDPRINT + + + + + %(AdditionalDependencies);$(DDK_LIB_PATH)\classpnp.lib + + + %(AdditionalIncludeDirectories);..\inc;..\..\inc;..\..\..\inc + %(PreprocessorDefinitions);DEBUG_USE_KDPRINT + + + %(AdditionalIncludeDirectories);..\inc;..\..\inc;..\..\..\inc + %(PreprocessorDefinitions);DEBUG_USE_KDPRINT + + + + + %(AdditionalIncludeDirectories);..\inc;..\..\inc;..\..\..\inc + %(PreprocessorDefinitions);DEBUG_USE_KDPRINT + + + + + %(AdditionalDependencies);$(DDK_LIB_PATH)\classpnp.lib + + + %(AdditionalIncludeDirectories);..\inc;..\..\inc;..\..\..\inc + %(PreprocessorDefinitions);DEBUG_USE_KDPRINT + + + %(AdditionalIncludeDirectories);..\inc;..\..\inc;..\..\..\inc + %(PreprocessorDefinitions);DEBUG_USE_KDPRINT + + + + + %(AdditionalIncludeDirectories);..\inc;..\..\inc;..\..\..\inc + %(PreprocessorDefinitions);DEBUG_USE_KDPRINT + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/storage/class/disk/src/disk.vcxproj.Filters b/storage/class/disk/src/disk.vcxproj.Filters new file mode 100644 index 00000000..7c1cdf7d --- /dev/null +++ b/storage/class/disk/src/disk.vcxproj.Filters @@ -0,0 +1,43 @@ + + + + + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* + {F46D90F7-048E-494E-B795-E7FE53BA14F3} + + + h;hpp;hxx;hm;inl;inc;xsd + {99D7E70D-CDF2-4F0C-A0DC-E296CCFD9C4D} + + + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml + {3C108ECD-99BB-4DF0-9937-B9E5541E1831} + + + inf;inv;inx;mof;mc; + {64085F1A-1949-4F74-A70E-5A1FB0584FD8} + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Resource Files + + + \ No newline at end of file diff --git a/storage/class/disk/src/diskdev.inf b/storage/class/disk/src/diskdev.inf new file mode 100644 index 00000000..78bea6a4 --- /dev/null +++ b/storage/class/disk/src/diskdev.inf @@ -0,0 +1,113 @@ +; disk.inf +; +; Installation inf for the Disk drive adapter. +; +; SAMPLE INF File for Class Driver +; FOR DDK - Driver Development Kit +; +; (c) Copyright 1999 Microsoft Corp. +; + +[Version] +Signature="$Windows NT$" +Provider=%MS% +ClassGUID={4d36e967-e325-11ce-bfc1-08002be10318} +Class=DiskDrive +DriverVer=08/27/1999,5.2.1425.0 +;CatalogFile=your_cat_here.cat ; Supply your own catalog file here. + +[DestinationDirs] +DefaultDestDir = 12 + +; +; Driver information +; + +[Manufacturer] +%MS% = MS.Mfg, NTx86, NTia64, NTamd64 + +[MS.Mfg.NTx86] +%MS.DeviceDesc0% = disk, GenDisk +%MS.DeviceDesc1% = disk, GenOptical + +[MS.Mfg.NTia64] +%MS.DeviceDesc0% = disk, GenDisk +%MS.DeviceDesc1% = disk, GenOptical + +[MS.Mfg.NTamd64] +%MS.DeviceDesc0% = disk, GenDisk +%MS.DeviceDesc1% = disk, GenOptical + + +; +; General installation section +; + +[disk.NT] +CopyFiles=disk.CopyFiles + +; +; File sections +; + +[disk.CopyFiles] +disk.sys + + +; +; Service Installation +; + +[disk.NT.Services] +AddService = disk, 0x00000002 , disk_Service_Inst + +[disk_Service_Inst] +DisplayName = %disk.SvcDesc% +ServiceType = 1 ; SERVICE_KERNEL_DRIVER +StartType = 0 ; SERVICE_SYSTEM_START +ErrorControl = 1 ; SERVICE_ERROR_NORMAL +LoadOrderGroup = SCSI Class +ServiceBinary = %12%\disk.sys + + +; +; Source file information +; + +[SourceDisksNames.x86] +1 = %DiskId1%,,,\i386 + +[SourceDisksNames.ia64] +1 = %DiskId1%,,,\ia64 + +[SourceDisksNames.amd64] +1 = %DiskId1%,,,\amd64 + +[SourceDisksFiles] +; Files for disk Microsoft Corp. Installation Disk #1 (DiskDrive) +disk.sys = 1,, + + +[Strings] + +; +; Non-Localizable Strings +; + +REG_SZ = 0x00000000 +REG_MULTI_SZ = 0x00010000 +REG_EXPAND_SZ = 0x00020000 +REG_BINARY = 0x00000001 +REG_DWORD = 0x00010001 +SERVICEROOT = "System\CurrentControlSet\Services" + +; +; Localizable Strings +; + +MS.DeviceDesc0 = "Disk drive" +MS.DeviceDesc1 = "Optical disk drive" +DiskId1 = "Microsoft Corp. Installation Disk #1 (DiskDrive)" +MS = "Microsoft Corp." +disk.SvcDesc="Disk Drive" + diff --git a/storage/class/disk/src/diskwmi.c b/storage/class/disk/src/diskwmi.c new file mode 100644 index 00000000..c1a0945e --- /dev/null +++ b/storage/class/disk/src/diskwmi.c @@ -0,0 +1,3501 @@ +/*++ + +Copyright (C) Microsoft Corporation, 1991 - 2010 + +Module Name: + + diskwmi.c + +Abstract: + + SCSI disk class driver - WMI support routines + +Environment: + + kernel mode only + +Notes: + +Revision History: + +--*/ + +#include "disk.h" + +#ifdef DEBUG_USE_WPP +#include "diskwmi.tmh" +#endif + +NTSTATUS +DiskSendFailurePredictIoctl( + PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, + PSTORAGE_PREDICT_FAILURE checkFailure + ); + +NTSTATUS +DiskGetIdentifyInfo( + PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, + PBOOLEAN SupportSmart + ); + +NTSTATUS +DiskDetectFailurePrediction( + PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, + PFAILURE_PREDICTION_METHOD FailurePredictCapability, + BOOLEAN ScsiAddressAvailable + ); + +NTSTATUS +DiskReadFailurePredictThresholds( + PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, + PSTORAGE_FAILURE_PREDICT_THRESHOLDS DiskSmartThresholds + ); + +NTSTATUS +DiskReadSmartLog( + IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, + IN UCHAR SectorCount, + IN UCHAR LogAddress, + OUT PUCHAR Buffer + ); + +NTSTATUS +DiskWriteSmartLog( + IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, + IN UCHAR SectorCount, + IN UCHAR LogAddress, + IN PUCHAR Buffer + ); + +IO_WORKITEM_ROUTINE DiskReregWorker; + +IO_COMPLETION_ROUTINE DiskInfoExceptionComplete; + +// +// WMI reregistration globals +// +// Since it will take too long to do a mode sense on some drive, we +// need a good way to effect the mode sense for the info exceptions +// mode page so that we can determine if SMART is supported and enabled +// for the drive. So the strategy is to do an asynchronous mode sense +// when the device starts and then look at the info exceptions mode +// page within the completion routine. Now within the completion +// routine we cannot call IoWMIRegistrationControl since we are at DPC +// level, so we create a stack of device objects that will be processed +// by a single work item that is fired off only when the stack +// transitions from empty to non empty. +// +SINGLE_LIST_ENTRY DiskReregHead; +KSPIN_LOCK DiskReregSpinlock; +LONG DiskReregWorkItems; + +GUIDREGINFO DiskWmiFdoGuidList[] = +{ + { + WMI_DISK_GEOMETRY_GUID, + 1, + 0 + }, + + { + WMI_STORAGE_FAILURE_PREDICT_STATUS_GUID, + 1, + WMIREG_FLAG_EXPENSIVE + }, + + { + WMI_STORAGE_FAILURE_PREDICT_DATA_GUID, + 1, + WMIREG_FLAG_EXPENSIVE + }, + + { + WMI_STORAGE_FAILURE_PREDICT_FUNCTION_GUID, + 1, + WMIREG_FLAG_EXPENSIVE + }, + + { + WMI_STORAGE_PREDICT_FAILURE_EVENT_GUID, + 1, + WMIREG_FLAG_EVENT_ONLY_GUID + }, + + { + WMI_STORAGE_FAILURE_PREDICT_THRESHOLDS_GUID, + 1, + WMIREG_FLAG_EXPENSIVE + }, + + { + WMI_STORAGE_SCSI_INFO_EXCEPTIONS_GUID, + 1, + 0 + } +}; + + +GUID DiskPredictFailureEventGuid = WMI_STORAGE_PREDICT_FAILURE_EVENT_GUID; + +#define DiskGeometryGuid 0 +#define SmartStatusGuid 1 +#define SmartDataGuid 2 +#define SmartPerformFunction 3 + #define AllowDisallowPerformanceHit 1 + #define EnableDisableHardwareFailurePrediction 2 + #define EnableDisableFailurePredictionPolling 3 + #define GetFailurePredictionCapability 4 + #define EnableOfflineDiags 5 + +#define SmartEventGuid 4 +#define SmartThresholdsGuid 5 +#define ScsiInfoExceptionsGuid 6 + +#ifdef ALLOC_PRAGMA + +#pragma alloc_text(PAGE, DiskWmiFunctionControl) +#pragma alloc_text(PAGE, DiskFdoQueryWmiRegInfo) +#pragma alloc_text(PAGE, DiskFdoQueryWmiDataBlock) +#pragma alloc_text(PAGE, DiskFdoSetWmiDataBlock) +#pragma alloc_text(PAGE, DiskFdoSetWmiDataItem) +#pragma alloc_text(PAGE, DiskFdoExecuteWmiMethod) + +#pragma alloc_text(PAGE, DiskDetectFailurePrediction) +#pragma alloc_text(PAGE, DiskEnableDisableFailurePrediction) +#pragma alloc_text(PAGE, DiskEnableDisableFailurePredictPolling) +#pragma alloc_text(PAGE, DiskReadFailurePredictStatus) +#pragma alloc_text(PAGE, DiskReadFailurePredictData) +#pragma alloc_text(PAGE, DiskReadFailurePredictThresholds) +#pragma alloc_text(PAGE, DiskGetIdentifyInfo) +#pragma alloc_text(PAGE, DiskReadSmartLog) +#pragma alloc_text(PAGE, DiskWriteSmartLog) +#pragma alloc_text(PAGE, DiskPerformSmartCommand) +#pragma alloc_text(PAGE, DiskSendFailurePredictIoctl) +#pragma alloc_text(PAGE, DiskReregWorker) +#pragma alloc_text(PAGE, DiskInitializeReregistration) + +#if (NTDDI_VERSION >= NTDDI_WINBLUE) +#pragma alloc_text(PAGE, DiskGetModePage) +#pragma alloc_text(PAGE, DiskEnableInfoExceptions) +#endif // (NTDDI_VERSION >= NTDDI_WINBLUE) + +#endif + + +// +// Note: +// Some port drivers assume that the SENDCMDINPARAMS structure will always be atleast +// sizeof(SENDCMDINPARAMS). So do not adjust for the [pBuffer] if it isn't being used +// + +// +// SMART/IDE specific routines +// + +// +// Read SMART data attributes. +// SrbControl should be : sizeof(SRB_IO_CONTROL) + MAX[ sizeof(SENDCMDINPARAMS), sizeof(SENDCMDOUTPARAMS) - 1 + READ_ATTRIBUTE_BUFFER_SIZE ] +// Attribute data returned at &SendCmdOutParams->bBuffer[0] +// +#define DiskReadSmartData(FdoExtension, \ + SrbControl, \ + BufferSize) \ + DiskPerformSmartCommand(FdoExtension, \ + IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS, \ + SMART_CMD, \ + READ_ATTRIBUTES, \ + 0, \ + 0, \ + (SrbControl), \ + (BufferSize)) + + +// +// Read SMART data thresholds. +// SrbControl should be : sizeof(SRB_IO_CONTROL) + MAX[ sizeof(SENDCMDINPARAMS), sizeof(SENDCMDOUTPARAMS) - 1 + READ_THRESHOLD_BUFFER_SIZE ] +// Attribute data returned at &SendCmdOutParams->bBuffer[0] +// +#define DiskReadSmartThresholds(FdoExtension, \ + SrbControl, \ + BufferSize) \ + DiskPerformSmartCommand(FdoExtension, \ + IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS, \ + SMART_CMD, \ + READ_THRESHOLDS, \ + 0, \ + 0, \ + (SrbControl), \ + (BufferSize)) + + +// +// Read SMART status +// SrbControl should be : sizeof(SRB_IO_CONTROL) + MAX[ sizeof(SENDCMDINPARAMS), sizeof(SENDCMDOUTPARAMS) - 1 + sizeof(IDEREGS) ] +// Failure predicted if SendCmdOutParams->bBuffer[3] == 0xf4 and SendCmdOutParams->bBuffer[4] == 0x2c +// +#define DiskReadSmartStatus(FdoExtension, \ + SrbControl, \ + BufferSize) \ + DiskPerformSmartCommand(FdoExtension, \ + IOCTL_SCSI_MINIPORT_RETURN_STATUS, \ + SMART_CMD, \ + RETURN_SMART_STATUS, \ + 0, \ + 0, \ + (SrbControl), \ + (BufferSize)) + + +// +// Read disks IDENTIFY data +// SrbControl should be : sizeof(SRB_IO_CONTROL) + MAX[ sizeof(SENDCMDINPARAMS), sizeof(SENDCMDOUTPARAMS) - 1 + IDENTIFY_BUFFER_SIZE ] +// Identify data returned at &SendCmdOutParams->bBuffer[0] +// +#define DiskGetIdentifyData(FdoExtension, \ + SrbControl, \ + BufferSize) \ + DiskPerformSmartCommand(FdoExtension, \ + IOCTL_SCSI_MINIPORT_IDENTIFY, \ + ID_CMD, \ + 0, \ + 0, \ + 0, \ + (SrbControl), \ + (BufferSize)) + + +// +// Enable SMART +// +_inline NTSTATUS +DiskEnableSmart( + PFUNCTIONAL_DEVICE_EXTENSION FdoExtension + ) +{ + UCHAR srbControl[sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS)] = {0}; + ULONG bufferSize = sizeof(srbControl); + + return DiskPerformSmartCommand(FdoExtension, + IOCTL_SCSI_MINIPORT_ENABLE_SMART, + SMART_CMD, + ENABLE_SMART, + 0, + 0, + (PSRB_IO_CONTROL)srbControl, + &bufferSize); +} + + +// +// Disable SMART +// +_inline NTSTATUS +DiskDisableSmart( + PFUNCTIONAL_DEVICE_EXTENSION FdoExtension + ) +{ + UCHAR srbControl[sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS)] = {0}; + ULONG bufferSize = sizeof(srbControl); + + return DiskPerformSmartCommand(FdoExtension, + IOCTL_SCSI_MINIPORT_DISABLE_SMART, + SMART_CMD, + DISABLE_SMART, + 0, + 0, + (PSRB_IO_CONTROL)srbControl, + &bufferSize); +} + + +// +// Enable Attribute Autosave +// +_inline NTSTATUS +DiskEnableSmartAttributeAutosave( + PFUNCTIONAL_DEVICE_EXTENSION FdoExtension + ) +{ + UCHAR srbControl[sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS)] = {0}; + ULONG bufferSize = sizeof(srbControl); + + return DiskPerformSmartCommand(FdoExtension, + IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE, + SMART_CMD, + ENABLE_DISABLE_AUTOSAVE, + 0xf1, + 0, + (PSRB_IO_CONTROL)srbControl, + &bufferSize); +} + + +// +// Disable Attribute Autosave +// +_inline NTSTATUS +DiskDisableSmartAttributeAutosave( + PFUNCTIONAL_DEVICE_EXTENSION FdoExtension + ) +{ + UCHAR srbControl[sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS)] = {0}; + ULONG bufferSize = sizeof(srbControl); + + return DiskPerformSmartCommand(FdoExtension, + IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE, + SMART_CMD, + ENABLE_DISABLE_AUTOSAVE, + 0x00, + 0, + (PSRB_IO_CONTROL)srbControl, + &bufferSize); +} + + +// +// Initialize execution of SMART online diagnostics +// +_inline NTSTATUS +DiskExecuteSmartDiagnostics( + PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, + UCHAR Subcommand + ) +{ + UCHAR srbControl[sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS)] = {0}; + ULONG bufferSize = sizeof(srbControl); + + return DiskPerformSmartCommand(FdoExtension, + IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS, + SMART_CMD, + EXECUTE_OFFLINE_DIAGS, + 0, + Subcommand, + (PSRB_IO_CONTROL)srbControl, + &bufferSize); +} + + +NTSTATUS +DiskReadSmartLog( + IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, + IN UCHAR SectorCount, + IN UCHAR LogAddress, + OUT PUCHAR Buffer + ) +{ + PSRB_IO_CONTROL srbControl; + NTSTATUS status; + PSENDCMDOUTPARAMS sendCmdOutParams; + ULONG logSize, bufferSize; + + PAGED_CODE(); + + logSize = SectorCount * SMART_LOG_SECTOR_SIZE; + bufferSize = sizeof(SRB_IO_CONTROL) + max( sizeof(SENDCMDINPARAMS), sizeof(SENDCMDOUTPARAMS) - 1 + logSize ); + + srbControl = ExAllocatePoolWithTag(NonPagedPoolNx, + bufferSize, + DISK_TAG_SMART); + + if (srbControl != NULL) + { + status = DiskPerformSmartCommand(FdoExtension, + IOCTL_SCSI_MINIPORT_READ_SMART_LOG, + SMART_CMD, + SMART_READ_LOG, + SectorCount, + LogAddress, + srbControl, + &bufferSize); + + if (NT_SUCCESS(status)) + { + sendCmdOutParams = (PSENDCMDOUTPARAMS)((PUCHAR)srbControl + + sizeof(SRB_IO_CONTROL)); + RtlCopyMemory(Buffer, + &sendCmdOutParams->bBuffer[0], + logSize); + } + + FREE_POOL(srbControl); + } else { + status = STATUS_INSUFFICIENT_RESOURCES; + } + return(status); +} + + +NTSTATUS +DiskWriteSmartLog( + IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, + IN UCHAR SectorCount, + IN UCHAR LogAddress, + IN PUCHAR Buffer + ) +{ + PSRB_IO_CONTROL srbControl; + NTSTATUS status; + PSENDCMDINPARAMS sendCmdInParams; + ULONG logSize, bufferSize; + + PAGED_CODE(); + + logSize = SectorCount * SMART_LOG_SECTOR_SIZE; + bufferSize = sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS) - 1 + + logSize; + + srbControl = ExAllocatePoolWithTag(NonPagedPoolNx, + bufferSize, + DISK_TAG_SMART); + + if (srbControl != NULL) + { + sendCmdInParams = (PSENDCMDINPARAMS)((PUCHAR)srbControl + + sizeof(SRB_IO_CONTROL)); + RtlCopyMemory(&sendCmdInParams->bBuffer[0], + Buffer, + logSize); + status = DiskPerformSmartCommand(FdoExtension, + IOCTL_SCSI_MINIPORT_WRITE_SMART_LOG, + SMART_CMD, + SMART_WRITE_LOG, + SectorCount, + LogAddress, + srbControl, + &bufferSize); + + FREE_POOL(srbControl); + } else { + status = STATUS_INSUFFICIENT_RESOURCES; + } + return(status); +} + + +NTSTATUS +DiskPerformSmartCommand( + IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, + IN ULONG SrbControlCode, + IN UCHAR Command, + IN UCHAR Feature, + IN UCHAR SectorCount, + IN UCHAR SectorNumber, + IN OUT PSRB_IO_CONTROL SrbControl, + OUT PULONG BufferSize + ) +/*++ + +Routine Description: + + This routine will perform some SMART command + +Arguments: + + FdoExtension is the FDO device extension + + SrbControlCode is the SRB control code to use for the request + + Command is the SMART command to be executed. It may be SMART_CMD or + ID_CMD. + + Feature is the value to place in the IDE feature register. + + SectorCount is the value to place in the IDE SectorCount register + + SrbControl is the buffer used to build the SRB_IO_CONTROL and pass + any input parameters. It also returns the output parameters. + + *BufferSize on entry has total size of SrbControl and on return has + the size used in SrbControl. + + + +Return Value: + + status + +--*/ +{ + PCOMMON_DEVICE_EXTENSION commonExtension = (PCOMMON_DEVICE_EXTENSION)FdoExtension; + PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData); + PUCHAR buffer; + PSENDCMDINPARAMS cmdInParameters; + NTSTATUS status; + ULONG availableBufferSize; + KEVENT event; + PIRP irp; + IO_STATUS_BLOCK ioStatus = { 0 }; + SCSI_REQUEST_BLOCK srb = {0}; + LARGE_INTEGER startingOffset; + ULONG length; + PIO_STACK_LOCATION irpStack; + UCHAR srbExBuffer[CLASS_SRBEX_NO_SRBEX_DATA_BUFFER_SIZE] = {0}; + PSTORAGE_REQUEST_BLOCK srbEx = (PSTORAGE_REQUEST_BLOCK)srbExBuffer; + PSTOR_ADDR_BTL8 storAddrBtl8; + + PAGED_CODE(); + + // + // Point to the 'buffer' portion of the SRB_CONTROL and compute how + // much room we have left in the srb control. Abort if the buffer + // isn't at least the size of SRB_IO_CONTROL. + // + + buffer = (PUCHAR)SrbControl + sizeof(SRB_IO_CONTROL); + + cmdInParameters = (PSENDCMDINPARAMS)buffer; + + if (*BufferSize >= sizeof(SRB_IO_CONTROL)) { + availableBufferSize = *BufferSize - sizeof(SRB_IO_CONTROL); + } else { + return STATUS_BUFFER_TOO_SMALL; + } + +#if DBG + + // + // Ensure control codes and buffer lengths passed are correct + // + { + ULONG controlCode = 0; + ULONG lengthNeeded = sizeof(SENDCMDINPARAMS); + + if (Command == SMART_CMD) + { + switch (Feature) + { + case ENABLE_SMART: + { + controlCode = IOCTL_SCSI_MINIPORT_ENABLE_SMART; + break; + } + + case DISABLE_SMART: + { + controlCode = IOCTL_SCSI_MINIPORT_DISABLE_SMART; + break; + } + + case RETURN_SMART_STATUS: + { + controlCode = IOCTL_SCSI_MINIPORT_RETURN_STATUS; + lengthNeeded = max( lengthNeeded, sizeof(SENDCMDOUTPARAMS) - 1 + sizeof(IDEREGS) ); + break; + } + + case ENABLE_DISABLE_AUTOSAVE: + { + controlCode = IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE; + break; + } + + case SAVE_ATTRIBUTE_VALUES: + { + controlCode = IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES; + break; + } + + + case EXECUTE_OFFLINE_DIAGS: + { + controlCode = IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS; + break; + } + + case READ_ATTRIBUTES: + { + controlCode = IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS; + lengthNeeded = max( lengthNeeded, sizeof(SENDCMDOUTPARAMS) - 1 + READ_ATTRIBUTE_BUFFER_SIZE ); + break; + } + + case READ_THRESHOLDS: + { + controlCode = IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS; + lengthNeeded = max( lengthNeeded, sizeof(SENDCMDOUTPARAMS) - 1 + READ_THRESHOLD_BUFFER_SIZE ); + break; + } + + case SMART_READ_LOG: + { + controlCode = IOCTL_SCSI_MINIPORT_READ_SMART_LOG; + lengthNeeded = max( lengthNeeded, sizeof(SENDCMDOUTPARAMS) - 1 + (SectorCount * SMART_LOG_SECTOR_SIZE) ); + break; + } + + case SMART_WRITE_LOG: + { + controlCode = IOCTL_SCSI_MINIPORT_WRITE_SMART_LOG; + lengthNeeded = lengthNeeded - 1 + (SectorCount * SMART_LOG_SECTOR_SIZE); + break; + } + + } + + } else if (Command == ID_CMD) { + + controlCode = IOCTL_SCSI_MINIPORT_IDENTIFY; + lengthNeeded = max( lengthNeeded, sizeof(SENDCMDOUTPARAMS) - 1 + IDENTIFY_BUFFER_SIZE ); + + } else { + + NT_ASSERT(FALSE); + } + + NT_ASSERT(controlCode == SrbControlCode); + NT_ASSERT(availableBufferSize >= lengthNeeded); + } + +#endif + + // + // Build SrbControl and input to SMART command + // + SrbControl->HeaderLength = sizeof(SRB_IO_CONTROL); + RtlMoveMemory (SrbControl->Signature, "SCSIDISK", 8); + SrbControl->Timeout = FdoExtension->TimeOutValue; + SrbControl->Length = availableBufferSize; + SrbControl->ControlCode = SrbControlCode; + + cmdInParameters->cBufferSize = sizeof(SENDCMDINPARAMS); + cmdInParameters->bDriveNumber = diskData->ScsiAddress.TargetId; + cmdInParameters->irDriveRegs.bFeaturesReg = Feature; + cmdInParameters->irDriveRegs.bSectorCountReg = SectorCount; + cmdInParameters->irDriveRegs.bSectorNumberReg = SectorNumber; + cmdInParameters->irDriveRegs.bCylLowReg = SMART_CYL_LOW; + cmdInParameters->irDriveRegs.bCylHighReg = SMART_CYL_HI; + cmdInParameters->irDriveRegs.bCommandReg = Command; + + // + // Create and send irp + // + KeInitializeEvent(&event, NotificationEvent, FALSE); + + startingOffset.QuadPart = (LONGLONG) 1; + + length = SrbControl->HeaderLength + SrbControl->Length; + + irp = IoBuildSynchronousFsdRequest( + IRP_MJ_SCSI, + commonExtension->LowerDeviceObject, + SrbControl, + length, + &startingOffset, + &event, + &ioStatus); + + if (irp == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + irpStack = IoGetNextIrpStackLocation(irp); + + // + // Set major and minor codes. + // + + irpStack->MajorFunction = IRP_MJ_SCSI; + irpStack->MinorFunction = 1; + + // + // Fill in SRB fields. + // + + if (FdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { + irpStack->Parameters.Others.Argument1 = srbEx; + + // + // Set up STORAGE_REQUEST_BLOCK fields + // + + srbEx->Length = FIELD_OFFSET(STORAGE_REQUEST_BLOCK, Signature); + srbEx->Function = SRB_FUNCTION_STORAGE_REQUEST_BLOCK; + srbEx->Signature = SRB_SIGNATURE; + srbEx->Version = STORAGE_REQUEST_BLOCK_VERSION_1; + srbEx->SrbLength = sizeof(srbExBuffer); + srbEx->SrbFunction = SRB_FUNCTION_IO_CONTROL; + srbEx->RequestPriority = IoGetIoPriorityHint(irp); + srbEx->AddressOffset = sizeof(STORAGE_REQUEST_BLOCK); + + srbEx->SrbFlags = FdoExtension->SrbFlags; + SET_FLAG(srbEx->SrbFlags, SRB_FLAGS_DATA_IN); + SET_FLAG(srbEx->SrbFlags, SRB_FLAGS_NO_QUEUE_FREEZE); + SET_FLAG(srbEx->SrbFlags, SRB_FLAGS_NO_KEEP_AWAKE); + + srbEx->RequestAttribute = SRB_SIMPLE_TAG_REQUEST; + srbEx->RequestTag = SP_UNTAGGED; + + srbEx->OriginalRequest = irp; + + // + // Set timeout to requested value. + // + + srbEx->TimeOutValue = SrbControl->Timeout; + + // + // Set the data buffer. + // + + srbEx->DataBuffer = SrbControl; + srbEx->DataTransferLength = length; + + // + // Set up address fields + // + + storAddrBtl8 = (PSTOR_ADDR_BTL8) ((PUCHAR)srbEx + srbEx->AddressOffset); + storAddrBtl8->Type = STOR_ADDRESS_TYPE_BTL8; + storAddrBtl8->AddressLength = STOR_ADDR_BTL8_ADDRESS_LENGTH; + storAddrBtl8->Path = diskData->ScsiAddress.PathId; + storAddrBtl8->Target = diskData->ScsiAddress.TargetId; + storAddrBtl8->Lun = srb.Lun = diskData->ScsiAddress.Lun; + + } else { + irpStack->Parameters.Others.Argument1 = &srb; + + srb.PathId = diskData->ScsiAddress.PathId; + srb.TargetId = diskData->ScsiAddress.TargetId; + srb.Lun = diskData->ScsiAddress.Lun; + + srb.Function = SRB_FUNCTION_IO_CONTROL; + srb.Length = sizeof(SCSI_REQUEST_BLOCK); + + srb.SrbFlags = FdoExtension->SrbFlags; + SET_FLAG(srb.SrbFlags, SRB_FLAGS_DATA_IN); + SET_FLAG(srb.SrbFlags, SRB_FLAGS_NO_QUEUE_FREEZE); + SET_FLAG(srb.SrbFlags, SRB_FLAGS_NO_KEEP_AWAKE); + + srb.QueueAction = SRB_SIMPLE_TAG_REQUEST; + srb.QueueTag = SP_UNTAGGED; + + srb.OriginalRequest = irp; + + // + // Set timeout to requested value. + // + + srb.TimeOutValue = SrbControl->Timeout; + + // + // Set the data buffer. + // + + srb.DataBuffer = SrbControl; + srb.DataTransferLength = length; + } + + // + // Flush the data buffer for output. This will insure that the data is + // written back to memory. Since the data-in flag is the the port driver + // will flush the data again for input which will ensure the data is not + // in the cache. + // + + KeFlushIoBuffers(irp->MdlAddress, FALSE, TRUE); + + // + // Call port driver to handle this request. + // + + status = IoCallDriver(commonExtension->LowerDeviceObject, irp); + + if (status == STATUS_PENDING) { + KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL); + status = ioStatus.Status; + } + + return status; +} + + +NTSTATUS +DiskGetIdentifyInfo( + PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, + PBOOLEAN SupportSmart + ) +{ + UCHAR outBuffer[sizeof(SRB_IO_CONTROL) + max( sizeof(SENDCMDINPARAMS), sizeof(SENDCMDOUTPARAMS) - 1 + IDENTIFY_BUFFER_SIZE )] = {0}; + ULONG outBufferSize = sizeof(outBuffer); + NTSTATUS status; + + PAGED_CODE(); + + status = DiskGetIdentifyData(FdoExtension, + (PSRB_IO_CONTROL)outBuffer, + &outBufferSize); + + if (NT_SUCCESS(status)) + { + PUSHORT identifyData = (PUSHORT)&(outBuffer[sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDOUTPARAMS) - 1]); + USHORT commandSetSupported = identifyData[82]; + + *SupportSmart = ((commandSetSupported != 0xffff) && + (commandSetSupported != 0) && + ((commandSetSupported & 1) == 1)); + } else { + *SupportSmart = FALSE; + } + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskGetIdentifyInfo: SMART %s supported for device %p, status %lx\n", + *SupportSmart ? "is" : "is not", + FdoExtension->DeviceObject, + status)); + + return status; +} + + +// +// FP Ioctl specific routines +// + +NTSTATUS +DiskSendFailurePredictIoctl( + PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, + PSTORAGE_PREDICT_FAILURE checkFailure + ) +{ + KEVENT event; + PDEVICE_OBJECT deviceObject; + IO_STATUS_BLOCK ioStatus = { 0 }; + PIRP irp; + NTSTATUS status; + + PAGED_CODE(); + + KeInitializeEvent(&event, SynchronizationEvent, FALSE); + + deviceObject = IoGetAttachedDeviceReference(FdoExtension->DeviceObject); + + irp = IoBuildDeviceIoControlRequest( + IOCTL_STORAGE_PREDICT_FAILURE, + deviceObject, + NULL, + 0, + checkFailure, + sizeof(STORAGE_PREDICT_FAILURE), + FALSE, + &event, + &ioStatus); + + if (irp != NULL) + { + status = IoCallDriver(deviceObject, irp); + if (status == STATUS_PENDING) + { + KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL); + status = ioStatus.Status; + } + + } else { + status = STATUS_INSUFFICIENT_RESOURCES; + } + + ObDereferenceObject(deviceObject); + + return status; +} + +#if (NTDDI_VERSION >= NTDDI_WINBLUE) + +NTSTATUS +DiskGetModePage( + _In_ PDEVICE_OBJECT Fdo, + _In_ UCHAR PageMode, + _In_ UCHAR PageControl, + _In_ PMODE_PARAMETER_HEADER ModeData, + _Inout_ PULONG ModeDataSize, + _Out_ PVOID* PageData + ) +{ + ULONG size = 0; + PVOID pageData = NULL; + + PAGED_CODE(); + + if (ModeData == NULL || + ModeDataSize == NULL || + *ModeDataSize < sizeof(MODE_PARAMETER_HEADER) || + PageData == NULL) { + return STATUS_INVALID_PARAMETER; + } + + RtlZeroMemory (ModeData, *ModeDataSize); + + size = ClassModeSenseEx(Fdo, + (PCHAR) ModeData, + *ModeDataSize, + PageMode, + PageControl); + + if (size < sizeof(MODE_PARAMETER_HEADER)) { + + // + // Retry the request in case of a check condition. + // + size = ClassModeSenseEx(Fdo, + (PCHAR) ModeData, + *ModeDataSize, + PageMode, + PageControl); + + if (size < sizeof(MODE_PARAMETER_HEADER)) { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DiskGetModePage: Mode Sense for Page Mode %d with Page Control %d failed\n", + PageMode, PageControl)); + *ModeDataSize = 0; + return STATUS_IO_DEVICE_ERROR; + } + } + + // + // If the length is greater than length indicated by the mode data reset + // the data to the mode data. + // + if (size > (ULONG) (ModeData->ModeDataLength + 1)) { + size = ModeData->ModeDataLength + 1; + } + + *ModeDataSize = size; + + // + // Find the mode page + // + pageData = ClassFindModePage((PCHAR) ModeData, + size, + PageMode, + TRUE); + + if (pageData) { + *PageData = pageData; + return STATUS_SUCCESS; + } else { + *PageData = NULL; + return STATUS_NOT_SUPPORTED; + } +} + +NTSTATUS +DiskEnableInfoExceptions( + _In_ PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, + _In_ BOOLEAN Enable + ) +{ + PDISK_DATA diskData = (PDISK_DATA)(FdoExtension->CommonExtension.DriverData); + NTSTATUS status = STATUS_NOT_SUPPORTED; + PMODE_PARAMETER_HEADER modeData; + PMODE_INFO_EXCEPTIONS pageData; + MODE_INFO_EXCEPTIONS changeablePageData; + ULONG modeDataSize; + + PAGED_CODE(); + + modeDataSize = MODE_DATA_SIZE; + + modeData = ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned, + modeDataSize, + DISK_TAG_INFO_EXCEPTION); + + if (modeData == NULL) { + + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DiskEnableInfoExceptions: Unable to allocate mode " + "data buffer\n")); + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // First see which data is actually changeable. + // + status = DiskGetModePage(FdoExtension->DeviceObject, + MODE_PAGE_FAULT_REPORTING, + 1, // Page Control = 1 indicates we want changeable values. + modeData, + &modeDataSize, + (PVOID*)&pageData); + + if (!NT_SUCCESS(status) || pageData == NULL) { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_WMI, "DiskEnableInfoExceptions: does NOT support SMART for device %p\n", + FdoExtension->DeviceObject)); + FREE_POOL(modeData); + return STATUS_NOT_SUPPORTED; + } + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_WMI, "DiskEnableInfoExceptions: DOES support SMART for device %p\n", + FdoExtension->DeviceObject)); + + // + // At the very least, the DEXCPT bit must be changeable. + // If it's not, bail out now. + // + if (pageData->Dexcpt == 0) { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_WMI, "DiskEnableInfoExceptions: does NOT support DEXCPT bit for device %p\n", + FdoExtension->DeviceObject)); + FREE_POOL(modeData); + return STATUS_NOT_SUPPORTED; + } + + // + // Cache away which values are changeable. + // + RtlCopyMemory(&changeablePageData, pageData, sizeof(MODE_INFO_EXCEPTIONS)); + + // + // Now get the current values. + // + status = DiskGetModePage(FdoExtension->DeviceObject, + MODE_PAGE_FAULT_REPORTING, + 0, // Page Control = 0 indicates we want current values. + modeData, + &modeDataSize, + (PVOID*)&pageData); + + if (!NT_SUCCESS(status) || pageData == NULL) { + // + // At this point we know the device supports this mode page so + // assert if something goes wrong here. + // + NT_ASSERT(NT_SUCCESS(status) && pageData); + FREE_POOL(modeData); + return STATUS_NOT_SUPPORTED; + } + + // + // If the device is currently configured to not report any informational + // exceptions and we cannot change the value of that field, there's + // nothing to be done. + // + if (pageData->ReportMethod == 0 && changeablePageData.ReportMethod == 0) { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_WMI, "DiskEnableInfoExceptions: MRIE field is 0 and is not changeable for device %p\n", + FdoExtension->DeviceObject)); + FREE_POOL(modeData); + return STATUS_NOT_SUPPORTED; + } + + // + // If the PERF bit is changeable, set it now. + // + if (changeablePageData.Perf) { + pageData->Perf = diskData->AllowFPPerfHit ? 0 : 1; + } + + // + // If the MRIE field is changeable, set it to 4 so that informational + // exceptions get reported with the "Recovered Error" sense key. + // + if (changeablePageData.ReportMethod) { + pageData->ReportMethod = 4; + } + + // + // Finally, set the DEXCPT bit appropriately to enable/disable + // informational exception reporting and send the Mode Select. + // + pageData->Dexcpt = !Enable; + + status = ClassModeSelect(FdoExtension->DeviceObject, + (PCHAR)modeData, + modeDataSize, + pageData->PSBit); + + // + // Update the failure prediction state. Note that for this particular + // mode FailurePredictionNone is used when it's not enabled. + // + if (NT_SUCCESS(status)) { + if (Enable) { + diskData->FailurePredictionCapability = FailurePredictionSense; + diskData->FailurePredictionEnabled = TRUE; + } else { + diskData->FailurePredictionCapability = FailurePredictionNone; + diskData->FailurePredictionEnabled = FALSE; + } + } + + FREE_POOL(modeData); + + return status; +} +#endif + + +// +// FP type independent routines +// + +NTSTATUS +DiskEnableDisableFailurePrediction( + PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, + BOOLEAN Enable + ) +/*++ + +Routine Description: + + Enable or disable failure prediction at the hardware level + +Arguments: + + FdoExtension + + Enable + +Return Value: + + NT Status + +--*/ +{ + NTSTATUS status; + PCOMMON_DEVICE_EXTENSION commonExtension = &(FdoExtension->CommonExtension); + PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData); + + PAGED_CODE(); + + switch(diskData->FailurePredictionCapability) + { + case FailurePredictionSmart: + { + if (Enable) + { + status = DiskEnableSmart(FdoExtension); + } else { + status = DiskDisableSmart(FdoExtension); + } + + if (NT_SUCCESS(status)) { + diskData->FailurePredictionEnabled = Enable; + } + + break; + } + + case FailurePredictionSense: + case FailurePredictionIoctl: + { + // + // We assume that the drive is already setup properly for + // failure prediction + // + status = STATUS_SUCCESS; + break; + } + + default: + { + status = STATUS_INVALID_DEVICE_REQUEST; + } + } + return status; +} + + +NTSTATUS +DiskEnableDisableFailurePredictPolling( + PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, + BOOLEAN Enable, + ULONG PollTimeInSeconds + ) +/*++ + +Routine Description: + + Enable or disable polling for hardware failure detection + +Arguments: + + FdoExtension + + Enable + + PollTimeInSeconds - if 0 then no change to current polling timer + +Return Value: + + NT Status + +--*/ +{ + NTSTATUS status; + PCOMMON_DEVICE_EXTENSION commonExtension = (PCOMMON_DEVICE_EXTENSION)FdoExtension; + PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData); + + PAGED_CODE(); + + if (Enable) + { + status = DiskEnableDisableFailurePrediction(FdoExtension, + Enable); + } else { + status = STATUS_SUCCESS; + } + + if (NT_SUCCESS(status)) + { + status = ClassSetFailurePredictionPoll(FdoExtension, + Enable ? diskData->FailurePredictionCapability : + FailurePredictionNone, + PollTimeInSeconds); + + // + // Even if this failed we do not want to disable FP on the + // hardware. FP is only ever disabled on the hardware by + // specific command of the user. + // + } + + return status; +} + + +NTSTATUS +DiskReadFailurePredictStatus( + PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, + PSTORAGE_FAILURE_PREDICT_STATUS DiskSmartStatus + ) +/*++ + +Routine Description: + + Obtains current failure prediction status + +Arguments: + + FdoExtension + + DiskSmartStatus + +Return Value: + + NT Status + +--*/ +{ + PCOMMON_DEVICE_EXTENSION commonExtension = (PCOMMON_DEVICE_EXTENSION)FdoExtension; + PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData); + NTSTATUS status; + + PAGED_CODE(); + + DiskSmartStatus->PredictFailure = FALSE; + + switch(diskData->FailurePredictionCapability) + { + case FailurePredictionSmart: + { + UCHAR outBuffer[sizeof(SRB_IO_CONTROL) + max( sizeof(SENDCMDINPARAMS), sizeof(SENDCMDOUTPARAMS) - 1 + sizeof(IDEREGS) )] = {0}; + ULONG outBufferSize = sizeof(outBuffer); + PSENDCMDOUTPARAMS cmdOutParameters; + + status = DiskReadSmartStatus(FdoExtension, + (PSRB_IO_CONTROL)outBuffer, + &outBufferSize); + + if (NT_SUCCESS(status)) + { + cmdOutParameters = (PSENDCMDOUTPARAMS)(outBuffer + + sizeof(SRB_IO_CONTROL)); + + DiskSmartStatus->Reason = 0; // Unknown; + DiskSmartStatus->PredictFailure = ((cmdOutParameters->bBuffer[3] == 0xf4) && + (cmdOutParameters->bBuffer[4] == 0x2c)); + } + break; + } + + case FailurePredictionSense: + { + DiskSmartStatus->Reason = FdoExtension->FailureReason; + DiskSmartStatus->PredictFailure = FdoExtension->FailurePredicted; + status = STATUS_SUCCESS; + break; + } + + case FailurePredictionIoctl: + case FailurePredictionNone: + default: + { + status = STATUS_INVALID_DEVICE_REQUEST; + break; + } + } + + return status; +} + + +NTSTATUS +DiskReadFailurePredictData( + PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, + PSTORAGE_FAILURE_PREDICT_DATA DiskSmartData + ) +/*++ + +Routine Description: + + Obtains current failure prediction data. Not available for + FAILURE_PREDICT_SENSE types. + +Arguments: + + FdoExtension + + DiskSmartData + +Return Value: + + NT Status + +--*/ +{ + PCOMMON_DEVICE_EXTENSION commonExtension = (PCOMMON_DEVICE_EXTENSION)FdoExtension; + PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData); + NTSTATUS status; + + PAGED_CODE(); + + switch(diskData->FailurePredictionCapability) + { + case FailurePredictionSmart: + { + PUCHAR outBuffer; + ULONG outBufferSize; + PSENDCMDOUTPARAMS cmdOutParameters; + + outBufferSize = sizeof(SRB_IO_CONTROL) + max( sizeof(SENDCMDINPARAMS), sizeof(SENDCMDOUTPARAMS) - 1 + READ_ATTRIBUTE_BUFFER_SIZE ); + + outBuffer = ExAllocatePoolWithTag(NonPagedPoolNx, + outBufferSize, + DISK_TAG_SMART); + + if (outBuffer != NULL) + { + status = DiskReadSmartData(FdoExtension, + (PSRB_IO_CONTROL)outBuffer, + &outBufferSize); + + if (NT_SUCCESS(status)) + { + cmdOutParameters = (PSENDCMDOUTPARAMS)(outBuffer + + sizeof(SRB_IO_CONTROL)); + + DiskSmartData->Length = READ_ATTRIBUTE_BUFFER_SIZE; + RtlCopyMemory(DiskSmartData->VendorSpecific, + cmdOutParameters->bBuffer, + min(READ_ATTRIBUTE_BUFFER_SIZE, sizeof(DiskSmartData->VendorSpecific))); + } + FREE_POOL(outBuffer); + } else { + status = STATUS_INSUFFICIENT_RESOURCES; + } + + break; + } + + case FailurePredictionSense: + { + DiskSmartData->Length = sizeof(ULONG); + *((PULONG)DiskSmartData->VendorSpecific) = FdoExtension->FailureReason; + + status = STATUS_SUCCESS; + break; + } + + case FailurePredictionIoctl: + case FailurePredictionNone: + default: + { + status = STATUS_INVALID_DEVICE_REQUEST; + break; + } + } + + return status; +} + + +NTSTATUS +DiskReadFailurePredictThresholds( + PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, + PSTORAGE_FAILURE_PREDICT_THRESHOLDS DiskSmartThresholds + ) +/*++ + +Routine Description: + + Obtains current failure prediction thresholds. Not available for + FAILURE_PREDICT_SENSE types. + +Arguments: + + FdoExtension + + DiskSmartData + +Return Value: + + NT Status + +--*/ +{ + PCOMMON_DEVICE_EXTENSION commonExtension = (PCOMMON_DEVICE_EXTENSION)FdoExtension; + PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData); + NTSTATUS status; + + PAGED_CODE(); + + switch(diskData->FailurePredictionCapability) + { + case FailurePredictionSmart: + { + PUCHAR outBuffer; + PSENDCMDOUTPARAMS cmdOutParameters; + ULONG outBufferSize; + + outBufferSize = sizeof(SRB_IO_CONTROL) + max( sizeof(SENDCMDINPARAMS), sizeof(SENDCMDOUTPARAMS) - 1 + READ_THRESHOLD_BUFFER_SIZE ); + + outBuffer = ExAllocatePoolWithTag(NonPagedPoolNx, + outBufferSize, + DISK_TAG_SMART); + + if (outBuffer != NULL) + { + status = DiskReadSmartThresholds(FdoExtension, + (PSRB_IO_CONTROL)outBuffer, + &outBufferSize); + + if (NT_SUCCESS(status)) + { + cmdOutParameters = (PSENDCMDOUTPARAMS)(outBuffer + + sizeof(SRB_IO_CONTROL)); + + RtlCopyMemory(DiskSmartThresholds->VendorSpecific, + cmdOutParameters->bBuffer, + min(READ_THRESHOLD_BUFFER_SIZE, sizeof(DiskSmartThresholds->VendorSpecific))); + } + FREE_POOL(outBuffer); + } else { + status = STATUS_INSUFFICIENT_RESOURCES; + } + + break; + } + + case FailurePredictionSense: + case FailurePredictionIoctl: + case FailurePredictionNone: + default: + { + status = STATUS_INVALID_DEVICE_REQUEST; + break; + } + } + + return status; +} + + +VOID +DiskReregWorker( + IN PDEVICE_OBJECT DevObject, + IN PVOID Context + ) +{ + PDISKREREGREQUEST reregRequest; + NTSTATUS status; + PDEVICE_OBJECT deviceObject; + PIRP irp; + + PAGED_CODE(); + UNREFERENCED_PARAMETER(DevObject); + + NT_ASSERT(Context != NULL); + _Analysis_assume_(Context != NULL); + + do + { + reregRequest = (PDISKREREGREQUEST)ExInterlockedPopEntryList( + &DiskReregHead, + &DiskReregSpinlock); + + if (reregRequest != NULL) + { + deviceObject = reregRequest->DeviceObject; + irp = reregRequest->Irp; + + status = IoWMIRegistrationControl(deviceObject, + WMIREG_ACTION_UPDATE_GUIDS); + + // + // Release remove lock and free irp, now that we are done + // processing this + // + ClassReleaseRemoveLock(deviceObject, irp); + + IoFreeMdl(irp->MdlAddress); + IoFreeIrp(irp); + + FREE_POOL(reregRequest); + + } else { + + NT_ASSERTMSG("Disk Re-registration request list should not be empty", FALSE); + + status = STATUS_INTERNAL_ERROR; + } + + if (!NT_SUCCESS(status)) + { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskReregWorker: Reregistration failed %x\n", + status)); + } + + } while (InterlockedDecrement(&DiskReregWorkItems)); + + IoFreeWorkItem((PIO_WORKITEM)Context); +} + + +NTSTATUS +DiskInitializeReregistration( + VOID + ) +{ + PAGED_CODE(); + + // + // Initialize the spinlock used to manage the + // list of disks reregistering their guids + // + KeInitializeSpinLock(&DiskReregSpinlock); + + return(STATUS_SUCCESS); +} + + +NTSTATUS +DiskPostReregisterRequest( + PDEVICE_OBJECT DeviceObject, + PIRP Irp + ) +{ + PDISKREREGREQUEST reregRequest; + PIO_WORKITEM workItem; + NTSTATUS status; + + workItem = IoAllocateWorkItem(DeviceObject); + + if (!workItem) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + reregRequest = ExAllocatePoolWithTag(NonPagedPoolNx, + sizeof(DISKREREGREQUEST), + DISK_TAG_SMART); + if (reregRequest != NULL) + { + // + // add the disk that needs reregistration to the stack of disks + // to reregister. If the list is transitioning from empty to + // non empty then also kick off the work item so that the + // reregistration worker can do the reregister. + // + reregRequest->DeviceObject = DeviceObject; + reregRequest->Irp = Irp; + ExInterlockedPushEntryList( + &DiskReregHead, + &reregRequest->Next, + &DiskReregSpinlock); + + if (InterlockedIncrement(&DiskReregWorkItems) == 1) + { + // + // There is no worker routine running, queue this one. + // When the work item runs, it will process the reregistration + // list. + // + + IoQueueWorkItem(workItem, + DiskReregWorker, + DelayedWorkQueue, + workItem); + } else { + + // + // There is a worker routine already running, so we + // can free this unused work item. + // + + IoFreeWorkItem(workItem); + } + + status = STATUS_SUCCESS; + + } else { + + IoFreeWorkItem(workItem); + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskPostReregisterRequest: could not allocate reregRequest for %p\n", + DeviceObject)); + status = STATUS_INSUFFICIENT_RESOURCES; + } + + return(status); +} + + +NTSTATUS +DiskInfoExceptionComplete( + PDEVICE_OBJECT DeviceObject, + PIRP Irp, + PVOID Context + ) +{ + PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; + PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData); + PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); + PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp); + PSCSI_REQUEST_BLOCK srb = Context; + NTSTATUS status; + BOOLEAN retry; + ULONG retryInterval; + ULONG srbStatus; + BOOLEAN freeLockAndIrp = TRUE; + PVOID originalSenseInfoBuffer = irpStack->Parameters.Others.Argument3; + PSTORAGE_REQUEST_BLOCK srbEx = NULL; + PVOID dataBuffer = NULL; + ULONG dataLength = 0; + PVOID senseBuffer = NULL; + UCHAR cdbLength8 = 0; + ULONG cdbLength32 = 0; + UCHAR senseBufferLength = 0; + + srbStatus = SRB_STATUS(srb->SrbStatus); + + if (srb->Function == SRB_FUNCTION_STORAGE_REQUEST_BLOCK) { + srbEx = (PSTORAGE_REQUEST_BLOCK)srb; + dataBuffer = srbEx->DataBuffer; + dataLength = srbEx->DataTransferLength; + if ((srbEx->SrbFunction == SRB_FUNCTION_EXECUTE_SCSI) && + (srbEx->NumSrbExData > 0)) { + (void)GetSrbScsiData(srbEx, &cdbLength8, &cdbLength32, NULL, &senseBuffer, &senseBufferLength); + } + } else { + dataBuffer = srb->DataBuffer; + dataLength = srb->DataTransferLength; + senseBuffer = srb->SenseInfoBuffer; + } + + // + // Check SRB status for success of completing request. + // SRB_STATUS_DATA_OVERRUN also indicates success. + // + if ((srbStatus != SRB_STATUS_SUCCESS) && + (srbStatus != SRB_STATUS_DATA_OVERRUN)) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskInfoExceptionComplete: IRP %p, SRB %p\n", Irp, srb)); + + if (TEST_FLAG(srb->SrbStatus, SRB_STATUS_QUEUE_FROZEN)) + { + ClassReleaseQueue(DeviceObject); + } + + retry = ClassInterpretSenseInfo( + DeviceObject, + srb, + irpStack->MajorFunction, + 0, + MAXIMUM_RETRIES - + ((ULONG)(ULONG_PTR)irpStack->Parameters.Others.Argument4), + &status, + &retryInterval); + + // + // If the status is verified required and the this request + // should bypass verify required then retry the request. + // + + if (TEST_FLAG(irpStack->Flags, SL_OVERRIDE_VERIFY_VOLUME) && + status == STATUS_VERIFY_REQUIRED) + { + status = STATUS_IO_DEVICE_ERROR; + retry = TRUE; + } + + retry = retry && irpStack->Parameters.Others.Argument4; + + irpStack->Parameters.Others.Argument4 = (PVOID)((ULONG_PTR)irpStack->Parameters.Others.Argument4 - 1); + + if (retry) + { + // + // Retry request. + // + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskInfoExceptionComplete: Retry request %p\n", Irp)); + + NT_ASSERT(dataBuffer == MmGetMdlVirtualAddress(Irp->MdlAddress)); + + if (srb->Function == SRB_FUNCTION_STORAGE_REQUEST_BLOCK) { + + // + // Reset byte count of transfer in SRB Extension. + // + srbEx->DataTransferLength = Irp->MdlAddress->ByteCount; + + // + // Zero SRB statuses. + // + + srbEx->SrbStatus = 0; + if ((srbEx->SrbFunction == SRB_FUNCTION_EXECUTE_SCSI) && + (srbEx->NumSrbExData > 0)) { + SetSrbScsiData(srbEx, cdbLength8, cdbLength32, 0, senseBuffer, senseBufferLength); + } + + // + // Set the no disconnect flag, disable synchronous data transfers and + // disable tagged queuing. This fixes some errors. + // + + SET_FLAG(srbEx->SrbFlags, SRB_FLAGS_DISABLE_DISCONNECT); + SET_FLAG(srbEx->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER); + CLEAR_FLAG(srbEx->SrbFlags, SRB_FLAGS_QUEUE_ACTION_ENABLE); + + srbEx->RequestAttribute = SRB_SIMPLE_TAG_REQUEST; + srbEx->RequestTag = SP_UNTAGGED; + + } else { + + // + // Reset byte count of transfer in SRB Extension. + // + srb->DataTransferLength = Irp->MdlAddress->ByteCount; + + // + // Zero SRB statuses. + // + + srb->SrbStatus = srb->ScsiStatus = 0; + + // + // Set the no disconnect flag, disable synchronous data transfers and + // disable tagged queuing. This fixes some errors. + // + + SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_DISCONNECT); + SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER); + CLEAR_FLAG(srb->SrbFlags, SRB_FLAGS_QUEUE_ACTION_ENABLE); + + srb->QueueAction = SRB_SIMPLE_TAG_REQUEST; + srb->QueueTag = SP_UNTAGGED; + } + + // + // Set up major SCSI function. + // + + nextIrpStack->MajorFunction = IRP_MJ_SCSI; + + // + // Save SRB address in next stack for port driver. + // + + nextIrpStack->Parameters.Scsi.Srb = srb; + + + IoSetCompletionRoutine(Irp, + DiskInfoExceptionComplete, + srb, + TRUE, TRUE, TRUE); + + (VOID)IoCallDriver(commonExtension->LowerDeviceObject, Irp); + + return STATUS_MORE_PROCESSING_REQUIRED; + } + + } else { + + // + // Get the results from the mode sense + // + PMODE_INFO_EXCEPTIONS pageData; + PMODE_PARAMETER_HEADER modeData; + ULONG modeDataLength; + + modeData = dataBuffer; + modeDataLength = dataLength; + + pageData = ClassFindModePage((PCHAR)modeData, + modeDataLength, + MODE_PAGE_FAULT_REPORTING, + TRUE); + if (pageData != NULL) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_WMI, "DiskInfoExceptionComplete: %p supports SMART\n", + DeviceObject)); + + diskData->ScsiInfoExceptionsSupported = TRUE; + + // + // The DEXCPT bit must be 0 and the MRIE field must be valid. + // + if (pageData->Dexcpt == 0 && + pageData->ReportMethod >= 2 && + pageData->ReportMethod <= 6) + { + diskData->FailurePredictionCapability = FailurePredictionSense; + diskData->FailurePredictionEnabled = TRUE; + status = DiskPostReregisterRequest(DeviceObject, Irp); + + if (NT_SUCCESS(status)) + { + // + // Make sure we won't free the remove lock and the irp + // since we need to keep these until after the work + // item has completed running + // + freeLockAndIrp = FALSE; + } + } else { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_WMI, "DiskInfoExceptionComplete: %p is not enabled for SMART\n", + DeviceObject)); + + } + + } else { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_WMI, "DiskInfoExceptionComplete: %p does not supports SMART\n", + DeviceObject)); + + } + + // + // Set status for successful request + // + + status = STATUS_SUCCESS; + + } // end if (SRB_STATUS(srb->SrbStatus) == SRB_STATUS_SUCCESS) + + // + // Free the srb + // + if (senseBuffer != originalSenseInfoBuffer) + { + // + // Free the original sense info buffer in case the port driver has overwritten it + // + FREE_POOL(originalSenseInfoBuffer); + } + + FREE_POOL(senseBuffer); + FREE_POOL(dataBuffer); + FREE_POOL(srb); + + if (freeLockAndIrp) + { + // + // Set status in completing IRP. + // + + Irp->IoStatus.Status = status; + + // + // If pending has be returned for this irp then mark the current stack as + // pending. + // + + if (Irp->PendingReturned) { + IoMarkIrpPending(Irp); + } + + ClassReleaseRemoveLock(DeviceObject, Irp); + IoFreeMdl(Irp->MdlAddress); + IoFreeIrp(Irp); + } + + return(STATUS_MORE_PROCESSING_REQUIRED); +} + + +NTSTATUS +DiskInfoExceptionCheck( + PFUNCTIONAL_DEVICE_EXTENSION FdoExtension + ) +{ + PUCHAR modeData; + PSCSI_REQUEST_BLOCK srb; + PCDB cdb; + PIRP irp; + PIO_STACK_LOCATION irpStack; + PVOID senseInfoBuffer = NULL; + UCHAR senseInfoBufferLength = 0; + ULONG isRemoved; + ULONG srbSize; + PSTORAGE_REQUEST_BLOCK srbEx = NULL; + PSTOR_ADDR_BTL8 storAddrBtl8 = NULL; + PSRBEX_DATA_SCSI_CDB16 srbExDataCdb16 = NULL; + + modeData = ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned, + MODE_DATA_SIZE, + DISK_TAG_INFO_EXCEPTION); + if (modeData == NULL) + { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_WMI, "DiskInfoExceptionCheck: Can't allocate mode data " + "buffer\n")); + return(STATUS_INSUFFICIENT_RESOURCES); + } + + if (FdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { + srbSize = CLASS_SRBEX_SCSI_CDB16_BUFFER_SIZE; + } else { + srbSize = SCSI_REQUEST_BLOCK_SIZE; + } + srb = ExAllocatePoolWithTag(NonPagedPoolNx, + srbSize, + DISK_TAG_SRB); + if (srb == NULL) + { + FREE_POOL(modeData); + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_WMI, "DiskInfoExceptionCheck: Can't allocate srb " + "buffer\n")); + return(STATUS_INSUFFICIENT_RESOURCES); + } + RtlZeroMemory(srb, srbSize); + + // + // Sense buffer is in aligned nonpaged pool. + // + + senseInfoBuffer = ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned, + SENSE_BUFFER_SIZE_EX, + '7CcS'); + + if (senseInfoBuffer == NULL) + { + FREE_POOL(srb); + FREE_POOL(modeData); + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_WMI, "DiskInfoExceptionCheck: Can't allocate request sense " + "buffer\n")); + return(STATUS_INSUFFICIENT_RESOURCES); + } + + senseInfoBufferLength = SENSE_BUFFER_SIZE_EX; + + // + // Build device I/O control request with METHOD_NEITHER data transfer. + // We'll queue a completion routine to cleanup the MDL's and such ourself. + // + + irp = IoAllocateIrp( + (CCHAR) (FdoExtension->CommonExtension.LowerDeviceObject->StackSize + 1), + FALSE); + + if (irp == NULL) + { + FREE_POOL(senseInfoBuffer); + FREE_POOL(srb); + FREE_POOL(modeData); + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_WMI, "DiskInfoExceptionCheck: Can't allocate Irp\n")); + return(STATUS_INSUFFICIENT_RESOURCES); + } + + isRemoved = ClassAcquireRemoveLock(FdoExtension->DeviceObject, irp); + + if (isRemoved) + { + ClassReleaseRemoveLock(FdoExtension->DeviceObject, irp); + IoFreeIrp(irp); + FREE_POOL(senseInfoBuffer); + FREE_POOL(srb); + FREE_POOL(modeData); + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_WMI, "DiskInfoExceptionCheck: RemoveLock says isRemoved\n")); + return(STATUS_DEVICE_DOES_NOT_EXIST); + } + + // + // Get next stack location. + // + + IoSetNextIrpStackLocation(irp); + irpStack = IoGetCurrentIrpStackLocation(irp); + irpStack->DeviceObject = FdoExtension->DeviceObject; + + // + // Save retry count in current Irp stack. + // + irpStack->Parameters.Others.Argument4 = (PVOID)MAXIMUM_RETRIES; + + // + // Save allocated sense info buffer in case the port driver overwrites it + // + irpStack->Parameters.Others.Argument3 = senseInfoBuffer; + + irpStack = IoGetNextIrpStackLocation(irp); + + // + // Set up SRB for execute scsi request. Save SRB address in next stack + // for the port driver. + // + + irpStack->MajorFunction = IRP_MJ_SCSI; + irpStack->Parameters.Scsi.Srb = srb; + + IoSetCompletionRoutine(irp, + DiskInfoExceptionComplete, + srb, + TRUE, + TRUE, + TRUE); + + irp->MdlAddress = IoAllocateMdl( modeData, + MODE_DATA_SIZE, + FALSE, + FALSE, + irp ); + if (irp->MdlAddress == NULL) + { + ClassReleaseRemoveLock(FdoExtension->DeviceObject, irp); + FREE_POOL(srb); + FREE_POOL(modeData); + FREE_POOL(senseInfoBuffer); + IoFreeIrp( irp ); + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_WMI, "DiskINfoExceptionCheck: Can't allocate MDL\n")); + return STATUS_INSUFFICIENT_RESOURCES; + } + + MmBuildMdlForNonPagedPool(irp->MdlAddress); + + // + // Build the MODE SENSE CDB. + // + + if (FdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { + + // + // Set up STORAGE_REQUEST_BLOCK fields + // + + srbEx = (PSTORAGE_REQUEST_BLOCK)srb; + srbEx->Length = FIELD_OFFSET(STORAGE_REQUEST_BLOCK, Signature); + srbEx->Function = SRB_FUNCTION_STORAGE_REQUEST_BLOCK; + srbEx->Signature = SRB_SIGNATURE; + srbEx->Version = STORAGE_REQUEST_BLOCK_VERSION_1; + srbEx->SrbLength = srbSize; + srbEx->SrbFunction = SRB_FUNCTION_EXECUTE_SCSI; + srbEx->RequestPriority = IoGetIoPriorityHint(irp); + srbEx->AddressOffset = sizeof(STORAGE_REQUEST_BLOCK); + srbEx->NumSrbExData = 1; + + // Set timeout value from device extension. + srbEx->TimeOutValue = FdoExtension->TimeOutValue; + + // Set the transfer length. + srbEx->DataTransferLength = MODE_DATA_SIZE; + srbEx->DataBuffer = modeData; + + srbEx->SrbFlags = FdoExtension->SrbFlags; + + SET_FLAG(srbEx->SrbFlags, SRB_FLAGS_DATA_IN); + + // + // Disable synchronous transfer for these requests. + // + SET_FLAG(srbEx->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER); + + // + // Don't freeze the queue on an error + // + SET_FLAG(srbEx->SrbFlags, SRB_FLAGS_NO_QUEUE_FREEZE); + + srbEx->RequestAttribute = SRB_SIMPLE_TAG_REQUEST; + srbEx->RequestTag = SP_UNTAGGED; + + // Set up IRP Address. + srbEx->OriginalRequest = irp; + + // + // Set up address fields + // + + storAddrBtl8 = (PSTOR_ADDR_BTL8) ((PUCHAR)srbEx + srbEx->AddressOffset); + storAddrBtl8->Type = STOR_ADDRESS_TYPE_BTL8; + storAddrBtl8->AddressLength = STOR_ADDR_BTL8_ADDRESS_LENGTH; + + // + // Set up SCSI SRB extended data fields + // + + srbEx->SrbExDataOffset[0] = sizeof(STORAGE_REQUEST_BLOCK) + + sizeof(STOR_ADDR_BTL8); + if ((srbEx->SrbExDataOffset[0] + sizeof(SRBEX_DATA_SCSI_CDB16)) <= srbEx->SrbLength) { + srbExDataCdb16 = (PSRBEX_DATA_SCSI_CDB16)((PUCHAR)srbEx + srbEx->SrbExDataOffset[0]); + srbExDataCdb16->Type = SrbExDataTypeScsiCdb16; + srbExDataCdb16->Length = SRBEX_DATA_SCSI_CDB16_LENGTH; + srbExDataCdb16->CdbLength = 6; + + // Enable auto request sense. + srbExDataCdb16->SenseInfoBufferLength = senseInfoBufferLength; + srbExDataCdb16->SenseInfoBuffer = senseInfoBuffer; + + cdb = (PCDB)srbExDataCdb16->Cdb; + } else { + // Should not happen + NT_ASSERT(FALSE); + + ClassReleaseRemoveLock(FdoExtension->DeviceObject, irp); + FREE_POOL(srb); + FREE_POOL(modeData); + FREE_POOL(senseInfoBuffer); + IoFreeIrp( irp ); + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_WMI, "DiskINfoExceptionCheck: Insufficient extended SRB size\n")); + return STATUS_INTERNAL_ERROR; + } + + } else { + + // + // Write length to SRB. + // + srb->Length = SCSI_REQUEST_BLOCK_SIZE; + + // + // Set SCSI bus address. + // + + srb->Function = SRB_FUNCTION_EXECUTE_SCSI; + + // + // Enable auto request sense. + // + + srb->SenseInfoBufferLength = senseInfoBufferLength; + srb->SenseInfoBuffer = senseInfoBuffer; + + // + // Set timeout value from device extension. + // + srb->TimeOutValue = FdoExtension->TimeOutValue; + + // + // Set the transfer length. + // + srb->DataTransferLength = MODE_DATA_SIZE; + srb->DataBuffer = modeData; + + srb->SrbFlags = FdoExtension->SrbFlags; + + SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_IN); + + // + // Disable synchronous transfer for these requests. + // + SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER); + + // + // Don't freeze the queue on an error + // + SET_FLAG(srb->SrbFlags, SRB_FLAGS_NO_QUEUE_FREEZE); + + srb->QueueAction = SRB_SIMPLE_TAG_REQUEST; + srb->QueueTag = SP_UNTAGGED; + + // + // Set up IRP Address. + // + srb->OriginalRequest = irp; + + srb->CdbLength = 6; + cdb = (PCDB)srb->Cdb; + + } + + cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE; + cdb->MODE_SENSE.PageCode = MODE_PAGE_FAULT_REPORTING; + cdb->MODE_SENSE.AllocationLength = MODE_DATA_SIZE; + + // + // Call the port driver with the request and wait for it to complete. + // + + IoMarkIrpPending(irp); + IoCallDriver(FdoExtension->CommonExtension.LowerDeviceObject, + irp); + + return(STATUS_PENDING); +} + + +NTSTATUS +DiskDetectFailurePrediction( + PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, + PFAILURE_PREDICTION_METHOD FailurePredictCapability, + BOOLEAN ScsiAddressAvailable + ) +/*++ + +Routine Description: + + Detect if device has any failure prediction capabilities. First we + check for IDE SMART capability. This is done by sending the drive an + IDENTIFY command and checking if the SMART command set bit is set. + + Next we check if SCSI SMART (aka Information Exception Control Page, + X3T10/94-190 Rev 4). This is done by querying for the Information + Exception mode page. + + Lastly we check if the device has IOCTL failure prediction. This mechanism + a filter driver implements IOCTL_STORAGE_PREDICT_FAILURE and will respond + with the information in the IOCTL. We do this by sending the ioctl and + if the status returned is STATUS_SUCCESS we assume that it is supported. + +Arguments: + + FdoExtension + + *FailurePredictCapability + + ScsiAddressAvailable TRUE if there is a valid SCSI_ADDRESS available + for this device, FALSE otherwise. + If FALSE we do not allow SMART IOCTLs (FailurePredictionSmart capability) + which require a valid SCSI_ADDRESS. The other capabilities + DriverData); + BOOLEAN supportFP; + NTSTATUS status; + STORAGE_PREDICT_FAILURE checkFailure; + STORAGE_FAILURE_PREDICT_STATUS diskSmartStatus; + + PAGED_CODE(); + + // + // Assume no failure predict mechanisms + // + *FailurePredictCapability = FailurePredictionNone; + + // + // See if this is an IDE drive that supports SMART. If so enable SMART + // and then ensure that it suports the SMART READ STATUS command + // + + if (ScsiAddressAvailable) + { + DiskGetIdentifyInfo(FdoExtension, &supportFP); + + if (supportFP) + { + status = DiskEnableSmart(FdoExtension); + if (NT_SUCCESS(status)) + { + *FailurePredictCapability = FailurePredictionSmart; + diskData->FailurePredictionEnabled = TRUE; + + status = DiskReadFailurePredictStatus(FdoExtension, + &diskSmartStatus); + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_WMI, "Disk: Device %p %s IDE SMART\n", + FdoExtension->DeviceObject, + NT_SUCCESS(status) ? "does" : "does not")); + + if (!NT_SUCCESS(status)) + { + *FailurePredictCapability = FailurePredictionNone; + diskData->FailurePredictionEnabled = FALSE; + } + } + return(status); + } + } + // + // See if there is a a filter driver to intercept + // IOCTL_STORAGE_PREDICT_FAILURE + // + status = DiskSendFailurePredictIoctl(FdoExtension, + &checkFailure); + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_WMI, "Disk: Device %p %s IOCTL_STORAGE_FAILURE_PREDICT\n", + FdoExtension->DeviceObject, + NT_SUCCESS(status) ? "does" : "does not")); + + if (NT_SUCCESS(status)) + { + *FailurePredictCapability = FailurePredictionIoctl; + diskData->FailurePredictionEnabled = TRUE; + if (checkFailure.PredictFailure) + { + checkFailure.PredictFailure = 512; + ClassNotifyFailurePredicted(FdoExtension, + (PUCHAR)&checkFailure, + sizeof(checkFailure), + (BOOLEAN)(FdoExtension->FailurePredicted == FALSE), + 0x11, + diskData->ScsiAddress.PathId, + diskData->ScsiAddress.TargetId, + diskData->ScsiAddress.Lun); + + FdoExtension->FailurePredicted = TRUE; + } + return(status); + } + + // + // Finally we assume it will not be a scsi smart drive. but + // we'll also send off an asynchronous mode sense so that if + // it is SMART we'll reregister the device object + // + + *FailurePredictCapability = FailurePredictionNone; + + DiskInfoExceptionCheck(FdoExtension); + + return(STATUS_SUCCESS); +} + + +NTSTATUS +DiskWmiFunctionControl( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN ULONG GuidIndex, + IN CLASSENABLEDISABLEFUNCTION Function, + IN BOOLEAN Enable + ) +/*++ + +Routine Description: + + This routine is a callback into the driver to enabled or disable event + generation or data block collection. A device should only expect a + single enable when the first event or data consumer enables events or + data collection and a single disable when the last event or data + consumer disables events or data collection. Data blocks will only + receive collection enable/disable if they were registered as requiring + it. + + + When NT boots, failure prediction is not automatically enabled, although + it may have been persistantly enabled on a previous boot. Polling is also + not automatically enabled. When the first data block that accesses SMART + such as SmartStatusGuid, SmartDataGuid, SmartPerformFunction, or + SmartEventGuid is accessed then SMART is automatically enabled in the + hardware. Polling is enabled when SmartEventGuid is enabled and disabled + when it is disabled. Hardware SMART is only disabled when the DisableSmart + method is called. Polling is also disabled when this is called regardless + of the status of the other guids or events. + +Arguments: + + DeviceObject is the device whose data block is being queried + + GuidIndex is the index into the list of guids provided when the + device registered + + Function specifies which functionality is being enabled or disabled + + Enable is TRUE then the function is being enabled else disabled + +Return Value: + + status + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension; + + PAGED_CODE(); + + if ((Function == DataBlockCollection) && Enable) + { + if ((GuidIndex == SmartStatusGuid) || + (GuidIndex == SmartDataGuid) || + (GuidIndex == SmartThresholdsGuid) || + (GuidIndex == SmartPerformFunction)) + { + status = DiskEnableDisableFailurePrediction(fdoExtension, + TRUE); + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_WMI, "Disk: DeviceObject %p, Irp %p Enable -> %lx\n", + DeviceObject, + Irp, + status)); + + } else { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_WMI, "Disk: DeviceObject %p, Irp %p, GuidIndex %d %s for Collection\n", + DeviceObject, Irp, + GuidIndex, + Enable ? "Enabled" : "Disabled")); + } + } else if (Function == EventGeneration) { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_WMI, "Disk: DeviceObject %p, Irp %p, GuidIndex %d %s for Event Generation\n", + DeviceObject, Irp, + GuidIndex, + Enable ? "Enabled" : "Disabled")); + + + if ((GuidIndex == SmartEventGuid) && Enable) + { + status = DiskEnableDisableFailurePredictPolling(fdoExtension, + Enable, + 0); + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_WMI, "Disk: DeviceObject %p, Irp %p %s -> %lx\n", + DeviceObject, + Irp, + Enable ? "DiskEnableSmartPolling" : "DiskDisableSmartPolling", + status)); + } + +#if DBG + } else { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_WMI, "Disk: DeviceObject %p, Irp %p, GuidIndex %d %s for function %d\n", + DeviceObject, Irp, + GuidIndex, + Enable ? "Enabled" : "Disabled", + Function)); +#endif + } + + status = ClassWmiCompleteRequest(DeviceObject, + Irp, + status, + 0, + IO_NO_INCREMENT); + return status; +} + + + +NTSTATUS +DiskFdoQueryWmiRegInfo( + IN PDEVICE_OBJECT DeviceObject, + OUT ULONG *RegFlags, + OUT PUNICODE_STRING InstanceName + ) +/*++ + +Routine Description: + + This routine is a callback into the driver to retrieve the list of + guids or data blocks that the driver wants to register with WMI. This + routine may not pend or block. Driver should NOT call + ClassWmiCompleteRequest. + +Arguments: + + DeviceObject is the device whose data block is being queried + + *RegFlags returns with a set of flags that describe the guids being + registered for this device. If the device wants enable and disable + collection callbacks before receiving queries for the registered + guids then it should return the WMIREG_FLAG_EXPENSIVE flag. Also the + returned flags may specify WMIREG_FLAG_INSTANCE_PDO in which case + the instance name is determined from the PDO associated with the + device object. Note that the PDO must have an associated devnode. If + WMIREG_FLAG_INSTANCE_PDO is not set then Name must return a unique + name for the device. + + InstanceName returns with the instance name for the guids if + WMIREG_FLAG_INSTANCE_PDO is not set in the returned *RegFlags. The + caller will call ExFreePool with the buffer returned. + + +Return Value: + + status + +--*/ +{ + PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; + PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData); + + PAGED_CODE(); + UNREFERENCED_PARAMETER(InstanceName); + + SET_FLAG(DiskWmiFdoGuidList[SmartThresholdsGuid].Flags, WMIREG_FLAG_REMOVE_GUID); + SET_FLAG(DiskWmiFdoGuidList[ScsiInfoExceptionsGuid].Flags, WMIREG_FLAG_REMOVE_GUID); + + switch (diskData->FailurePredictionCapability) + { + case FailurePredictionSmart: + { + CLEAR_FLAG(DiskWmiFdoGuidList[SmartThresholdsGuid].Flags, WMIREG_FLAG_REMOVE_GUID); + // + // Fall Through + // + } + case FailurePredictionIoctl: + { + CLEAR_FLAG(DiskWmiFdoGuidList[SmartStatusGuid].Flags, WMIREG_FLAG_REMOVE_GUID); + CLEAR_FLAG(DiskWmiFdoGuidList[SmartDataGuid].Flags, WMIREG_FLAG_REMOVE_GUID); + CLEAR_FLAG(DiskWmiFdoGuidList[SmartEventGuid].Flags, WMIREG_FLAG_REMOVE_GUID); + CLEAR_FLAG(DiskWmiFdoGuidList[SmartPerformFunction].Flags, WMIREG_FLAG_REMOVE_GUID); + + break; + } + + case FailurePredictionSense: + { + CLEAR_FLAG(DiskWmiFdoGuidList[SmartStatusGuid].Flags, WMIREG_FLAG_REMOVE_GUID); + CLEAR_FLAG(DiskWmiFdoGuidList[SmartEventGuid].Flags, WMIREG_FLAG_REMOVE_GUID); + CLEAR_FLAG(DiskWmiFdoGuidList[SmartPerformFunction].Flags, WMIREG_FLAG_REMOVE_GUID); + CLEAR_FLAG(DiskWmiFdoGuidList[ScsiInfoExceptionsGuid].Flags, WMIREG_FLAG_REMOVE_GUID); + SET_FLAG (DiskWmiFdoGuidList[SmartDataGuid].Flags, WMIREG_FLAG_REMOVE_GUID); + break; + } + + + default: + { + SET_FLAG (DiskWmiFdoGuidList[SmartStatusGuid].Flags, WMIREG_FLAG_REMOVE_GUID); + SET_FLAG (DiskWmiFdoGuidList[SmartDataGuid].Flags, WMIREG_FLAG_REMOVE_GUID); + SET_FLAG (DiskWmiFdoGuidList[SmartEventGuid].Flags, WMIREG_FLAG_REMOVE_GUID); + SET_FLAG (DiskWmiFdoGuidList[SmartPerformFunction].Flags, WMIREG_FLAG_REMOVE_GUID); + break; + } + } + + // + // Use devnode for FDOs + *RegFlags = WMIREG_FLAG_INSTANCE_PDO; + + return STATUS_SUCCESS; +} + + +NTSTATUS +DiskFdoQueryWmiRegInfoEx( + IN PDEVICE_OBJECT DeviceObject, + OUT ULONG *RegFlags, + OUT PUNICODE_STRING InstanceName, + OUT PUNICODE_STRING MofName + ) +/*++ + +Routine Description: + + This routine is a callback into the driver to retrieve the list of + guids or data blocks that the driver wants to register with WMI. This + routine may not pend or block. Driver should NOT call + ClassWmiCompleteRequest. + +Arguments: + + DeviceObject is the device whose data block is being queried + + *RegFlags returns with a set of flags that describe the guids being + registered for this device. If the device wants enable and disable + collection callbacks before receiving queries for the registered + guids then it should return the WMIREG_FLAG_EXPENSIVE flag. Also the + returned flags may specify WMIREG_FLAG_INSTANCE_PDO in which case + the instance name is determined from the PDO associated with the + device object. Note that the PDO must have an associated devnode. If + WMIREG_FLAG_INSTANCE_PDO is not set then Name must return a unique + name for the device. + + InstanceName returns with the instance name for the guids if + WMIREG_FLAG_INSTANCE_PDO is not set in the returned *RegFlags. The + caller will call ExFreePool with the buffer returned. + + MofName returns initialized with the mof resource name for the + binary mof resource attached to the driver's image file. If the + driver does not have a mof resource then it should leave this + parameter untouched. + +Return Value: + + status + +--*/ +{ + NTSTATUS status; + + UNREFERENCED_PARAMETER(MofName); + + status = DiskFdoQueryWmiRegInfo(DeviceObject, + RegFlags, + InstanceName); + + // + // Leave MofName alone since disk doesn't have one + // + return(status); +} + + +NTSTATUS +DiskFdoQueryWmiDataBlock( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN ULONG GuidIndex, + IN ULONG BufferAvail, + OUT PUCHAR Buffer + ) +/*++ + +Routine Description: + + This routine is a callback into the driver to query for the contents of + a data block. When the driver has finished filling the data block it + must call ClassWmiCompleteRequest to complete the irp. The driver can + return STATUS_PENDING if the irp cannot be completed immediately. + +Arguments: + + DeviceObject is the device whose data block is being queried + + Irp is the Irp that makes this request + + GuidIndex is the index into the list of guids provided when the + device registered + + BufferAvail on has the maximum size available to write the data + block. + + Buffer on return is filled with the returned data block + + +Return Value: + + status + +--*/ +{ + NTSTATUS status; + PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension; + PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; + PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData); + ULONG sizeNeeded; + + PAGED_CODE(); + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_WMI, "Disk: DiskQueryWmiDataBlock, Device %p, Irp %p, GuiIndex %d\n" + " BufferAvail %lx Buffer %p\n", + DeviceObject, Irp, + GuidIndex, BufferAvail, Buffer)); + + switch (GuidIndex) + { + case DiskGeometryGuid: + { + sizeNeeded = sizeof(DISK_GEOMETRY); + if (BufferAvail >= sizeNeeded) + { + if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) + { + // + // Issue ReadCapacity to update device extension + // with information for current media. + status = DiskReadDriveCapacity(commonExtension->PartitionZeroExtension->DeviceObject); + + // + // Note whether the drive is ready. + diskData->ReadyStatus = status; + + if (!NT_SUCCESS(status)) + { + break; + } + } + + // + // Copy drive geometry information from device extension. + RtlMoveMemory(Buffer, + &(fdoExtension->DiskGeometry), + sizeof(DISK_GEOMETRY)); + + status = STATUS_SUCCESS; + } else { + status = STATUS_BUFFER_TOO_SMALL; + } + break; + } + + case SmartStatusGuid: + { + PSTORAGE_FAILURE_PREDICT_STATUS diskSmartStatus; + + NT_ASSERT(diskData->FailurePredictionCapability != FailurePredictionNone); + + sizeNeeded = sizeof(STORAGE_FAILURE_PREDICT_STATUS); + if (BufferAvail >= sizeNeeded) + { + STORAGE_PREDICT_FAILURE checkFailure; + + diskSmartStatus = (PSTORAGE_FAILURE_PREDICT_STATUS)Buffer; + + status = DiskSendFailurePredictIoctl(fdoExtension, + &checkFailure); + + if (NT_SUCCESS(status)) + { + if (diskData->FailurePredictionCapability == + FailurePredictionSense) + { + diskSmartStatus->Reason = *((PULONG)checkFailure.VendorSpecific); + } else { + diskSmartStatus->Reason = 0; // unknown + } + + diskSmartStatus->PredictFailure = (checkFailure.PredictFailure != 0); + } + } else { + status = STATUS_BUFFER_TOO_SMALL; + } + break; + } + + case SmartDataGuid: + { + PSTORAGE_FAILURE_PREDICT_DATA diskSmartData; + + NT_ASSERT((diskData->FailurePredictionCapability == + FailurePredictionSmart) || + (diskData->FailurePredictionCapability == + FailurePredictionIoctl)); + + sizeNeeded = sizeof(STORAGE_FAILURE_PREDICT_DATA); + if (BufferAvail >= sizeNeeded) + { + PSTORAGE_PREDICT_FAILURE checkFailure = (PSTORAGE_PREDICT_FAILURE)Buffer; + + diskSmartData = (PSTORAGE_FAILURE_PREDICT_DATA)Buffer; + + status = DiskSendFailurePredictIoctl(fdoExtension, + checkFailure); + + if (NT_SUCCESS(status)) + { + diskSmartData->Length = 512; + } + } else { + status = STATUS_BUFFER_TOO_SMALL; + } + + break; + } + + case SmartThresholdsGuid: + { + PSTORAGE_FAILURE_PREDICT_THRESHOLDS diskSmartThresholds; + + NT_ASSERT((diskData->FailurePredictionCapability == + FailurePredictionSmart)); + + sizeNeeded = sizeof(STORAGE_FAILURE_PREDICT_THRESHOLDS); + if (BufferAvail >= sizeNeeded) + { + diskSmartThresholds = (PSTORAGE_FAILURE_PREDICT_THRESHOLDS)Buffer; + status = DiskReadFailurePredictThresholds(fdoExtension, + diskSmartThresholds); + } else { + status = STATUS_BUFFER_TOO_SMALL; + } + + break; + } + + case SmartPerformFunction: + { + sizeNeeded = 0; + status = STATUS_SUCCESS; + break; + } + + case ScsiInfoExceptionsGuid: + { + PSTORAGE_SCSI_INFO_EXCEPTIONS infoExceptions; + MODE_INFO_EXCEPTIONS modeInfo; + + NT_ASSERT((diskData->FailurePredictionCapability == + FailurePredictionSense)); + + sizeNeeded = sizeof(STORAGE_SCSI_INFO_EXCEPTIONS); + if (BufferAvail >= sizeNeeded) + { + infoExceptions = (PSTORAGE_SCSI_INFO_EXCEPTIONS)Buffer; + status = DiskGetInfoExceptionInformation(fdoExtension, + &modeInfo); + if (NT_SUCCESS(status)) + { + infoExceptions->PageSavable = modeInfo.PSBit; + infoExceptions->Flags = modeInfo.Flags; + infoExceptions->MRIE = modeInfo.ReportMethod; + infoExceptions->Padding = 0; + REVERSE_BYTES(&infoExceptions->IntervalTimer, + &modeInfo.IntervalTimer); + REVERSE_BYTES(&infoExceptions->ReportCount, + &modeInfo.ReportCount) + } + } else { + status = STATUS_BUFFER_TOO_SMALL; + } + + break; + } + + default: + { + sizeNeeded = 0; + status = STATUS_WMI_GUID_NOT_FOUND; + } + } + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_WMI, "Disk: DiskQueryWmiDataBlock Device %p, Irp %p returns %lx\n", + DeviceObject, Irp, status)); + + status = ClassWmiCompleteRequest(DeviceObject, + Irp, + status, + sizeNeeded, + IO_NO_INCREMENT); + + return status; +} + + +NTSTATUS +DiskFdoSetWmiDataBlock( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN ULONG GuidIndex, + IN ULONG BufferSize, + IN PUCHAR Buffer + ) +/*++ + +Routine Description: + + This routine is a callback into the driver to query for the contents of + a data block. When the driver has finished filling the data block it + must call ClassWmiCompleteRequest to complete the irp. The driver can + return STATUS_PENDING if the irp cannot be completed immediately. + +Arguments: + + DeviceObject is the device whose data block is being queried + + Irp is the Irp that makes this request + + GuidIndex is the index into the list of guids provided when the + device registered + + BufferSize has the size of the data block passed + + Buffer has the new values for the data block + + +Return Value: + + status + +--*/ +{ + NTSTATUS status; + PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension; + PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; + PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData); + + PAGED_CODE(); + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_WMI, "Disk: DiskSetWmiDataBlock, Device %p, Irp %p, GuiIndex %d\n" + " BufferSize %#x Buffer %p\n", + DeviceObject, Irp, + GuidIndex, BufferSize, Buffer)); + + if (GuidIndex == ScsiInfoExceptionsGuid) + { + PSTORAGE_SCSI_INFO_EXCEPTIONS infoExceptions; + MODE_INFO_EXCEPTIONS modeInfo = {0}; + + if (BufferSize >= sizeof(STORAGE_SCSI_INFO_EXCEPTIONS)) + { + infoExceptions = (PSTORAGE_SCSI_INFO_EXCEPTIONS)Buffer; + + modeInfo.PageCode = MODE_PAGE_FAULT_REPORTING; + modeInfo.PageLength = sizeof(MODE_INFO_EXCEPTIONS) - 2; + + modeInfo.PSBit = 0; + modeInfo.Flags = infoExceptions->Flags; + + modeInfo.ReportMethod = infoExceptions->MRIE; + + REVERSE_BYTES(&modeInfo.IntervalTimer[0], + &infoExceptions->IntervalTimer); + + REVERSE_BYTES(&modeInfo.ReportCount[0], + &infoExceptions->ReportCount); + + if (modeInfo.Perf == 1) + { + diskData->AllowFPPerfHit = FALSE; + } else { + diskData->AllowFPPerfHit = TRUE; + } + + status = DiskSetInfoExceptionInformation(fdoExtension, + &modeInfo); + } else { + status = STATUS_INVALID_PARAMETER; + } + + } else if (GuidIndex <= SmartThresholdsGuid) + { + status = STATUS_WMI_READ_ONLY; + } else { + status = STATUS_WMI_GUID_NOT_FOUND; + } + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_WMI, "Disk: DiskSetWmiDataBlock Device %p, Irp %p returns %lx\n", + DeviceObject, Irp, status)); + + status = ClassWmiCompleteRequest(DeviceObject, + Irp, + status, + 0, + IO_NO_INCREMENT); + + return status; +} + + +NTSTATUS +DiskFdoSetWmiDataItem( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN ULONG GuidIndex, + IN ULONG DataItemId, + IN ULONG BufferSize, + IN PUCHAR Buffer + ) +/*++ + +Routine Description: + + This routine is a callback into the driver to query for the contents of + a data block. When the driver has finished filling the data block it + must call ClassWmiCompleteRequest to complete the irp. The driver can + return STATUS_PENDING if the irp cannot be completed immediately. + +Arguments: + + DeviceObject is the device whose data block is being queried + + Irp is the Irp that makes this request + + GuidIndex is the index into the list of guids provided when the + device registered + + DataItemId has the id of the data item being set + + BufferSize has the size of the data item passed + + Buffer has the new values for the data item + + +Return Value: + + status + +--*/ +{ + NTSTATUS status; + + PAGED_CODE(); + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_WMI, "Disk: DiskSetWmiDataItem, Device %p, Irp %p, GuiIndex %d, DataId %d\n" + " BufferSize %#x Buffer %p\n", + DeviceObject, Irp, + GuidIndex, DataItemId, BufferSize, Buffer)); + + if (GuidIndex <= SmartThresholdsGuid) + { + status = STATUS_WMI_READ_ONLY; + } else { + status = STATUS_WMI_GUID_NOT_FOUND; + } + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_WMI, "Disk: DiskSetWmiDataItem Device %p, Irp %p returns %lx\n", + DeviceObject, Irp, status)); + + status = ClassWmiCompleteRequest(DeviceObject, + Irp, + status, + 0, + IO_NO_INCREMENT); + + return status; +} + + +NTSTATUS +DiskFdoExecuteWmiMethod( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN ULONG GuidIndex, + IN ULONG MethodId, + IN ULONG InBufferSize, + IN ULONG OutBufferSize, + IN PUCHAR Buffer + ) +/*++ + +Routine Description: + + This routine is a callback into the driver to execute a method. When the + driver has finished filling the data block it must call + ClassWmiCompleteRequest to complete the irp. The driver can + return STATUS_PENDING if the irp cannot be completed immediately. + +Arguments: + + DeviceObject is the device whose data block is being queried + + Irp is the Irp that makes this request + + GuidIndex is the index into the list of guids provided when the + device registered + + MethodId has the id of the method being called + + InBufferSize has the size of the data block passed in as the input to + the method. + + OutBufferSize on entry has the maximum size available to write the + returned data block. + + Buffer is filled with the returned data block + + +Return Value: + + status + +--*/ +{ + PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension; + PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; + PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData); + ULONG sizeNeeded = 0; + NTSTATUS status; + + PAGED_CODE(); + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_WMI, "Disk: DiskExecuteWmiMethod, DeviceObject %p, Irp %p, Guid Id %d, MethodId %d\n" + " InBufferSize %#x, OutBufferSize %#x, Buffer %p\n", + DeviceObject, Irp, + GuidIndex, MethodId, InBufferSize, OutBufferSize, Buffer)); + + switch(GuidIndex) + { + case SmartPerformFunction: + { + + NT_ASSERT((diskData->FailurePredictionCapability == + FailurePredictionSmart) || + (diskData->FailurePredictionCapability == + FailurePredictionIoctl) || + (diskData->FailurePredictionCapability == + FailurePredictionSense)); + + + switch(MethodId) + { + // + // void AllowPerformanceHit([in] boolean Allow) + // + case AllowDisallowPerformanceHit: + { + BOOLEAN allowPerfHit; + + sizeNeeded = 0; + if (InBufferSize >= sizeof(BOOLEAN)) + { + status = STATUS_SUCCESS; + + allowPerfHit = *((PBOOLEAN)Buffer); + if (diskData->AllowFPPerfHit != allowPerfHit) + { + diskData->AllowFPPerfHit = allowPerfHit; + if (diskData->FailurePredictionCapability == + FailurePredictionSense) + { + MODE_INFO_EXCEPTIONS modeInfo; + + status = DiskGetInfoExceptionInformation(fdoExtension, + &modeInfo); + if (NT_SUCCESS(status)) + { + modeInfo.Perf = allowPerfHit ? 0 : 1; + status = DiskSetInfoExceptionInformation(fdoExtension, + &modeInfo); + } + } + else + { + status = STATUS_INVALID_DEVICE_REQUEST; + } + } + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_WMI, "DiskFdoWmiExecuteMethod: AllowPerformanceHit %x for device %p --> %lx\n", + allowPerfHit, + fdoExtension->DeviceObject, + status)); + } else { + status = STATUS_INVALID_PARAMETER; + } + break; + } + + // + // void EnableDisableHardwareFailurePrediction([in] boolean Enable) + // + case EnableDisableHardwareFailurePrediction: + { + BOOLEAN enable; + + sizeNeeded = 0; + if (InBufferSize >= sizeof(BOOLEAN)) + { + status = STATUS_SUCCESS; + enable = *((PBOOLEAN)Buffer); + if (!enable) + { + // + // If we are disabling we need to also disable + // polling + // + DiskEnableDisableFailurePredictPolling( + fdoExtension, + enable, + 0); + } + + status = DiskEnableDisableFailurePrediction( + fdoExtension, + enable); + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_WMI, "DiskFdoWmiExecuteMethod: EnableDisableHardwareFailurePrediction: %x for device %p --> %lx\n", + enable, + fdoExtension->DeviceObject, + status)); + } else { + status = STATUS_INVALID_PARAMETER; + } + break; + } + + // + // void EnableDisableFailurePredictionPolling( + // [in] uint32 Period, + // [in] boolean Enable) + // + case EnableDisableFailurePredictionPolling: + { + BOOLEAN enable; + ULONG period; + + sizeNeeded = 0; + if (InBufferSize >= (sizeof(ULONG) + sizeof(BOOLEAN))) + { + period = *((PULONG)Buffer); + Buffer += sizeof(ULONG); + enable = *((PBOOLEAN)Buffer); + + status = DiskEnableDisableFailurePredictPolling( + fdoExtension, + enable, + period); + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_WMI, "DiskFdoWmiExecuteMethod: EnableDisableFailurePredictionPolling: %x %x for device %p --> %lx\n", + enable, + period, + fdoExtension->DeviceObject, + status)); + } else { + status = STATUS_INVALID_PARAMETER; + } + break; + } + + // + // void GetFailurePredictionCapability([out] uint32 Capability) + // + case GetFailurePredictionCapability: + { + sizeNeeded = sizeof(ULONG); + if (OutBufferSize >= sizeNeeded) + { + status = STATUS_SUCCESS; + *((PFAILURE_PREDICTION_METHOD)Buffer) = diskData->FailurePredictionCapability; + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_WMI, "DiskFdoWmiExecuteMethod: GetFailurePredictionCapability: %x for device %p --> %lx\n", + *((PFAILURE_PREDICTION_METHOD)Buffer), + fdoExtension->DeviceObject, + status)); + } else { + status = STATUS_BUFFER_TOO_SMALL; + } + break; + } + + // + // void EnableOfflineDiags([out] boolean Success); + // + case EnableOfflineDiags: + { + sizeNeeded = sizeof(BOOLEAN); + if (OutBufferSize >= sizeNeeded) + { + if (diskData->FailurePredictionCapability == + FailurePredictionSmart) + { + // + // Initiate or resume offline diagnostics. + // This may cause a loss of performance + // to the disk, but mayincrease the amount + // of disk checking. + // + status = DiskExecuteSmartDiagnostics(fdoExtension, + 0); + + } else { + status = STATUS_INVALID_DEVICE_REQUEST; + } + + *((PBOOLEAN)Buffer) = NT_SUCCESS(status); + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_WMI, "DiskFdoWmiExecuteMethod: EnableOfflineDiags for device %p --> %lx\n", + fdoExtension->DeviceObject, + status)); + } else { + status = STATUS_BUFFER_TOO_SMALL; + } + break; + } + + // + // void ReadLogSectors([in] uint8 LogAddress, + // [in] uint8 SectorCount, + // [out] uint32 Length, + // [out, WmiSizeIs("Length")] uint8 LogSectors[] + // ); + // + case ReadLogSectors: + { + if (diskData->FailurePredictionCapability == + FailurePredictionSmart) + { + if (InBufferSize >= sizeof(READ_LOG_SECTORS_IN)) + { + PREAD_LOG_SECTORS_IN inParams; + PREAD_LOG_SECTORS_OUT outParams; + ULONG readSize; + + inParams = (PREAD_LOG_SECTORS_IN)Buffer; + readSize = inParams->SectorCount * SMART_LOG_SECTOR_SIZE; + sizeNeeded = FIELD_OFFSET(READ_LOG_SECTORS_OUT, + LogSectors) + readSize; + + if (OutBufferSize >= sizeNeeded) + { + outParams = (PREAD_LOG_SECTORS_OUT)Buffer; + status = DiskReadSmartLog(fdoExtension, + inParams->SectorCount, + inParams->LogAddress, + outParams->LogSectors); + + if (NT_SUCCESS(status)) + { + outParams->Length = readSize; + } else { + // + // SMART command failure is + // indicated by successful + // execution, but no data returned + // + outParams->Length = 0; + status = STATUS_SUCCESS; + } + } else { + status = STATUS_BUFFER_TOO_SMALL; + } + + } else { + status = STATUS_INVALID_PARAMETER; + } + } else { + status = STATUS_INVALID_DEVICE_REQUEST; + } + break; + } + + // void WriteLogSectors([in] uint8 LogAddress, + // [in] uint8 SectorCount, + // [in] uint32 Length, + // [in, WmiSizeIs("Length")] uint8 LogSectors[], + // [out] boolean Success + // ); + case WriteLogSectors: + { + if (diskData->FailurePredictionCapability == + FailurePredictionSmart) + { + if ((LONG)InBufferSize >= FIELD_OFFSET(WRITE_LOG_SECTORS_IN, + LogSectors)) + { + PWRITE_LOG_SECTORS_IN inParams; + PWRITE_LOG_SECTORS_OUT outParams; + ULONG writeSize; + + inParams = (PWRITE_LOG_SECTORS_IN)Buffer; + writeSize = inParams->SectorCount * SMART_LOG_SECTOR_SIZE; + if (InBufferSize >= (FIELD_OFFSET(WRITE_LOG_SECTORS_IN, + LogSectors) + + writeSize)) + { + sizeNeeded = sizeof(WRITE_LOG_SECTORS_OUT); + + if (OutBufferSize >= sizeNeeded) + { + outParams = (PWRITE_LOG_SECTORS_OUT)Buffer; + status = DiskWriteSmartLog(fdoExtension, + inParams->SectorCount, + inParams->LogAddress, + inParams->LogSectors); + + if (NT_SUCCESS(status)) + { + outParams->Success = TRUE; + } else { + outParams->Success = FALSE; + status = STATUS_SUCCESS; + } + } else { + status = STATUS_BUFFER_TOO_SMALL; + } + } else { + status = STATUS_INVALID_PARAMETER; + } + } else { + status = STATUS_INVALID_PARAMETER; + } + } else { + status = STATUS_INVALID_DEVICE_REQUEST; + } + break; + } + + // void ExecuteSelfTest([in] uint8 Subcommand, + // [out, + // Values{"0", "1", "2"}, + // ValueMap{"Successful Completion", + // "Captive Mode Required", + // "Unsuccessful Completion"} + // ] + // uint32 ReturnCode); + case ExecuteSelfTest: + { + if (diskData->FailurePredictionCapability == + FailurePredictionSmart) + { + if (InBufferSize >= sizeof(EXECUTE_SELF_TEST_IN)) + { + sizeNeeded = sizeof(EXECUTE_SELF_TEST_OUT); + if (OutBufferSize >= sizeNeeded) + { + PEXECUTE_SELF_TEST_IN inParam; + PEXECUTE_SELF_TEST_OUT outParam; + + inParam = (PEXECUTE_SELF_TEST_IN)Buffer; + outParam = (PEXECUTE_SELF_TEST_OUT)Buffer; + + if (DiskIsValidSmartSelfTest(inParam->Subcommand)) + { + status = DiskExecuteSmartDiagnostics(fdoExtension, + inParam->Subcommand); + if (NT_SUCCESS(status)) + { + // + // Return self test executed + // without a problem + // + outParam->ReturnCode = 0; + } else { + // + // Return Self test execution + // failed status + // + outParam->ReturnCode = 2; + status = STATUS_SUCCESS; + } + } else { + // + // If self test subcommand requires + // captive mode then return that + // status + // + outParam->ReturnCode = 1; + status = STATUS_SUCCESS; + } + + } else { + status = STATUS_BUFFER_TOO_SMALL; + } + + } else { + status = STATUS_INVALID_PARAMETER; + } + } else { + status = STATUS_INVALID_DEVICE_REQUEST; + } + + break; + } + + default : + { + sizeNeeded = 0; + status = STATUS_WMI_ITEMID_NOT_FOUND; + break; + } + } + + break; + } + + case DiskGeometryGuid: + case SmartStatusGuid: + case SmartDataGuid: + case SmartEventGuid: + case SmartThresholdsGuid: + case ScsiInfoExceptionsGuid: + { + sizeNeeded = 0; + status = STATUS_INVALID_DEVICE_REQUEST; + break; + } + + default: + { + sizeNeeded = 0; + status = STATUS_WMI_GUID_NOT_FOUND; + } + } + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_WMI, "Disk: DiskExecuteMethod Device %p, Irp %p returns %lx\n", + DeviceObject, Irp, status)); + + status = ClassWmiCompleteRequest(DeviceObject, + Irp, + status, + sizeNeeded, + IO_NO_INCREMENT); + + return status; +} + + diff --git a/storage/class/disk/src/enum.c b/storage/class/disk/src/enum.c new file mode 100644 index 00000000..d5521caf --- /dev/null +++ b/storage/class/disk/src/enum.c @@ -0,0 +1,1313 @@ +/*++ + +Copyright (C) Microsoft Corporation, 1991 - 1999 + +Module Name: + + pnp.c + +Abstract: + + SCSI disk class driver + +Environment: + + kernel mode only + +Notes: + +Revision History: + +--*/ + +#include "disk.h" +#include "ntintsafe.h" + +#ifdef DEBUG_USE_WPP +#include "enum.tmh" +#endif + +#ifdef ALLOC_PRAGMA + +#pragma alloc_text(PAGE, DiskConvertExtendedToLayout) +#pragma alloc_text(PAGE, DiskConvertPartitionToExtended) +#pragma alloc_text(PAGE, DiskConvertLayoutToExtended) +#pragma alloc_text(PAGE, DiskCreatePdo) +#pragma alloc_text(PAGE, DiskEnumerateDevice) +#pragma alloc_text(PAGE, DiskUpdateRemovablePartitions) +#pragma alloc_text(PAGE, DiskUpdatePartitions) +#pragma alloc_text(PAGE, DiskCreatePdo) + +#endif + + +PDRIVE_LAYOUT_INFORMATION +DiskConvertExtendedToLayout( + IN CONST PDRIVE_LAYOUT_INFORMATION_EX LayoutEx + ) +{ + ULONG i; + ULONG LayoutSize; + PDRIVE_LAYOUT_INFORMATION Layout; + PPARTITION_INFORMATION Partition; + PPARTITION_INFORMATION_EX PartitionEx; + NTSTATUS status; + + PAGED_CODE (); + + NT_ASSERT ( LayoutEx ); + + + // + // The only valid conversion is from an MBR extended layout structure to + // the old structure. + // + + if (LayoutEx->PartitionStyle != PARTITION_STYLE_MBR) { + NT_ASSERT ( FALSE ); + return NULL; + } + + // + // Use safe interger function + // + + status = RtlULongMult(LayoutEx->PartitionCount, sizeof(PARTITION_INFORMATION), &LayoutSize); + if (!NT_SUCCESS(status)) { + return NULL; + } + status = RtlULongAdd(LayoutSize, FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION, PartitionEntry[0]), + &LayoutSize); + if (!NT_SUCCESS(status)) { + return NULL; + } + + Layout = ExAllocatePoolWithTag ( + NonPagedPoolNx, + LayoutSize, + DISK_TAG_PART_LIST + ); + + if ( Layout == NULL ) { + return NULL; + } + + Layout->Signature = LayoutEx->Mbr.Signature; + Layout->PartitionCount = LayoutEx->PartitionCount; + + for (i = 0; i < LayoutEx->PartitionCount; i++) { + + Partition = &Layout->PartitionEntry[i]; + PartitionEx = &LayoutEx->PartitionEntry[i]; + + Partition->StartingOffset = PartitionEx->StartingOffset; + Partition->PartitionLength = PartitionEx->PartitionLength; + Partition->RewritePartition = PartitionEx->RewritePartition; + Partition->PartitionNumber = PartitionEx->PartitionNumber; + + Partition->PartitionType = PartitionEx->Mbr.PartitionType; + Partition->BootIndicator = PartitionEx->Mbr.BootIndicator; + Partition->RecognizedPartition = PartitionEx->Mbr.RecognizedPartition; + Partition->HiddenSectors = PartitionEx->Mbr.HiddenSectors; + } + + return Layout; +} + + +VOID +DiskConvertPartitionToExtended( + IN PPARTITION_INFORMATION Partition, + OUT PPARTITION_INFORMATION_EX PartitionEx + ) + +/*++ + +Routine Description: + + Convert a PARTITION_INFORMATION structure to a PARTITION_INFORMATION_EX + structure. + +Arguments: + + Partition - A pointer to the PARTITION_INFORMATION structure to convert. + + PartitionEx - A pointer to a buffer where the converted + PARTITION_INFORMATION_EX structure is to be stored. + +Return Values: + + None. + +--*/ + +{ + PAGED_CODE (); + + NT_ASSERT ( PartitionEx != NULL ); + NT_ASSERT ( Partition != NULL ); + + PartitionEx->PartitionStyle = PARTITION_STYLE_MBR; + PartitionEx->StartingOffset = Partition->StartingOffset; + PartitionEx->PartitionLength = Partition->PartitionLength; + PartitionEx->RewritePartition = Partition->RewritePartition; + PartitionEx->PartitionNumber = Partition->PartitionNumber; + + PartitionEx->Mbr.PartitionType = Partition->PartitionType; + PartitionEx->Mbr.BootIndicator = Partition->BootIndicator; + PartitionEx->Mbr.RecognizedPartition = Partition->RecognizedPartition; + PartitionEx->Mbr.HiddenSectors = Partition->HiddenSectors; +} + + +PDRIVE_LAYOUT_INFORMATION_EX +DiskConvertLayoutToExtended( + IN CONST PDRIVE_LAYOUT_INFORMATION Layout + ) + +/*++ + +Routine Description: + + Convert a DRIVE_LAYOUT_INFORMATION structure into a + DRIVE_LAYOUT_INFORMATION_EX structure. + +Arguments: + + Layout - The source DRIVE_LAYOUT_INFORMATION structure. + +Return Values: + + The resultant DRIVE_LAYOUT_INFORMATION_EX structure. This buffer must + be freed by the callee using ExFreePool. + +--*/ + +{ + ULONG i; + ULONG size; + PDRIVE_LAYOUT_INFORMATION_EX layoutEx; + NTSTATUS status; + + PAGED_CODE (); + + NT_ASSERT ( Layout != NULL ); + + + // + // Allocate enough space for a DRIVE_LAYOUT_INFORMATION_EX structure + // plus as many PARTITION_INFORMATION_EX structures as are in the + // source array. + // + + // + // Use safe interger function + // + + status = RtlULongMult(Layout->PartitionCount, sizeof(PARTITION_INFORMATION_EX), &size); + if (!NT_SUCCESS(status)) { + return NULL; + } + status = RtlULongAdd(size, FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry[0]), + &size); + if (!NT_SUCCESS(status)) { + return NULL; + } + + layoutEx = ExAllocatePoolWithTag( + NonPagedPoolNx, + size, + DISK_TAG_PART_LIST + ); + + if ( layoutEx == NULL ) { + return NULL; + } + + // + // Convert the disk information. + // + + layoutEx->PartitionStyle = PARTITION_STYLE_MBR; + layoutEx->PartitionCount = Layout->PartitionCount; + layoutEx->Mbr.Signature = Layout->Signature; + + for (i = 0; i < Layout->PartitionCount; i++) { + + // + // Convert each entry. + // + + DiskConvertPartitionToExtended ( + &Layout->PartitionEntry[i], + &layoutEx->PartitionEntry[i] + ); + } + + return layoutEx; +} + + +NTSTATUS +DiskEnumerateDevice( + IN PDEVICE_OBJECT Fdo + ) + +/*++ + +Routine Description: + + This routine is called by the class driver to update the PDO list off + of this FDO. The disk driver also calls it internally to re-create + device objects. + + This routine will read the partition table and create new PDO objects as + necessary. PDO's that no longer exist will be pulled out of the PDO list + so that pnp will destroy them. + +Arguments: + + Fdo - a pointer to the FDO being re-enumerated + +Return Value: + + status + +--*/ + +{ + PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension; + PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension; + PPHYSICAL_DEVICE_EXTENSION pdoExtension = NULL; + PDISK_DATA diskData = (PDISK_DATA) commonExtension->DriverData; + PDEVICE_OBJECT pdo = NULL; + PDRIVE_LAYOUT_INFORMATION_EX partitionList; + NTSTATUS status; + BOOLEAN freePartitionList = FALSE; + + NT_ASSERT(commonExtension->IsFdo); + + PAGED_CODE(); + + // + // If our cached partition table is valid, there is nothing to be done + // + + if ( diskData->CachedPartitionTableValid == TRUE ) + { + return STATUS_SUCCESS; + } + + // + // Update our image of the size of the drive. This may be necessary if + // the drive size is extended or we just released a reservation to + // ensure the kernel doesn't reject the partition table. + // + + DiskReadDriveCapacity(Fdo); + + // + // Lock out anyone else trying to repartition the disk. + // + + DiskAcquirePartitioningLock(fdoExtension); + + // + // Create objects for all the partitions on the device. + // + + status = DiskReadPartitionTableEx(fdoExtension, FALSE, &partitionList); + + // + // If the I/O read partition table failed and this is a removable device, + // then fix up the partition list to make it look like there is one + // zero length partition. + // + + if ((!NT_SUCCESS(status) || partitionList->PartitionCount == 0) && + Fdo->Characteristics & FILE_REMOVABLE_MEDIA) { + + SIZE_T partitionListSize; + + // + // Remember whether the drive is ready. + // + + diskData->ReadyStatus = status; + + // + // Allocate and zero a partition list. + // + + partitionListSize = + FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry[1]); + + partitionList = ExAllocatePoolWithTag(NonPagedPoolNx, + partitionListSize, + DISK_TAG_PART_LIST); + + if (partitionList != NULL) { + + RtlZeroMemory( partitionList, partitionListSize ); + + // + // Set the partition count to one and the status to success + // so one device object will be created. Set the partition type + // to a bogus value. + // + + partitionList->PartitionStyle = PARTITION_STYLE_MBR; + partitionList->PartitionCount = 1; + + freePartitionList = TRUE; + + status = STATUS_SUCCESS; + } else { + status = STATUS_INSUFFICIENT_RESOURCES; + } + } + + if (NT_SUCCESS(status)) { + + diskData->UpdatePartitionRoutine(Fdo, partitionList); + } + + DiskReleasePartitioningLock(fdoExtension); + + if (freePartitionList) { + FREE_POOL(partitionList); + } + + return(STATUS_SUCCESS); + +} // end DiskEnumerateDevice() + + +VOID +DiskUpdateRemovablePartitions( + IN PDEVICE_OBJECT Fdo, + IN OUT PDRIVE_LAYOUT_INFORMATION_EX PartitionList + ) + +/*++ + +Routine Description: + + This routine is called by the class DLL to update the PDO list off of this + FDO. The disk driver also calls it internally to re-create device objects. + + This routine will read the partition table and update the size of the + single partition device object which always exists for removable devices. + +Arguments: + + Fdo - a pointer to the FDO being reenumerated. + +Return Value: + + status + +--*/ + +{ + + PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension; + PPHYSICAL_DEVICE_EXTENSION pdoExtension = NULL; + + ULONG partitionCount; + + ULONG partitionNumber; + ULONG partitionOrdinal = 0; + ULONG newPartitionNumber; + + PDISK_DATA pdoData; + NTSTATUS status; + + PPARTITION_INFORMATION_EX partitionEntry; + PARTITION_STYLE partitionStyle; + + PAGED_CODE(); + + NT_ASSERT(Fdo->Characteristics & FILE_REMOVABLE_MEDIA); + + partitionStyle = PartitionList->PartitionStyle; + partitionCount = PartitionList->PartitionCount; + + for(partitionNumber = 0; + partitionNumber < partitionCount; + partitionNumber++) { + + partitionEntry = &(PartitionList->PartitionEntry[partitionNumber]); + + partitionEntry->PartitionNumber = 0; + } + + // + // Get exclusive access to the child list while repartitioning. + // + + ClassAcquireChildLock(fdoExtension); + + // + // Removable media should never have more than one PDO. + // + + pdoExtension = fdoExtension->CommonExtension.ChildList; + + if(pdoExtension == NULL) { + + PARTITION_INFORMATION_EX tmpPartitionEntry = { 0 }; + PDEVICE_OBJECT pdo; + + // + // There is no PDO currently. Create one and pre-initialize it with + // a zero length. + // + + tmpPartitionEntry.PartitionNumber = 1; + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_ENUM, "DiskUpdateRemovablePartitions: Creating RM partition\n")); + + status = DiskCreatePdo(Fdo, + 0, + &tmpPartitionEntry, + partitionStyle, + &pdo); + + if(!NT_SUCCESS(status)) { + + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_ENUM, "DiskUpdateRemovablePartitions: error %lx creating " + "new PDO for RM partition\n", + status)); + + goto DiskUpdateRemovablePartitionsExit; + } + + // + // mark the new device as enumerated + // + + pdoExtension = pdo->DeviceExtension; + pdoExtension->IsMissing = FALSE; + + } + + pdoData = pdoExtension->CommonExtension.DriverData; + + // + // Search the partition list for a valid entry. We're looking for a + // primary partition since we only support the one. + // + + for(partitionNumber = 0; + partitionNumber < partitionCount; + partitionNumber++) { + + partitionEntry = &(PartitionList->PartitionEntry[partitionNumber]); + + + // + // Is this partition interesting? + // + + if (partitionStyle == PARTITION_STYLE_MBR) { + + if(partitionEntry->Mbr.PartitionType == PARTITION_ENTRY_UNUSED || + IsContainerPartition(partitionEntry->Mbr.PartitionType)) { + + continue; + } + } + + partitionOrdinal++; + + // + // We have found the first and thus only partition allowed on + // this disk. Update the information in the PDO to match the new + // partition. + // + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_ENUM, "DiskUpdateRemovablePartitions: Matched %wZ to #%d, " + "ordinal %d\n", + &pdoExtension->CommonExtension.DeviceName, + partitionEntry->PartitionNumber, + partitionOrdinal)); + + + partitionEntry->PartitionNumber = 1; + + pdoData->PartitionStyle = partitionStyle; + pdoData->PartitionOrdinal = partitionOrdinal; + NT_ASSERT(partitionEntry->PartitionLength.LowPart != 0x23456789); + + pdoExtension->CommonExtension.StartingOffset = + partitionEntry->StartingOffset; + + pdoExtension->CommonExtension.PartitionLength = + partitionEntry->PartitionLength; + + + if (partitionStyle == PARTITION_STYLE_MBR) { + + pdoData->Mbr.HiddenSectors = partitionEntry->Mbr.HiddenSectors; + pdoData->Mbr.BootIndicator = partitionEntry->Mbr.BootIndicator; + + + // + // If this partition is being re-written then update the type + // information as well + // + + if (partitionEntry->RewritePartition) { + pdoData->Mbr.PartitionType = partitionEntry->Mbr.PartitionType; + } + + } else { + + pdoData->Efi.PartitionType = partitionEntry->Gpt.PartitionType; + pdoData->Efi.PartitionId = partitionEntry->Gpt.PartitionId; + pdoData->Efi.Attributes = partitionEntry->Gpt.Attributes; + + RtlCopyMemory( + pdoData->Efi.PartitionName, + partitionEntry->Gpt.Name, + sizeof (pdoData->Efi.PartitionName) + ); + } + + // + // Mark this one as found + // + + pdoExtension->IsMissing = FALSE; + goto DiskUpdateRemovablePartitionsExit; + } + + // + // No interesting partition was found. + // + + if (partitionStyle == PARTITION_STYLE_MBR) { + + pdoData->Mbr.HiddenSectors = 0; + pdoData->Mbr.PartitionType = PARTITION_ENTRY_UNUSED; + + } else { + + RtlZeroMemory (&pdoData->Efi, + sizeof (pdoData->Efi) + ); + } + + pdoExtension->CommonExtension.StartingOffset.QuadPart = 0; + pdoExtension->CommonExtension.PartitionLength.QuadPart = 0; + +DiskUpdateRemovablePartitionsExit: + + // + // Update the parent device object + // + + { + PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension; + PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData); + + if (partitionStyle == PARTITION_STYLE_MBR) + { + diskData->PartitionStyle = PARTITION_STYLE_MBR; + diskData->Mbr.Signature = PartitionList->Mbr.Signature; + } + else + { + diskData->PartitionStyle = PARTITION_STYLE_GPT; + diskData->Efi.DiskId = PartitionList->Gpt.DiskId; + } + } + + ClassReleaseChildLock(fdoExtension); + return; +} + + +VOID +DiskUpdatePartitions( + IN PDEVICE_OBJECT Fdo, + IN OUT PDRIVE_LAYOUT_INFORMATION_EX PartitionList + ) + +/*++ + +Routine Description: + + This routine will synchronize the information held in the partition list + with the device objects hanging off this Fdo. Any new partition objects + will be created, any non-existant ones will be marked as un-enumerated. + + This will be done in several stages: + + * Clear state (partition number) from every entry in the partition + list + + * Set IsMissing flag on every child of this FDO + + * For each child of the FDO: + if a matching partition exists in the partition list, + update the partition number in the table, update the + ordinal in the object and mark the object as enumerated + + * For each un-enumerated device object + zero out the partition information to invalidate the device + delete the symbolic link if any + + * For each un-matched entry in the partition list: + create a new partition object + update the partition number in the list entry + create a new symbolic link if necessary + +Arguments: + + Fdo - a pointer to the functional device object this partition list is for + + PartitionList - a pointer to the partition list being updated + +Return Value: + + none + +--*/ + +{ + PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension; + + PPHYSICAL_DEVICE_EXTENSION oldChildList = NULL; + PPHYSICAL_DEVICE_EXTENSION pdoExtension = NULL; + + ULONG partitionCount; + + ULONG partitionNumber; + ULONG partitionOrdinal; + ULONG newPartitionNumber; + + PPARTITION_INFORMATION_EX partitionEntry; + PDISK_DATA pdoData; + PARTITION_STYLE partitionStyle; + + NTSTATUS status; + + PAGED_CODE(); + + // + // Get exclusive access to the child list. + // + + ClassAcquireChildLock(fdoExtension); + + partitionStyle = PartitionList->PartitionStyle; + partitionCount = PartitionList->PartitionCount; + + // + // Pull all the child device objects off the children list. We'll + // add them back later. + // + + oldChildList = fdoExtension->CommonExtension.ChildList; + fdoExtension->CommonExtension.ChildList = NULL; + + // + // Clear the partition numbers from the list entries + // + + for(partitionNumber = 0; + partitionNumber < partitionCount; + partitionNumber++) { + + partitionEntry = &(PartitionList->PartitionEntry[partitionNumber]); + partitionEntry->PartitionNumber = 0; + } + + // + // Now match each child partition to it's entry (if any) in the partition + // list. + // + + while(oldChildList != NULL) { + + pdoExtension = oldChildList; + pdoData = pdoExtension->CommonExtension.DriverData; + + // + // Check all partition entries for a match on offset and length + // + + partitionOrdinal = 0; + + for(partitionNumber = 0; + partitionNumber < partitionCount; + partitionNumber++) { + + partitionEntry = &(PartitionList->PartitionEntry[partitionNumber]); + + // + // Is this an interesting partition entry? + // + + if (partitionStyle == PARTITION_STYLE_MBR) { + + if((partitionEntry->Mbr.PartitionType == PARTITION_ENTRY_UNUSED) || + (IsContainerPartition(partitionEntry->Mbr.PartitionType))) { + + continue; + } + } + + partitionOrdinal++; + + if(partitionEntry->PartitionNumber) { + + // + // This partition has already been found - skip it + // + + continue; + } + + // + // Let's see if the partition information matches + // + + if(partitionEntry->StartingOffset.QuadPart != + pdoExtension->CommonExtension.StartingOffset.QuadPart) { + continue; + } + + if(partitionEntry->PartitionLength.QuadPart != + pdoExtension->CommonExtension.PartitionLength.QuadPart) { + continue; + } + + // + // Yep - it matches. Update the information in the entry + // + + partitionEntry->PartitionNumber = pdoExtension->CommonExtension.PartitionNumber; + + if (partitionStyle == PARTITION_STYLE_MBR) { + + pdoData->Mbr.HiddenSectors = partitionEntry->Mbr.HiddenSectors; + + } + + break; + } + + if(partitionNumber != partitionCount) { + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_ENUM, "DiskUpdatePartitions: Matched %wZ to #%d, ordinal " + "%d\n", + &pdoExtension->CommonExtension.DeviceName, + partitionEntry->PartitionNumber, + partitionOrdinal)); + + NT_ASSERT(partitionEntry->PartitionLength.LowPart != 0x23456789); + // NT_ASSERT(pdoExtension->CommonExtension.PartitionLength.QuadPart != 0); + + pdoData->PartitionStyle = partitionStyle; + + // + // we found a match - update the information in the device object + // extension and driverdata + // + + pdoData->PartitionOrdinal = partitionOrdinal; + + // + // If this partition is being re-written then update the type + // information as well + // + + + if (partitionStyle == PARTITION_STYLE_MBR) { + + if(partitionEntry->RewritePartition) { + pdoData->Mbr.PartitionType = partitionEntry->Mbr.PartitionType; + } + + } else { + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_ENUM, "DiskUpdatePartitions: EFI Partition %ws\n", + pdoData->Efi.PartitionName + )); + + pdoData->Efi.PartitionType = partitionEntry->Gpt.PartitionType; + pdoData->Efi.PartitionId = partitionEntry->Gpt.PartitionId; + pdoData->Efi.Attributes = partitionEntry->Gpt.Attributes; + + RtlCopyMemory( + pdoData->Efi.PartitionName, + partitionEntry->Gpt.Name, + sizeof (pdoData->Efi.PartitionName) + ); + } + + // + // Mark this one as found. + // + + pdoExtension->IsMissing = FALSE; + + // + // Pull it out of the old child list and add it into the + // real one. + // + + oldChildList = pdoExtension->CommonExtension.ChildList; + + pdoExtension->CommonExtension.ChildList = + fdoExtension->CommonExtension.ChildList; + + fdoExtension->CommonExtension.ChildList = pdoExtension; + + } else { + + PDEVICE_OBJECT nextPdo; + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_ENUM, "DiskUpdatePartitions: Deleting %wZ\n", + &pdoExtension->CommonExtension.DeviceName)); + + if (partitionStyle == PARTITION_STYLE_GPT) { + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_ENUM, "DiskUpdatePartitions: EFI Partition %ws\n", + pdoData->Efi.PartitionName + )); + } + // + // no matching entry in the partition list - throw this partition + // object away + // + + pdoExtension->CommonExtension.PartitionLength.QuadPart = 0; + + // + // grab a pointer to the next child before we mark this one as + // missing since missing devices could vanish at any time. + // + + oldChildList = pdoExtension->CommonExtension.ChildList; + pdoExtension->CommonExtension.ChildList = (PVOID) -1; + + // + // Now tell the class driver that this child is "missing" - this + // will cause it to be deleted. + // + + + ClassMarkChildMissing(pdoExtension, FALSE); + } + } + + // + // At this point the old child list had best be empty. + // + + NT_ASSERT(oldChildList == NULL); + + // + // Iterate through the partition entries and create any partition + // objects that don't already exist + // + + partitionOrdinal = 0; + newPartitionNumber = 0; + + for(partitionNumber = 0; + partitionNumber < partitionCount; + partitionNumber++) { + + PDEVICE_OBJECT pdo; + + partitionEntry = &(PartitionList->PartitionEntry[partitionNumber]); + + // + // Is this partition interesting + // + + if (partitionStyle == PARTITION_STYLE_MBR) { + + if((partitionEntry->Mbr.PartitionType == PARTITION_ENTRY_UNUSED) || + (IsContainerPartition(partitionEntry->Mbr.PartitionType))) { + + continue; + } + } + + // + // Increment the count of interesting partitions + // + + partitionOrdinal++; + newPartitionNumber++; + + // + // Has this already been matched + // + + if(partitionEntry->PartitionNumber == 0) { + + LONG i; + + // + // find the first safe partition number for this device + // + + for(i = 0; i < (LONG) partitionCount; i++) { + + + PPARTITION_INFORMATION_EX tmp = &(PartitionList->PartitionEntry[i]); + + if (partitionStyle == PARTITION_STYLE_MBR) { + if (tmp->Mbr.PartitionType == PARTITION_ENTRY_UNUSED || + IsContainerPartition(tmp->Mbr.PartitionType)) { + continue; + } + } + + if(tmp->PartitionNumber == newPartitionNumber) { + + // + // Found a matching partition number - increment the count + // and restart the scan. + // + + newPartitionNumber++; + i = -1; + continue; + } + } + + // + // Assign this partition a partition number + // + + partitionEntry->PartitionNumber = newPartitionNumber; + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_ENUM, "DiskUpdatePartitions: Found new partition #%d, ord %d " + "starting at %#016I64x and running for %#016I64x\n", + partitionEntry->PartitionNumber, + partitionOrdinal, + partitionEntry->StartingOffset.QuadPart, + partitionEntry->PartitionLength.QuadPart)); + + ClassReleaseChildLock(fdoExtension); + + status = DiskCreatePdo(Fdo, + partitionOrdinal, + partitionEntry, + partitionStyle, + &pdo); + + ClassAcquireChildLock(fdoExtension); + + if(!NT_SUCCESS(status)) { + + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_ENUM, "DiskUpdatePartitions: error %lx creating " + "new PDO for partition ordinal %d, number %d\n", + status, + partitionOrdinal, + partitionEntry->PartitionNumber)); + + // + // don't increment the partition number - we'll try to reuse + // it for the next child. + // + + partitionEntry->PartitionNumber = 0; + newPartitionNumber--; + + continue; + } + + // + // mark the new device as enumerated + // + + pdoExtension = pdo->DeviceExtension; + pdoExtension->IsMissing = FALSE; + + // + // This number's taken already - try to scanning the partition + // table more than once for a new number. + // + + } + } + + // + // Update the parent device object + // + + { + PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension; + PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData); + + if (partitionStyle == PARTITION_STYLE_MBR) + { + diskData->PartitionStyle = PARTITION_STYLE_MBR; + diskData->Mbr.Signature = PartitionList->Mbr.Signature; + } + else + { + diskData->PartitionStyle = PARTITION_STYLE_GPT; + diskData->Efi.DiskId = PartitionList->Gpt.DiskId; + } + } + + ClassReleaseChildLock(fdoExtension); + return; +} + + +NTSTATUS +DiskCreatePdo( + IN PDEVICE_OBJECT Fdo, + IN ULONG PartitionOrdinal, + IN PPARTITION_INFORMATION_EX PartitionEntry, + IN PARTITION_STYLE PartitionStyle, + OUT PDEVICE_OBJECT *Pdo + ) + +/*++ + +Routine Description: + + This routine will create and initialize a new partition device object + (PDO) and insert it into the FDO partition list. + +Arguments: + + Fdo - a pointer to the functional device object this PDO will be a child + of + + PartitionOrdinal - the partition ordinal for this PDO + + PartitionEntry - the partition information for this device object + + PartitionStyle - what style of partition table entry PartitionEntry is; + currently either MBR or EFI + + Pdo - a location to store the pdo pointer upon successful completion + +Return Value: + + status + +--*/ + +{ + PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension; + PDEVICE_OBJECT pdo = NULL; + PPHYSICAL_DEVICE_EXTENSION pdoExtension = NULL; + + PUCHAR deviceName = NULL; + + PDISK_DATA diskData = fdoExtension->CommonExtension.DriverData; + + ULONG numberListElements; + + NTSTATUS status = STATUS_SUCCESS; + + PAGED_CODE(); + + // + // Create partition object and set up partition parameters. + // + + status = DiskGenerateDeviceName(FALSE, + fdoExtension->DeviceNumber, + PartitionEntry->PartitionNumber, + &PartitionEntry->StartingOffset, + &PartitionEntry->PartitionLength, + &deviceName); + + if(!NT_SUCCESS(status)) { + + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_ENUM, "DiskCreatePdo - Can't generate name %lx\n", status)); + return status; + } + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_ENUM, "DiskCreatePdo: Create device object %s\n", deviceName)); + + status = ClassCreateDeviceObject(Fdo->DriverObject, + deviceName, + Fdo, + FALSE, + &pdo); + + if (!NT_SUCCESS(status)) { + + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_ENUM, "DiskEnumerateDevice: Can't create device object for %s\n", deviceName)); + + FREE_POOL(deviceName); + return status; + } + + FREE_POOL(deviceName); + + // + // Set up device extension fields. + // + + pdoExtension = pdo->DeviceExtension; + + // + // Set up device object fields. + // + + SET_FLAG(pdo->Flags, DO_DIRECT_IO); + + pdo->StackSize = (CCHAR) + pdoExtension->CommonExtension.LowerDeviceObject->StackSize + 1; + + // + // Get pointer to new disk data. + // + + diskData = (PDISK_DATA) pdoExtension->CommonExtension.DriverData; + + // + // Set the alignment requirements for the device based on the + // host adapter requirements + // + + if (Fdo->AlignmentRequirement > pdo->AlignmentRequirement) { + pdo->AlignmentRequirement = Fdo->AlignmentRequirement; + } + + if (fdoExtension->SrbFlags & SRB_FLAGS_QUEUE_ACTION_ENABLE) { + numberListElements = 30; + } else { + numberListElements = 8; + } + + // + // Build the lookaside list for srb's for this partition based on + // whether the adapter and disk can do tagged queueing. Don't bother to + // check the status - this can't fail when called for a PDO. + // + + ClassInitializeSrbLookasideList((PCOMMON_DEVICE_EXTENSION) pdoExtension, + numberListElements); + + // + // Set the sense-data pointer in the device extension. + // + + diskData->PartitionOrdinal = PartitionOrdinal; + pdoExtension->CommonExtension.PartitionNumber = PartitionEntry->PartitionNumber; + + // + // Initialize relevant data. + // + + diskData->PartitionStyle = PartitionStyle; + + if (PartitionStyle == PARTITION_STYLE_MBR) { + + diskData->Mbr.PartitionType = PartitionEntry->Mbr.PartitionType; + diskData->Mbr.BootIndicator = PartitionEntry->Mbr.BootIndicator; + diskData->Mbr.HiddenSectors = PartitionEntry->Mbr.HiddenSectors; + + } else { + + diskData->Efi.PartitionType = PartitionEntry->Gpt.PartitionType; + diskData->Efi.PartitionId = PartitionEntry->Gpt.PartitionId; + diskData->Efi.Attributes = PartitionEntry->Gpt.Attributes; + RtlCopyMemory (diskData->Efi.PartitionName, + PartitionEntry->Gpt.Name, + sizeof (diskData->Efi.PartitionName) + ); + } + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_ENUM, "DiskEnumerateDevice: Partition type is %x\n", + diskData->Mbr.PartitionType)); + + pdoExtension->CommonExtension.StartingOffset = + PartitionEntry->StartingOffset; + + pdoExtension->CommonExtension.PartitionLength = + PartitionEntry->PartitionLength; + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_ENUM, "DiskCreatePdo: hidden sectors value for pdo %#p set to %#x\n", + pdo, + diskData->Mbr.HiddenSectors)); + + // + // Check for removable media support. + // + + if (fdoExtension->DeviceDescriptor->RemovableMedia) { + SET_FLAG(pdo->Characteristics, FILE_REMOVABLE_MEDIA); + } + + pdoExtension->CommonExtension.DeviceObject = pdo; + + CLEAR_FLAG(pdo->Flags, DO_DEVICE_INITIALIZING); + + *Pdo = pdo; + + return status; +} + + +/* + * DiskAcquirePartitioningLock + * + * Acquire the PartitioningEvent. + * + * NOTE: This function is called by several ioctl handlers which run in user context. + * Because we are acquiring an exclusion object in a user thread, we have to make sure + * that the thread is not killed or suspended while we are holding the event. + * So we call KeEnterCriticalRegion/KeLeaveCriticalRegion while holding the PartitioningEvent. + * THEREFORE, it is VERY IMPORTANT that DiskAcquirePartitioningLock and DiskReleasePartitioningLock + * are called on the SAME THREAD. + */ +VOID +DiskAcquirePartitioningLock( + IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension + ) +{ + PDISK_DATA diskData = FdoExtension->CommonExtension.DriverData; + + PAGED_CODE(); + + ASSERT_FDO(FdoExtension->DeviceObject); + + /* + * Don't let user-mode thread get suspended while we are holding the partitioning lock + */ + KeEnterCriticalRegion(); + + KeWaitForSingleObject(&(diskData->PartitioningEvent), + UserRequest, + KernelMode, + FALSE, + NULL); + return; +} + + +VOID +DiskReleasePartitioningLock( + IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension + ) +{ + PDISK_DATA diskData = FdoExtension->CommonExtension.DriverData; + + PAGED_CODE(); + + ASSERT_FDO(FdoExtension->DeviceObject); + + KeSetEvent(&(diskData->PartitioningEvent), IO_NO_INCREMENT, FALSE); + + KeLeaveCriticalRegion(); + + return; +} diff --git a/storage/class/disk/src/geometry.c b/storage/class/disk/src/geometry.c new file mode 100644 index 00000000..911a33a4 --- /dev/null +++ b/storage/class/disk/src/geometry.c @@ -0,0 +1,1672 @@ +/*++ + +Copyright (C) Microsoft Corporation, 1991 - 1999 + +Module Name: + + geometry.c + +Abstract: + + SCSI disk class driver - this module contains all the code for generating + disk geometries. + +Environment: + + kernel mode only + +Notes: + +Revision History: + +--*/ + + +#include "disk.h" +#include "ntddstor.h" + +#ifdef DEBUG_USE_WPP +#include "geometry.tmh" +#endif + +#if defined(_X86_) || defined(_AMD64_) + +DISK_GEOMETRY_SOURCE +DiskUpdateGeometry( + IN PFUNCTIONAL_DEVICE_EXTENSION DeviceExtension + ); + +NTSTATUS +DiskUpdateRemovableGeometry ( + IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension + ); + +VOID +DiskScanBusDetectInfo( + IN PDRIVER_OBJECT DriverObject, + IN HANDLE BusKey + ); + +NTSTATUS +DiskSaveBusDetectInfo( + IN PDRIVER_OBJECT DriverObject, + IN HANDLE TargetKey, + IN ULONG DiskNumber + ); + +NTSTATUS +DiskSaveGeometryDetectInfo( + IN PDRIVER_OBJECT DriverObject, + IN HANDLE HardwareKey + ); + +NTSTATUS +DiskGetPortGeometry( + IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, + OUT PDISK_GEOMETRY Geometry + ); + +typedef struct _DISK_DETECT_INFO { + BOOLEAN Initialized; + ULONG Style; + ULONG Signature; + ULONG MbrCheckSum; + PDEVICE_OBJECT Device; + CM_INT13_DRIVE_PARAMETER DriveParameters; +} DISK_DETECT_INFO, *PDISK_DETECT_INFO; + +// +// Information about the disk geometries collected and saved into the registry +// by NTDETECT.COM or the system firmware. +// + +PDISK_DETECT_INFO DetectInfoList = NULL; +ULONG DetectInfoCount = 0; +LONG DetectInfoUsedCount = 0; + +#define GET_STARTING_SECTOR(p) ( \ + (ULONG) (p->StartingSectorLsb0) + \ + (ULONG) (p->StartingSectorLsb1 << 8 ) + \ + (ULONG) (p->StartingSectorMsb0 << 16) + \ + (ULONG) (p->StartingSectorMsb1 << 24) ) + +#define GET_ENDING_S_OF_CHS(p) ( \ + (UCHAR) (p->EndingCylinderLsb & 0x3F) ) + +// +// Definitions from hal.h +// + +// +// Boot record disk partition table entry structure format +// + +typedef struct _PARTITION_DESCRIPTOR +{ + UCHAR ActiveFlag; + UCHAR StartingTrack; + UCHAR StartingCylinderLsb; + UCHAR StartingCylinderMsb; + UCHAR PartitionType; + UCHAR EndingTrack; + UCHAR EndingCylinderLsb; + UCHAR EndingCylinderMsb; + UCHAR StartingSectorLsb0; + UCHAR StartingSectorLsb1; + UCHAR StartingSectorMsb0; + UCHAR StartingSectorMsb1; + UCHAR PartitionLengthLsb0; + UCHAR PartitionLengthLsb1; + UCHAR PartitionLengthMsb0; + UCHAR PartitionLengthMsb1; + +} PARTITION_DESCRIPTOR, *PPARTITION_DESCRIPTOR; + +// +// Number of partition table entries +// + +#define NUM_PARTITION_TABLE_ENTRIES 4 + +// +// Partition table record and boot signature offsets in 16-bit words +// + +#define PARTITION_TABLE_OFFSET ( 0x1be / 2) +#define BOOT_SIGNATURE_OFFSET ((0x200 / 2) - 1) + +// +// Boot record signature value +// + +#define BOOT_RECORD_SIGNATURE (0xaa55) + + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(INIT, DiskSaveDetectInfo) +#pragma alloc_text(INIT, DiskScanBusDetectInfo) +#pragma alloc_text(INIT, DiskSaveBusDetectInfo) +#pragma alloc_text(INIT, DiskSaveGeometryDetectInfo) + +#pragma alloc_text(PAGE, DiskUpdateGeometry) +#pragma alloc_text(PAGE, DiskUpdateRemovableGeometry) +#pragma alloc_text(PAGE, DiskGetPortGeometry) +#pragma alloc_text(PAGE, DiskIsNT4Geometry) +#pragma alloc_text(PAGE, DiskGetDetectInfo) +#pragma alloc_text(PAGE, DiskReadSignature) +#endif + + +NTSTATUS +DiskSaveDetectInfo( + PDRIVER_OBJECT DriverObject + ) + +/*++ + +Routine Description: + + This routine saves away the firmware information about the disks which has + been saved in the registry. It generates a list (DetectInfoList) which + contains the disk geometries, signatures & checksums of all drives which + were examined by NtDetect. This list is later used to assign geometries + to disks as they are initialized. + +Arguments: + + DriverObject - the driver being initialized. This is used to get to the + hardware database. + +Return Value: + + status. + +--*/ + +{ + OBJECT_ATTRIBUTES objectAttributes = {0}; + HANDLE hardwareKey; + + UNICODE_STRING unicodeString; + HANDLE busKey; + + NTSTATUS status; + + PAGED_CODE(); + + InitializeObjectAttributes( + &objectAttributes, + DriverObject->HardwareDatabase, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, + NULL, + NULL); + + // + // Create the hardware base key. + // + + status = ZwOpenKey(&hardwareKey, KEY_READ, &objectAttributes); + + if(!NT_SUCCESS(status)) { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskSaveDetectInfo: Cannot open hardware data. " + "Name: %wZ\n", + DriverObject->HardwareDatabase)); + return status; + } + + status = DiskSaveGeometryDetectInfo(DriverObject, hardwareKey); + + if(!NT_SUCCESS(status)) { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskSaveDetectInfo: Can't query configuration data " + "(%#08lx)\n", + status)); + ZwClose(hardwareKey); + return status; + } + + // + // Open EISA bus key. + // + + RtlInitUnicodeString(&unicodeString, L"EisaAdapter"); + InitializeObjectAttributes(&objectAttributes, + &unicodeString, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, + hardwareKey, + NULL); + + status = ZwOpenKey(&busKey, + KEY_READ, + &objectAttributes); + + if(NT_SUCCESS(status)) { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskSaveDetectInfo: Opened EisaAdapter key\n")); + DiskScanBusDetectInfo(DriverObject, busKey); + ZwClose(busKey); + } + + // + // Open MultiFunction bus key. + // + + RtlInitUnicodeString(&unicodeString, L"MultifunctionAdapter"); + InitializeObjectAttributes(&objectAttributes, + &unicodeString, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, + hardwareKey, + NULL); + + status = ZwOpenKey(&busKey, + KEY_READ, + &objectAttributes); + + if(NT_SUCCESS(status)) { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskSaveDetectInfo: Opened MultifunctionAdapter key\n")); + DiskScanBusDetectInfo(DriverObject, busKey); + ZwClose(busKey); + } + + ZwClose(hardwareKey); + + return STATUS_SUCCESS; +} + + +VOID +DiskCleanupDetectInfo( + IN PDRIVER_OBJECT DriverObject + ) +/*++ + +Routine Description: + + This routine will cleanup the data structure built by DiskSaveDetectInfo. + +Arguments: + + DriverObject - a pointer to the kernel object for this driver. + +Return Value: + + none + +--*/ + +{ + UNREFERENCED_PARAMETER(DriverObject); + FREE_POOL(DetectInfoList); + return; +} + + +NTSTATUS +DiskSaveGeometryDetectInfo( + IN PDRIVER_OBJECT DriverObject, + IN HANDLE HardwareKey + ) +{ + UNICODE_STRING unicodeString; + PKEY_VALUE_FULL_INFORMATION keyData; + ULONG length; + + PCM_FULL_RESOURCE_DESCRIPTOR fullDescriptor; + PCM_PARTIAL_RESOURCE_DESCRIPTOR partialDescriptor; + + PCM_INT13_DRIVE_PARAMETER driveParameters; + ULONG numberOfDrives; + + ULONG i; + + NTSTATUS status; + + PAGED_CODE(); + UNREFERENCED_PARAMETER(DriverObject); + + // + // Get disk BIOS geometry information. + // + + RtlInitUnicodeString(&unicodeString, L"Configuration Data"); + + keyData = ExAllocatePoolWithTag(PagedPool, + VALUE_BUFFER_SIZE, + DISK_TAG_UPDATE_GEOM); + + if(keyData == NULL) { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskSaveGeometryDetectInfo: Can't allocate config " + "data buffer\n")); + return STATUS_INSUFFICIENT_RESOURCES; + } + + status = ZwQueryValueKey(HardwareKey, + &unicodeString, + KeyValueFullInformation, + keyData, + VALUE_BUFFER_SIZE, + &length); + + if(!NT_SUCCESS(status)) { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskSaveGeometryDetectInfo: Can't query configuration " + "data (%#08lx)\n", + status)); + FREE_POOL(keyData); + return status; + } + + // + // Extract the resource list out of the key data. + // + + fullDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR) + (((PUCHAR) keyData) + keyData->DataOffset); + partialDescriptor = + fullDescriptor->PartialResourceList.PartialDescriptors; + length = partialDescriptor->u.DeviceSpecificData.DataSize; + + if((keyData->DataLength < sizeof(CM_FULL_RESOURCE_DESCRIPTOR)) || + (fullDescriptor->PartialResourceList.Count == 0) || + (partialDescriptor->Type != CmResourceTypeDeviceSpecific) || + (length < sizeof(ULONG))) { + + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskSaveGeometryDetectInfo: BIOS header data too small " + "or invalid\n")); + FREE_POOL(keyData); + return STATUS_INVALID_PARAMETER; + } + + // + // Point to the BIOS data. THe BIOS data is located after the first + // partial Resource list which should be device specific data. + // + + { + PUCHAR buffer = (PUCHAR) keyData; + buffer += keyData->DataOffset; + buffer += sizeof(CM_FULL_RESOURCE_DESCRIPTOR); + driveParameters = (PCM_INT13_DRIVE_PARAMETER) buffer; + } + + numberOfDrives = length / sizeof(CM_INT13_DRIVE_PARAMETER); + + // + // Allocate our detect info list now that we know how many entries there + // are going to be. No other routine allocates detect info and this is + // done out of DriverEntry so we don't need to synchronize it's creation. + // + + length = sizeof(DISK_DETECT_INFO) * numberOfDrives; + DetectInfoList = ExAllocatePoolWithTag(PagedPool, + length, + DISK_TAG_UPDATE_GEOM); + + if(DetectInfoList == NULL) { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskSaveGeometryDetectInfo: Couldn't allocate %x bytes " + "for DetectInfoList\n", + length)); + + FREE_POOL(keyData); + return STATUS_INSUFFICIENT_RESOURCES; + } + + DetectInfoCount = numberOfDrives; + + RtlZeroMemory(DetectInfoList, length); + + // + // Copy the information out of the key data and into the list we've + // allocated. + // + + for(i = 0; i < numberOfDrives; i++) { +#pragma warning(suppress: 6386) // PREFast bug means it doesn't correctly remember the size of DetectInfoList + DetectInfoList[i].DriveParameters = driveParameters[i]; + } + + FREE_POOL(keyData); + return STATUS_SUCCESS; +} + + +VOID +DiskScanBusDetectInfo( + IN PDRIVER_OBJECT DriverObject, + IN HANDLE BusKey + ) +/*++ + +Routine Description: + + The routine queries the registry to determine which disks are visible to + the BIOS. If a disk is visable to the BIOS then the geometry information + is updated with the disk's signature and MBR checksum. + +Arguments: + + DriverObject - the object for this driver. + BusKey - handle to the bus key to be enumerated. + +Return Value: + + status + +--*/ +{ + ULONG busNumber; + + NTSTATUS status; + + for(busNumber = 0; ; busNumber++) { + + WCHAR buffer[32] = { 0 }; + UNICODE_STRING unicodeString; + + OBJECT_ATTRIBUTES objectAttributes = {0}; + + HANDLE spareKey; + HANDLE adapterKey; + + ULONG adapterNumber; + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskScanBusDetectInfo: Scanning bus %d\n", busNumber)); + + // + // Open controller name key. + // + + status = RtlStringCchPrintfW(buffer, sizeof(buffer) / sizeof(buffer[0]) - 1, L"%d", busNumber); + if (!NT_SUCCESS(status)) { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskScanBusDetectInfo: Format symbolic link failed with error: 0x%X\n", status)); + break; + } + + RtlInitUnicodeString(&unicodeString, buffer); + + InitializeObjectAttributes(&objectAttributes, + &unicodeString, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, + BusKey, + NULL); + + status = ZwOpenKey(&spareKey, KEY_READ, &objectAttributes); + + if(!NT_SUCCESS(status)) { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskScanBusDetectInfo: Error %#08lx opening bus " + "key %#x\n", + status, busNumber)); + break; + } + + // + // Open up a controller ordinal key. + // + + RtlInitUnicodeString(&unicodeString, L"DiskController"); + InitializeObjectAttributes(&objectAttributes, + &unicodeString, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, + spareKey, + NULL); + + status = ZwOpenKey(&adapterKey, KEY_READ, &objectAttributes); + ZwClose(spareKey); + + if(!NT_SUCCESS(status)) { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskScanBusDetectInfo: Error %#08lx opening " + "DiskController key\n", + status)); + continue; + } + + for(adapterNumber = 0; ; adapterNumber++) { + + HANDLE diskKey; + ULONG diskNumber; + + // + // Open disk key. + // + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskScanBusDetectInfo: Scanning disk key " + "%d\\DiskController\\%d\\DiskPeripheral\n", + busNumber, adapterNumber)); + + status = RtlStringCchPrintfW(buffer, sizeof(buffer) / sizeof(buffer[0]) - 1, L"%d\\DiskPeripheral", adapterNumber); + if (!NT_SUCCESS(status)) { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskScanBusDetectInfo: Format symbolic link failed with error: 0x%X\n", status)); + break; + } + + RtlInitUnicodeString(&unicodeString, buffer); + + InitializeObjectAttributes(&objectAttributes, + &unicodeString, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, + adapterKey, + NULL); + + status = ZwOpenKey(&diskKey, KEY_READ, &objectAttributes); + + if(!NT_SUCCESS(status)) { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskScanBusDetectInfo: Error %#08lx opening " + "disk key\n", + status)); + break; + } + + for(diskNumber = 0; ; diskNumber++) { + + HANDLE targetKey; + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskScanBusDetectInfo: Scanning target key " + "%d\\DiskController\\%d\\DiskPeripheral\\%d\n", + busNumber, adapterNumber, diskNumber)); + + status = RtlStringCchPrintfW(buffer, sizeof(buffer) / sizeof(buffer[0]) - 1, L"%d", diskNumber); + if (!NT_SUCCESS(status)) { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskScanBusDetectInfo: Format symbolic link failed with error: 0x%X\n", status)); + break; + } + + RtlInitUnicodeString(&unicodeString, buffer); + + InitializeObjectAttributes(&objectAttributes, + &unicodeString, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, + diskKey, + NULL); + + status = ZwOpenKey(&targetKey, KEY_READ, &objectAttributes); + + if(!NT_SUCCESS(status)) { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskScanBusDetectInfo: Error %#08lx " + "opening target key\n", + status)); + break; + } + + DiskSaveBusDetectInfo(DriverObject, targetKey, diskNumber); + + ZwClose(targetKey); + } + + ZwClose(diskKey); + } + + ZwClose(adapterKey); + } + + return; +} + + +NTSTATUS +DiskSaveBusDetectInfo( + IN PDRIVER_OBJECT DriverObject, + IN HANDLE TargetKey, + IN ULONG DiskNumber + ) +/*++ + +Routine Description: + + This routine will transfer the firmware/ntdetect reported information + in the specified target key into the appropriate entry in the + DetectInfoList. + +Arguments: + + DriverObject - the object for this driver. + + TargetKey - the key for the disk being saved. + + DiskNumber - the ordinal of the entry in the DiskPeripheral tree for this + entry + +Return Value: + + status + +--*/ +{ + PDISK_DETECT_INFO diskInfo; + + UNICODE_STRING unicodeString; + + PKEY_VALUE_FULL_INFORMATION keyData; + ULONG length; + + NTSTATUS status; + + PAGED_CODE(); + UNREFERENCED_PARAMETER(DriverObject); + + if (DiskNumber >= DetectInfoCount) + { + return STATUS_UNSUCCESSFUL; + } + + diskInfo = &(DetectInfoList[DiskNumber]); + + if(diskInfo->Initialized) { + + NT_ASSERT(FALSE); + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskSaveBusDetectInfo: disk entry %#x already has a " + "signature of %#08lx and mbr checksum of %#08lx\n", + DiskNumber, + diskInfo->Signature, + diskInfo->MbrCheckSum)); + return STATUS_UNSUCCESSFUL; + } + + RtlInitUnicodeString(&unicodeString, L"Identifier"); + + keyData = ExAllocatePoolWithTag(PagedPool, + VALUE_BUFFER_SIZE, + DISK_TAG_UPDATE_GEOM); + + if(keyData == NULL) { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskSaveBusDetectInfo: Couldn't allocate space for " + "registry data\n")); + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // Get disk peripheral identifier. + // + + status = ZwQueryValueKey(TargetKey, + &unicodeString, + KeyValueFullInformation, + keyData, + VALUE_BUFFER_SIZE, + &length); + + if(!NT_SUCCESS(status)) { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskSaveBusDetectInfo: Error %#08lx getting " + "Identifier\n", + status)); + FREE_POOL(keyData); + return status; + + } else if (keyData->DataLength < 9*sizeof(WCHAR)) { + + // + // the data is too short to use (we subtract 9 chars in normal path) + // + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskSaveBusDetectInfo: Saved data was invalid, " + "not enough data in registry!\n")); + FREE_POOL(keyData); + return STATUS_UNSUCCESSFUL; + + } else { + + UNICODE_STRING identifier; + ULONG value; + + // + // Complete unicode string. + // + + identifier.Buffer = (PWSTR) ((PUCHAR)keyData + keyData->DataOffset); + identifier.Length = (USHORT) keyData->DataLength; + identifier.MaximumLength = (USHORT) keyData->DataLength; + + // + // Get the first value out of the identifier - this will be the MBR + // checksum. + // + + status = RtlUnicodeStringToInteger(&identifier, 16, &value); + + if(!NT_SUCCESS(status)) { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskSaveBusDetectInfo: Error %#08lx converting " + "identifier %wZ into MBR xsum\n", + status, + &identifier)); + FREE_POOL(keyData); + return status; + } + + diskInfo->MbrCheckSum = value; + + // + // Shift the string over to get the disk signature + // + + identifier.Buffer += 9; + identifier.Length -= 9 * sizeof(WCHAR); + identifier.MaximumLength -= 9 * sizeof(WCHAR); + + status = RtlUnicodeStringToInteger(&identifier, 16, &value); + + if(!NT_SUCCESS(status)) { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskSaveBusDetectInfo: Error %#08lx converting " + "identifier %wZ into disk signature\n", + status, + &identifier)); + value = 0; + } + + diskInfo->Signature = value; + } + + // + // Here is where we would save away the extended int13 data. + // + + // + // Mark this entry as initialized so we can make sure not to do it again. + // + + diskInfo->Initialized = TRUE; + + FREE_POOL(keyData); + + return STATUS_SUCCESS; +} + + +DISK_GEOMETRY_SOURCE +DiskUpdateGeometry( + IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension + ) +/*++ + +Routine Description: + + This routine checks the DetectInfoList saved away during disk driver init + to see if any geometry information was reported for this drive. If the + geometry data exists (determined by matching non-zero signatures or + non-zero MBR checksums) then it will be saved in the RealGeometry member + of the disk data block. + + ClassReadDriveCapacity MUST be called after calling this routine to update + the cylinder count based on the size of the disk and the presence of any + disk management software. + +Arguments: + + DeviceExtension - Supplies a pointer to the device information for disk. + +Return Value: + + Inidicates whether the "RealGeometry" in the data block is now valid. + +--*/ + +{ + PDISK_DATA diskData = FdoExtension->CommonExtension.DriverData; + + ULONG i; + PDISK_DETECT_INFO diskInfo = NULL; + + BOOLEAN found = FALSE; + + NTSTATUS status; + + PAGED_CODE(); + + + NT_ASSERT((FdoExtension->DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) == 0); + + // + // If we've already set a non-default geometry for this drive then there's + // no need to try and update again. + // + + if(diskData->GeometrySource != DiskGeometryUnknown) { + return diskData->GeometrySource; + } + + // + // Scan through the saved detect info to see if we can find a match + // for this device. + // + + for(i = 0; i < DetectInfoCount; i++) { + + NT_ASSERT(DetectInfoList != NULL); + + diskInfo = &(DetectInfoList[i]); + + if((diskData->Mbr.Signature != 0) && + (diskData->Mbr.Signature == diskInfo->Signature)) { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskUpdateGeometry: found match for signature " + "%#08lx\n", + diskData->Mbr.Signature)); + found = TRUE; + break; + } else if((diskData->Mbr.Signature == 0) && + (diskData->Mbr.MbrCheckSum != 0) && + (diskData->Mbr.MbrCheckSum == diskInfo->MbrCheckSum)) { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskUpdateGeometry: found match for xsum %#08lx\n", + diskData->Mbr.MbrCheckSum)); + found = TRUE; + break; + } + } + + if(found) { + + ULONG cylinders; + ULONG sectorsPerTrack; + ULONG tracksPerCylinder; + + ULONG length; + + // + // Point to the array of drive parameters. + // + + cylinders = diskInfo->DriveParameters.MaxCylinders + 1; + sectorsPerTrack = diskInfo->DriveParameters.SectorsPerTrack; + tracksPerCylinder = diskInfo->DriveParameters.MaxHeads + 1; + + // + // Since the BIOS may not report the full drive, recalculate the drive + // size based on the volume size and the BIOS values for tracks per + // cylinder and sectors per track.. + // + + length = tracksPerCylinder * sectorsPerTrack; + + if (length == 0) { + + // + // The BIOS information is bogus. + // + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskUpdateGeometry: H (%d) or S(%d) is zero\n", + tracksPerCylinder, sectorsPerTrack)); + return DiskGeometryUnknown; + } + + // + // since we are copying the structure RealGeometry here, we should + // really initialize all the fields, especially since a zero'd + // BytesPerSector field would cause a trap in xHalReadPartitionTable() + // + + diskData->RealGeometry = FdoExtension->DiskGeometry; + + // + // Save the geometry information away in the disk data block and + // set the bit indicating that we found a valid one. + // + + diskData->RealGeometry.SectorsPerTrack = sectorsPerTrack; + diskData->RealGeometry.TracksPerCylinder = tracksPerCylinder; + diskData->RealGeometry.Cylinders.QuadPart = (LONGLONG)cylinders; + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskUpdateGeometry: BIOS spt %#x, #heads %#x, " + "#cylinders %#x\n", + sectorsPerTrack, tracksPerCylinder, cylinders)); + + diskData->GeometrySource = DiskGeometryFromBios; + diskInfo->Device = FdoExtension->DeviceObject; + + // + // Increment the count of used geometry entries. + // + + InterlockedIncrement(&DetectInfoUsedCount); + + } else { + + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskUpdateGeometry: no match found for signature %#08lx\n", diskData->Mbr.Signature)); + } + + if(diskData->GeometrySource == DiskGeometryUnknown) { + + // + // We couldn't find a geometry from the BIOS. Check with the port + // driver and see if it can provide one. + // + + status = DiskGetPortGeometry(FdoExtension, &(diskData->RealGeometry)); + + if(NT_SUCCESS(status)) { + + // + // Check the geometry to make sure it's valid. + // + + if((diskData->RealGeometry.TracksPerCylinder * + diskData->RealGeometry.SectorsPerTrack) != 0) { + + diskData->GeometrySource = DiskGeometryFromPort; + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskUpdateGeometry: using Port geometry for disk %#p\n", FdoExtension)); + + if (diskData->RealGeometry.BytesPerSector == 0) { + + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskDriverReinit: Port driver failed to " + "set BytesPerSector in the RealGeometry\n")); + diskData->RealGeometry.BytesPerSector = + FdoExtension->DiskGeometry.BytesPerSector; + if (diskData->RealGeometry.BytesPerSector == 0) { + NT_ASSERT(!"BytesPerSector is still zero!"); + } + + } + } + } + } + + // + // If we came up with a "real" geometry for this drive then set it in the + // device extension. + // + + if (diskData->GeometrySource != DiskGeometryUnknown) { + + FdoExtension->DiskGeometry = diskData->RealGeometry; + } + + return diskData->GeometrySource; +} + + +NTSTATUS +DiskUpdateRemovableGeometry ( + IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension + ) + +/*++ + +Routine Description: + + This routine updates the geometry of the disk. It will query the port + driver to see if it can provide any geometry info. If not it will use + the current head & sector count. + + Based on these values & the capacity of the drive as reported by + ClassReadDriveCapacity it will determine a new cylinder count for the + device. + +Arguments: + + Fdo - Supplies the functional device object whos size needs to be updated. + +Return Value: + + Returns the status of the opertion. + +--*/ +{ + PCOMMON_DEVICE_EXTENSION commonExtension = &(FdoExtension->CommonExtension); + PDISK_DATA diskData = commonExtension->DriverData; + PDISK_GEOMETRY geometry = &(diskData->RealGeometry); + + NTSTATUS status; + + PAGED_CODE(); + + if (FdoExtension->DeviceDescriptor) { + NT_ASSERT(FdoExtension->DeviceDescriptor->RemovableMedia); + } + NT_ASSERT(TEST_FLAG(FdoExtension->DeviceObject->Characteristics, + FILE_REMOVABLE_MEDIA)); + + // + // Attempt to determine the disk geometry. First we'll check with the + // port driver to see what it suggests for a value. + // + + status = DiskGetPortGeometry(FdoExtension, geometry); + + if(NT_SUCCESS(status) && + ((geometry->TracksPerCylinder * geometry->SectorsPerTrack) != 0)) { + + FdoExtension->DiskGeometry = (*geometry); + } + + return status; +} + + +NTSTATUS +DiskGetPortGeometry( + IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, + OUT PDISK_GEOMETRY Geometry + ) +/*++ + +Routine Description: + + This routine will query the port driver for disk geometry. Some port + drivers (in particular IDEPORT) may be able to provide geometry for the + device. + +Arguments: + + FdoExtension - the device object for the disk. + + Geometry - a structure to save the geometry information into (if any is + available) + +Return Value: + + STATUS_SUCCESS if geometry information can be provided or + error status indicating why it can't. + +--*/ +{ + PCOMMON_DEVICE_EXTENSION commonExtension = &(FdoExtension->CommonExtension); + PIRP irp; + PIO_STACK_LOCATION irpStack; + KEVENT event; + + NTSTATUS status; + + PAGED_CODE(); + + // + // Build an irp to send IOCTL_DISK_GET_DRIVE_GEOMETRY to the lower driver. + // + + irp = IoAllocateIrp(commonExtension->LowerDeviceObject->StackSize, FALSE); + + if(irp == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + irpStack = IoGetNextIrpStackLocation(irp); + + irpStack->MajorFunction = IRP_MJ_DEVICE_CONTROL; + + irpStack->Parameters.DeviceIoControl.IoControlCode = + IOCTL_DISK_GET_DRIVE_GEOMETRY; + irpStack->Parameters.DeviceIoControl.OutputBufferLength = + sizeof(DISK_GEOMETRY); + + irp->AssociatedIrp.SystemBuffer = Geometry; + + KeInitializeEvent(&event, SynchronizationEvent, FALSE); + + IoSetCompletionRoutine(irp, + ClassSignalCompletion, + &event, + TRUE, + TRUE, + TRUE); + + status = IoCallDriver(commonExtension->LowerDeviceObject, irp); + if (status == STATUS_PENDING) { + KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL); + status = irp->IoStatus.Status; + } + + IoFreeIrp(irp); + + return status; +} + + +BOOLEAN +DiskIsNT4Geometry( + IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension + ) + +/*++ + +Routine Description: + + The default geometry that was used in partitioning disks under Windows NT 4.0 was + + Sectors per Track = 0x20 = 32 + Tracks per Cylinder = 0x40 = 64 + + This was changed in Windows 2000 to + + Sectors per Track = 0x3F = 63 + Tracks per Cylinder = 0xFF = 255 + + If neither the BIOS nor the port driver can report the correct geometry, we will + default to the new numbers on such disks. Now LVM uses the geometry when creating + logical volumes and dynamic disks. So reporting an incorrect geometry will cause + the entire extended partition / dynamic disk to be destroyed + + In this routine, we will look at the Master Boot Record. In 90% of the cases, the + first entry corresponds to a partition that starts on the first track. If this is + so, we shall retrieve the logical block address associated with it and calculate + the correct geometry. Now, all partitions start on a cylinder boundary. So, for + the remaining 10% we will look at the ending CHS number to determine the geometry + +--*/ + +{ + PUSHORT readBuffer = NULL; + BOOLEAN bFoundNT4 = FALSE; + + PAGED_CODE(); + + readBuffer = ExAllocatePoolWithTag(NonPagedPoolNx, FdoExtension->DiskGeometry.BytesPerSector, DISK_TAG_UPDATE_GEOM); + + if (readBuffer) + { + KEVENT event; + LARGE_INTEGER diskOffset; + IO_STATUS_BLOCK ioStatus = { 0 }; + PIRP irp; + + KeInitializeEvent(&event, NotificationEvent, FALSE); + + // + // Read the Master Boot Record at disk offset 0 + // + + diskOffset.QuadPart = 0; + + irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ, FdoExtension->DeviceObject, readBuffer, FdoExtension->DiskGeometry.BytesPerSector, &diskOffset, &event, &ioStatus); + + if (irp) + { + PIO_STACK_LOCATION irpSp = IoGetNextIrpStackLocation(irp); + NTSTATUS status; + + irpSp->Flags |= SL_OVERRIDE_VERIFY_VOLUME; + + status = IoCallDriver(FdoExtension->DeviceObject, irp); + + if (status == STATUS_PENDING) + { + KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL); + status = ioStatus.Status; + } + + if (NT_SUCCESS(status)) + { + // + // Match the boot record signature + // + + if (readBuffer[BOOT_SIGNATURE_OFFSET] == BOOT_RECORD_SIGNATURE) + { + PPARTITION_DESCRIPTOR partitionTableEntry = (PPARTITION_DESCRIPTOR)&readBuffer[PARTITION_TABLE_OFFSET]; + ULONG uCount = 0; + + // + // Walk the entries looking for a clue as to what the geometry might be + // + + for (uCount = 0; uCount < NUM_PARTITION_TABLE_ENTRIES; uCount++) + { + // + // We are only concerned if there might be a logical volume or if this disk is part of a dynamic set + // + + if (IsContainerPartition(partitionTableEntry->PartitionType) || partitionTableEntry->PartitionType == PARTITION_LDM) + { + // + // In 90% of the cases, the first entry corresponds to a partition that starts on the first track + // + + if (partitionTableEntry->StartingTrack == 1 && GET_STARTING_SECTOR(partitionTableEntry) == 0x20) + { + bFoundNT4 = TRUE; + break; + } + + // + // In almost every case, the ending CHS number is on a cylinder boundary + // + + if (partitionTableEntry->EndingTrack == 0x3F && GET_ENDING_S_OF_CHS(partitionTableEntry) == 0x20) + { + bFoundNT4 = TRUE; + break; + } + } + + partitionTableEntry++; + } + } + else + { + // + // The Master Boot Record is invalid + // + } + } + } + + FREE_POOL(readBuffer); + } + + return bFoundNT4; +} + + +NTSTATUS +DiskReadDriveCapacity( + IN PDEVICE_OBJECT Fdo + ) +/*++ + +Routine Description: + + This routine is used by disk.sys as a wrapper for the classpnp API + ClassReadDriveCapacity. It will perform some additional operations to + attempt to determine drive geometry before it calls the classpnp version + of the routine. + + For fixed disks this involves calling DiskUpdateGeometry which will check + various sources (the BIOS, the port driver) for geometry information. + +Arguments: + + Fdo - a pointer to the device object to be checked. + +Return Value: + + status of ClassReadDriveCapacity. + +--*/ + +{ + PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension; + NTSTATUS status; + + if (TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)) { + DiskUpdateRemovableGeometry(fdoExtension); + } else { + DiskUpdateGeometry(fdoExtension); + } + + status = ClassReadDriveCapacity(Fdo); + + return status; +} + + +VOID +DiskDriverReinitialization( + IN PDRIVER_OBJECT DriverObject, + IN PVOID Nothing, + IN ULONG Count + ) +/*++ + +Routine Description: + + This routine will scan through the current list of disks and attempt to + match them to any remaining geometry information. This will only be done + on the first call to the routine. + + Note: This routine assumes that the system will not be adding or removing + devices during this phase of the init process. This is very likely + a bad assumption but it greatly simplifies the code. + +Arguments: + + DriverObject - a pointer to the object for the disk driver. + + Nothing - unused + + Count - an indication of how many times this routine has been called. + +Return Value: + + none + +--*/ + +{ + PDEVICE_OBJECT deviceObject; + PFUNCTIONAL_DEVICE_EXTENSION fdoExtension; + PDISK_DATA diskData; + + ULONG unmatchedDiskCount; + PDEVICE_OBJECT unmatchedDisk = NULL; + + ULONG i; + PDISK_DETECT_INFO diskInfo = NULL; + + UNREFERENCED_PARAMETER(Nothing); + + if(Count != 1) { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, "DiskDriverReinitialization: ignoring call %d\n", + Count)); + return; + } + + // + // Check to see how many entries in the detect info list have been matched. + // If there's only one remaining we'll see if we can find a disk to go with + // it. + // + + if(DetectInfoCount == 0) { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, "DiskDriverReinitialization: no detect info saved\n")); + return; + } + + if((DetectInfoCount - DetectInfoUsedCount) != 1) { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, "DiskDriverReinitialization: %d of %d geometry entries " + "used - will not attempt match\n", DetectInfoUsedCount, DetectInfoCount)); + return; + } + + // + // Scan through the list of disks and see if any of them are missing + // geometry information. If there is only one such disk we'll try to + // match it to the unmatched geometry. + // + + + // + // ISSUE-2000/5/24-henrygab - figure out if there's a way to keep + // removals from happening while doing this. + // + + for(deviceObject = DriverObject->DeviceObject, unmatchedDiskCount = 0; + deviceObject != NULL; +#pragma prefast(suppress:28175, "Need to access the opaque field to scan through the list of disks") + deviceObject = deviceObject->NextDevice) { + + fdoExtension = deviceObject->DeviceExtension; + + if (!fdoExtension->CommonExtension.IsFdo) { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskDriverReinit: %#p is not an FDO\n", + deviceObject)); + continue; + } + + // + // If the geometry for this one is already known then skip it. + // + + diskData = fdoExtension->CommonExtension.DriverData; + if(diskData->GeometrySource != DiskGeometryUnknown) { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskDriverReinit: FDO %#p has a geometry\n", + deviceObject)); + continue; + } + + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, "DiskDriverReinit: FDO %#p has no geometry\n", + deviceObject)); + + // + // Mark this one as using the default. It's past the time when disk + // might blunder across the geometry info. If we set the geometry + // from the bios we'll reset this field down below. + // + + diskData->GeometrySource = DiskGeometryFromDefault; + + // + // As long as we've only got one unmatched disk we're fine. + // + + unmatchedDiskCount++; + if(unmatchedDiskCount > 1) { + NT_ASSERT(unmatchedDisk != NULL); + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, "DiskDriverReinit: FDO %#p also has no geometry\n", + unmatchedDisk)); + unmatchedDisk = NULL; + break; + } + + unmatchedDisk = deviceObject; + } + + // + // If there's more or less than one ungeometried disk then we can't do + // anything about the geometry. + // + + if(unmatchedDiskCount != 1) { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskDriverReinit: Unable to match geometry\n")); + return; + + } + + fdoExtension = unmatchedDisk->DeviceExtension; + diskData = fdoExtension->CommonExtension.DriverData; + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskDriverReinit: Found possible match\n")); + + // + // Find the geometry which wasn't assigned. + // + + for(i = 0; i < DetectInfoCount; i++) { + if(DetectInfoList[i].Device == NULL) { + diskInfo = &(DetectInfoList[i]); + break; + } + } + + if (diskInfo != NULL) + { + // + // Save the geometry information away in the disk data block and + // set the bit indicating that we found a valid one. + // + + ULONG cylinders; + ULONG sectorsPerTrack; + ULONG tracksPerCylinder; + + ULONG length; + + // + // Point to the array of drive parameters. + // + + cylinders = diskInfo->DriveParameters.MaxCylinders + 1; + sectorsPerTrack = diskInfo->DriveParameters.SectorsPerTrack; + tracksPerCylinder = diskInfo->DriveParameters.MaxHeads + 1; + + // + // Since the BIOS may not report the full drive, recalculate the drive + // size based on the volume size and the BIOS values for tracks per + // cylinder and sectors per track.. + // + + length = tracksPerCylinder * sectorsPerTrack; + + if (length == 0) { + + // + // The BIOS information is bogus. + // + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskDriverReinit: H (%d) or S(%d) is zero\n", + tracksPerCylinder, sectorsPerTrack)); + return; + } + + // + // since we are copying the structure RealGeometry here, we should + // really initialize all the fields, especially since a zero'd + // BytesPerSector field would cause a trap in xHalReadPartitionTable() + // + + diskData->RealGeometry = fdoExtension->DiskGeometry; + + // + // Save the geometry information away in the disk data block and + // set the bit indicating that we found a valid one. + // + + diskData->RealGeometry.SectorsPerTrack = sectorsPerTrack; + diskData->RealGeometry.TracksPerCylinder = tracksPerCylinder; + diskData->RealGeometry.Cylinders.QuadPart = (LONGLONG)cylinders; + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskDriverReinit: BIOS spt %#x, #heads %#x, " + "#cylinders %#x\n", + sectorsPerTrack, tracksPerCylinder, cylinders)); + + diskData->GeometrySource = DiskGeometryGuessedFromBios; + diskInfo->Device = unmatchedDisk; + + // + // Now copy the geometry over to the fdo extension and call + // classpnp to redetermine the disk size and cylinder count. + // + + fdoExtension->DiskGeometry = diskData->RealGeometry; + + (VOID)ClassReadDriveCapacity(unmatchedDisk); + + if (diskData->RealGeometry.BytesPerSector == 0) { + + // + // if the BytesPerSector field is set to zero for a disk + // listed in the bios, then the system will bugcheck in + // xHalReadPartitionTable(). assert here since it is + // easier to determine what is happening this way. + // + + NT_ASSERT(!"RealGeometry not set to non-zero bps\n"); + } + } + + return; +} + + +NTSTATUS +DiskGetDetectInfo( + IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, + OUT PDISK_DETECTION_INFO DetectInfo + ) +/*++ + +Routine Description: + + Get the Int13 information from the BIOS DetectInfoList. + +Arguments: + + FdoExtension - Supplies a pointer to the FDO extension that we want to + obtain the detect information for. + + DetectInfo - A buffer where the detect information will be copied to. + +Return Value: + + NTSTATUS code. + +--*/ +{ + ULONG i; + BOOLEAN found = FALSE; + PDISK_DETECT_INFO diskInfo = NULL; + PDISK_DATA diskData = FdoExtension->CommonExtension.DriverData; + + PAGED_CODE (); + + // + // Fail for non-fixed drives. + // + + if (TEST_FLAG (FdoExtension->DeviceObject->Characteristics, FILE_REMOVABLE_MEDIA)) { + return STATUS_NOT_SUPPORTED; + } + + // + // There is no GPT detection info, so fail this. + // + + if (diskData->PartitionStyle == PARTITION_STYLE_GPT) { + return STATUS_NOT_SUPPORTED; + } + + for(i = 0; i < DetectInfoCount; i++) { + + + NT_ASSERT(DetectInfoList != NULL); + + diskInfo = &(DetectInfoList[i]); + + if((diskData->Mbr.Signature != 0) && + (diskData->Mbr.Signature == diskInfo->Signature)) { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskGetDetectInfo: found match for signature " + "%#08lx\n", + diskData->Mbr.Signature)); + found = TRUE; + break; + } else if((diskData->Mbr.Signature == 0) && + (diskData->Mbr.MbrCheckSum != 0) && + (diskData->Mbr.MbrCheckSum == diskInfo->MbrCheckSum)) { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskGetDetectInfo: found match for xsum %#08lx\n", + diskData->Mbr.MbrCheckSum)); + found = TRUE; + break; + } + } + + if ( found ) { + DetectInfo->DetectionType = DetectInt13; + DetectInfo->Int13.DriveSelect = diskInfo->DriveParameters.DriveSelect; + DetectInfo->Int13.MaxCylinders = diskInfo->DriveParameters.MaxCylinders; + DetectInfo->Int13.SectorsPerTrack = diskInfo->DriveParameters.SectorsPerTrack; + DetectInfo->Int13.MaxHeads = diskInfo->DriveParameters.MaxHeads; + DetectInfo->Int13.NumberDrives = diskInfo->DriveParameters.NumberDrives; + RtlZeroMemory (&DetectInfo->ExInt13, sizeof (DetectInfo->ExInt13)); + } + + return (found ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL); +} + + +NTSTATUS +DiskReadSignature( + IN PDEVICE_OBJECT Fdo + ) + +/*++ + +Routine Description: + + Read the disks signature from the drive. The signature can be either + a MBR signature or a GPT/EFI signature. + + The low-level signature reading is done by IoReadDiskSignature(). + +Arguments: + + Fdo - Pointer to the FDO of a disk to read the signature for. + +Return Value: + + NTSTATUS code. + +--*/ + + +{ + NTSTATUS Status; + PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension; + PDISK_DATA diskData = fdoExtension->CommonExtension.DriverData; + DISK_SIGNATURE Signature = { 0 }; + + PAGED_CODE(); + + Status = IoReadDiskSignature (Fdo, + fdoExtension->DiskGeometry.BytesPerSector, + &Signature); + + if (!NT_SUCCESS (Status)) { + return Status; + } + + if (Signature.PartitionStyle == PARTITION_STYLE_GPT) { + diskData->PartitionStyle = PARTITION_STYLE_GPT; + diskData->Efi.DiskId = Signature.Gpt.DiskId; + } else if (Signature.PartitionStyle == PARTITION_STYLE_MBR) { + diskData->PartitionStyle = PARTITION_STYLE_MBR; + diskData->Mbr.Signature = Signature.Mbr.Signature; + diskData->Mbr.MbrCheckSum = Signature.Mbr.CheckSum; + } else { + NT_ASSERT (FALSE); + Status = STATUS_UNSUCCESSFUL; + } + + return Status; +} + +#endif // defined(_X86_) || defined(_AMD64_) + diff --git a/storage/class/disk/src/pnp.c b/storage/class/disk/src/pnp.c new file mode 100644 index 00000000..bb3a33c5 --- /dev/null +++ b/storage/class/disk/src/pnp.c @@ -0,0 +1,1098 @@ +/*++ + +Copyright (C) Microsoft Corporation, 1991 - 1999 + +Module Name: + + pnp.c + +Abstract: + + SCSI disk class driver + +Environment: + + kernel mode only + +Notes: + +Revision History: + +--*/ + +#include "disk.h" + + +#ifdef DEBUG_USE_WPP +#include "pnp.tmh" +#endif + +extern PULONG InitSafeBootMode; +ULONG diskDeviceSequenceNumber = 0; +extern BOOLEAN DiskIsPastReinit; + + +#ifdef ALLOC_PRAGMA + +#pragma alloc_text(PAGE, DiskAddDevice) +#pragma alloc_text(PAGE, DiskInitFdo) +#pragma alloc_text(PAGE, DiskStartFdo) +#pragma alloc_text(PAGE, DiskGenerateDeviceName) +#pragma alloc_text(PAGE, DiskCreateSymbolicLinks) +#pragma alloc_text(PAGE, DiskDeleteSymbolicLinks) +#pragma alloc_text(PAGE, DiskRemoveDevice) +#endif + + +NTSTATUS +DiskAddDevice( + IN PDRIVER_OBJECT DriverObject, + IN PDEVICE_OBJECT PhysicalDeviceObject + ) + +/*++ + +Routine Description: + + This routine gets a port drivers capabilities, obtains the + inquiry data, searches the SCSI bus for the port driver and creates + the device objects for the disks found. + +Arguments: + + DriverObject - Pointer to driver object created by system. + + Pdo - Device object use to send requests to port driver. + +Return Value: + + True is returned if one disk was found and successfully created. + +--*/ + +{ + ULONG rootPartitionMountable = FALSE; + + PCONFIGURATION_INFORMATION configurationInformation; + ULONG diskCount; + + NTSTATUS status; + + PAGED_CODE(); + + // + // See if we should be allowing file systems to mount on partition zero. + // + + TRY { + HANDLE deviceKey = NULL; + + UNICODE_STRING diskKeyName; + OBJECT_ATTRIBUTES objectAttributes = {0}; + HANDLE diskKey; + + RTL_QUERY_REGISTRY_TABLE queryTable[2] = { 0 }; + + status = IoOpenDeviceRegistryKey(PhysicalDeviceObject, + PLUGPLAY_REGKEY_DEVICE, + KEY_READ, + &deviceKey); + + if(!NT_SUCCESS(status)) { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DiskAddDevice: Error %#08lx opening device key " + "for pdo %p\n", + status, PhysicalDeviceObject)); + LEAVE; + } + + RtlInitUnicodeString(&diskKeyName, L"Disk"); + InitializeObjectAttributes(&objectAttributes, + &diskKeyName, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, + deviceKey, + NULL); + + status = ZwOpenKey(&diskKey, KEY_READ, &objectAttributes); + ZwClose(deviceKey); + + if(!NT_SUCCESS(status)) { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DiskAddDevice: Error %#08lx opening disk key " + "for pdo %p device key %p\n", + status, PhysicalDeviceObject, deviceKey)); + LEAVE; + } + + queryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT; + queryTable[0].Name = L"RootPartitionMountable"; + queryTable[0].EntryContext = &(rootPartitionMountable); + +#pragma prefast(suppress:6309, "We don't have QueryRoutine so Context doesn't make any sense") + status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE, + diskKey, + queryTable, + NULL, + NULL); + + if(!NT_SUCCESS(status)) { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DiskAddDevice: Error %#08lx reading value from " + "disk key %p for pdo %p\n", + status, diskKey, PhysicalDeviceObject)); + } + + ZwClose(diskKey); + + } FINALLY { + + // + // Do nothing. + // + + if(!NT_SUCCESS(status)) { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_PNP, "DiskAddDevice: Will %sallow file system to mount on " + "partition zero of disk %p\n", + (rootPartitionMountable ? "" : "not "), + PhysicalDeviceObject)); + } + } + + // + // Create device objects for disk + // + + diskCount = 0; + + status = DiskCreateFdo( + DriverObject, + PhysicalDeviceObject, + &diskCount, + (BOOLEAN) !rootPartitionMountable + ); + + // + // Get the number of disks already initialized. + // + + configurationInformation = IoGetConfigurationInformation(); + + if (NT_SUCCESS(status)) { + + // + // Increment system disk device count. + // + + configurationInformation->DiskCount++; + + } + + return status; + +} // end DiskAddDevice() + + +NTSTATUS +DiskInitFdo( + IN PDEVICE_OBJECT Fdo + ) + +/*++ + +Routine Description: + + This routine is called to do one-time initialization of new device objects + + +Arguments: + + Fdo - a pointer to the functional device object for this device + +Return Value: + + status + +--*/ + +{ + PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension; + PDISK_DATA diskData = (PDISK_DATA) fdoExtension->CommonExtension.DriverData; + + ULONG srbFlags = 0; + ULONG timeOut = 0; + ULONG bytesPerSector; + + PULONG dmSkew; + + NTSTATUS status = STATUS_SUCCESS; + + PAGED_CODE(); + + // + // Build the lookaside list for srb's for the physical disk. Should only + // need a couple. If this fails then we don't have an emergency SRB so + // fail the call to initialize. + // + + ClassInitializeSrbLookasideList((PCOMMON_DEVICE_EXTENSION) fdoExtension, + PARTITION0_LIST_SIZE); + + if (fdoExtension->DeviceDescriptor->RemovableMedia) + { + SET_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA); + } + + // + // Initialize the srb flags. + // + + // + // Because all requests share a common sense buffer, it is possible + // for the buffer to be overwritten if the port driver completes + // multiple failed requests that require a request sense before the + // class driver's completion routine can consume the data in the buffer. + // To prevent this, we allow the port driver to allocate a unique sense + // buffer each time it needs one. We are responsible for freeing this + // buffer. This also allows the adapter to be configured to support + // additional sense data beyond the minimum 18 bytes. + // + + SET_FLAG(fdoExtension->SrbFlags, SRB_FLAGS_PORT_DRIVER_ALLOCSENSE); + + if (fdoExtension->DeviceDescriptor->CommandQueueing && + fdoExtension->AdapterDescriptor->CommandQueueing) { + + SET_FLAG(fdoExtension->SrbFlags, SRB_FLAGS_QUEUE_ACTION_ENABLE); + + } + + // + // Look for controllers that require special flags. + // + + ClassScanForSpecial(fdoExtension, DiskBadControllers, DiskSetSpecialHacks); + + // + // Clear buffer for drive geometry. + // + + RtlZeroMemory(&(fdoExtension->DiskGeometry), + sizeof(DISK_GEOMETRY)); + + // + // Allocate request sense buffer. + // + + fdoExtension->SenseData = ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned, + SENSE_BUFFER_SIZE_EX, + DISK_TAG_START); + + if (fdoExtension->SenseData == NULL) { + + // + // The buffer can not be allocated. + // + + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DiskInitFdo: Can not allocate request sense buffer\n")); + + status = STATUS_INSUFFICIENT_RESOURCES; + return status; + } + + // + // Set the buffer size of SenseData + // + + fdoExtension->SenseDataLength = SENSE_BUFFER_SIZE_EX; + + // + // Physical device object will describe the entire + // device, starting at byte offset 0. + // + + fdoExtension->CommonExtension.StartingOffset.QuadPart = (LONGLONG)(0); + + // + // Set timeout value in seconds. + // + if ( (fdoExtension->MiniportDescriptor != NULL) && + (fdoExtension->MiniportDescriptor->IoTimeoutValue > 0) ) { + // + // use the value set by Storport miniport driver + // + fdoExtension->TimeOutValue = fdoExtension->MiniportDescriptor->IoTimeoutValue; + } else { + // + // get timeout value from registry + // + timeOut = ClassQueryTimeOutRegistryValue(Fdo); + + if (timeOut) { + fdoExtension->TimeOutValue = timeOut; + } else { + fdoExtension->TimeOutValue = SCSI_DISK_TIMEOUT; + } + } + // + // If this is a removable drive, build an entry in devicemap\scsi + // indicating it's physicaldriveN name, set up the appropriate + // update partitions routine and set the flags correctly. + // note: only do this after the timeout value is set, above. + // + + if (TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)) { + + ClassUpdateInformationInRegistry( Fdo, + "PhysicalDrive", + fdoExtension->DeviceNumber, + NULL, + 0); + // + // Enable media change notification for removable disks + // + ClassInitializeMediaChangeDetection(fdoExtension, + (PUCHAR)"Disk"); + + } else { + + SET_FLAG(fdoExtension->DeviceFlags, DEV_SAFE_START_UNIT); + SET_FLAG(fdoExtension->SrbFlags, SRB_FLAGS_NO_QUEUE_FREEZE); + + } + + // + // The commands we send during the init could cause the flags to change + // in case of any error. Save the SRB flags locally and restore it at + // the end of this function, so that the class driver can get it. + // + + srbFlags = fdoExtension->SrbFlags; + + + // + // Read the drive capacity. Don't use the disk version of the routine here + // since we don't know the disk signature yet - the disk version will + // attempt to determine the BIOS reported geometry. + // + + (VOID)ClassReadDriveCapacity(Fdo); + + // + // Set up sector size fields. + // + // Stack variables will be used to update + // the partition device extensions. + // + // The device extension field SectorShift is + // used to calculate sectors in I/O transfers. + // + // The DiskGeometry structure is used to service + // IOCTls used by the format utility. + // + + bytesPerSector = fdoExtension->DiskGeometry.BytesPerSector; + + // + // Make sure sector size is not zero. + // + + if (bytesPerSector == 0) { + + // + // Default sector size for disk is 512. + // + + bytesPerSector = fdoExtension->DiskGeometry.BytesPerSector = 512; + fdoExtension->SectorShift = 9; + } + + // + // Determine is DM Driver is loaded on an IDE drive that is + // under control of Atapi - this could be either a crashdump or + // an Atapi device is sharing the controller with an IDE disk. + // + + HalExamineMBR(fdoExtension->CommonExtension.DeviceObject, + fdoExtension->DiskGeometry.BytesPerSector, + (ULONG)0x54, + &dmSkew); + + if (dmSkew) { + + // + // Update the device extension, so that the call to IoReadPartitionTable + // will get the correct information. Any I/O to this disk will have + // to be skewed by *dmSkew sectors aka DMByteSkew. + // + + fdoExtension->DMSkew = *dmSkew; + fdoExtension->DMActive = TRUE; + fdoExtension->DMByteSkew = fdoExtension->DMSkew * bytesPerSector; + + FREE_POOL(dmSkew); + } + +#if defined(_X86_) || defined(_AMD64_) + + // + // Try to read the signature off the disk and determine the correct drive + // geometry based on that. This requires rereading the disk size to get + // the cylinder count updated correctly. + // + + if(!TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)) { + + DiskReadSignature(Fdo); + DiskReadDriveCapacity(Fdo); + + if (diskData->GeometrySource == DiskGeometryUnknown) + { + // + // Neither the BIOS nor the port driver could provide us with a reliable + // geometry. Before we use the default, look to see if it was partitioned + // under Windows NT4 [or earlier] and apply the one that was used back then + // + + if (DiskIsNT4Geometry(fdoExtension)) + { + diskData->RealGeometry = fdoExtension->DiskGeometry; + diskData->RealGeometry.SectorsPerTrack = 0x20; + diskData->RealGeometry.TracksPerCylinder = 0x40; + fdoExtension->DiskGeometry = diskData->RealGeometry; + + diskData->GeometrySource = DiskGeometryFromNT4; + } + } + } + +#endif + + DiskCreateSymbolicLinks(Fdo); + + // + // Get the SCSI address if it's available for use with SMART ioctls. + // SMART ioctls are used for failure prediction, so we need to get + // the SCSI address before initializing failure prediction. + // + + { + PIRP irp; + KEVENT event; + IO_STATUS_BLOCK statusBlock = { 0 }; + + KeInitializeEvent(&event, SynchronizationEvent, FALSE); + + irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_ADDRESS, + fdoExtension->CommonExtension.LowerDeviceObject, + NULL, + 0L, + &(diskData->ScsiAddress), + sizeof(SCSI_ADDRESS), + FALSE, + &event, + &statusBlock); + + status = STATUS_UNSUCCESSFUL; + + if(irp != NULL) { + + status = IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp); + + if(status == STATUS_PENDING) { + KeWaitForSingleObject(&event, + Executive, + KernelMode, + FALSE, + NULL); + status = statusBlock.Status; + } + } + } + + // + // Determine the type of disk and enable failure prediction in the hardware + // and enable failure prediction polling. + // + + if (*InitSafeBootMode == 0) + { + DiskDetectFailurePrediction(fdoExtension, + &diskData->FailurePredictionCapability, + NT_SUCCESS(status)); + + if (diskData->FailurePredictionCapability != FailurePredictionNone) + { + // + // Cool, we've got some sort of failure prediction, enable it + // at the hardware and then enable polling for it + // + + // + // By default we allow performance to be degradeded if failure + // prediction is enabled. + // + + diskData->AllowFPPerfHit = TRUE; + + // + // Enable polling only after Atapi and SBP2 add support for the new + // SRB flag that indicates that the request should not reset the + // drive spin down idle timer. + // + + status = DiskEnableDisableFailurePredictPolling(fdoExtension, + TRUE, + DISK_DEFAULT_FAILURE_POLLING_PERIOD); + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "DiskInitFdo: Failure Prediction Poll enabled as " + "%d for device %p, Status = %lx\n", + diskData->FailurePredictionCapability, + Fdo, + status)); + } + } else { + + // + // In safe boot mode we do not enable failure prediction, as perhaps + // it is the reason why normal boot does not work + // + + diskData->FailurePredictionCapability = FailurePredictionNone; + + } + + // + // Initialize the verify mutex + // + + KeInitializeMutex(&diskData->VerifyMutex, MAX_SECTORS_PER_VERIFY); + + // + // Initialize the flush group context + // + + RtlZeroMemory(&diskData->FlushContext, sizeof(DISK_GROUP_CONTEXT)); + + InitializeListHead(&diskData->FlushContext.CurrList); + InitializeListHead(&diskData->FlushContext.NextList); + + KeInitializeSpinLock(&diskData->FlushContext.Spinlock); + KeInitializeEvent(&diskData->FlushContext.Event, SynchronizationEvent, FALSE); + + + // + // Restore the saved value + // + fdoExtension->SrbFlags = srbFlags; + + return STATUS_SUCCESS; + +} // end DiskInitFdo() + +NTSTATUS +DiskStopDevice( + IN PDEVICE_OBJECT DeviceObject, + IN UCHAR Type + ) + +{ + UNREFERENCED_PARAMETER(DeviceObject); + UNREFERENCED_PARAMETER(Type); + return STATUS_SUCCESS; +} + +NTSTATUS +DiskGenerateDeviceName( + IN ULONG DeviceNumber, + OUT PCCHAR *RawName + ) + +/*++ + +Routine Description: + + This routine will allocate a unicode string buffer and then fill it in + with a generated name for the specified device object. + + It is the responsibility of the user to allocate a UNICODE_STRING structure + to pass in and to free UnicodeName->Buffer when done with it. + +Arguments: + + DeviceObject - a pointer to the device object + + UnicodeName - a unicode string to put the name buffer into + +Return Value: + + status + +--*/ + +#define FDO_NAME_FORMAT "\\Device\\Harddisk%d\\DR%d" + +{ + CHAR rawName[64] = { 0 }; + NTSTATUS status; + + PAGED_CODE(); + + status = RtlStringCchPrintfA(rawName, sizeof(rawName) - 1, FDO_NAME_FORMAT, DeviceNumber, + diskDeviceSequenceNumber++); + if (!NT_SUCCESS(status)) { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DiskGenerateDeviceName: Format FDO name failed with error: 0x%X\n", status)); + return status; + } + + *RawName = ExAllocatePoolWithTag(PagedPool, + strlen(rawName) + 1, + DISK_TAG_NAME); + + if(*RawName == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + status = RtlStringCchCopyA(*RawName, strlen(rawName) + 1, rawName); + if (!NT_SUCCESS(status)) { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DiskGenerateDeviceName: Device name copy failed with error: 0x%X\n", status)); + FREE_POOL(*RawName); + return status; + } + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "DiskGenerateDeviceName: generated \"%s\"\n", rawName)); + + return STATUS_SUCCESS; +} + + +VOID +DiskCreateSymbolicLinks( + IN PDEVICE_OBJECT DeviceObject + ) + +/*++ + +Routine Description: + + This routine will generate a symbolic link for the specified device object + using the well known form \\Device\HarddiskX\PartitionY, where X and Y is + always 0 which represents the entire disk object. + + This routine will not try to delete any previous symbolic link for the + same generated name - the caller must make sure the symbolic link has + been broken before calling this routine. + +Arguments: + + DeviceObject - the device object to make a well known name for + +Return Value: + + STATUS + +--*/ + +{ + PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; + PDISK_DATA diskData = commonExtension->DriverData; + + WCHAR wideSourceName[64] = { 0 }; + UNICODE_STRING unicodeSourceName; + + NTSTATUS status; + + PAGED_CODE(); + + // + // Build the destination for the link first using the device name + // stored in the device object + // + + NT_ASSERT(commonExtension->DeviceName.Buffer); + + if(!diskData->LinkStatus.WellKnownNameCreated) { + // + // Put together the source name using the partition and device number + // in the device extension and disk data segment + // + + status = RtlStringCchPrintfW(wideSourceName, sizeof(wideSourceName) / sizeof(wideSourceName[0]) - 1, + L"\\Device\\Harddisk%d\\Partition0", + commonExtension->PartitionZeroExtension->DeviceNumber); + + if (NT_SUCCESS(status)) { + + RtlInitUnicodeString(&unicodeSourceName, wideSourceName); + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "DiskCreateSymbolicLink: Linking %wZ to %wZ\n", + &unicodeSourceName, + &commonExtension->DeviceName)); + + status = IoCreateSymbolicLink(&unicodeSourceName, + &commonExtension->DeviceName); + + if(NT_SUCCESS(status)){ + diskData->LinkStatus.WellKnownNameCreated = TRUE; + } + } + } + + if (!diskData->LinkStatus.PhysicalDriveLinkCreated) { + + // + // Create a physical drive N link using the device number we saved + // away during AddDevice. + // + + status = RtlStringCchPrintfW(wideSourceName, sizeof(wideSourceName) / sizeof(wideSourceName[0]) - 1, + L"\\DosDevices\\PhysicalDrive%d", + commonExtension->PartitionZeroExtension->DeviceNumber); + if (NT_SUCCESS(status)) { + + RtlInitUnicodeString(&unicodeSourceName, wideSourceName); + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "DiskCreateSymbolicLink: Linking %wZ to %wZ\n", + &unicodeSourceName, + &(commonExtension->DeviceName))); + + status = IoCreateSymbolicLink(&unicodeSourceName, + &(commonExtension->DeviceName)); + + if(NT_SUCCESS(status)) { + diskData->LinkStatus.PhysicalDriveLinkCreated = TRUE; + } + } + } + + + return; +} + + +VOID +DiskDeleteSymbolicLinks( + IN PDEVICE_OBJECT DeviceObject + ) + +/*++ + +Routine Description: + + This routine will delete the well known name (symlink) for the specified + device. It generates the link name using information stored in the + device extension + +Arguments: + + DeviceObject - the device object we are unlinking + +Return Value: + + status + +--*/ + +{ + PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; + PDISK_DATA diskData = commonExtension->DriverData; + + WCHAR wideLinkName[64] = { 0 }; + UNICODE_STRING unicodeLinkName; + NTSTATUS status; + + PAGED_CODE(); + + if(diskData->LinkStatus.WellKnownNameCreated) { + + status = RtlStringCchPrintfW(wideLinkName, sizeof(wideLinkName) / sizeof(wideLinkName[0]) - 1, + L"\\Device\\Harddisk%d\\Partition0", + commonExtension->PartitionZeroExtension->DeviceNumber); + if (NT_SUCCESS(status)) { + RtlInitUnicodeString(&unicodeLinkName, wideLinkName); + IoDeleteSymbolicLink(&unicodeLinkName); + } + diskData->LinkStatus.WellKnownNameCreated = FALSE; + } + + if(diskData->LinkStatus.PhysicalDriveLinkCreated) { + + status = RtlStringCchPrintfW(wideLinkName, sizeof(wideLinkName) / sizeof(wideLinkName[0]) - 1, + L"\\DosDevices\\PhysicalDrive%d", + commonExtension->PartitionZeroExtension->DeviceNumber); + if (NT_SUCCESS(status)) { + RtlInitUnicodeString(&unicodeLinkName, wideLinkName); + IoDeleteSymbolicLink(&unicodeLinkName); + } + diskData->LinkStatus.PhysicalDriveLinkCreated = FALSE; + } + + + return; +} + + +NTSTATUS +DiskRemoveDevice( + IN PDEVICE_OBJECT DeviceObject, + IN UCHAR Type + ) + +/*++ + +Routine Description: + + This routine will release any resources the device may have allocated for + this device object and return. + +Arguments: + + DeviceObject - the device object being removed + +Return Value: + + status + +--*/ + +{ + PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; + PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension; + + PAGED_CODE(); + + // + // Handle query and cancel + // + + if((Type == IRP_MN_QUERY_REMOVE_DEVICE) || + (Type == IRP_MN_CANCEL_REMOVE_DEVICE)) { + return STATUS_SUCCESS; + } + + // + // Delete our object directory. + // + + if(fdoExtension->DeviceDirectory != NULL) { + ZwMakeTemporaryObject(fdoExtension->DeviceDirectory); + ZwClose(fdoExtension->DeviceDirectory); + fdoExtension->DeviceDirectory = NULL; + } + + if(Type == IRP_MN_REMOVE_DEVICE) { + + FREE_POOL(fdoExtension->SenseData); + + IoGetConfigurationInformation()->DiskCount--; + + } + + DiskDeleteSymbolicLinks(DeviceObject); + + if (Type == IRP_MN_REMOVE_DEVICE) + { + ClassDeleteSrbLookasideList(commonExtension); + } + + return STATUS_SUCCESS; +} + + +NTSTATUS +DiskStartFdo( + IN PDEVICE_OBJECT Fdo + ) + +/*++ + +Routine Description: + + This routine will query the underlying device for any information necessary + to complete initialization of the device. This will include physical + disk geometry, mode sense information and such. + + This routine does not perform partition enumeration - that is left to the + re-enumeration routine + + If this routine fails it will return an error value. It does not clean up + any resources - that is left for the Stop/Remove routine. + +Arguments: + + Fdo - a pointer to the functional device object for this device + +Return Value: + + status + +--*/ + +{ + PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension; + PCOMMON_DEVICE_EXTENSION commonExtension = &(fdoExtension->CommonExtension); + PDISK_DATA diskData = commonExtension->DriverData; + STORAGE_HOTPLUG_INFO hotplugInfo = { 0 }; + DISK_CACHE_INFORMATION cacheInfo = { 0 }; + ULONG isPowerProtected = 0; + NTSTATUS status; + + PAGED_CODE(); + + // + // Get the hotplug information, so we can turn off write cache if needed + // + // NOTE: Capabilities info is not good enough to determine hotplugedness + // as we cannot determine device relations information and other + // dependencies. Get the hotplug info instead + // + + { + PIRP irp; + KEVENT event; + IO_STATUS_BLOCK statusBlock = { 0 }; + + KeInitializeEvent(&event, SynchronizationEvent, FALSE); + + irp = IoBuildDeviceIoControlRequest(IOCTL_STORAGE_GET_HOTPLUG_INFO, + Fdo, + NULL, + 0L, + &hotplugInfo, + sizeof(STORAGE_HOTPLUG_INFO), + FALSE, + &event, + &statusBlock); + + if (irp != NULL) { + + // send to self -- classpnp handles this + status = IoCallDriver(Fdo, irp); + if (status == STATUS_PENDING) { + KeWaitForSingleObject(&event, + Executive, + KernelMode, + FALSE, + NULL); + + status = statusBlock.Status; + } + NT_ASSERT(NT_SUCCESS(status)); + } + } + + // + // Clear the DEV_WRITE_CACHE flag now and set + // it below only if we read that from the disk + // + CLEAR_FLAG(fdoExtension->DeviceFlags, DEV_WRITE_CACHE); + ADJUST_FUA_FLAG(fdoExtension); + + diskData->WriteCacheOverride = DiskWriteCacheDefault; + + // + // Look into the registry to see if the user + // has chosen to override the default setting + // + ClassGetDeviceParameter(fdoExtension, + DiskDeviceParameterSubkey, + DiskDeviceUserWriteCacheSetting, + (PULONG)&diskData->WriteCacheOverride); + + if (diskData->WriteCacheOverride == DiskWriteCacheDefault) + { + // + // The user has not overridden the default settings + // + if (TEST_FLAG(fdoExtension->ScanForSpecialFlags, CLASS_SPECIAL_DISABLE_WRITE_CACHE)) + { + // + // This flag indicates that we have faulty firmware and this + // may cause the filesystem to refuse to mount on this media + // + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_PNP, "DiskStartFdo: Turning off write cache for %p due to a firmware issue\n", Fdo)); + + diskData->WriteCacheOverride = DiskWriteCacheDisable; + } + else if (hotplugInfo.DeviceHotplug && !hotplugInfo.WriteCacheEnableOverride) + { + // + // This flag indicates that the device is hotpluggable making it unsafe to enable caching + // + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_PNP, "DiskStartFdo: Turning off write cache for %p due to hotpluggable device\n", Fdo)); + + diskData->WriteCacheOverride = DiskWriteCacheDisable; + } + else if (hotplugInfo.MediaHotplug) + { + // + // This flag indicates that the media in the device cannot be reliably locked + // + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_PNP, "DiskStartFdo: Turning off write cache for %p due to unlockable media\n", Fdo)); + + diskData->WriteCacheOverride = DiskWriteCacheDisable; + } + else + { + // + // Even though the device does not seem to have any obvious problems + // we leave it to the user to modify the previous write cache setting + // + } + } + + // + // Query the disk to see if write cache is enabled + // and set the DEV_WRITE_CACHE flag appropriately + // + + status = DiskGetCacheInformation(fdoExtension, &cacheInfo); + + if (NT_SUCCESS(status)) + { + if (cacheInfo.WriteCacheEnabled == TRUE) + { + SET_FLAG(fdoExtension->DeviceFlags, DEV_WRITE_CACHE); + ADJUST_FUA_FLAG(fdoExtension); + + if (diskData->WriteCacheOverride == DiskWriteCacheDisable) + { + // + // Write cache is currently enabled on this + // device, but we would like to turn it off + // + cacheInfo.WriteCacheEnabled = FALSE; + + DiskSetCacheInformation(fdoExtension, &cacheInfo); + } + } + else + { + if (diskData->WriteCacheOverride == DiskWriteCacheEnable) + { + // + // Write cache is currently disabled on this + // device, but we would like to turn it on + // + cacheInfo.WriteCacheEnabled = TRUE; + + DiskSetCacheInformation(fdoExtension, &cacheInfo); + } + } + } + + // + // Query the registry to see if this disk is power-protected or not + // + + CLEAR_FLAG(fdoExtension->DeviceFlags, DEV_POWER_PROTECTED); + + ClassGetDeviceParameter(fdoExtension, DiskDeviceParameterSubkey, DiskDeviceCacheIsPowerProtected, &isPowerProtected); + + if (isPowerProtected == 1) + { + SET_FLAG(fdoExtension->DeviceFlags, DEV_POWER_PROTECTED); + } + + ADJUST_FUA_FLAG(fdoExtension); + + return STATUS_SUCCESS; + +} // end DiskStartFdo() + diff --git a/storage/filters/addfilter/addfilter.sln b/storage/filters/addfilter/addfilter.sln index 180cd0ca..539a5073 100644 --- a/storage/filters/addfilter/addfilter.sln +++ b/storage/filters/addfilter/addfilter.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "addfilter", "src\addfilter.vcxproj", "{DB3111FA-5EA9-43C5-82C9-B9C8053C488F}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "addfilter", "src\addfilter.vcxproj", "{7FB29A64-E54D-40CA-AF78-2347B8E90BCB}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +13,14 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {DB3111FA-5EA9-43C5-82C9-B9C8053C488F}.Debug|Win32.ActiveCfg = Debug|Win32 - {DB3111FA-5EA9-43C5-82C9-B9C8053C488F}.Debug|Win32.Build.0 = Debug|Win32 - {DB3111FA-5EA9-43C5-82C9-B9C8053C488F}.Release|Win32.ActiveCfg = Release|Win32 - {DB3111FA-5EA9-43C5-82C9-B9C8053C488F}.Release|Win32.Build.0 = Release|Win32 - {DB3111FA-5EA9-43C5-82C9-B9C8053C488F}.Debug|x64.ActiveCfg = Debug|x64 - {DB3111FA-5EA9-43C5-82C9-B9C8053C488F}.Debug|x64.Build.0 = Debug|x64 - {DB3111FA-5EA9-43C5-82C9-B9C8053C488F}.Release|x64.ActiveCfg = Release|x64 - {DB3111FA-5EA9-43C5-82C9-B9C8053C488F}.Release|x64.Build.0 = Release|x64 + {7FB29A64-E54D-40CA-AF78-2347B8E90BCB}.Debug|Win32.ActiveCfg = Debug|Win32 + {7FB29A64-E54D-40CA-AF78-2347B8E90BCB}.Debug|Win32.Build.0 = Debug|Win32 + {7FB29A64-E54D-40CA-AF78-2347B8E90BCB}.Release|Win32.ActiveCfg = Release|Win32 + {7FB29A64-E54D-40CA-AF78-2347B8E90BCB}.Release|Win32.Build.0 = Release|Win32 + {7FB29A64-E54D-40CA-AF78-2347B8E90BCB}.Debug|x64.ActiveCfg = Debug|x64 + {7FB29A64-E54D-40CA-AF78-2347B8E90BCB}.Debug|x64.Build.0 = Debug|x64 + {7FB29A64-E54D-40CA-AF78-2347B8E90BCB}.Release|x64.ActiveCfg = Release|x64 + {7FB29A64-E54D-40CA-AF78-2347B8E90BCB}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/storage/filters/addfilter/src/addfilter.vcxproj b/storage/filters/addfilter/src/addfilter.vcxproj index 5b02e329..401a37eb 100644 --- a/storage/filters/addfilter/src/addfilter.vcxproj +++ b/storage/filters/addfilter/src/addfilter.vcxproj @@ -19,11 +19,11 @@ - {DB3111FA-5EA9-43C5-82C9-B9C8053C488F} + {7FB29A64-E54D-40CA-AF78-2347B8E90BCB} $(MSBuildProjectName) Debug Win32 - {A9F55797-8AB2-4835-A740-6D1B85080D93} + {397B8C6C-A536-444A-8878-DCEDB2A025F9} diff --git a/storage/filters/addfilter/src/addfilter.vcxproj.Filters b/storage/filters/addfilter/src/addfilter.vcxproj.Filters index cfd4115f..ed2c76b5 100644 --- a/storage/filters/addfilter/src/addfilter.vcxproj.Filters +++ b/storage/filters/addfilter/src/addfilter.vcxproj.Filters @@ -3,15 +3,15 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {7AB43DA2-567B-4EA6-85D1-5D797B79E2D5} + {C7A4F292-62DA-4FC0-83E2-5555F22B36BF} h;hpp;hxx;hm;inl;inc;xsd - {03051893-B6D1-4E2C-B507-42F32DBDEE5F} + {0FDB2550-C5A7-43FD-B4B2-07773CEFEDDB} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {8946B58F-86D1-40B9-BC68-9E7EAB25EEFA} + {6B9535FA-975A-43A7-B0E4-9DF2361CA2D8} diff --git a/storage/iscsi/iscsi.sln b/storage/iscsi/iscsi.sln index 8e9396a7..09bf338b 100644 --- a/storage/iscsi/iscsi.sln +++ b/storage/iscsi/iscsi.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "EmptyProject", "src\EmptyProject.vcxproj", "{6DC3C926-3EE7-43D0-9575-9A77DF02F1C0}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "EmptyProject", "src\EmptyProject.vcxproj", "{FD5B8601-22DE-4A00-BAF6-9DD8D0BFA736}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +13,14 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {6DC3C926-3EE7-43D0-9575-9A77DF02F1C0}.Debug|Win32.ActiveCfg = Debug|Win32 - {6DC3C926-3EE7-43D0-9575-9A77DF02F1C0}.Debug|Win32.Build.0 = Debug|Win32 - {6DC3C926-3EE7-43D0-9575-9A77DF02F1C0}.Release|Win32.ActiveCfg = Release|Win32 - {6DC3C926-3EE7-43D0-9575-9A77DF02F1C0}.Release|Win32.Build.0 = Release|Win32 - {6DC3C926-3EE7-43D0-9575-9A77DF02F1C0}.Debug|x64.ActiveCfg = Debug|x64 - {6DC3C926-3EE7-43D0-9575-9A77DF02F1C0}.Debug|x64.Build.0 = Debug|x64 - {6DC3C926-3EE7-43D0-9575-9A77DF02F1C0}.Release|x64.ActiveCfg = Release|x64 - {6DC3C926-3EE7-43D0-9575-9A77DF02F1C0}.Release|x64.Build.0 = Release|x64 + {FD5B8601-22DE-4A00-BAF6-9DD8D0BFA736}.Debug|Win32.ActiveCfg = Debug|Win32 + {FD5B8601-22DE-4A00-BAF6-9DD8D0BFA736}.Debug|Win32.Build.0 = Debug|Win32 + {FD5B8601-22DE-4A00-BAF6-9DD8D0BFA736}.Release|Win32.ActiveCfg = Release|Win32 + {FD5B8601-22DE-4A00-BAF6-9DD8D0BFA736}.Release|Win32.Build.0 = Release|Win32 + {FD5B8601-22DE-4A00-BAF6-9DD8D0BFA736}.Debug|x64.ActiveCfg = Debug|x64 + {FD5B8601-22DE-4A00-BAF6-9DD8D0BFA736}.Debug|x64.Build.0 = Debug|x64 + {FD5B8601-22DE-4A00-BAF6-9DD8D0BFA736}.Release|x64.ActiveCfg = Release|x64 + {FD5B8601-22DE-4A00-BAF6-9DD8D0BFA736}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/storage/iscsi/src/EmptyProject.vcxproj b/storage/iscsi/src/EmptyProject.vcxproj index c9ad85f8..1859ceef 100644 --- a/storage/iscsi/src/EmptyProject.vcxproj +++ b/storage/iscsi/src/EmptyProject.vcxproj @@ -19,12 +19,12 @@ - {6DC3C926-3EE7-43D0-9575-9A77DF02F1C0} + {FD5B8601-22DE-4A00-BAF6-9DD8D0BFA736} $(MSBuildProjectName) false Debug Win32 - {A25DA04D-0F32-49B4-A66F-5A40647F7D7E} + {90DC0765-F04B-4C99-9D2F-643FAF30E4ED} diff --git a/storage/iscsi/src/EmptyProject.vcxproj.Filters b/storage/iscsi/src/EmptyProject.vcxproj.Filters index d0c6ac93..4418304b 100644 --- a/storage/iscsi/src/EmptyProject.vcxproj.Filters +++ b/storage/iscsi/src/EmptyProject.vcxproj.Filters @@ -3,15 +3,15 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {389E59B5-5F73-4BF6-A7AB-E90ADCAAB13A} + {E173FC59-40EE-4F3E-8AD1-F7AAD06B8E6A} h;hpp;hxx;hm;inl;inc;xsd - {5435109E-A1E9-4A75-98B3-3A3D5711BD05} + {DBEDD0D9-C92D-4107-BC37-22DEEBD50A60} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {43B3CCA5-BAE4-4DDC-952D-F1D913E7C293} + {FEC8E2D6-F35E-4CF0-B0F1-E9CD45C55166} \ No newline at end of file diff --git a/storage/iscsi/src/iscsihba.mof b/storage/iscsi/src/iscsihba.mof index 5a2e9f01..71a7d9d6 100644 --- a/storage/iscsi/src/iscsihba.mof +++ b/storage/iscsi/src/iscsihba.mof @@ -333,6 +333,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -4085,6 +4114,35 @@ class ISCSI_TargetMapping + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -8287,6 +8345,35 @@ class MSiSCSI_RADIUSConfig + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/storage/miniports/lsi_u3/lsi_u3.sln b/storage/miniports/lsi_u3/lsi_u3.sln index 83d496e5..3a65768d 100644 --- a/storage/miniports/lsi_u3/lsi_u3.sln +++ b/storage/miniports/lsi_u3/lsi_u3.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lsi_u3", "src\lsi_u3.vcxproj", "{A153DF0A-DD74-4E6A-B101-7D805F58859E}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lsi_u3", "src\lsi_u3.vcxproj", "{5604AA6B-FB19-4251-9086-76975D9B64A9}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +13,14 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {A153DF0A-DD74-4E6A-B101-7D805F58859E}.Debug|Win32.ActiveCfg = Debug|Win32 - {A153DF0A-DD74-4E6A-B101-7D805F58859E}.Debug|Win32.Build.0 = Debug|Win32 - {A153DF0A-DD74-4E6A-B101-7D805F58859E}.Release|Win32.ActiveCfg = Release|Win32 - {A153DF0A-DD74-4E6A-B101-7D805F58859E}.Release|Win32.Build.0 = Release|Win32 - {A153DF0A-DD74-4E6A-B101-7D805F58859E}.Debug|x64.ActiveCfg = Debug|x64 - {A153DF0A-DD74-4E6A-B101-7D805F58859E}.Debug|x64.Build.0 = Debug|x64 - {A153DF0A-DD74-4E6A-B101-7D805F58859E}.Release|x64.ActiveCfg = Release|x64 - {A153DF0A-DD74-4E6A-B101-7D805F58859E}.Release|x64.Build.0 = Release|x64 + {5604AA6B-FB19-4251-9086-76975D9B64A9}.Debug|Win32.ActiveCfg = Debug|Win32 + {5604AA6B-FB19-4251-9086-76975D9B64A9}.Debug|Win32.Build.0 = Debug|Win32 + {5604AA6B-FB19-4251-9086-76975D9B64A9}.Release|Win32.ActiveCfg = Release|Win32 + {5604AA6B-FB19-4251-9086-76975D9B64A9}.Release|Win32.Build.0 = Release|Win32 + {5604AA6B-FB19-4251-9086-76975D9B64A9}.Debug|x64.ActiveCfg = Debug|x64 + {5604AA6B-FB19-4251-9086-76975D9B64A9}.Debug|x64.Build.0 = Debug|x64 + {5604AA6B-FB19-4251-9086-76975D9B64A9}.Release|x64.ActiveCfg = Release|x64 + {5604AA6B-FB19-4251-9086-76975D9B64A9}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/storage/miniports/lsi_u3/src/lsi_u3.vcxproj b/storage/miniports/lsi_u3/src/lsi_u3.vcxproj index c8c23197..865d1649 100644 --- a/storage/miniports/lsi_u3/src/lsi_u3.vcxproj +++ b/storage/miniports/lsi_u3/src/lsi_u3.vcxproj @@ -19,11 +19,11 @@ - {A153DF0A-DD74-4E6A-B101-7D805F58859E} + {5604AA6B-FB19-4251-9086-76975D9B64A9} $(MSBuildProjectName) Debug Win32 - {531FF5B8-3943-4795-ABBA-FB4D662B6DAD} + {5E93E1AB-7A16-49EE-95FC-15786A9773CE} @@ -103,7 +103,7 @@ %(AdditionalIncludeDirectories);..\..\inc - %(AdditionalDependencies);$(DDK_LIB_PATH)\storport.lib;$(DDK_LIB_PATH)\ntoskrnl.lib + %(AdditionalDependencies);$(DDK_LIB_PATH)\storport.lib @@ -122,7 +122,7 @@ %(AdditionalIncludeDirectories);..\..\inc - %(AdditionalDependencies);$(DDK_LIB_PATH)\storport.lib;$(DDK_LIB_PATH)\ntoskrnl.lib + %(AdditionalDependencies);$(DDK_LIB_PATH)\storport.lib @@ -141,7 +141,7 @@ %(AdditionalIncludeDirectories);..\..\inc - %(AdditionalDependencies);$(DDK_LIB_PATH)\storport.lib;$(DDK_LIB_PATH)\ntoskrnl.lib + %(AdditionalDependencies);$(DDK_LIB_PATH)\storport.lib @@ -160,7 +160,7 @@ %(AdditionalIncludeDirectories);..\..\inc - %(AdditionalDependencies);$(DDK_LIB_PATH)\storport.lib;$(DDK_LIB_PATH)\ntoskrnl.lib + %(AdditionalDependencies);$(DDK_LIB_PATH)\storport.lib diff --git a/storage/miniports/lsi_u3/src/lsi_u3.vcxproj.Filters b/storage/miniports/lsi_u3/src/lsi_u3.vcxproj.Filters index 73740c82..a2cdb480 100644 --- a/storage/miniports/lsi_u3/src/lsi_u3.vcxproj.Filters +++ b/storage/miniports/lsi_u3/src/lsi_u3.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {02888A8B-1B09-41F1-A02A-9B5559D69646} + {9B1331DA-4E8F-4E3A-8367-CAC8F077EC8B} h;hpp;hxx;hm;inl;inc;xsd - {AD1CE29F-4336-4621-943B-E8804DFB6691} + {F4B1DC38-0127-43F5-B17A-2602A68C099A} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {180DBD8C-6EE7-4126-B7EB-6D73118FD824} + {7F228B50-E184-486C-A497-F81D562ED33A} inf;inv;inx;mof;mc; - {286AEE48-D81E-4E73-9C1F-C5620803D643} + {7817713B-6E96-45AD-AD6E-2A26F7D9741E} diff --git a/storage/miniports/storahci/src/common.c b/storage/miniports/storahci/src/common.c index 99b58113..c37803bd 100644 --- a/storage/miniports/storahci/src/common.c +++ b/storage/miniports/storahci/src/common.c @@ -7093,7 +7093,7 @@ Return Value: if (!FillClippedSGL(StorPortGetScatterGatherList(ChannelExtension->AdapterExtension, (PSCSI_REQUEST_BLOCK)Srb), (PSTOR_SCATTER_GATHER_LIST) &srbExtension->LocalSgl, - sizeof(SRB_IO_CONTROL) + protocolDataRequest->ProtocolSpecificData.ProtocolDataOffset, + sizeof(SRB_IO_CONTROL) + FIELD_OFFSET(STORAGE_PROTOCOL_DATA_DESCRIPTOR, ProtocolSpecificData) + protocolDataRequest->ProtocolSpecificData.ProtocolDataOffset, sizeof(IDENTIFY_DEVICE_DATA))) { Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST; status = STOR_STATUS_BUFFER_TOO_SMALL; @@ -7297,7 +7297,9 @@ Return Value: // Set up command to be sent to device. // Using NULL as physical address of buffer so that SGL won't be set in calling function. // - logPageBuffer = (PVOID)((PUCHAR)protocolDataRequest + protocolDataRequest->ProtocolSpecificData.ProtocolDataOffset); + logPageBuffer = (PVOID)((PUCHAR)protocolDataRequest + + FIELD_OFFSET(STORAGE_PROTOCOL_DATA_DESCRIPTOR, ProtocolSpecificData) + + protocolDataRequest->ProtocolSpecificData.ProtocolDataOffset); logPageBlocks = protocolDataRequest->ProtocolSpecificData.ProtocolDataLength / IDE_GP_LOG_SECTOR_SIZE; if (smartLog) { @@ -7327,7 +7329,7 @@ Return Value: // if (!FillClippedSGL(StorPortGetScatterGatherList(ChannelExtension->AdapterExtension, (PSCSI_REQUEST_BLOCK)Srb), (PSTOR_SCATTER_GATHER_LIST) &srbExtension->LocalSgl, - sizeof(SRB_IO_CONTROL) + protocolDataRequest->ProtocolSpecificData.ProtocolDataOffset, + sizeof(SRB_IO_CONTROL) + FIELD_OFFSET(STORAGE_PROTOCOL_DATA_DESCRIPTOR, ProtocolSpecificData) + protocolDataRequest->ProtocolSpecificData.ProtocolDataOffset, logPageBlocks * IDE_GP_LOG_SECTOR_SIZE)) { Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST; status = STOR_STATUS_BUFFER_TOO_SMALL; @@ -7366,6 +7368,7 @@ Return Value: PSRB_IO_CONTROL srbControl = NULL; ULONG srbFlags = SrbGetSrbFlags(Srb); PSTORAGE_PROTOCOL_DATA_DESCRIPTOR protocolDataRequest = NULL; + ULONGLONG protocolSpecificDataBufferOffset = 0; srbControl = (PSRB_IO_CONTROL)SrbGetDataBuffer(Srb); srbDataBufferLength = SrbGetDataTransferLength(Srb); @@ -7389,9 +7392,11 @@ Return Value: } protocolDataRequest = (PSTORAGE_PROTOCOL_DATA_DESCRIPTOR)(srbControl + 1); + protocolSpecificDataBufferOffset = (ULONGLONG)sizeof(SRB_IO_CONTROL) + + FIELD_OFFSET(STORAGE_PROTOCOL_DATA_DESCRIPTOR, ProtocolSpecificData) + + protocolDataRequest->ProtocolSpecificData.ProtocolDataOffset; - if ((ULONGLONG)srbDataBufferLength < ((ULONGLONG)sizeof(SRB_IO_CONTROL) + - protocolDataRequest->ProtocolSpecificData.ProtocolDataOffset + + if ((ULONGLONG)srbDataBufferLength < (protocolSpecificDataBufferOffset + protocolDataRequest->ProtocolSpecificData.ProtocolDataLength)) { Srb->SrbStatus = SRB_STATUS_BAD_SRB_BLOCK_LENGTH; status = STOR_STATUS_INVALID_PARAMETER; @@ -7401,7 +7406,7 @@ Return Value: // // Data buffer of Protocol Data should be pointer aligned. // - if ((((ULONGLONG)sizeof(SRB_IO_CONTROL) + protocolDataRequest->ProtocolSpecificData.ProtocolDataOffset) % sizeof(PVOID)) != 0) { + if ((protocolSpecificDataBufferOffset % sizeof(PVOID)) != 0) { Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST; status = STOR_STATUS_INVALID_PARAMETER; goto exit; diff --git a/storage/miniports/storahci/src/entrypts.c b/storage/miniports/storahci/src/entrypts.c index 3f52aa17..4a950473 100644 --- a/storage/miniports/storahci/src/entrypts.c +++ b/storage/miniports/storahci/src/entrypts.c @@ -572,7 +572,7 @@ Note: //3.4 Initializing the rest of PORT_CONFIGURATION_INFORMATION ConfigInfo->MaximumTransferLength = AHCI_MAX_TRANSFER_LENGTH; - ConfigInfo->NumberOfPhysicalBreaks = 0x20; + ConfigInfo->NumberOfPhysicalBreaks = 0x21; // Since "NumberOfPhysicalBreaks" has been used in storage stack as the count of entries, use value of physical breaks plus one. ConfigInfo->AlignmentMask = 1; // ATA devices need WORD alignment ConfigInfo->ScatterGather = TRUE; ConfigInfo->ResetTargetSupported = TRUE; @@ -858,6 +858,9 @@ AhciHwPassiveInitialize ( UCHAR i; ULONG status = STOR_STATUS_SUCCESS; BOOLEAN enableD3Cold = FALSE; + BOOLEAN d3ColdSupported = FALSE; + BOOLEAN reportF1State = FALSE; + ULONG bufferSize = sizeof(STOR_POFX_DEVICE_V2); PAHCI_ADAPTER_EXTENSION adapterExtension = (PAHCI_ADAPTER_EXTENSION)AdapterExtension; @@ -873,9 +876,24 @@ AhciHwPassiveInitialize ( AhciAdapterEvaluateDSMMethod(adapterExtension); + // + // Get and cache D3Cold support. + // + status = StorPortGetD3ColdSupport(AdapterExtension, + NULL, + &d3ColdSupported); + if (status == STOR_STATUS_SUCCESS) { + adapterExtension->StateFlags.D3ColdSupported = d3ColdSupported; + } + + + if (reportF1State) { + bufferSize += STOR_POFX_COMPONENT_IDLE_STATE_SIZE; + } + // 3. allocate STOR_POFX_DEVICE data structure for adapter, initialize the structure and register for runtime power management. status = StorPortAllocatePool(AdapterExtension, - sizeof(STOR_POFX_DEVICE_V2), + bufferSize, AHCI_POOL_TAG, (PVOID*)&adapterExtension->PoFxDevice); @@ -892,14 +910,14 @@ AhciHwPassiveInitialize ( if (IsD3ColdAllowed(adapterExtension)) { adapterExtension->PoFxDevice->Flags = STOR_POFX_DEVICE_FLAG_ENABLE_D3_COLD; } - + // indicate dump miniport can't bring adapter to active adapterExtension->PoFxDevice->Flags |= STOR_POFX_DEVICE_FLAG_NO_DUMP_ACTIVE; adapterExtension->PoFxDevice->Components[0].Version = STOR_POFX_COMPONENT_VERSION_V1; adapterExtension->PoFxDevice->Components[0].Size = STOR_POFX_COMPONENT_SIZE; - adapterExtension->PoFxDevice->Components[0].FStateCount = 1; - adapterExtension->PoFxDevice->Components[0].DeepestWakeableFState = 0; + adapterExtension->PoFxDevice->Components[0].FStateCount = reportF1State ? 2 : 1; + adapterExtension->PoFxDevice->Components[0].DeepestWakeableFState = reportF1State ? 1 : 0; adapterExtension->PoFxDevice->Components[0].Id = STORPORT_POFX_ADAPTER_GUID; adapterExtension->PoFxDevice->Components[0].FStates[0].Version = STOR_POFX_COMPONENT_IDLE_STATE_VERSION_V1; @@ -908,6 +926,15 @@ AhciHwPassiveInitialize ( adapterExtension->PoFxDevice->Components[0].FStates[0].ResidencyRequirement = 0; adapterExtension->PoFxDevice->Components[0].FStates[0].NominalPower = STOR_POFX_UNKNOWN_POWER; + if (reportF1State) { + adapterExtension->StateFlags.UseAdapterF1InsteadOfD3 = FALSE; + adapterExtension->PoFxDevice->Components[0].FStates[1].Version = STOR_POFX_COMPONENT_IDLE_STATE_VERSION_V1; + adapterExtension->PoFxDevice->Components[0].FStates[1].Size = STOR_POFX_COMPONENT_IDLE_STATE_SIZE; + adapterExtension->PoFxDevice->Components[0].FStates[1].TransitionLatency = 1; + adapterExtension->PoFxDevice->Components[0].FStates[1].ResidencyRequirement = 0; + adapterExtension->PoFxDevice->Components[0].FStates[1].NominalPower = STOR_POFX_UNKNOWN_POWER; + } + // registry runtime power management for Adapter status = StorPortInitializePoFxPower(AdapterExtension, NULL, (PSTOR_POFX_DEVICE)adapterExtension->PoFxDevice, &enableD3Cold); @@ -920,11 +947,11 @@ AhciHwPassiveInitialize ( goto Exit; } + // register success adapterExtension->StateFlags.PoFxEnabled = TRUE; adapterExtension->StateFlags.PoFxActive = TRUE; - Exit: return TRUE; } @@ -1170,6 +1197,9 @@ Return Value: if (ScsiAdapterPoFxPowerActive < controlTypeList->MaxControlType) { controlTypeList->SupportedTypeList[ScsiAdapterPoFxPowerActive] = TRUE; } + if (ScsiAdapterPoFxPowerSetFState < controlTypeList->MaxControlType) { + controlTypeList->SupportedTypeList[ScsiAdapterPoFxPowerSetFState] = TRUE; + } if (ScsiAdapterPower < controlTypeList->MaxControlType) { controlTypeList->SupportedTypeList[ScsiAdapterPower] = TRUE; } @@ -1179,6 +1209,10 @@ Return Value: if (ScsiAdapterSystemPowerHints < controlTypeList->MaxControlType) { controlTypeList->SupportedTypeList[ScsiAdapterSystemPowerHints] = TRUE; } + if (ScsiAdapterSurpriseRemoval < controlTypeList->MaxControlType) { + controlTypeList->SupportedTypeList[ScsiAdapterSurpriseRemoval] = TRUE; + } + break; // ScsiStopAdapter maybe called with PnP or Power activities. @@ -1230,6 +1264,10 @@ Return Value: break; } + case ScsiAdapterPoFxPowerSetFState: { + break; + } + case ScsiAdapterPower: { PSTOR_ADAPTER_CONTROL_POWER adapterPower = (PSTOR_ADAPTER_CONTROL_POWER)Parameters; @@ -1284,6 +1322,16 @@ Return Value: break; } + case ScsiAdapterSurpriseRemoval: { + // + // For AHCI, all the cleanup that needs to happen for adapter surprise removals is done in + // the several ScsiUnitSurpriseRemovals that will be sent down for each LUN. There is no + // extra work needed to handle adapter surprise removals. + // + status = ScsiAdapterControlSuccess; + break; + } + default: status = ScsiAdapterControlUnsuccessful; break; @@ -1853,7 +1901,10 @@ Return Values: sact = StorPortReadRegisterUlong(ChannelExtension->AdapterExtension, &ChannelExtension->Px->SACT); - if(sact != 0) { + if ((sact == MAXULONG) && IsAdapterRemoved(ChannelExtension)) { + // controller has been surprise removed + return; + } else if (sact != 0) { //5.1 NCQ, Handle error processing ChannelExtension->StateFlags.CallAhciNcqErrorRecovery = 1; @@ -1861,8 +1912,7 @@ Return Values: if (ChannelExtension->StateFlags.NCQ_Succeeded == 0) { ChannelExtension->StateFlags.NCQ_Activated = 0; } - } - else { + } else { //5.1 Non-NCQ, Handle error processing ChannelExtension->StateFlags.CallAhciNonQueuedErrorRecovery = 1; } @@ -1881,6 +1931,10 @@ Return Values: if (pxis.DMPS || pxis.PCS) { cmd.AsUlong = StorPortReadRegisterUlong(ChannelExtension->AdapterExtension, &ChannelExtension->Px->CMD.AsUlong); + if ((cmd.AsUlong == MAXULONG) && IsAdapterRemoved(ChannelExtension)) { + return; + } + // Device Mechanical Presence Status if (pxis.DMPS) { pxisMask.AsUlong = 0; @@ -1917,6 +1971,11 @@ Return Values: ssts.AsUlong = StorPortReadRegisterUlong(ChannelExtension->AdapterExtension, &ChannelExtension->Px->SSTS.AsUlong); + if ((ssts.AsUlong == MAXULONG) && IsAdapterRemoved(ChannelExtension)) { + // controller has been surprise removed + return; + } + if (!IgnoreHotPlug(ChannelExtension)) { //If a ZPODD drive has already been found and it is a ZPODD system if ((ChannelExtension->AdapterExtension->StateFlags.SupportsAcpiDSM == 1) && @@ -1935,18 +1994,15 @@ Return Values: ChannelExtension->SlotManager.NormalQueueSlice = 0; ChannelExtension->SlotManager.SingleIoSlice = 0; ChannelExtension->SlotManager.HighPriorityAttribute = 0; - } - else { + } else { NT_ASSERT(FALSE); // Looks like a hardware issue, will recover in P_Running_StartAttempt() when ZPODD is powered on again. } - } - else if (ssts.DET == 3) { + } else if (ssts.DET == 3) { // ... (*) and there is presence on the wire ... // ... try to get the channel started. P_Running_StartAttempt(ChannelExtension, TRUE); } - } - else if ((ssts.DET == 0) && (ssts.IPM == 0)) { + } else if ((ssts.DET == 0) && (ssts.IPM == 0)) { // Handle bus rescan processing processing ChannelExtension->StateFlags.CallAhciReportBusChange = 1; } @@ -2032,6 +2088,11 @@ Return Values: // preserve taskfile for using in command completion process ChannelExtension->TaskFileData.AsUlong = StorPortReadRegisterUlong(ChannelExtension->AdapterExtension, &ChannelExtension->Px->TFD.AsUlong); + if ((ChannelExtension->TaskFileData.AsUlong == MAXULONG) && IsAdapterRemoved(ChannelExtension)) { + // controller has been surprise removed + return; + } + //2.4 error process if (ErrorRecoveryIsPending(ChannelExtension)) { AhciPortErrorRecovery(ChannelExtension); @@ -2046,9 +2107,14 @@ Return Values: ci = StorPortReadRegisterUlong(ChannelExtension->AdapterExtension, &ChannelExtension->Px->CI); sact = StorPortReadRegisterUlong(ChannelExtension->AdapterExtension, &ChannelExtension->Px->SACT); + if (((ci == MAXULONG) || (sact == MAXULONG)) && IsAdapterRemoved(ChannelExtension)) { + // controller has been surprise removed + return; + } + outstanding = ci | sact; - if ((ChannelExtension->SlotManager.CommandsIssued & ~outstanding) > 0) { + if ((ChannelExtension->SlotManager.CommandsIssued & (~outstanding)) > 0) { // all completed commands by hardware will be marked completed ChannelExtension->SlotManager.CommandsToComplete |= (ChannelExtension->SlotManager.CommandsIssued & ~outstanding); ChannelExtension->SlotManager.CommandsIssued &= outstanding; @@ -2065,6 +2131,11 @@ Return Values: //6.1 Partial to Slumber auto transit cmd.AsUlong = StorPortReadRegisterUlong(ChannelExtension->AdapterExtension, &ChannelExtension->Px->CMD.AsUlong); + if ((cmd.AsUlong == MAXULONG) && IsAdapterRemoved(ChannelExtension)) { + // controller has been surprise removed + return; + } + if (PartialToSlumberTransitionIsAllowed(ChannelExtension, cmd, ci, sact)) { ULONG status; // convert interval value from ms to us. allow 20ms of coalescing with other timers @@ -2115,6 +2186,11 @@ Return Values: PAHCI_ADAPTER_EXTENSION adapterExtension = (PAHCI_ADAPTER_EXTENSION)AdapterExtension; is = StorPortReadRegisterUlong(AdapterExtension, adapterExtension->IS); + + if (adapterExtension->StateFlags.Removed) { + return FALSE; + } + interruptPorts = (is & adapterExtension->PortImplemented); // @@ -2265,6 +2341,9 @@ Return Value: if (ScsiUnitPoFxPowerSetFState < controlTypeList->MaxControlType) { controlTypeList->SupportedTypeList[ScsiUnitPoFxPowerSetFState] = TRUE; } + if (ScsiUnitSurpriseRemoval < controlTypeList->MaxControlType) { + controlTypeList->SupportedTypeList[ScsiUnitSurpriseRemoval] = TRUE; + } status = ScsiUnitControlSuccess; break; } @@ -2361,7 +2440,7 @@ Return Value: channelExtension->PoFxDevice->Version = STOR_POFX_DEVICE_VERSION_V3; channelExtension->PoFxDevice->Size = STOR_POFX_DEVICE_V3_SIZE; - channelExtension->PoFxDevice->ComponentCount = 1; + channelExtension->PoFxDevice->ComponentCount = 1; // // The dump version of StorAHCI is not able to bring the @@ -2511,6 +2590,38 @@ Return Value: break; } + // + // ScsiUnitSurpriseRemoval is called when Storport processes the surprise removal IRP for the unit. + // + case ScsiUnitSurpriseRemoval: { + PSTOR_ADDR_BTL8 storAddrBtl8 = (PSTOR_ADDR_BTL8)Parameters; + STOR_LOCK_HANDLE lockhandle = {0}; + + if (IsPortValid(adapterExtension, storAddrBtl8->Path)) { + + PAHCI_CHANNEL_EXTENSION channelExtension = adapterExtension->PortExtension[storAddrBtl8->Path]; + AhciInterruptSpinlockAcquire(adapterExtension, channelExtension->PortNumber, &lockhandle); + + // + // Complete all issued commands. + // + channelExtension->SlotManager.CommandsToComplete = channelExtension->SlotManager.CommandsIssued; + channelExtension->SlotManager.CommandsIssued = 0; + channelExtension->SlotManager.HighPriorityAttribute &= ~channelExtension->SlotManager.CommandsToComplete; + + AhciCompleteIssuedSRBs(channelExtension, SRB_STATUS_NO_DEVICE, TRUE); + + // + // Complete all other commands miniport owns for this device. + // + AhciPortFailAllIos(channelExtension, SRB_STATUS_NO_DEVICE, TRUE); + + AhciInterruptSpinlockRelease(adapterExtension, channelExtension->PortNumber, &lockhandle); + } + + break; + } + default: status = ScsiUnitControlUnsuccessful; break; diff --git a/storage/miniports/storahci/src/entrypts.h b/storage/miniports/storahci/src/entrypts.h index 39613040..fbf2cb5b 100644 --- a/storage/miniports/storahci/src/entrypts.h +++ b/storage/miniports/storahci/src/entrypts.h @@ -107,11 +107,12 @@ typedef struct _CHANNEL_STATE_FLAGS { ULONG PoFxActive : 1; ULONG D3ColdEnabled : 1; + ULONG D3ColdSupported : 1; ULONG CallAhciNcqErrorRecovery : 1; ULONG NcqErrorRecoveryInProcess : 1; ULONG PuisEnabled : 1; - ULONG Reserved0 : 13; + ULONG Reserved0 : 12; ULONG Reserved1; } CHANNEL_STATE_FLAGS, *PCHANNEL_STATE_FLAGS; @@ -504,7 +505,11 @@ typedef struct _ADAPTER_STATE_FLAGS { ULONG Removed : 1; ULONG InterruptMessagePerPort : 1; - ULONG Reserved : 24; + ULONG D3ColdSupported : 1; + ULONG D3ColdEnabled : 1; + ULONG UseAdapterF1InsteadOfD3 : 1; + + ULONG Reserved : 21; } ADAPTER_STATE_FLAGS, *PADAPTER_STATE_FLAGS; diff --git a/storage/miniports/storahci/src/inbox/storahci.vcxproj b/storage/miniports/storahci/src/inbox/storahci.vcxproj index 977cb1a8..d01b9e8b 100644 --- a/storage/miniports/storahci/src/inbox/storahci.vcxproj +++ b/storage/miniports/storahci/src/inbox/storahci.vcxproj @@ -19,12 +19,12 @@ - {66561B18-E3A6-4D08-B79C-ADBC83B33CC9} + {8DC63CF7-4E1A-460D-844C-3E66E9763E83} $(MSBuildProjectName) false Debug Win32 - {C3249A63-508D-46A3-85F3-864258EAE676} + {874F1EA1-366A-414A-BF67-108615454853} @@ -114,7 +114,7 @@ %(AdditionalIncludeDirectories);..\..\inc - %(AdditionalDependencies);$(DDK_LIB_PATH)\storport.lib;$(DDK_LIB_PATH)\ntoskrnl.lib + %(AdditionalDependencies);$(DDK_LIB_PATH)\storport.lib @@ -132,7 +132,7 @@ %(AdditionalIncludeDirectories);..\..\inc - %(AdditionalDependencies);$(DDK_LIB_PATH)\storport.lib;$(DDK_LIB_PATH)\ntoskrnl.lib + %(AdditionalDependencies);$(DDK_LIB_PATH)\storport.lib @@ -150,7 +150,7 @@ %(AdditionalIncludeDirectories);..\..\inc - %(AdditionalDependencies);$(DDK_LIB_PATH)\storport.lib;$(DDK_LIB_PATH)\ntoskrnl.lib + %(AdditionalDependencies);$(DDK_LIB_PATH)\storport.lib @@ -168,7 +168,7 @@ %(AdditionalIncludeDirectories);..\..\inc - %(AdditionalDependencies);$(DDK_LIB_PATH)\storport.lib;$(DDK_LIB_PATH)\ntoskrnl.lib + %(AdditionalDependencies);$(DDK_LIB_PATH)\storport.lib diff --git a/storage/miniports/storahci/src/inbox/storahci.vcxproj.Filters b/storage/miniports/storahci/src/inbox/storahci.vcxproj.Filters index 9076cdbe..cadb74aa 100644 --- a/storage/miniports/storahci/src/inbox/storahci.vcxproj.Filters +++ b/storage/miniports/storahci/src/inbox/storahci.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {9EB59641-A672-4F68-9C17-A371E91449CE} + {20D3C073-33A3-4EA0-AFC3-00B7B63AFE8F} h;hpp;hxx;hm;inl;inc;xsd - {DD0D39C8-5872-460B-9E3D-172F3706B7F2} + {66457EF6-68E0-4E0D-97B0-CDB4D856FF3C} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {E8C7370D-F09C-4651-828A-61C162298E8C} + {95130444-F6D4-4084-BBD5-30BF9A6B72E3} inf;inv;inx;mof;mc; - {796BADD8-030C-428E-AF41-30317E212214} + {41883C82-5F94-4FFF-8959-40226FA13DA4} diff --git a/storage/miniports/storahci/src/io.c b/storage/miniports/storahci/src/io.c index 11d1d195..722ca7b6 100644 --- a/storage/miniports/storahci/src/io.c +++ b/storage/miniports/storahci/src/io.c @@ -182,6 +182,8 @@ Input Parameters: PVOID tempTail, foundSrb; ULONG srbsFound; + UNREFERENCED_PARAMETER(ChannelExtension); + if (Queue->Tail == NULL) { Queue->Tail = (PVOID) Srb; Queue->Head = (PVOID) Srb; @@ -189,23 +191,11 @@ Input Parameters: tempTail = Queue->Tail; if (SrbGetNextSrb(tempTail) == NULL) { //Verify SRBs are not about to be severed from the Queue SrbSetNextSrb(tempTail, (PVOID)Srb); - } else { - //intentional bugcheck to check queuing errors. Suppress null pointer dereferencing warnings - #pragma warning (suppress: 6011) - NT_ASSERT(FALSE); ChannelExtension = NULL; ChannelExtension->PortNumber++; } Queue->Tail = (PVOID)Srb; - if (SrbGetNextSrb(Srb) != NULL) { //Verify NextSrb is not in use by anyone - //intentional bugcheck to check queuing errors. Suppress null pointer dereferencing warnings - #pragma warning (suppress: 6011) - NT_ASSERT(FALSE); ChannelExtension = NULL; ChannelExtension->PortNumber++; - } } Queue->CurrentDepth++; if (Queue->Head == NULL) { //It is impossible for Head to be NULL here - //intentional bugcheck to check queuing errors. Suppress null pointer dereferencing warnings - #pragma warning (suppress: 6011) - NT_ASSERT(FALSE); ChannelExtension = NULL; ChannelExtension->PortNumber++; srbsFound = 0; } else { foundSrb = Queue->Head; @@ -220,11 +210,6 @@ Input Parameters: Queue->DepthHistoryIndex++; Queue->DepthHistoryIndex %= 100; Queue->DepthHistory[Queue->DepthHistoryIndex] = Signature; - if (Queue->CurrentDepth != srbsFound ) { - //intentional bugcheck to check queuing errors. Suppress null pointer dereferencing warnings - #pragma warning (suppress: 6011) - NT_ASSERT(FALSE); ChannelExtension = NULL; ChannelExtension->PortNumber++; - } if (Queue->CurrentDepth > Queue->DeepestDepth) { Queue->DeepestDepth = Queue->CurrentDepth; } @@ -241,6 +226,8 @@ RemoveQueue ( PVOID nextSrb, foundSrb; ULONG srbsFound; + UNREFERENCED_PARAMETER(ChannelExtension); + //Check to see if the queue is empty if (Queue->Head == NULL) { return NULL; @@ -270,11 +257,6 @@ RemoveQueue ( Queue->DepthHistoryIndex++; Queue->DepthHistoryIndex %= 100; Queue->DepthHistory[Queue->DepthHistoryIndex] = Signature; - if (Queue->CurrentDepth != srbsFound ) { - //intentional bugcheck to check queuing errors. Suppress null pointer dereferencing warnings - #pragma warning (suppress: 6011) - NT_ASSERT(FALSE); ChannelExtension = NULL; ChannelExtension->PortNumber++; - } if (Queue->CurrentDepth > Queue->DeepestDepth) { Queue->DeepestDepth = Queue->CurrentDepth; } @@ -1143,13 +1125,19 @@ Note: This routine can be called even the Port is stopped. sact = StorPortReadRegisterUlong(ChannelExtension->AdapterExtension, &ChannelExtension->Px->SACT); // 3.2 if the tag returned can't be used, something is seriously wrong. Reject the command to be retried later if( ( ( (1 << srbExtension->QueueTag) & ci) > 0) || ( ( (1 << srbExtension->QueueTag) & sact) > 0) ) { - NT_ASSERT(FALSE); //can this happen? catch it. - if (!IsMiniportInternalSrb(ChannelExtension, Srb)) { // pause device only for IOs from Storport StorPortPauseDevice(ChannelExtension->AdapterExtension, pathId, targetId, lun, 1); //pause for 1 seconds. } - Srb->SrbStatus = SRB_STATUS_BUSY; + + // One reason why this can happen is if the adapter was removed. + if (IsAdapterRemoved(ChannelExtension)) { + Srb->SrbStatus = SRB_STATUS_NO_DEVICE; + } else { + NT_ASSERT(FALSE); //can this happen? catch it. + Srb->SrbStatus = SRB_STATUS_BUSY; + } + MarkSrbToBeCompleted(Srb); AhciCompleteRequest(ChannelExtension, Srb, AtDIRQL); RecordExecutionHistory(ChannelExtension, 0x10040020);//Tag given for slot in use diff --git a/storage/miniports/storahci/src/pnppower.c b/storage/miniports/storahci/src/pnppower.c index 710a4340..dec0fde7 100644 --- a/storage/miniports/storahci/src/pnppower.c +++ b/storage/miniports/storahci/src/pnppower.c @@ -1668,7 +1668,7 @@ AhciDeviceInitialize ( UpdateSetFeatureCommands(ChannelExtension, IDE_FEATURE_INVALID, IDE_FEATURE_SET_TRANSFER_MODE, 0, 0x44); } - //1.2 Persist Write Cache + //1.2 Persist Write Cache UpdateSetFeatureCommands(ChannelExtension, IDE_FEATURE_INVALID, IDE_FEATURE_ENABLE_WRITE_CACHE, 0, 0); } else if (IsAtapiDevice(&ChannelExtension->DeviceExtension->DeviceParameters)) { diff --git a/storage/miniports/storahci/src/util.h b/storage/miniports/storahci/src/util.h index cd2809ae..b07b465a 100644 --- a/storage/miniports/storahci/src/util.h +++ b/storage/miniports/storahci/src/util.h @@ -616,16 +616,37 @@ DeviceIncursSeekPenalty( _In_ PAHCI_CHANNEL_EXTENSION ChannelExtension ) { - if (IsAtaDevice(&ChannelExtension->DeviceExtension->DeviceParameters) && - ChannelExtension->DeviceExtension->IdentifyDeviceData->NominalMediaRotationRate >= 0x0401 && - ChannelExtension->DeviceExtension->IdentifyDeviceData->NominalMediaRotationRate <= 0xFFFE) { - // - // NominalMediaRotationRate = 0 means no rate is reported. - // NominalMediaRotationRate = 1 means there is no seek penalty (e.g. pure SSD). - // NominalMediaRotationRate = 0x0401-0xFFFE is the rotation rate (i.e. incurs seek penalty). - // All other values are reserved. - // - return TRUE; + if (IsAtaDevice(&ChannelExtension->DeviceExtension->DeviceParameters)) { + if (ChannelExtension->DeviceExtension->IdentifyDeviceData->NominalMediaRotationRate >= 0x0401 && + ChannelExtension->DeviceExtension->IdentifyDeviceData->NominalMediaRotationRate <= 0xFFFE) { + // + // NominalMediaRotationRate = 0 means no rate is reported. + // NominalMediaRotationRate = 1 means there is no seek penalty (e.g. pure SSD). + // NominalMediaRotationRate = 0x0401-0xFFFE is the rotation rate (i.e. incurs seek penalty). + // All other values are reserved. + // + return TRUE; + } + } + return FALSE; +} + +__inline +BOOLEAN +DeviceIncursNoSeekPenalty( +_In_ PAHCI_CHANNEL_EXTENSION ChannelExtension +) +{ + if (IsAtaDevice(&ChannelExtension->DeviceExtension->DeviceParameters)) { + if (ChannelExtension->DeviceExtension->IdentifyDeviceData->NominalMediaRotationRate == 1) { + // + // NominalMediaRotationRate = 0 means no rate is reported. + // NominalMediaRotationRate = 1 means there is no seek penalty (e.g. pure SSD). + // NominalMediaRotationRate = 0x0401-0xFFFE is the rotation rate (i.e. incurs seek penalty). + // All other values are reserved. + // + return TRUE; + } } return FALSE; } @@ -1482,6 +1503,23 @@ AtaFormFactorToStorageFormFactor( return formFactor; } +__inline +BOOLEAN +IsAdapterRemoved( + _In_ PAHCI_CHANNEL_EXTENSION ChannelExtension + ) +{ + // + // When the adapter is removed, its registers are read as + // all 0xF's by the PCI bus. We use the PxSSTS register because + // it has several reserved bits which will unlikely be defined + // in the lifetime of the spec. + // + ULONG ssts = StorPortReadRegisterUlong(ChannelExtension->AdapterExtension, &ChannelExtension->Px->SSTS.AsUlong); + return (ssts == MAXULONG); +} + + VOID PortBusChangeProcess ( _In_ PAHCI_CHANNEL_EXTENSION ChannelExtension diff --git a/storage/miniports/storahci/storahci.sln b/storage/miniports/storahci/storahci.sln index acfc7652..b213872f 100644 --- a/storage/miniports/storahci/storahci.sln +++ b/storage/miniports/storahci/storahci.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "storahci", "src\inbox\storahci.vcxproj", "{66561B18-E3A6-4D08-B79C-ADBC83B33CC9}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "storahci", "src\inbox\storahci.vcxproj", "{8DC63CF7-4E1A-460D-844C-3E66E9763E83}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +13,14 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {66561B18-E3A6-4D08-B79C-ADBC83B33CC9}.Debug|Win32.ActiveCfg = Debug|Win32 - {66561B18-E3A6-4D08-B79C-ADBC83B33CC9}.Debug|Win32.Build.0 = Debug|Win32 - {66561B18-E3A6-4D08-B79C-ADBC83B33CC9}.Release|Win32.ActiveCfg = Release|Win32 - {66561B18-E3A6-4D08-B79C-ADBC83B33CC9}.Release|Win32.Build.0 = Release|Win32 - {66561B18-E3A6-4D08-B79C-ADBC83B33CC9}.Debug|x64.ActiveCfg = Debug|x64 - {66561B18-E3A6-4D08-B79C-ADBC83B33CC9}.Debug|x64.Build.0 = Debug|x64 - {66561B18-E3A6-4D08-B79C-ADBC83B33CC9}.Release|x64.ActiveCfg = Release|x64 - {66561B18-E3A6-4D08-B79C-ADBC83B33CC9}.Release|x64.Build.0 = Release|x64 + {8DC63CF7-4E1A-460D-844C-3E66E9763E83}.Debug|Win32.ActiveCfg = Debug|Win32 + {8DC63CF7-4E1A-460D-844C-3E66E9763E83}.Debug|Win32.Build.0 = Debug|Win32 + {8DC63CF7-4E1A-460D-844C-3E66E9763E83}.Release|Win32.ActiveCfg = Release|Win32 + {8DC63CF7-4E1A-460D-844C-3E66E9763E83}.Release|Win32.Build.0 = Release|Win32 + {8DC63CF7-4E1A-460D-844C-3E66E9763E83}.Debug|x64.ActiveCfg = Debug|x64 + {8DC63CF7-4E1A-460D-844C-3E66E9763E83}.Debug|x64.Build.0 = Debug|x64 + {8DC63CF7-4E1A-460D-844C-3E66E9763E83}.Release|x64.ActiveCfg = Release|x64 + {8DC63CF7-4E1A-460D-844C-3E66E9763E83}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/storage/ramdisk/ReadMe.md b/storage/ramdisk/ReadMe.md new file mode 100644 index 00000000..f1278157 --- /dev/null +++ b/storage/ramdisk/ReadMe.md @@ -0,0 +1,188 @@ +RAMDisk Storage Driver Sample +============================= + +The RAMDisk storage driver sample demonstrates how to write a software only function driver using the Kernel Mode Driver Framework (KMDF). This driver creates a RAM disk drive.The RAM disk can be used like any other disk, but the contents of the disk will be lost when the computer is shut down. + +**Note**   + +To build this sample, you can use Microsoft Visual Studio 2013 (Express, Professional, or Ultimate) and Windows Driver Kit (WDK) 8.1 Update. You can get Visual Studio 2013 and WDK 8.1 Update [here](http://go.microsoft.com/fwlink/p/?LInkID=239721). + +You can also build this sample with Visual Studio 2013 (Professional or Ultimate) and [Windows Driver Kit (WDK) 8.1](http://go.microsoft.com/fwlink/p/?LInkID=391348). + +For Windows Driver Kit (WDK) 8 samples, download the [WDK 8 samples pack](%20http://go.microsoft.com/fwlink/?LinkId=317090). The samples in the WDK 8 samples pack will build only with Microsoft Visual Studio Professional 2012 (Professional or Ultimate) and WDK 8. + +Operating system requirements +----------------------------- + +Client + +Windows 7 + +Server + +Windows Server 2008 R2 + +Build the sample +---------------- + +Download and extract the sample +------------------------------- + +Click the download button on this page. Click **Save**, and then click **Open Folder**. Right click ramdisk.zip, and choose **Extract All**. Specify or browse to a folder for the extracted files. For example, you could extract to c:\\RamDiskStorageDriver. + +Open the driver solution in Visual Studio +----------------------------------------- + +Navigate to the folder that has the extracted sample. Double click the solution file, ramdisk.sln. In Microsoft Visual Studio, locate Solution Explorer. (If this is not already open, choose **Solution Explorer** from the **View** menu.) In Solution Explorer, you can see one solution that has two projects. There is a driver project named **WdfRamdisk** and a package project named **package** (lower case). + +Set the configuration and platform in Visual Studio +--------------------------------------------------- + +In Visual Studio, in Solution Explorer, right click **Solution ‘ramdisk’ (2 projects)**, and choose **Configuration Manager**. Set the configuration and the platform. Make sure that the configuration and platform are the same for both the driver project and the package project. Do not check the **Deploy** boxes. Here are some examples of configuration and platform settings. + + +++++ + + + + + + + + + + + +
Configuration +Platform +Description
Win8.1 Debug +x64 +The driver will run on an x64 hardware platform that is running Windows 8.1. The driver will not run on any earlier versions of Windows.Win7 Debug +x64 +The driver will run on an x64 hardware platform that is running Windows 7 or a later version of Windows.
+ +Build the sample using Visual Studio +------------------------------------ + +In Visual Studio, on the **Build** menu, choose **Build Solution**. + +For more information about using Visual Studio to build a driver package, see [Building a Driver](http://msdn.microsoft.com/en-us/library/windows/hardware/ff554644). + +Locate the built driver package +------------------------------- + +In File Explorer, navigate to the folder that contains your built driver package. The location of this folder varies depending on what you set for configuration and platform. For example, if your settings are Win7 Debug and x64, the package is your solution folder under x64\\Win7Debug\\Package. + +The package contains these files: + + ++++ + + + + + + + + + + + +
File +Description
Kmdfsamples.cat +A signed catalog file, which serves as the signature for the entire package.Ramdisk.inf +An information (INF) file that contains information needed to install the driver.
+ +Run the sample +-------------- + +The computer where you install the driver is called the *target computer* or the *test computer*. Typically this is a separate computer from where you develop and build the driver package. The computer where you develop and build the driver is called the *host computer*. + +The process of moving the driver package to the target computer and installing the driver is called *deploying the driver*. You can deploy RAMDisk sample driver automatically or manually. + +Automatic deployment +-------------------- + +Before you automatically deploy a driver, you must provision the target computer. For instructions, see [Configuring a Computer for Driver Deployment, Testing, and Debugging](http://msdn.microsoft.com/en-us/library/windows/hardware/). + +1. On the host computer, in Visual Studio, in Solution Explorer, right click **package** (lower case), and choose **Properties**. Navigate to **Configuration Properties \> Driver Install \> Deployment**. +2. Check **Enable deployment**, and check **Remove previous driver versions before deployment**. For **Target Computer Name**, select the name of a target computer that you provisioned previously. Select **Hardware ID Driver Update**, and enter **Ramdisk** for the hardware ID. Click **OK**. +3. On the **Build** menu, choose **Deploy Package** or **Build Solution**. + +Manual deployment +----------------- + +Before you manually deploy a driver, you must turn on test signing and install a certificate on the target computer. You also need to copy the [DevCon](http://msdn.microsoft.com/en-us/library/windows/hardware/ff544707) tool to the target computer. For instructions, see [Preparing a Computer for Manual Driver Deployment](http://msdn.microsoft.com/en-us/library/windows/hardware/dn265571). + +1. Copy all of the files in your driver package to a folder on the target computer (for example, c:\\RamdiskStorageDriverPackage). +2. On the target computer, open a Command Prompt window as Administrator. Navigate to your driver package folder, and enter the following command: + + **Devcon install ramdisk.inf Ramdisk** + +View the installed driver in Device Manager +------------------------------------------- + +On the target computer, in a Command Prompt window, enter **devmgmt** to open Device Manager. In Device Manager, on the **View** menu, choose **Devices by type**. In the device tree, locate **WDF Sample RAM disk Driver** (for example, this might be under the **Sample Device** node). + +The RAM disk sample is a root enumerated software driver. To see this in Device Manager, choose **Devices by connection** from the **View** menu. Locate **WDF Sample RAM disk Driver** as a child of the root node of the device tree. + +Save a file on the RAM disk +--------------------------- + +On the target computer, open a Command Prompt window as Administrator. Enter **R:** to switch to the RAM disk drive. In your Command Prompt window, enter **notepad** to open Notepad. Type some text in your notepad document, and then save the document on the R drive. In your Command Prompt window, enter **dir** to verify that the file was saved. + +View Ramdisk entries in the Registry +------------------------------------ + +The INF file in the RAM disk driver package specifies parameters that get saved in the registry. On the target computer, open the registry editor (Regedit.exe). In the registry editor, locate the Parameters key for the Ramdisk service. For example, + +**HKLM**\\**SYSTEM**\\**CurrentControlSet**\\**Services**\\**Ramdisk**\\**Parameters** + +The registry key has these entries: + + +++++ + + + + + + + + + + + + +
Parameter +Value +Description
DiskSize +0x100000 +The size, in bytes, of the RAM disk drive.DriveLetter +R: +The driver letter associated with the RAM disk drive.RootDirEntries +0x200 +The number of entries in the root directory.
+ +Using MSBuild +------------- + +As an alternative to building the RAMDisk Storage Driver sample in Visual Studio, you can build it in a Visual Studio Command Prompt window. In Visual Studio, on the **Tools** menu, choose **Visual Studio Command Prompt**. In the Visual Studio Command Prompt window, navigate to the folder that has the solution file, ramdisk.sln. Use the [MSBuild](http://go.microsoft.com/fwlink/p/?linkID=262804) command to build the solution. Here are some examples: + +**msbuild /p:configuration=â€Win7 Debug†/p:platform=â€x64†ramdisk.sln** + +**msbuild /p:configuration=â€Win8 Release†/p:platform=â€win32†ramdisk.sln** + +For more information about using [MSBuild](http://go.microsoft.com/fwlink/p/?linkID=262804) to build a driver package, see [Building a Driver](http://msdn.microsoft.com/en-us/library/windows/hardware/ff554644). + diff --git a/storage/ramdisk/ramdisk.sln b/storage/ramdisk/ramdisk.sln new file mode 100644 index 00000000..b9097f75 --- /dev/null +++ b/storage/ramdisk/ramdisk.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0 +MinimumVisualStudioVersion = 12.0 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WdfRamdisk", "src\WdfRamdisk.vcxproj", "{FAEE8721-3E3F-4338-8E7B-1BE9FC028C15}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {FAEE8721-3E3F-4338-8E7B-1BE9FC028C15}.Debug|Win32.ActiveCfg = Debug|Win32 + {FAEE8721-3E3F-4338-8E7B-1BE9FC028C15}.Debug|Win32.Build.0 = Debug|Win32 + {FAEE8721-3E3F-4338-8E7B-1BE9FC028C15}.Release|Win32.ActiveCfg = Release|Win32 + {FAEE8721-3E3F-4338-8E7B-1BE9FC028C15}.Release|Win32.Build.0 = Release|Win32 + {FAEE8721-3E3F-4338-8E7B-1BE9FC028C15}.Debug|x64.ActiveCfg = Debug|x64 + {FAEE8721-3E3F-4338-8E7B-1BE9FC028C15}.Debug|x64.Build.0 = Debug|x64 + {FAEE8721-3E3F-4338-8E7B-1BE9FC028C15}.Release|x64.ActiveCfg = Release|x64 + {FAEE8721-3E3F-4338-8E7B-1BE9FC028C15}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/storage/ramdisk/src/WdfRamdisk.vcxproj b/storage/ramdisk/src/WdfRamdisk.vcxproj new file mode 100644 index 00000000..64f70c23 --- /dev/null +++ b/storage/ramdisk/src/WdfRamdisk.vcxproj @@ -0,0 +1,160 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {FAEE8721-3E3F-4338-8E7B-1BE9FC028C15} + $(MSBuildProjectName) + 1 + Debug + Win32 + {987E33B7-1E8D-4015-A46C-08667083FC5F} + + + + Windows10 + False + Universal + KMDF + WindowsKernelModeDriver10.0 + Driver + + + Windows10 + True + Universal + KMDF + WindowsKernelModeDriver10.0 + Driver + + + Windows10 + False + Universal + KMDF + WindowsKernelModeDriver10.0 + Driver + + + Windows10 + True + Universal + KMDF + WindowsKernelModeDriver10.0 + Driver + + + + $(IntDir) + + + + + + + + + + + + + + + + $(InfArch) + true + .\$(IntDir)\ramdisk.inf + + + + WdfRamdisk + + + WdfRamdisk + + + WdfRamdisk + + + WdfRamdisk + + + + true + Level4 + + + + + %(AdditionalDependencies);$(DDK_LIB_PATH)\ntstrsafe.lib + + + + + true + Level4 + + + + + %(AdditionalDependencies);$(DDK_LIB_PATH)\ntstrsafe.lib + + + + + true + Level4 + + + + + %(AdditionalDependencies);$(DDK_LIB_PATH)\ntstrsafe.lib + + + + + true + Level4 + + + + + %(AdditionalDependencies);$(DDK_LIB_PATH)\ntstrsafe.lib + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/storage/ramdisk/src/WdfRamdisk.vcxproj.Filters b/storage/ramdisk/src/WdfRamdisk.vcxproj.Filters new file mode 100644 index 00000000..1e94b2f4 --- /dev/null +++ b/storage/ramdisk/src/WdfRamdisk.vcxproj.Filters @@ -0,0 +1,42 @@ + + + + + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* + {D9F38118-6A63-448F-A1E6-428B134C40FF} + + + h;hpp;hxx;hm;inl;inc;xsd + {13BF032A-5FDD-40A6-BA9C-3C48A3EF713E} + + + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml + {301177B6-FDBA-46E7-BA20-E5AAE5CA0223} + + + inf;inv;inx;mof;mc; + {8D1F3AF6-FD7D-4065-8ADA-FFBF156120D3} + + + + + Driver Files + + + Driver Files + + + + + Source Files + + + Source Files + + + + + Resource Files + + + \ No newline at end of file diff --git a/storage/ramdisk/src/forward_progress.c b/storage/ramdisk/src/forward_progress.c new file mode 100644 index 00000000..a7c29c7a --- /dev/null +++ b/storage/ramdisk/src/forward_progress.c @@ -0,0 +1,347 @@ + +/*++ + +Copyright (c) 1990-2000 Microsoft Corporation + +Module Name: + + forwardprogress.c + +Abstract: + + Show the forward progress feature + + + +--*/ + +// +// NOTE: Forward progress was added in v1.9 +// + +#if KMDF_VERSION_MINOR >= 9 + +#include "ramdisk.h" + +VOID +EvtForwardProgressRequestDestroy( + WDFOBJECT Request + ) + +/*++ + +Routine Description: + + This event is called when the request memory is about to be freed. + Reserved requests get deleted only when the queue gets deleted. + + +Arguments: + + Request - Handle to a framework request object. + + +Return Value: + + VOID + +--*/ +{ + PFWD_PROGRESS_REQUEST_CONTEXT fwdReqContext; + + fwdReqContext = GetForwardProgressRequestContext(Request); +} + +VOID +EvtForwardProgressRequestCleanup( + WDFOBJECT Request + ) + +/*++ + +Routine Description: + + This event is called when the reserved request is about to be deleted. + NOTE: In case of reserved request this callback doesn't get called after the + I/O is done but only when the request is about to be deleted. + +Arguments: + + Request - Handle to a framework request object. + + +Return Value: + + VOID + +--*/ +{ + PFWD_PROGRESS_REQUEST_CONTEXT reqContext; + + reqContext = GetForwardProgressRequestContext(Request); + + // + // Cleanup any resources allocated earlier for reserved requests here. + // +} + + +NTSTATUS +AllocateAdditionalRequestContext( + _In_ WDFREQUEST Request + ) + +/*++ + +Routine Description: + Allocate resources used by request. + Set the EvtCleanupCallback and EvtDestroyCallback + to show the lifetime of a Reserved request. + +Arguments: + + Request - Handle to a framework request object. + +Return Value: + + + NTSTATUS + +--*/ +{ + WDF_OBJECT_ATTRIBUTES requestContextAttributes; + PFWD_PROGRESS_REQUEST_CONTEXT reqContext; + NTSTATUS status; + + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&requestContextAttributes, + FWD_PROGRESS_REQUEST_CONTEXT); + requestContextAttributes.EvtCleanupCallback = EvtForwardProgressRequestCleanup; + requestContextAttributes.EvtDestroyCallback = EvtForwardProgressRequestDestroy; + status = WdfObjectAllocateContext(Request, + &requestContextAttributes, + &reqContext); + + return status; +} + + +WDF_IO_FORWARD_PROGRESS_ACTION +EvtIoWdmIrpForForwardProgress( + _In_ WDFQUEUE Queue, + _In_ PIRP Irp + ) + +/*++ + +Routine Description: + A driver's EvtIoWdmIrpForForwardProgress callback function is used for + examining an IRP and tell the framework whether to use a reserved + request object for the IRP or to fail the I/O request by completing + it with an error status value. + +Arguments: + + Queue - Handle to the framework queue object that is associated with the + I/O request. + + Irp - +Return Value: + + WDF_IO_FORWARD_PROGRESS_ACTION + WdfIoForwardProgressActionFailRequest is returned it causes + the Framework to fail the IRP. + WdfIoForwardProgressActionUseReservedRequest is returned it causes + the framework to use a reserved request to handle the IRP. +--*/ +{ + PIO_STACK_LOCATION irpStack; + WDF_IO_FORWARD_PROGRESS_ACTION action; + + UNREFERENCED_PARAMETER(Queue); + + irpStack = IoGetCurrentIrpStackLocation(Irp); + switch (irpStack->MajorFunction) { + case IRP_MJ_READ: + case IRP_MJ_WRITE: + case IRP_MJ_DEVICE_CONTROL: + case IRP_MJ_INTERNAL_DEVICE_CONTROL: + + // + // Use reserved request for reads, writes, IOCTL's + // + action = WdfIoForwardProgressActionUseReservedRequest; + break; + + default: + // + // Just for demonstration of the available actions fail the + // other I/O IRP's + // + action = WdfIoForwardProgressActionFailRequest; + break; + } + + return action; +} + +NTSTATUS +EvtIoAllocateResourcesForReservedRequest( + _In_ WDFQUEUE Queue, + _In_ WDFREQUEST Request + ) + +/*++ + +Routine Description: + + A driver's EvtIoAllocateResourcesForReservedRequest callback function + allocates and stores request-specific resources for request objects that + the framework is reserving for low-memory situations. + + NOTE: You can't call WdfRequestGetIoQueue for Reserved requests + Use the Queue handle passed in. + + +Arguments: + + Queue - Handle to the framework queue object that is associated with the + I/O request. + + Request - Handle to a framework request object. + + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status; + PFWD_PROGRESS_REQUEST_CONTEXT fwdReqContext; + + UNREFERENCED_PARAMETER(Queue); + + status = STATUS_SUCCESS; + ASSERT(WdfRequestIsReserved(Request)); + + // + // Allocate all resources needed for the request here. If you need to + // pre-allocate memory or any other resource do it in this callback and + // store it in the context. + // + status = AllocateAdditionalRequestContext(Request); + if (NT_SUCCESS(status)) { + + fwdReqContext = GetForwardProgressRequestContext(Request); + } + + return status; +} + +NTSTATUS +EvtIoAllocateResources( + _In_ WDFQUEUE Queue, + _In_ WDFREQUEST Request + ) + +/*++ + +Routine Description: + + This event is called for the driver to allocate request + resources for immediate use (unlike reserved requests which is for use under + low memory). + It is called immediately after the framework has received an IRP and created + a request object for the IRP. + + +Arguments: + + Queue - Handle to the framework queue object that is associated with the + I/O request. + + Request - Handle to a framework request object. + + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status; + PFWD_PROGRESS_REQUEST_CONTEXT fwdReqContext; + + UNREFERENCED_PARAMETER(Queue); + status = STATUS_SUCCESS; + + // + // Allocate all resources needed for the request here and store it in the request + // context. + // + fwdReqContext = GetForwardProgressRequestContext(Request); + + return status; +} + +NTSTATUS +SetForwardProgressOnQueue( + _In_ WDFQUEUE Queue + ) + +/*++ + +Routine Description: + Set forward progress on the top level( handles one of the major I/O IRP) + queue we created. + The default is always a top level queue or if the queue was configured + with WdfDeviceConfigureRequestDispatching. + +Arguments: + + Queue - Handle to the framework queue object that is associated with the + I/O request. + + +Return Value: + + NTSTATUS + +--*/ +{ + + WDF_IO_QUEUE_FORWARD_PROGRESS_POLICY forwardProgressPolicy; + NTSTATUS status; + + // + // The policy is configurable by the user. In the code segment below + // WdfIoForwardProgressReservedPolicyUseExamine + // is demonstrated. If your driver supports paging I/O you should select + // WdfIoForwardProgressReservedPolicyPagingIO. + // MAX_RESERVED_REQUESTS should be adjusted depending on the number of parallel + // requests the driver wants to handle under low memory conditions. It may + // require some hit and trial to get the right number. + // + WDF_IO_QUEUE_FORWARD_PROGRESS_POLICY_EXAMINE_INIT( + &forwardProgressPolicy, + MAX_RESERVED_REQUESTS, + EvtIoWdmIrpForForwardProgress + ); + + forwardProgressPolicy.EvtIoAllocateResourcesForReservedRequest = + EvtIoAllocateResourcesForReservedRequest; + forwardProgressPolicy.EvtIoAllocateRequestResources = EvtIoAllocateResources; + + status = WdfIoQueueAssignForwardProgressPolicy(Queue, + &forwardProgressPolicy + ); + if (!NT_SUCCESS(status)) { + KdPrint(("Error WdfIoQueueAssignForwardProgressPolicy 0x%x\n",status)); + return status; + } + + return status; +} + +#endif + diff --git a/storage/ramdisk/src/forward_progress.h b/storage/ramdisk/src/forward_progress.h new file mode 100644 index 00000000..00bb6aa6 --- /dev/null +++ b/storage/ramdisk/src/forward_progress.h @@ -0,0 +1,52 @@ +/*++ + +Copyright (c) 1990-2000 Microsoft Corporation + +Module Name: + + forward_progress.h + +Abstract: + + This is the driver object header for forward progress + + +Environment: + + kernel mode only + +Revision History: + +--*/ + +#pragma once + +// +// NOTE: Forward progress was added in v1.9 +// + +#if KMDF_VERSION_MINOR >= 9 + +EVT_WDF_OBJECT_CONTEXT_CLEANUP EvtForwardProgressRequestCleanup; +EVT_WDF_OBJECT_CONTEXT_DESTROY EvtForwardProgressRequestDestroy; +EVT_WDF_IO_WDM_IRP_FOR_FORWARD_PROGRESS EvtIoWdmIrpForForwardProgress; +EVT_WDF_IO_ALLOCATE_RESOURCES_FOR_RESERVED_REQUEST EvtIoAllocateResourcesForReservedRequest; +EVT_WDF_IO_ALLOCATE_REQUEST_RESOURCES EvtIoAllocateResources; + +#define MAX_RESERVED_REQUESTS 8 +#define MEMORY_SIZE 0x100 + +typedef struct _FWD_PROGRESS_REQUEST_CONTEXT { + WDFMEMORY Memory; +} FWD_PROGRESS_REQUEST_CONTEXT, *PFWD_PROGRESS_REQUEST_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(FWD_PROGRESS_REQUEST_CONTEXT, GetForwardProgressRequestContext) + + +NTSTATUS +SetForwardProgressOnQueue( + _In_ WDFQUEUE Queue + ); + +#endif + diff --git a/storage/ramdisk/src/ramdisk.c b/storage/ramdisk/src/ramdisk.c new file mode 100644 index 00000000..ce571706 --- /dev/null +++ b/storage/ramdisk/src/ramdisk.c @@ -0,0 +1,898 @@ +/*++ + +Copyright (c) Microsoft Corporation, All Rights Reserved + +Module Name: + + Ramdisk.c + +Abstract: + + This is the Ramdisk sample driver. This version of the driver has been + modified to support the driver frameworks. This driver basically creates + a nonpaged pool and exposes that as a storage media. User can + find the device in the disk manager and format the media to use + as FAT or NTFS volume. + +Environment: + + Kernel mode only. + +--*/ + +#include "ramdisk.h" + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(INIT, DriverEntry) +#pragma alloc_text(PAGE, RamDiskEvtDeviceAdd) +#pragma alloc_text(PAGE, RamDiskEvtDeviceContextCleanup) +#pragma alloc_text(PAGE, RamDiskQueryDiskRegParameters) +#pragma alloc_text(PAGE, RamDiskFormatDisk) +#endif + +NTSTATUS +DriverEntry( + IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegistryPath + ) + +/*++ + +Routine Description: + + Installable driver initialization entry point. + This entry point is called directly by the I/O system. + +Arguments: + + DriverObject - pointer to the driver object + + RegistryPath - pointer to a unicode string representing the path + to driver-specific key in the registry + +Return Value: + + STATUS_SUCCESS if successful. + +--*/ + +{ + WDF_DRIVER_CONFIG config; + + KdPrint(("Windows Ramdisk Driver - Driver Framework Edition.\n")); + + + WDF_DRIVER_CONFIG_INIT( &config, RamDiskEvtDeviceAdd ); + + return WdfDriverCreate(DriverObject, RegistryPath, WDF_NO_OBJECT_ATTRIBUTES, &config, WDF_NO_HANDLE); +} + +VOID +RamDiskEvtIoRead( + IN WDFQUEUE Queue, + IN WDFREQUEST Request, + IN size_t Length + ) +/*++ + +Routine Description: + + This event is called when the framework receives IRP_MJ_READ request. + +Arguments: + + Queue - Handle to the framework queue object that is associated with the + I/O request. + + Request - Handle to a framework request object. + + Length - Length of the data buffer associated with the request. + The default property of the queue is to not dispatch + zero length read & write requests to the driver and + complete is with status success. So we will never get + a zero length request. + +Return Value: + + VOID + +--*/ +{ + PDEVICE_EXTENSION devExt = QueueGetExtension(Queue)->DeviceExtension; + NTSTATUS Status = STATUS_INVALID_PARAMETER; + WDF_REQUEST_PARAMETERS Parameters; + LARGE_INTEGER ByteOffset; + WDFMEMORY hMemory; + + _Analysis_assume_(Length > 0); + + WDF_REQUEST_PARAMETERS_INIT(&Parameters); + WdfRequestGetParameters(Request, &Parameters); + + ByteOffset.QuadPart = Parameters.Parameters.Read.DeviceOffset; + + if (RamDiskCheckParameters(devExt, ByteOffset, Length)) { + + Status = WdfRequestRetrieveOutputMemory(Request, &hMemory); + if(NT_SUCCESS(Status)){ + + Status = WdfMemoryCopyFromBuffer(hMemory, // Destination + 0, // Offset into the destination + devExt->DiskImage + ByteOffset.LowPart, // source + Length); + } + } + + WdfRequestCompleteWithInformation(Request, Status, (ULONG_PTR)Length); +} + +VOID +RamDiskEvtIoWrite( + IN WDFQUEUE Queue, + IN WDFREQUEST Request, + IN size_t Length + ) + +/*++ + +Routine Description: + + This event is invoked when the framework receives IRP_MJ_WRITE request. + +Arguments: + + Queue - Handle to the framework queue object that is associated with the + I/O request. + + Request - Handle to a framework request object. + + Length - Length of the data buffer associated with the request. + The default property of the queue is to not dispatch + zero length read & write requests to the driver and + complete is with status success. So we will never get + a zero length request. + +Return Value: + + VOID + +--*/ +{ + PDEVICE_EXTENSION devExt = QueueGetExtension(Queue)->DeviceExtension; + NTSTATUS Status = STATUS_INVALID_PARAMETER; + WDF_REQUEST_PARAMETERS Parameters; + LARGE_INTEGER ByteOffset; + WDFMEMORY hMemory; + + _Analysis_assume_(Length > 0); + + WDF_REQUEST_PARAMETERS_INIT(&Parameters); + WdfRequestGetParameters(Request, &Parameters); + + ByteOffset.QuadPart = Parameters.Parameters.Write.DeviceOffset; + + if (RamDiskCheckParameters(devExt, ByteOffset, Length)) { + + Status = WdfRequestRetrieveInputMemory(Request, &hMemory); + if(NT_SUCCESS(Status)){ + + Status = WdfMemoryCopyToBuffer(hMemory, // Source + 0, // offset in Source memory where the copy has to start + devExt->DiskImage + ByteOffset.LowPart, // destination + Length); + } + + } + + WdfRequestCompleteWithInformation(Request, Status, (ULONG_PTR)Length); +} + +VOID +RamDiskEvtIoDeviceControl( + IN WDFQUEUE Queue, + IN WDFREQUEST Request, + IN size_t OutputBufferLength, + IN size_t InputBufferLength, + IN ULONG IoControlCode + ) +/*++ + +Routine Description: + + This event is called when the framework receives IRP_MJ_DEVICE_CONTROL + requests from the system. + +Arguments: + + Queue - Handle to the framework queue object that is associated + with the I/O request. + Request - Handle to a framework request object. + + OutputBufferLength - length of the request's output buffer, + if an output buffer is available. + InputBufferLength - length of the request's input buffer, + if an input buffer is available. + + IoControlCode - the driver-defined or system-defined I/O control code + (IOCTL) that is associated with the request. + + +Return Value: + + VOID + +--*/ +{ + NTSTATUS Status = STATUS_INVALID_DEVICE_REQUEST; + ULONG_PTR information = 0; + size_t bufSize; + PDEVICE_EXTENSION devExt = QueueGetExtension(Queue)->DeviceExtension; + + UNREFERENCED_PARAMETER(OutputBufferLength); + UNREFERENCED_PARAMETER(InputBufferLength); + + switch (IoControlCode) { + case IOCTL_DISK_GET_PARTITION_INFO: { + + PPARTITION_INFORMATION outputBuffer; + PBOOT_SECTOR bootSector = (PBOOT_SECTOR) devExt->DiskImage; + + information = sizeof(PARTITION_INFORMATION); + + Status = WdfRequestRetrieveOutputBuffer(Request, sizeof(PARTITION_INFORMATION), &outputBuffer, &bufSize); + if(NT_SUCCESS(Status) ) { + + outputBuffer->PartitionType = + (bootSector->bsFileSystemType[4] == '6') ? PARTITION_FAT_16 : PARTITION_FAT_12; + + outputBuffer->BootIndicator = FALSE; + outputBuffer->RecognizedPartition = TRUE; + outputBuffer->RewritePartition = FALSE; + outputBuffer->StartingOffset.QuadPart = 0; + outputBuffer->PartitionLength.QuadPart = devExt->DiskRegInfo.DiskSize; + outputBuffer->HiddenSectors = (ULONG) (1L); + outputBuffer->PartitionNumber = (ULONG) (-1L); + + Status = STATUS_SUCCESS; + } + } + break; + + case IOCTL_DISK_GET_DRIVE_GEOMETRY: { + + PDISK_GEOMETRY outputBuffer; + + // + // Return the drive geometry for the ram disk. Note that + // we return values which were made up to suit the disk size. + // + information = sizeof(DISK_GEOMETRY); + + Status = WdfRequestRetrieveOutputBuffer(Request, sizeof(DISK_GEOMETRY), &outputBuffer, &bufSize); + if(NT_SUCCESS(Status) && + bufSize >= sizeof(DISK_GEOMETRY)) { + + RtlCopyMemory(outputBuffer, &(devExt->DiskGeometry), sizeof(DISK_GEOMETRY)); + Status = STATUS_SUCCESS; + } + } + break; + + case IOCTL_DISK_CHECK_VERIFY: + case IOCTL_DISK_IS_WRITABLE: + + // + // Return status success + // + + Status = STATUS_SUCCESS; + break; + } + + WdfRequestCompleteWithInformation(Request, Status, information); +} + +VOID +RamDiskEvtDeviceContextCleanup( + IN WDFOBJECT Device + ) +/*++ + +Routine Description: + + EvtDeviceContextCleanup event callback cleans up anything done in + EvtDeviceAdd, except those things that are automatically cleaned + up by the Framework. + + In the case of this sample, everything is automatically handled. In a + driver derived from this sample, it's quite likely that this function could + be deleted. + +Arguments: + + Device - Handle to a framework device object. + +Return Value: + + VOID + +--*/ +{ + PDEVICE_EXTENSION pDeviceExtension = DeviceGetExtension(Device); + + PAGED_CODE(); + + if(pDeviceExtension->DiskImage) { + ExFreePool(pDeviceExtension->DiskImage); + } +} + +NTSTATUS +RamDiskEvtDeviceAdd( + IN WDFDRIVER Driver, + IN PWDFDEVICE_INIT DeviceInit + ) +/*++ +Routine Description: + + EvtDeviceAdd is called by the framework in response to AddDevice + call from the PnP manager. We create and initialize a device object to + represent a new instance of the device. + +Arguments: + + Driver - Handle to a framework driver object created in DriverEntry + + DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure. + +Return Value: + + NTSTATUS + +--*/ +{ + WDF_OBJECT_ATTRIBUTES deviceAttributes; + NTSTATUS status; + WDFDEVICE device; + WDF_OBJECT_ATTRIBUTES queueAttributes; + WDF_IO_QUEUE_CONFIG ioQueueConfig; + PDEVICE_EXTENSION pDeviceExtension; + PQUEUE_EXTENSION pQueueContext = NULL; + WDFQUEUE queue; + DECLARE_CONST_UNICODE_STRING(ntDeviceName, NT_DEVICE_NAME); + + PAGED_CODE(); + + UNREFERENCED_PARAMETER(Driver); + + // + // Storage drivers have to name their FDOs. Since we are not unique'fying + // the device name, we wouldn't be able to install more than one instance + // of this ramdisk driver. + // + status = WdfDeviceInitAssignName(DeviceInit, &ntDeviceName); + if (!NT_SUCCESS(status)) { + return status; + } + + WdfDeviceInitSetDeviceType(DeviceInit, FILE_DEVICE_DISK); + WdfDeviceInitSetIoType(DeviceInit, WdfDeviceIoDirect); + WdfDeviceInitSetExclusive(DeviceInit, FALSE); + + // + // Since this is a pure software only driver, there is no need to register + // any PNP/Power event callbacks. Framework will respond to these + // events appropriately. + // + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&deviceAttributes, DEVICE_EXTENSION); + deviceAttributes.EvtCleanupCallback = RamDiskEvtDeviceContextCleanup; + + status = WdfDeviceCreate(&DeviceInit, &deviceAttributes, &device); + if (!NT_SUCCESS(status)) { + return status; + } + + // + // Now that the WDF device object has been created, set up any context + // that it requires. + // + + pDeviceExtension = DeviceGetExtension(device); + + // + // Configure a default queue so that requests that are not + // configure-fowarded using WdfDeviceConfigureRequestDispatching to goto + // other queues get dispatched here. + // + WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE ( + &ioQueueConfig, + WdfIoQueueDispatchSequential + ); + + ioQueueConfig.EvtIoDeviceControl = RamDiskEvtIoDeviceControl; + ioQueueConfig.EvtIoRead = RamDiskEvtIoRead; + ioQueueConfig.EvtIoWrite = RamDiskEvtIoWrite; + + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&queueAttributes, QUEUE_EXTENSION); + + // + // By default, Static Driver Verifier (SDV) displays a warning if it + // doesn't find the EvtIoStop callback on a power-managed queue. + // The 'assume' below causes SDV to suppress this warning. If the driver + // has not explicitly set PowerManaged to WdfFalse, the framework creates + // power-managed queues when the device is not a filter driver. Normally + // the EvtIoStop is required for power-managed queues, but for this driver + // it is not needed b/c the driver doesn't hold on to the requests or + // forward them to other drivers. This driver completes the requests + // directly in the queue's handlers. If the EvtIoStop callback is not + // implemented, the framework waits for all driver-owned requests to be + // done before moving in the Dx/sleep states or before removing the + // device, which is the correct behavior for this type of driver. + // If the requests were taking an indeterminate amount of time to complete, + // or if the driver forwarded the requests to a lower driver/another stack, + // the queue should have an EvtIoStop/EvtIoResume. + // + __analysis_assume(ioQueueConfig.EvtIoStop != 0); + status = WdfIoQueueCreate( device, + &ioQueueConfig, + &queueAttributes, + &queue ); + __analysis_assume(ioQueueConfig.EvtIoStop == 0); + if (!NT_SUCCESS(status)) { + return status; + } + + // Context is the Queue handle + pQueueContext = QueueGetExtension(queue); + + // + // Set the context for our default queue as our device extension. + // + pQueueContext->DeviceExtension = pDeviceExtension; + +#if KMDF_VERSION_MINOR >= 9 + + // + // Enable forward progress on the queue we just created. + // NOTE: If you are planning to use this code without forward progress, + // comment out the call to SetForwardProgressOnQueue below. + // + status = SetForwardProgressOnQueue(queue); + if (!NT_SUCCESS(status)) { + return status; + } + +#endif + + // + // Now do any RAM-Disk specific initialization + // + pDeviceExtension->DiskRegInfo.DriveLetter.Buffer = + (PWSTR) &pDeviceExtension->DriveLetterBuffer; + pDeviceExtension->DiskRegInfo.DriveLetter.MaximumLength = + sizeof(pDeviceExtension->DriveLetterBuffer); + + // + // Get the disk parameters from the registry + // + RamDiskQueryDiskRegParameters( + WdfDriverGetRegistryPath(WdfDeviceGetDriver(device)), + &pDeviceExtension->DiskRegInfo + ); + + // + // Allocate memory for the disk image. + // + pDeviceExtension->DiskImage = ExAllocatePoolWithTag( + NonPagedPool, + pDeviceExtension->DiskRegInfo.DiskSize, + RAMDISK_TAG + ); + + if (pDeviceExtension->DiskImage) { + + UNICODE_STRING deviceName; + UNICODE_STRING win32Name; + + RamDiskFormatDisk(pDeviceExtension); + + status = STATUS_SUCCESS; + + // + // Now try to create a symbolic link for the drive letter. + // + RtlInitUnicodeString(&win32Name, DOS_DEVICE_NAME); + RtlInitUnicodeString(&deviceName, NT_DEVICE_NAME); + + pDeviceExtension->SymbolicLink.Buffer = (PWSTR) + &pDeviceExtension->DosDeviceNameBuffer; + pDeviceExtension->SymbolicLink.MaximumLength = + sizeof(pDeviceExtension->DosDeviceNameBuffer); + pDeviceExtension->SymbolicLink.Length = win32Name.Length; + + RtlCopyUnicodeString(&pDeviceExtension->SymbolicLink, &win32Name); + RtlAppendUnicodeStringToString(&pDeviceExtension->SymbolicLink, + &pDeviceExtension->DiskRegInfo.DriveLetter); + + status = WdfDeviceCreateSymbolicLink(device, + &pDeviceExtension->SymbolicLink); + } + + return status; +} + +VOID +RamDiskQueryDiskRegParameters( + _In_ PWSTR RegistryPath, + _In_ PDISK_INFO DiskRegInfo + ) + +/*++ + +Routine Description: + + This routine is called from the DriverEntry to get the debug + parameters from the registry. If the registry query fails, then + default values are used. + +Arguments: + + RegistryPath - Points the service path to get the registry parameters + +Return Value: + + None + +--*/ + +{ + + RTL_QUERY_REGISTRY_TABLE rtlQueryRegTbl[5 + 1]; // Need 1 for NULL + NTSTATUS Status; + DISK_INFO defDiskRegInfo; + + PAGED_CODE(); + + ASSERT(RegistryPath != NULL); + + // Set the default values + + defDiskRegInfo.DiskSize = DEFAULT_DISK_SIZE; + defDiskRegInfo.RootDirEntries = DEFAULT_ROOT_DIR_ENTRIES; + defDiskRegInfo.SectorsPerCluster = DEFAULT_SECTORS_PER_CLUSTER; + + RtlInitUnicodeString(&defDiskRegInfo.DriveLetter, DEFAULT_DRIVE_LETTER); + + RtlZeroMemory(rtlQueryRegTbl, sizeof(rtlQueryRegTbl)); + + // + // Setup the query table + // + + rtlQueryRegTbl[0].Flags = RTL_QUERY_REGISTRY_SUBKEY; + rtlQueryRegTbl[0].Name = L"Parameters"; + rtlQueryRegTbl[0].EntryContext = NULL; + rtlQueryRegTbl[0].DefaultType = (ULONG_PTR)NULL; + rtlQueryRegTbl[0].DefaultData = NULL; + rtlQueryRegTbl[0].DefaultLength = (ULONG_PTR)NULL; + + // + // Disk paramters + // + + rtlQueryRegTbl[1].Flags = RTL_QUERY_REGISTRY_DIRECT; + rtlQueryRegTbl[1].Name = L"DiskSize"; + rtlQueryRegTbl[1].EntryContext = &DiskRegInfo->DiskSize; + rtlQueryRegTbl[1].DefaultType = REG_DWORD; + rtlQueryRegTbl[1].DefaultData = &defDiskRegInfo.DiskSize; + rtlQueryRegTbl[1].DefaultLength = sizeof(ULONG); + + rtlQueryRegTbl[2].Flags = RTL_QUERY_REGISTRY_DIRECT; + rtlQueryRegTbl[2].Name = L"RootDirEntries"; + rtlQueryRegTbl[2].EntryContext = &DiskRegInfo->RootDirEntries; + rtlQueryRegTbl[2].DefaultType = REG_DWORD; + rtlQueryRegTbl[2].DefaultData = &defDiskRegInfo.RootDirEntries; + rtlQueryRegTbl[2].DefaultLength = sizeof(ULONG); + + rtlQueryRegTbl[3].Flags = RTL_QUERY_REGISTRY_DIRECT; + rtlQueryRegTbl[3].Name = L"SectorsPerCluster"; + rtlQueryRegTbl[3].EntryContext = &DiskRegInfo->SectorsPerCluster; + rtlQueryRegTbl[3].DefaultType = REG_DWORD; + rtlQueryRegTbl[3].DefaultData = &defDiskRegInfo.SectorsPerCluster; + rtlQueryRegTbl[3].DefaultLength = sizeof(ULONG); + + rtlQueryRegTbl[4].Flags = RTL_QUERY_REGISTRY_DIRECT; + rtlQueryRegTbl[4].Name = L"DriveLetter"; + rtlQueryRegTbl[4].EntryContext = &DiskRegInfo->DriveLetter; + rtlQueryRegTbl[4].DefaultType = REG_SZ; + rtlQueryRegTbl[4].DefaultData = defDiskRegInfo.DriveLetter.Buffer; + rtlQueryRegTbl[4].DefaultLength = 0; + + + Status = RtlQueryRegistryValues( + RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL, + RegistryPath, + rtlQueryRegTbl, + NULL, + NULL + ); + + if (NT_SUCCESS(Status) == FALSE) { + + DiskRegInfo->DiskSize = defDiskRegInfo.DiskSize; + DiskRegInfo->RootDirEntries = defDiskRegInfo.RootDirEntries; + DiskRegInfo->SectorsPerCluster = defDiskRegInfo.SectorsPerCluster; + RtlCopyUnicodeString(&DiskRegInfo->DriveLetter, &defDiskRegInfo.DriveLetter); + } + + KdPrint(("DiskSize = 0x%lx\n", DiskRegInfo->DiskSize)); + KdPrint(("RootDirEntries = 0x%lx\n", DiskRegInfo->RootDirEntries)); + KdPrint(("SectorsPerCluster = 0x%lx\n", DiskRegInfo->SectorsPerCluster)); + KdPrint(("DriveLetter = %wZ\n", &(DiskRegInfo->DriveLetter))); + + return; +} + +NTSTATUS +RamDiskFormatDisk( + IN PDEVICE_EXTENSION devExt + ) + +/*++ + +Routine Description: + + This routine formats the new disk. + + +Arguments: + + DeviceObject - Supplies a pointer to the device object that represents + the device whose capacity is to be read. + +Return Value: + + status is returned. + +--*/ +{ + + PBOOT_SECTOR bootSector = (PBOOT_SECTOR) devExt->DiskImage; + PUCHAR firstFatSector; + ULONG rootDirEntries; + ULONG sectorsPerCluster; + USHORT fatType; // Type FAT 12 or 16 + USHORT fatEntries; // Number of cluster entries in FAT + USHORT fatSectorCnt; // Number of sectors for FAT + PDIR_ENTRY rootDir; // Pointer to first entry in root dir + + PAGED_CODE(); + ASSERT(sizeof(BOOT_SECTOR) == 512); + ASSERT(devExt->DiskImage != NULL); + + RtlZeroMemory(devExt->DiskImage, devExt->DiskRegInfo.DiskSize); + + devExt->DiskGeometry.BytesPerSector = 512; + devExt->DiskGeometry.SectorsPerTrack = 32; // Using Ramdisk value + devExt->DiskGeometry.TracksPerCylinder = 2; // Using Ramdisk value + + // + // Calculate number of cylinders. + // + + devExt->DiskGeometry.Cylinders.QuadPart = devExt->DiskRegInfo.DiskSize / 512 / 32 / 2; + + // + // Our media type is RAMDISK_MEDIA_TYPE + // + + devExt->DiskGeometry.MediaType = RAMDISK_MEDIA_TYPE; + + KdPrint(( + "Cylinders: %I64d\n TracksPerCylinder: %lu\n SectorsPerTrack: %lu\n BytesPerSector: %lu\n", + devExt->DiskGeometry.Cylinders.QuadPart, devExt->DiskGeometry.TracksPerCylinder, + devExt->DiskGeometry.SectorsPerTrack, devExt->DiskGeometry.BytesPerSector + )); + + rootDirEntries = devExt->DiskRegInfo.RootDirEntries; + sectorsPerCluster = devExt->DiskRegInfo.SectorsPerCluster; + + // + // Round Root Directory entries up if necessary + // + + if (rootDirEntries & (DIR_ENTRIES_PER_SECTOR - 1)) { + + rootDirEntries = + (rootDirEntries + (DIR_ENTRIES_PER_SECTOR - 1)) & + ~ (DIR_ENTRIES_PER_SECTOR - 1); + } + + KdPrint(( + "Root dir entries: %lu\n Sectors/cluster: %lu\n", + rootDirEntries, sectorsPerCluster + )); + + // + // We need to have the 0xeb and 0x90 since this is one of the + // checks the file system recognizer uses + // + + bootSector->bsJump[0] = 0xeb; + bootSector->bsJump[1] = 0x3c; + bootSector->bsJump[2] = 0x90; + + // + // Set OemName to "RajuRam " + // NOTE: Fill all 8 characters, eg. sizeof(bootSector->bsOemName); + // + bootSector->bsOemName[0] = 'R'; + bootSector->bsOemName[1] = 'a'; + bootSector->bsOemName[2] = 'j'; + bootSector->bsOemName[3] = 'u'; + bootSector->bsOemName[4] = 'R'; + bootSector->bsOemName[5] = 'a'; + bootSector->bsOemName[6] = 'm'; + bootSector->bsOemName[7] = ' '; + + bootSector->bsBytesPerSec = (SHORT)devExt->DiskGeometry.BytesPerSector; + bootSector->bsResSectors = 1; + bootSector->bsFATs = 1; + bootSector->bsRootDirEnts = (USHORT)rootDirEntries; + + bootSector->bsSectors = (USHORT)(devExt->DiskRegInfo.DiskSize / + devExt->DiskGeometry.BytesPerSector); + bootSector->bsMedia = (UCHAR)devExt->DiskGeometry.MediaType; + bootSector->bsSecPerClus = (UCHAR)sectorsPerCluster; + + // + // Calculate number of sectors required for FAT + // + + fatEntries = + (bootSector->bsSectors - bootSector->bsResSectors - + bootSector->bsRootDirEnts / DIR_ENTRIES_PER_SECTOR) / + bootSector->bsSecPerClus + 2; + + // + // Choose between 12 and 16 bit FAT based on number of clusters we + // need to map + // + + if (fatEntries > 4087) { + fatType = 16; + fatSectorCnt = (fatEntries * 2 + 511) / 512; + fatEntries = fatEntries + fatSectorCnt; + fatSectorCnt = (fatEntries * 2 + 511) / 512; + } + else { + fatType = 12; + fatSectorCnt = (((fatEntries * 3 + 1) / 2) + 511) / 512; + fatEntries = fatEntries + fatSectorCnt; + fatSectorCnt = (((fatEntries * 3 + 1) / 2) + 511) / 512; + } + + bootSector->bsFATsecs = fatSectorCnt; + bootSector->bsSecPerTrack = (USHORT)devExt->DiskGeometry.SectorsPerTrack; + bootSector->bsHeads = (USHORT)devExt->DiskGeometry.TracksPerCylinder; + bootSector->bsBootSignature = 0x29; + bootSector->bsVolumeID = 0x12345678; + + // + // Set Label to "RamDisk " + // NOTE: Fill all 11 characters, eg. sizeof(bootSector->bsLabel); + // + bootSector->bsLabel[0] = 'R'; + bootSector->bsLabel[1] = 'a'; + bootSector->bsLabel[2] = 'm'; + bootSector->bsLabel[3] = 'D'; + bootSector->bsLabel[4] = 'i'; + bootSector->bsLabel[5] = 's'; + bootSector->bsLabel[6] = 'k'; + bootSector->bsLabel[7] = ' '; + bootSector->bsLabel[8] = ' '; + bootSector->bsLabel[9] = ' '; + bootSector->bsLabel[10] = ' '; + + // + // Set FileSystemType to "FAT1? " + // NOTE: Fill all 8 characters, eg. sizeof(bootSector->bsFileSystemType); + // + bootSector->bsFileSystemType[0] = 'F'; + bootSector->bsFileSystemType[1] = 'A'; + bootSector->bsFileSystemType[2] = 'T'; + bootSector->bsFileSystemType[3] = '1'; + bootSector->bsFileSystemType[4] = '?'; + bootSector->bsFileSystemType[5] = ' '; + bootSector->bsFileSystemType[6] = ' '; + bootSector->bsFileSystemType[7] = ' '; + + bootSector->bsFileSystemType[4] = ( fatType == 16 ) ? '6' : '2'; + + bootSector->bsSig2[0] = 0x55; + bootSector->bsSig2[1] = 0xAA; + + // + // The FAT is located immediately following the boot sector. + // + + firstFatSector = (PUCHAR)(bootSector + 1); + firstFatSector[0] = (UCHAR)devExt->DiskGeometry.MediaType; + firstFatSector[1] = 0xFF; + firstFatSector[2] = 0xFF; + + if (fatType == 16) { + firstFatSector[3] = 0xFF; + } + + // + // The Root Directory follows the FAT + // + rootDir = (PDIR_ENTRY)(bootSector + 1 + fatSectorCnt); + + // + // Set device name to "MS-RAMDR" + // NOTE: Fill all 8 characters, eg. sizeof(rootDir->deName); + // + rootDir->deName[0] = 'M'; + rootDir->deName[1] = 'S'; + rootDir->deName[2] = '-'; + rootDir->deName[3] = 'R'; + rootDir->deName[4] = 'A'; + rootDir->deName[5] = 'M'; + rootDir->deName[6] = 'D'; + rootDir->deName[7] = 'R'; + + // + // Set device extension name to "IVE" + // NOTE: Fill all 3 characters, eg. sizeof(rootDir->deExtension); + // + rootDir->deExtension[0] = 'I'; + rootDir->deExtension[1] = 'V'; + rootDir->deExtension[2] = 'E'; + + rootDir->deAttributes = DIR_ATTR_VOLUME; + + return STATUS_SUCCESS; +} + +BOOLEAN +RamDiskCheckParameters( + IN PDEVICE_EXTENSION devExt, + IN LARGE_INTEGER ByteOffset, + IN size_t Length + ) + +{ + // + // Check for invalid parameters. It is an error for the starting offset + // + length to go past the end of the buffer, or for the length to + // not be a proper multiple of the sector size. + // + // Others are possible, but we don't check them since we trust the + // file system. + // + + if( devExt->DiskRegInfo.DiskSize < Length || + ByteOffset.QuadPart < 0 || // QuadPart is signed so check for negative values + ((ULONGLONG)ByteOffset.QuadPart > (devExt->DiskRegInfo.DiskSize - Length)) || + (Length & (devExt->DiskGeometry.BytesPerSector - 1))) { + + // + // Do not give an I/O boost for parameter errors. + // + + KdPrint(( + "Error invalid parameter\n" + "ByteOffset: %I64x\n" + "Length: %lu\n", + ByteOffset.QuadPart, + Length + )); + + return FALSE; + } + + return TRUE; +} + diff --git a/storage/ramdisk/src/ramdisk.h b/storage/ramdisk/src/ramdisk.h new file mode 100644 index 00000000..764e1094 --- /dev/null +++ b/storage/ramdisk/src/ramdisk.h @@ -0,0 +1,196 @@ +/*++ + +Copyright (c) 1990-2003 Microsoft Corporation, All Rights Reserved + +Module Name: + + ramdisk.h + +Abstract: + + This file includes data declarations for the Ram Disk driver for NT. + +Environment: + + Kernel mode only. + +--*/ + +#ifndef _RAMDISK_H_ +#define _RAMDISK_H_ + +#pragma warning(disable:4201) // nameless struct/union warning + +#include +#include + +#pragma warning(default:4201) + +#include +#define NTSTRSAFE_LIB +#include +#include "forward_progress.h" + +#define NT_DEVICE_NAME L"\\Device\\Ramdisk" +#define DOS_DEVICE_NAME L"\\DosDevices\\" + +#define RAMDISK_TAG 'DmaR' // "RamD" +#define DOS_DEVNAME_LENGTH (sizeof(DOS_DEVICE_NAME)+sizeof(WCHAR)*10) +#define DRIVE_LETTER_LENGTH (sizeof(WCHAR)*10) + +#define DRIVE_LETTER_BUFFER_SIZE 10 +#define DOS_DEVNAME_BUFFER_SIZE (sizeof(DOS_DEVICE_NAME) / 2) + 10 + +#define RAMDISK_MEDIA_TYPE 0xF8 +#define DIR_ENTRIES_PER_SECTOR 16 + +#define DEFAULT_DISK_SIZE (1024*1024) // 1 MB +#define DEFAULT_ROOT_DIR_ENTRIES 512 +#define DEFAULT_SECTORS_PER_CLUSTER 2 +#define DEFAULT_DRIVE_LETTER L"Z:" + +typedef struct _DISK_INFO { + ULONG DiskSize; // Ramdisk size in bytes + ULONG RootDirEntries; // No. of root directory entries + ULONG SectorsPerCluster; // Sectors per cluster + UNICODE_STRING DriveLetter; // Drive letter to be used +} DISK_INFO, *PDISK_INFO; + +typedef struct _DEVICE_EXTENSION { + PUCHAR DiskImage; // Pointer to beginning of disk image + DISK_GEOMETRY DiskGeometry; // Drive parameters built by Ramdisk + DISK_INFO DiskRegInfo; // Disk parameters from the registry + UNICODE_STRING SymbolicLink; // Dos symbolic name; Drive letter + WCHAR DriveLetterBuffer[DRIVE_LETTER_BUFFER_SIZE]; + WCHAR DosDeviceNameBuffer[DOS_DEVNAME_BUFFER_SIZE]; +} DEVICE_EXTENSION, *PDEVICE_EXTENSION; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(DEVICE_EXTENSION, DeviceGetExtension) + +typedef struct _QUEUE_EXTENSION { + PDEVICE_EXTENSION DeviceExtension; +} QUEUE_EXTENSION, *PQUEUE_EXTENSION; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(QUEUE_EXTENSION, QueueGetExtension) + +#pragma pack(1) + +typedef struct _BOOT_SECTOR +{ + UCHAR bsJump[3]; // x86 jmp instruction, checked by FS + CCHAR bsOemName[8]; // OEM name of formatter + USHORT bsBytesPerSec; // Bytes per Sector + UCHAR bsSecPerClus; // Sectors per Cluster + USHORT bsResSectors; // Reserved Sectors + UCHAR bsFATs; // Number of FATs - we always use 1 + USHORT bsRootDirEnts; // Number of Root Dir Entries + USHORT bsSectors; // Number of Sectors + UCHAR bsMedia; // Media type - we use RAMDISK_MEDIA_TYPE + USHORT bsFATsecs; // Number of FAT sectors + USHORT bsSecPerTrack; // Sectors per Track - we use 32 + USHORT bsHeads; // Number of Heads - we use 2 + ULONG bsHiddenSecs; // Hidden Sectors - we set to 0 + ULONG bsHugeSectors; // Number of Sectors if > 32 MB size + UCHAR bsDriveNumber; // Drive Number - not used + UCHAR bsReserved1; // Reserved + UCHAR bsBootSignature; // New Format Boot Signature - 0x29 + ULONG bsVolumeID; // VolumeID - set to 0x12345678 + CCHAR bsLabel[11]; // Label - set to RamDisk + CCHAR bsFileSystemType[8];// File System Type - FAT12 or FAT16 + CCHAR bsReserved2[448]; // Reserved + UCHAR bsSig2[2]; // Originial Boot Signature - 0x55, 0xAA +} BOOT_SECTOR, *PBOOT_SECTOR; + +typedef struct _DIR_ENTRY +{ + UCHAR deName[8]; // File Name + UCHAR deExtension[3]; // File Extension + UCHAR deAttributes; // File Attributes + UCHAR deReserved; // Reserved + USHORT deTime; // File Time + USHORT deDate; // File Date + USHORT deStartCluster; // First Cluster of file + ULONG deFileSize; // File Length +} DIR_ENTRY, *PDIR_ENTRY; + +#pragma pack() + +// +// Directory Entry Attributes +// + +#define DIR_ATTR_READONLY 0x01 +#define DIR_ATTR_HIDDEN 0x02 +#define DIR_ATTR_SYSTEM 0x04 +#define DIR_ATTR_VOLUME 0x08 +#define DIR_ATTR_DIRECTORY 0x10 +#define DIR_ATTR_ARCHIVE 0x20 + +DRIVER_INITIALIZE DriverEntry; + +#if KMDF_VERSION_MINOR >= 7 + +EVT_WDF_DRIVER_DEVICE_ADD RamDiskEvtDeviceAdd; +EVT_WDF_DEVICE_CONTEXT_CLEANUP RamDiskEvtDeviceContextCleanup; +EVT_WDF_IO_QUEUE_IO_READ RamDiskEvtIoRead; +EVT_WDF_IO_QUEUE_IO_WRITE RamDiskEvtIoWrite; +EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL RamDiskEvtIoDeviceControl; + +#else + +NTSTATUS +RamDiskEvtDeviceAdd( + IN WDFDRIVER Driver, + IN PWDFDEVICE_INIT DeviceInit + ); + +VOID +RamDiskEvtDeviceContextCleanup( + IN WDFOBJECT Device + ); + +VOID +RamDiskEvtIoRead( + IN WDFQUEUE Queue, + IN WDFREQUEST Request, + IN size_t Length + ); + +VOID +RamDiskEvtIoWrite( + IN WDFQUEUE Queue, + IN WDFREQUEST Request, + IN size_t Length + ); + +VOID +RamDiskEvtIoDeviceControl( + IN WDFQUEUE Queue, + IN WDFREQUEST Request, + IN size_t OutputBufferLength, + IN size_t InputBufferLength, + IN ULONG IoControlCode + ); + +#endif + +VOID +RamDiskQueryDiskRegParameters( + _In_ PWSTR RegistryPath, + _In_ PDISK_INFO DiskRegInfo + ); + +NTSTATUS +RamDiskFormatDisk( + IN PDEVICE_EXTENSION DeviceExtension + ); + +BOOLEAN +RamDiskCheckParameters( + IN PDEVICE_EXTENSION devExt, + IN LARGE_INTEGER ByteOffset, + IN size_t Length + ); + +#endif // _RAMDISK_H_ + diff --git a/storage/ramdisk/src/ramdisk.inx b/storage/ramdisk/src/ramdisk.inx new file mode 100644 index 00000000..40ad4b1b --- /dev/null +++ b/storage/ramdisk/src/ramdisk.inx @@ -0,0 +1,102 @@ +; RAMDISK.INF +; Windows installation file for installing the Ramdisk driver +; Copyright (c) Microsoft Corporation All rights Reserved +; +; Installation Notes: +; +; Using Devcon: Type "devcon install ramdisk.inf Ramdisk" to install +; + +[Version] +Signature="$WINDOWS NT$" +Class=Sample +ClassGuid={78A1C341-4539-11d3-B88D-00C04FAD5171} +Provider=%MSFT% +DriverVer=11/14/1999,5.00.2183.1 +CatalogFile=KmdfSamples.cat + +[DestinationDirs] +DefaultDestDir = 12 + +[ClassInstall32] +Addreg=SampleClassReg + +[SampleClassReg] +HKR,,,0,%ClassName% +HKR,,Icon,,-5 + +[DiskCopyfiles] +WdfRamdisk.sys + +[SourceDisksNames] +1=%InstDisk%, + +[SourceDisksFiles] +WdfRamdisk.sys=1 + +[Manufacturer] +%MSFT% = DiskDevice,NT$ARCH$ + +; For XP and later +[DiskDevice.NT$ARCH$] +%DiskDevDesc% = DiskInstall, Ramdisk + +[DiskInstall.NT] +CopyFiles = DiskCopyfiles + +[DiskInstall.NT.Services] +AddService = Ramdisk, %SPSVCINST_ASSOCSERVICE%, DiskServiceInst + +[DiskServiceInst] +ServiceType = %SERVICE_KERNEL_DRIVER% +StartType = %SERVICE_DEMAND_START% +ErrorControl = %SERVICE_ERROR_NORMAL% +DisplayName = %DiskServiceDesc% +ServiceBinary = %12%\WdfRamdisk.sys +AddReg = DiskAddReg + +[DiskAddReg] +HKR, "Parameters", "BreakOnEntry", %REG_DWORD%, 0x00000000 +HKR, "Parameters", "DiskSize", %REG_DWORD%, 0x00100000 +HKR, "Parameters", "DriveLetter", %REG_SZ%, "R:" +HKR, "Parameters", "RootDirEntries", %REG_DWORD%, 0x00000200 +HKR, "Parameters", "SectorsPerCluster", %REG_DWORD%, 0x00000002 + + +;-------------- Coinstaller installation +[DestinationDirs] +CoInstaller_CopyFiles = 11 + +[DiskInstall.NT.CoInstallers] +AddReg=CoInstaller_AddReg +CopyFiles=CoInstaller_CopyFiles + +[CoInstaller_CopyFiles] +WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll + +[SourceDisksFiles] +WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll=1 ; make sure the number matches with SourceDisksNames + +[CoInstaller_AddReg] +HKR,,CoInstallers32,0x00010000, "WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll,WdfCoInstaller" + +[DiskInstall.NT.Wdf] +KmdfService = Ramdisk, Ramdisk_wdfsect +[Ramdisk_wdfsect] +KmdfLibraryVersion = $KMDFVERSION$ + + +[Strings] +MSFT = "Microsoft" +ClassName = "Sample Device" +DiskDevDesc = "WDF Sample RAM disk Driver" +DiskServiceDesc = "Ramdisk Driver" +InstDisk = "Ramdisk Install Disk" +;******************************************* +;Handy macro substitutions (non-localizable) +SPSVCINST_ASSOCSERVICE = 0x00000002 +SERVICE_KERNEL_DRIVER = 1 +SERVICE_DEMAND_START = 3 +SERVICE_ERROR_NORMAL = 1 +REG_DWORD = 0x00010001 +REG_SZ = 0x00000000 diff --git a/storage/ramdisk/src/ramdisk.rc b/storage/ramdisk/src/ramdisk.rc new file mode 100644 index 00000000..1d0ded22 --- /dev/null +++ b/storage/ramdisk/src/ramdisk.rc @@ -0,0 +1,11 @@ +#include + +#include + +#define VER_FILETYPE VFT_DLL +#define VER_FILESUBTYPE VFT2_UNKNOWN +#define VER_FILEDESCRIPTION_STR "Driver Frameworks Ramdisk Driver" +#define VER_INTERNALNAME_STR "ramdisk.sys" +#define VER_ORIGINALFILENAME_STR "ramdisk.sys" + +#include "common.ver" diff --git a/storage/sfloppy/sfloppy.sln b/storage/sfloppy/sfloppy.sln index 625b9b20..2735c399 100644 --- a/storage/sfloppy/sfloppy.sln +++ b/storage/sfloppy/sfloppy.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sfloppy", "src\sfloppy.vcxproj", "{5D81B127-32DF-4942-8E61-C6A5A43C52C8}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sfloppy", "src\sfloppy.vcxproj", "{D0708482-EBB5-4AA4-A213-83C4E1997327}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +13,14 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {5D81B127-32DF-4942-8E61-C6A5A43C52C8}.Debug|Win32.ActiveCfg = Debug|Win32 - {5D81B127-32DF-4942-8E61-C6A5A43C52C8}.Debug|Win32.Build.0 = Debug|Win32 - {5D81B127-32DF-4942-8E61-C6A5A43C52C8}.Release|Win32.ActiveCfg = Release|Win32 - {5D81B127-32DF-4942-8E61-C6A5A43C52C8}.Release|Win32.Build.0 = Release|Win32 - {5D81B127-32DF-4942-8E61-C6A5A43C52C8}.Debug|x64.ActiveCfg = Debug|x64 - {5D81B127-32DF-4942-8E61-C6A5A43C52C8}.Debug|x64.Build.0 = Debug|x64 - {5D81B127-32DF-4942-8E61-C6A5A43C52C8}.Release|x64.ActiveCfg = Release|x64 - {5D81B127-32DF-4942-8E61-C6A5A43C52C8}.Release|x64.Build.0 = Release|x64 + {D0708482-EBB5-4AA4-A213-83C4E1997327}.Debug|Win32.ActiveCfg = Debug|Win32 + {D0708482-EBB5-4AA4-A213-83C4E1997327}.Debug|Win32.Build.0 = Debug|Win32 + {D0708482-EBB5-4AA4-A213-83C4E1997327}.Release|Win32.ActiveCfg = Release|Win32 + {D0708482-EBB5-4AA4-A213-83C4E1997327}.Release|Win32.Build.0 = Release|Win32 + {D0708482-EBB5-4AA4-A213-83C4E1997327}.Debug|x64.ActiveCfg = Debug|x64 + {D0708482-EBB5-4AA4-A213-83C4E1997327}.Debug|x64.Build.0 = Debug|x64 + {D0708482-EBB5-4AA4-A213-83C4E1997327}.Release|x64.ActiveCfg = Release|x64 + {D0708482-EBB5-4AA4-A213-83C4E1997327}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/storage/sfloppy/src/floppy.c b/storage/sfloppy/src/floppy.c index b35f7b6a..f4c9634d 100644 --- a/storage/sfloppy/src/floppy.c +++ b/storage/sfloppy/src/floppy.c @@ -1907,7 +1907,7 @@ Return Value: if ((pageData != NULL) && (pageData->PageLength + 2 >= - offsetof(MODE_FLEXIBLE_DISK_PAGE, StartWritePrecom))) { + (UCHAR)offsetof(MODE_FLEXIBLE_DISK_PAGE, StartWritePrecom))) { // // Pull out the heads, cylinders, and sectors. @@ -2152,7 +2152,7 @@ Return Value: if ((pageData == NULL) || (pageData->PageLength + 2 < - offsetof(MODE_FLEXIBLE_DISK_PAGE, StartWritePrecom))) { + (UCHAR)offsetof(MODE_FLEXIBLE_DISK_PAGE, StartWritePrecom))) { ExFreePool(modeData); return(STATUS_INVALID_DEVICE_REQUEST); diff --git a/storage/sfloppy/src/sfloppy.inf b/storage/sfloppy/src/sfloppy.inf index 186db7bb..c7926d37 100644 --- a/storage/sfloppy/src/sfloppy.inf +++ b/storage/sfloppy/src/sfloppy.inf @@ -32,13 +32,6 @@ DefaultDestDir=12 [Manufacturer] %GenManufacturer%=floppy_device,NTx86,NTia64,NTamd64 -[floppy_device] -%sfloppy_devdesc%=sfloppy_install,GenSFloppy -%sfloppy_devdesc%=sfloppy_install,SCSI\DiskMATSHITALS-120_COSM___04 -%sfloppy_devdesc%=sfloppy_install,SCSI\DiskCOMPAQ__LS-120_VER5___AB -%sfloppy_devdesc%=sfloppy_install,SCSI\DiskCOMPAQ__LS-120_HIMA___01 -%sfloppy_devdesc%=sfloppy_install,SCSI\DiskMATSHITALS-120_VER5___00 - [floppy_device.NTx86] %sfloppy_devdesc%=sfloppy_install,GenSFloppy %sfloppy_devdesc%=sfloppy_install,SCSI\DiskMATSHITALS-120_COSM___04 diff --git a/storage/sfloppy/src/sfloppy.vcxproj b/storage/sfloppy/src/sfloppy.vcxproj index a432f928..51ddc866 100644 --- a/storage/sfloppy/src/sfloppy.vcxproj +++ b/storage/sfloppy/src/sfloppy.vcxproj @@ -19,12 +19,12 @@
- {5D81B127-32DF-4942-8E61-C6A5A43C52C8} + {D0708482-EBB5-4AA4-A213-83C4E1997327} $(MSBuildProjectName) false Debug Win32 - {70BD061D-EA75-4D96-9296-D79A1887C7D3} + {FF40AD7B-43CA-4917-9BD5-1F66F696A48B} diff --git a/storage/sfloppy/src/sfloppy.vcxproj.Filters b/storage/sfloppy/src/sfloppy.vcxproj.Filters index b7fed0d6..6e61336a 100644 --- a/storage/sfloppy/src/sfloppy.vcxproj.Filters +++ b/storage/sfloppy/src/sfloppy.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {8D3F32CD-4FD5-462D-A317-9B725AB465BC} + {72E51A2A-765E-4295-BC0C-8BA66207BCEE} h;hpp;hxx;hm;inl;inc;xsd - {892C7033-E808-47F9-80E6-F68B9B2970B9} + {A0E005F4-468E-41D1-B484-84ED829BCCEE} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {DB7B6F5B-7BB7-4A6C-9284-6BEDF6E46D99} + {94587BDC-6D5B-42D6-BCE5-BEC6E77511AE} inf;inv;inx;mof;mc; - {465C4749-C790-46BF-9CEA-4C11509670EE} + {F24E2189-1E6D-44D7-AF6D-A39A4B8B8160} diff --git a/storage/tools/spti/spti.sln b/storage/tools/spti/spti.sln index 7aba3f7e..81ef3611 100644 --- a/storage/tools/spti/spti.sln +++ b/storage/tools/spti/spti.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "spti", "src\spti.vcxproj", "{AD224B88-A7D7-4303-AF16-F972B5159493}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "spti", "src\spti.vcxproj", "{06D7097B-3EC8-4A0F-B1B4-3281A547FF8E}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +13,14 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {AD224B88-A7D7-4303-AF16-F972B5159493}.Debug|Win32.ActiveCfg = Debug|Win32 - {AD224B88-A7D7-4303-AF16-F972B5159493}.Debug|Win32.Build.0 = Debug|Win32 - {AD224B88-A7D7-4303-AF16-F972B5159493}.Release|Win32.ActiveCfg = Release|Win32 - {AD224B88-A7D7-4303-AF16-F972B5159493}.Release|Win32.Build.0 = Release|Win32 - {AD224B88-A7D7-4303-AF16-F972B5159493}.Debug|x64.ActiveCfg = Debug|x64 - {AD224B88-A7D7-4303-AF16-F972B5159493}.Debug|x64.Build.0 = Debug|x64 - {AD224B88-A7D7-4303-AF16-F972B5159493}.Release|x64.ActiveCfg = Release|x64 - {AD224B88-A7D7-4303-AF16-F972B5159493}.Release|x64.Build.0 = Release|x64 + {06D7097B-3EC8-4A0F-B1B4-3281A547FF8E}.Debug|Win32.ActiveCfg = Debug|Win32 + {06D7097B-3EC8-4A0F-B1B4-3281A547FF8E}.Debug|Win32.Build.0 = Debug|Win32 + {06D7097B-3EC8-4A0F-B1B4-3281A547FF8E}.Release|Win32.ActiveCfg = Release|Win32 + {06D7097B-3EC8-4A0F-B1B4-3281A547FF8E}.Release|Win32.Build.0 = Release|Win32 + {06D7097B-3EC8-4A0F-B1B4-3281A547FF8E}.Debug|x64.ActiveCfg = Debug|x64 + {06D7097B-3EC8-4A0F-B1B4-3281A547FF8E}.Debug|x64.Build.0 = Debug|x64 + {06D7097B-3EC8-4A0F-B1B4-3281A547FF8E}.Release|x64.ActiveCfg = Release|x64 + {06D7097B-3EC8-4A0F-B1B4-3281A547FF8E}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/storage/tools/spti/src/spti.vcxproj b/storage/tools/spti/src/spti.vcxproj index 7d29715b..83ca7201 100644 --- a/storage/tools/spti/src/spti.vcxproj +++ b/storage/tools/spti/src/spti.vcxproj @@ -19,11 +19,11 @@ - {AD224B88-A7D7-4303-AF16-F972B5159493} + {06D7097B-3EC8-4A0F-B1B4-3281A547FF8E} $(MSBuildProjectName) Debug Win32 - {385079F7-5826-4E2F-AF88-176A9338646C} + {3808D033-40D7-4C7A-8DA1-D7E82C8FD640} diff --git a/storage/tools/spti/src/spti.vcxproj.Filters b/storage/tools/spti/src/spti.vcxproj.Filters index 7d986f7a..c33a7ead 100644 --- a/storage/tools/spti/src/spti.vcxproj.Filters +++ b/storage/tools/spti/src/spti.vcxproj.Filters @@ -3,15 +3,15 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {F406A289-67B3-40DA-BF00-D802F47EC89A} + {04D905C4-521E-4922-A82E-9166E240F4AE} h;hpp;hxx;hm;inl;inc;xsd - {018A4F52-238E-4856-BAF1-C38B0D6145F1} + {9101E840-E8E3-427D-8033-C66E6D748653} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {5B9E60E4-CD1B-4C14-B6FD-2D55F070CEF5} + {023F3BB8-A899-4718-AD48-F2A263DC147C} diff --git a/thermal/simsensor/simsensor.sln b/thermal/simsensor/simsensor.sln index 02088936..734db11c 100644 --- a/thermal/simsensor/simsensor.sln +++ b/thermal/simsensor/simsensor.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "simsensor", "simsensor.vcxproj", "{19059D30-607E-40DE-B097-7D6A9F00BB84}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "simsensor", "simsensor.vcxproj", "{C59FD02E-3C7E-4DC3-94C7-7E04827E0934}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +13,14 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {19059D30-607E-40DE-B097-7D6A9F00BB84}.Debug|Win32.ActiveCfg = Debug|Win32 - {19059D30-607E-40DE-B097-7D6A9F00BB84}.Debug|Win32.Build.0 = Debug|Win32 - {19059D30-607E-40DE-B097-7D6A9F00BB84}.Release|Win32.ActiveCfg = Release|Win32 - {19059D30-607E-40DE-B097-7D6A9F00BB84}.Release|Win32.Build.0 = Release|Win32 - {19059D30-607E-40DE-B097-7D6A9F00BB84}.Debug|x64.ActiveCfg = Debug|x64 - {19059D30-607E-40DE-B097-7D6A9F00BB84}.Debug|x64.Build.0 = Debug|x64 - {19059D30-607E-40DE-B097-7D6A9F00BB84}.Release|x64.ActiveCfg = Release|x64 - {19059D30-607E-40DE-B097-7D6A9F00BB84}.Release|x64.Build.0 = Release|x64 + {C59FD02E-3C7E-4DC3-94C7-7E04827E0934}.Debug|Win32.ActiveCfg = Debug|Win32 + {C59FD02E-3C7E-4DC3-94C7-7E04827E0934}.Debug|Win32.Build.0 = Debug|Win32 + {C59FD02E-3C7E-4DC3-94C7-7E04827E0934}.Release|Win32.ActiveCfg = Release|Win32 + {C59FD02E-3C7E-4DC3-94C7-7E04827E0934}.Release|Win32.Build.0 = Release|Win32 + {C59FD02E-3C7E-4DC3-94C7-7E04827E0934}.Debug|x64.ActiveCfg = Debug|x64 + {C59FD02E-3C7E-4DC3-94C7-7E04827E0934}.Debug|x64.Build.0 = Debug|x64 + {C59FD02E-3C7E-4DC3-94C7-7E04827E0934}.Release|x64.ActiveCfg = Release|x64 + {C59FD02E-3C7E-4DC3-94C7-7E04827E0934}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/thermal/simsensor/simsensor.vcxproj b/thermal/simsensor/simsensor.vcxproj index 88595b8b..fc01a580 100644 --- a/thermal/simsensor/simsensor.vcxproj +++ b/thermal/simsensor/simsensor.vcxproj @@ -19,12 +19,12 @@ - {19059D30-607E-40DE-B097-7D6A9F00BB84} + {C59FD02E-3C7E-4DC3-94C7-7E04827E0934} $(MSBuildProjectName) 1 Debug Win32 - {22F66120-1AA5-41DF-8C9A-63886E47FC1A} + {614E84B8-6A38-4F03-93D6-E41FEA710542} diff --git a/thermal/simsensor/simsensor.vcxproj.Filters b/thermal/simsensor/simsensor.vcxproj.Filters index 8c8cbc53..135dc024 100644 --- a/thermal/simsensor/simsensor.vcxproj.Filters +++ b/thermal/simsensor/simsensor.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {3EC12CC9-21D8-436D-8722-4DD0F6125A49} + {C3D02E88-9BD3-4979-BB31-99764D1517A9} h;hpp;hxx;hm;inl;inc;xsd - {B88FDD7A-5C49-4803-B834-C45E7571667B} + {69FA9ACE-C62E-4ABA-A9A2-9F2C43CCDD50} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {3E0876AF-D4ED-4594-9977-099E5CE49B4E} + {17C8F8C4-E1A8-404B-BEB5-1D12BD37AC27} inf;inv;inx;mof;mc; - {A822817B-1BD0-4030-9E30-3A878433B703} + {9DB4A799-2FC4-47D4-A5BA-F2395218E4AE} diff --git a/thermal/thermalclient/simtc.vcxproj b/thermal/thermalclient/simtc.vcxproj index 1e74c0eb..23b7b735 100644 --- a/thermal/thermalclient/simtc.vcxproj +++ b/thermal/thermalclient/simtc.vcxproj @@ -19,12 +19,12 @@ - {0BCA7B3F-F0AB-42D0-93B2-42518BF9A7EC} + {8C2AD3B6-D9D6-4ECA-8D92-A714B4046119} $(MSBuildProjectName) 1 Debug Win32 - {C78C663A-88D6-48F0-8E97-3B7C3075FF66} + {96B796D8-F417-486F-8B8A-C1BA76C20398} diff --git a/thermal/thermalclient/simtc.vcxproj.Filters b/thermal/thermalclient/simtc.vcxproj.Filters index 1bee78bf..47ec9236 100644 --- a/thermal/thermalclient/simtc.vcxproj.Filters +++ b/thermal/thermalclient/simtc.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {566850EE-263A-4AAE-A2CA-5DF9161D85D0} + {3F670431-8219-4202-9710-75D4686C3657} h;hpp;hxx;hm;inl;inc;xsd - {4049C3FC-425B-4EB0-9C80-6CDF1C3FFCA5} + {8DE58803-401C-49AD-A147-C3F70346A0DB} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {380247F4-A6BC-4F5C-ABDB-4D150B6FBA6B} + {964EADB1-B2FC-4397-A2F0-B4C72031CC67} inf;inv;inx;mof;mc; - {6EDA0278-4010-45AA-BF59-3EB5044A1C25} + {0C7838AB-73FB-4DBB-B61F-2BAEF26FB05E} diff --git a/thermal/thermalclient/thermalclient.sln b/thermal/thermalclient/thermalclient.sln index 912ef9f1..6415ed75 100644 --- a/thermal/thermalclient/thermalclient.sln +++ b/thermal/thermalclient/thermalclient.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "simtc", "simtc.vcxproj", "{0BCA7B3F-F0AB-42D0-93B2-42518BF9A7EC}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "simtc", "simtc.vcxproj", "{8C2AD3B6-D9D6-4ECA-8D92-A714B4046119}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +13,14 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {0BCA7B3F-F0AB-42D0-93B2-42518BF9A7EC}.Debug|Win32.ActiveCfg = Debug|Win32 - {0BCA7B3F-F0AB-42D0-93B2-42518BF9A7EC}.Debug|Win32.Build.0 = Debug|Win32 - {0BCA7B3F-F0AB-42D0-93B2-42518BF9A7EC}.Release|Win32.ActiveCfg = Release|Win32 - {0BCA7B3F-F0AB-42D0-93B2-42518BF9A7EC}.Release|Win32.Build.0 = Release|Win32 - {0BCA7B3F-F0AB-42D0-93B2-42518BF9A7EC}.Debug|x64.ActiveCfg = Debug|x64 - {0BCA7B3F-F0AB-42D0-93B2-42518BF9A7EC}.Debug|x64.Build.0 = Debug|x64 - {0BCA7B3F-F0AB-42D0-93B2-42518BF9A7EC}.Release|x64.ActiveCfg = Release|x64 - {0BCA7B3F-F0AB-42D0-93B2-42518BF9A7EC}.Release|x64.Build.0 = Release|x64 + {8C2AD3B6-D9D6-4ECA-8D92-A714B4046119}.Debug|Win32.ActiveCfg = Debug|Win32 + {8C2AD3B6-D9D6-4ECA-8D92-A714B4046119}.Debug|Win32.Build.0 = Debug|Win32 + {8C2AD3B6-D9D6-4ECA-8D92-A714B4046119}.Release|Win32.ActiveCfg = Release|Win32 + {8C2AD3B6-D9D6-4ECA-8D92-A714B4046119}.Release|Win32.Build.0 = Release|Win32 + {8C2AD3B6-D9D6-4ECA-8D92-A714B4046119}.Debug|x64.ActiveCfg = Debug|x64 + {8C2AD3B6-D9D6-4ECA-8D92-A714B4046119}.Debug|x64.Build.0 = Debug|x64 + {8C2AD3B6-D9D6-4ECA-8D92-A714B4046119}.Release|x64.ActiveCfg = Release|x64 + {8C2AD3B6-D9D6-4ECA-8D92-A714B4046119}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/tools/sdv/samples/SDV-FailDriver-KMDF/SDV-FailDriver-KMDF.sln b/tools/sdv/samples/SDV-FailDriver-KMDF/SDV-FailDriver-KMDF.sln index e860a7c9..f5a65853 100644 --- a/tools/sdv/samples/SDV-FailDriver-KMDF/SDV-FailDriver-KMDF.sln +++ b/tools/sdv/samples/SDV-FailDriver-KMDF/SDV-FailDriver-KMDF.sln @@ -3,15 +3,15 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Library", "Library", "{D5C1E603-5DC3-4EC1-8CED-9881BD89D1C8}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Library", "Library", "{162D69A5-1E20-46D9-A76A-F8C13814A72B}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Driver", "Driver", "{6451DC47-EA7A-48A5-97AF-B8D2F6B93A64}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Driver", "Driver", "{F2A70EFC-5B8A-48F0-A850-A10B7F1BF6CD}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fail_library1", "library\fail_library1.vcxproj", "{728D894D-D708-4DC2-801C-8572A7BA00AD}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fail_library1", "library\fail_library1.vcxproj", "{94A7D7B0-5847-4D82-AEF8-DEBB9791264D}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fail_driver1", "driver\fail_driver1.vcxproj", "{A11169AD-B0A3-45A3-8855-47672EB9DD9F}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fail_driver1", "driver\fail_driver1.vcxproj", "{C7B6DCCE-A00A-4FFE-943C-BE627739F557}" ProjectSection(ProjectDependencies) = postProject - {728D894D-D708-4DC2-801C-8572A7BA00AD} = {728D894D-D708-4DC2-801C-8572A7BA00AD} + {94A7D7B0-5847-4D82-AEF8-DEBB9791264D} = {94A7D7B0-5847-4D82-AEF8-DEBB9791264D} EndProjectSection EndProject Global @@ -22,28 +22,28 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {728D894D-D708-4DC2-801C-8572A7BA00AD}.Debug|Win32.ActiveCfg = Debug|Win32 - {728D894D-D708-4DC2-801C-8572A7BA00AD}.Debug|Win32.Build.0 = Debug|Win32 - {728D894D-D708-4DC2-801C-8572A7BA00AD}.Release|Win32.ActiveCfg = Release|Win32 - {728D894D-D708-4DC2-801C-8572A7BA00AD}.Release|Win32.Build.0 = Release|Win32 - {728D894D-D708-4DC2-801C-8572A7BA00AD}.Debug|x64.ActiveCfg = Debug|x64 - {728D894D-D708-4DC2-801C-8572A7BA00AD}.Debug|x64.Build.0 = Debug|x64 - {728D894D-D708-4DC2-801C-8572A7BA00AD}.Release|x64.ActiveCfg = Release|x64 - {728D894D-D708-4DC2-801C-8572A7BA00AD}.Release|x64.Build.0 = Release|x64 - {A11169AD-B0A3-45A3-8855-47672EB9DD9F}.Debug|Win32.ActiveCfg = Debug|Win32 - {A11169AD-B0A3-45A3-8855-47672EB9DD9F}.Debug|Win32.Build.0 = Debug|Win32 - {A11169AD-B0A3-45A3-8855-47672EB9DD9F}.Release|Win32.ActiveCfg = Release|Win32 - {A11169AD-B0A3-45A3-8855-47672EB9DD9F}.Release|Win32.Build.0 = Release|Win32 - {A11169AD-B0A3-45A3-8855-47672EB9DD9F}.Debug|x64.ActiveCfg = Debug|x64 - {A11169AD-B0A3-45A3-8855-47672EB9DD9F}.Debug|x64.Build.0 = Debug|x64 - {A11169AD-B0A3-45A3-8855-47672EB9DD9F}.Release|x64.ActiveCfg = Release|x64 - {A11169AD-B0A3-45A3-8855-47672EB9DD9F}.Release|x64.Build.0 = Release|x64 + {94A7D7B0-5847-4D82-AEF8-DEBB9791264D}.Debug|Win32.ActiveCfg = Debug|Win32 + {94A7D7B0-5847-4D82-AEF8-DEBB9791264D}.Debug|Win32.Build.0 = Debug|Win32 + {94A7D7B0-5847-4D82-AEF8-DEBB9791264D}.Release|Win32.ActiveCfg = Release|Win32 + {94A7D7B0-5847-4D82-AEF8-DEBB9791264D}.Release|Win32.Build.0 = Release|Win32 + {94A7D7B0-5847-4D82-AEF8-DEBB9791264D}.Debug|x64.ActiveCfg = Debug|x64 + {94A7D7B0-5847-4D82-AEF8-DEBB9791264D}.Debug|x64.Build.0 = Debug|x64 + {94A7D7B0-5847-4D82-AEF8-DEBB9791264D}.Release|x64.ActiveCfg = Release|x64 + {94A7D7B0-5847-4D82-AEF8-DEBB9791264D}.Release|x64.Build.0 = Release|x64 + {C7B6DCCE-A00A-4FFE-943C-BE627739F557}.Debug|Win32.ActiveCfg = Debug|Win32 + {C7B6DCCE-A00A-4FFE-943C-BE627739F557}.Debug|Win32.Build.0 = Debug|Win32 + {C7B6DCCE-A00A-4FFE-943C-BE627739F557}.Release|Win32.ActiveCfg = Release|Win32 + {C7B6DCCE-A00A-4FFE-943C-BE627739F557}.Release|Win32.Build.0 = Release|Win32 + {C7B6DCCE-A00A-4FFE-943C-BE627739F557}.Debug|x64.ActiveCfg = Debug|x64 + {C7B6DCCE-A00A-4FFE-943C-BE627739F557}.Debug|x64.Build.0 = Debug|x64 + {C7B6DCCE-A00A-4FFE-943C-BE627739F557}.Release|x64.ActiveCfg = Release|x64 + {C7B6DCCE-A00A-4FFE-943C-BE627739F557}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {728D894D-D708-4DC2-801C-8572A7BA00AD} = {D5C1E603-5DC3-4EC1-8CED-9881BD89D1C8} - {A11169AD-B0A3-45A3-8855-47672EB9DD9F} = {6451DC47-EA7A-48A5-97AF-B8D2F6B93A64} + {94A7D7B0-5847-4D82-AEF8-DEBB9791264D} = {162D69A5-1E20-46D9-A76A-F8C13814A72B} + {C7B6DCCE-A00A-4FFE-943C-BE627739F557} = {F2A70EFC-5B8A-48F0-A850-A10B7F1BF6CD} EndGlobalSection EndGlobal diff --git a/tools/sdv/samples/SDV-FailDriver-KMDF/driver/fail_driver1.vcxproj b/tools/sdv/samples/SDV-FailDriver-KMDF/driver/fail_driver1.vcxproj index 8ac5e0b9..7a50e41a 100644 --- a/tools/sdv/samples/SDV-FailDriver-KMDF/driver/fail_driver1.vcxproj +++ b/tools/sdv/samples/SDV-FailDriver-KMDF/driver/fail_driver1.vcxproj @@ -19,13 +19,13 @@ - {A11169AD-B0A3-45A3-8855-47672EB9DD9F} + {C7B6DCCE-A00A-4FFE-943C-BE627739F557} $(MSBuildProjectName) 1 false Debug Win32 - {C5026428-4450-46F0-B0CC-7A1B8B7E8280} + {6966CAEE-CE04-4D25-9875-4AEF3D8996DA} diff --git a/tools/sdv/samples/SDV-FailDriver-KMDF/driver/fail_driver1.vcxproj.Filters b/tools/sdv/samples/SDV-FailDriver-KMDF/driver/fail_driver1.vcxproj.Filters index 5d660f8a..ae7c7e70 100644 --- a/tools/sdv/samples/SDV-FailDriver-KMDF/driver/fail_driver1.vcxproj.Filters +++ b/tools/sdv/samples/SDV-FailDriver-KMDF/driver/fail_driver1.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {30A4A780-2DFC-41D4-99B1-D23A78A414FD} + {A16A5FE6-FA81-4783-80D1-98C34A071F87} h;hpp;hxx;hm;inl;inc;xsd - {FF170C4A-770D-4CAA-A5FC-E311A6227B66} + {0FBD4010-4C7C-4257-90F4-072C980F0185} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {34D9A95C-C791-4359-B54F-EBC71B91D059} + {A7C33620-384C-413F-B7D1-9730C933D08A} inf;inv;inx;mof;mc; - {A0135220-5D6B-4816-9FC7-EF176706BB60} + {0EFF4338-76DE-4363-99CA-F90B51F129C9} diff --git a/tools/sdv/samples/SDV-FailDriver-KMDF/library/fail_library1.vcxproj b/tools/sdv/samples/SDV-FailDriver-KMDF/library/fail_library1.vcxproj index 14d00860..c54c77f0 100644 --- a/tools/sdv/samples/SDV-FailDriver-KMDF/library/fail_library1.vcxproj +++ b/tools/sdv/samples/SDV-FailDriver-KMDF/library/fail_library1.vcxproj @@ -19,13 +19,13 @@ - {728D894D-D708-4DC2-801C-8572A7BA00AD} + {94A7D7B0-5847-4D82-AEF8-DEBB9791264D} $(MSBuildProjectName) 1 false Debug Win32 - {015611E2-6392-444B-887C-7E0E45A32564} + {931CA2A4-0AE4-4271-8F6F-3A1F1621CBAA} diff --git a/tools/sdv/samples/SDV-FailDriver-KMDF/library/fail_library1.vcxproj.Filters b/tools/sdv/samples/SDV-FailDriver-KMDF/library/fail_library1.vcxproj.Filters index 795d7213..096701f3 100644 --- a/tools/sdv/samples/SDV-FailDriver-KMDF/library/fail_library1.vcxproj.Filters +++ b/tools/sdv/samples/SDV-FailDriver-KMDF/library/fail_library1.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {9EEF04C2-5849-4B4A-8237-82D36B8FF935} + {D7579C99-00DB-4864-84F1-FC06F14F5684} h;hpp;hxx;hm;inl;inc;xsd - {91E0B963-B841-4BB6-9277-5B0103E8A74B} + {EAF05F4C-8A24-401B-B31A-8E45BB55A755} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {FCC726ED-80DF-45A4-A2B1-7DE7947CF430} + {4A5E0201-5E51-4E94-9931-91EC0A7162CF} inf;inv;inx;mof;mc; - {D599A040-468F-428B-8505-D32A07F1AD7B} + {82A19C94-017E-4038-8319-B8E0A6A6565C} diff --git a/tools/sdv/samples/SDV-FailDriver-NDIS/SDV-FailDriver-NDIS.sln b/tools/sdv/samples/SDV-FailDriver-NDIS/SDV-FailDriver-NDIS.sln index 7afd533e..c8228562 100644 --- a/tools/sdv/samples/SDV-FailDriver-NDIS/SDV-FailDriver-NDIS.sln +++ b/tools/sdv/samples/SDV-FailDriver-NDIS/SDV-FailDriver-NDIS.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sdvmp", "driver\sdvmp.vcxproj", "{427E31D4-C49F-45F7-9330-F66C6511D2B0}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sdvmp", "driver\sdvmp.vcxproj", "{9FB0FC7C-E49D-4662-8A3C-F9E100FE597F}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +13,14 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {427E31D4-C49F-45F7-9330-F66C6511D2B0}.Debug|Win32.ActiveCfg = Debug|Win32 - {427E31D4-C49F-45F7-9330-F66C6511D2B0}.Debug|Win32.Build.0 = Debug|Win32 - {427E31D4-C49F-45F7-9330-F66C6511D2B0}.Release|Win32.ActiveCfg = Release|Win32 - {427E31D4-C49F-45F7-9330-F66C6511D2B0}.Release|Win32.Build.0 = Release|Win32 - {427E31D4-C49F-45F7-9330-F66C6511D2B0}.Debug|x64.ActiveCfg = Debug|x64 - {427E31D4-C49F-45F7-9330-F66C6511D2B0}.Debug|x64.Build.0 = Debug|x64 - {427E31D4-C49F-45F7-9330-F66C6511D2B0}.Release|x64.ActiveCfg = Release|x64 - {427E31D4-C49F-45F7-9330-F66C6511D2B0}.Release|x64.Build.0 = Release|x64 + {9FB0FC7C-E49D-4662-8A3C-F9E100FE597F}.Debug|Win32.ActiveCfg = Debug|Win32 + {9FB0FC7C-E49D-4662-8A3C-F9E100FE597F}.Debug|Win32.Build.0 = Debug|Win32 + {9FB0FC7C-E49D-4662-8A3C-F9E100FE597F}.Release|Win32.ActiveCfg = Release|Win32 + {9FB0FC7C-E49D-4662-8A3C-F9E100FE597F}.Release|Win32.Build.0 = Release|Win32 + {9FB0FC7C-E49D-4662-8A3C-F9E100FE597F}.Debug|x64.ActiveCfg = Debug|x64 + {9FB0FC7C-E49D-4662-8A3C-F9E100FE597F}.Debug|x64.Build.0 = Debug|x64 + {9FB0FC7C-E49D-4662-8A3C-F9E100FE597F}.Release|x64.ActiveCfg = Release|x64 + {9FB0FC7C-E49D-4662-8A3C-F9E100FE597F}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/tools/sdv/samples/SDV-FailDriver-NDIS/driver/sdvmp.vcxproj b/tools/sdv/samples/SDV-FailDriver-NDIS/driver/sdvmp.vcxproj index e4f2bbe0..9173fb0d 100644 --- a/tools/sdv/samples/SDV-FailDriver-NDIS/driver/sdvmp.vcxproj +++ b/tools/sdv/samples/SDV-FailDriver-NDIS/driver/sdvmp.vcxproj @@ -19,12 +19,12 @@ - {427E31D4-C49F-45F7-9330-F66C6511D2B0} + {9FB0FC7C-E49D-4662-8A3C-F9E100FE597F} $(MSBuildProjectName) false Debug Win32 - {64EB7D32-D5C7-4693-9468-2EA899CDFF8A} + {238E1F6A-833F-4C08-A6FF-81E5DE0D9CC4} diff --git a/tools/sdv/samples/SDV-FailDriver-NDIS/driver/sdvmp.vcxproj.Filters b/tools/sdv/samples/SDV-FailDriver-NDIS/driver/sdvmp.vcxproj.Filters index 7cfd9313..3a34320b 100644 --- a/tools/sdv/samples/SDV-FailDriver-NDIS/driver/sdvmp.vcxproj.Filters +++ b/tools/sdv/samples/SDV-FailDriver-NDIS/driver/sdvmp.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {EE18592D-D9CA-46DA-AFB4-FE3854CADE97} + {2CE179FB-8222-49D1-978A-A2BA05CDA7B7} h;hpp;hxx;hm;inl;inc;xsd - {4A94D719-CB73-4056-BCEF-07B57C94FF87} + {2610987D-58AB-4BE0-83E8-156BFD45ED70} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {6D8E8529-4A36-4CDE-A6D8-835A8E036BF1} + {36AA2952-8F33-4E30-B29A-A7963DC4FA02} inf;inv;inx;mof;mc; - {9ACFD768-2B3F-427E-A478-4776F5AB95EF} + {507BF12B-8672-4B6E-ACD4-BC295EDF6F2E} diff --git a/tools/sdv/samples/SDV-FailDriver-STORPORT/SDV-FailDriver-STORPORT.sln b/tools/sdv/samples/SDV-FailDriver-STORPORT/SDV-FailDriver-STORPORT.sln index b9b29228..d85d275a 100644 --- a/tools/sdv/samples/SDV-FailDriver-STORPORT/SDV-FailDriver-STORPORT.sln +++ b/tools/sdv/samples/SDV-FailDriver-STORPORT/SDV-FailDriver-STORPORT.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lsi_u3", "driver\lsi_u3.vcxproj", "{85233D28-0D55-441F-A21F-A75655270EC1}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lsi_u3", "driver\lsi_u3.vcxproj", "{94AE0D66-FB0C-45A1-BC8D-D3EB0BB5AF5C}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +13,14 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {85233D28-0D55-441F-A21F-A75655270EC1}.Debug|Win32.ActiveCfg = Debug|Win32 - {85233D28-0D55-441F-A21F-A75655270EC1}.Debug|Win32.Build.0 = Debug|Win32 - {85233D28-0D55-441F-A21F-A75655270EC1}.Release|Win32.ActiveCfg = Release|Win32 - {85233D28-0D55-441F-A21F-A75655270EC1}.Release|Win32.Build.0 = Release|Win32 - {85233D28-0D55-441F-A21F-A75655270EC1}.Debug|x64.ActiveCfg = Debug|x64 - {85233D28-0D55-441F-A21F-A75655270EC1}.Debug|x64.Build.0 = Debug|x64 - {85233D28-0D55-441F-A21F-A75655270EC1}.Release|x64.ActiveCfg = Release|x64 - {85233D28-0D55-441F-A21F-A75655270EC1}.Release|x64.Build.0 = Release|x64 + {94AE0D66-FB0C-45A1-BC8D-D3EB0BB5AF5C}.Debug|Win32.ActiveCfg = Debug|Win32 + {94AE0D66-FB0C-45A1-BC8D-D3EB0BB5AF5C}.Debug|Win32.Build.0 = Debug|Win32 + {94AE0D66-FB0C-45A1-BC8D-D3EB0BB5AF5C}.Release|Win32.ActiveCfg = Release|Win32 + {94AE0D66-FB0C-45A1-BC8D-D3EB0BB5AF5C}.Release|Win32.Build.0 = Release|Win32 + {94AE0D66-FB0C-45A1-BC8D-D3EB0BB5AF5C}.Debug|x64.ActiveCfg = Debug|x64 + {94AE0D66-FB0C-45A1-BC8D-D3EB0BB5AF5C}.Debug|x64.Build.0 = Debug|x64 + {94AE0D66-FB0C-45A1-BC8D-D3EB0BB5AF5C}.Release|x64.ActiveCfg = Release|x64 + {94AE0D66-FB0C-45A1-BC8D-D3EB0BB5AF5C}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/tools/sdv/samples/SDV-FailDriver-STORPORT/driver/lsi_u3.vcxproj b/tools/sdv/samples/SDV-FailDriver-STORPORT/driver/lsi_u3.vcxproj index d1b9a392..e05a57e6 100644 --- a/tools/sdv/samples/SDV-FailDriver-STORPORT/driver/lsi_u3.vcxproj +++ b/tools/sdv/samples/SDV-FailDriver-STORPORT/driver/lsi_u3.vcxproj @@ -19,12 +19,12 @@ - {85233D28-0D55-441F-A21F-A75655270EC1} + {94AE0D66-FB0C-45A1-BC8D-D3EB0BB5AF5C} $(MSBuildProjectName) false Debug Win32 - {BBF416EE-8943-42D0-A5F3-DAAF62F3FDCB} + {7B51C76A-5AAB-49D5-80F6-235C68235E20} diff --git a/tools/sdv/samples/SDV-FailDriver-STORPORT/driver/lsi_u3.vcxproj.Filters b/tools/sdv/samples/SDV-FailDriver-STORPORT/driver/lsi_u3.vcxproj.Filters index 51d43f8f..7f8e0e77 100644 --- a/tools/sdv/samples/SDV-FailDriver-STORPORT/driver/lsi_u3.vcxproj.Filters +++ b/tools/sdv/samples/SDV-FailDriver-STORPORT/driver/lsi_u3.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {FE117081-70E1-41C8-A729-F3496F4F366B} + {F6235CEF-D6BE-4998-91D7-878E40CBB400} h;hpp;hxx;hm;inl;inc;xsd - {3EBD2AE7-1F95-4C6A-A853-80039B1D5035} + {0D05F536-41BB-49DD-A1EF-0559AD4C6581} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {36D30486-2B2A-473B-86B6-D83356FA1642} + {6A3C8712-80E5-4CB3-A94F-069CCCED2AA9} inf;inv;inx;mof;mc; - {C2632345-EC91-400B-8AAF-CB7AEA1EE30C} + {5593B524-AFE3-42DE-B210-850E716AB626} diff --git a/tools/sdv/samples/SDV-FailDriver-WDM/SDV-FailDriver-WDM.sln b/tools/sdv/samples/SDV-FailDriver-WDM/SDV-FailDriver-WDM.sln index 39dedc54..32a33275 100644 --- a/tools/sdv/samples/SDV-FailDriver-WDM/SDV-FailDriver-WDM.sln +++ b/tools/sdv/samples/SDV-FailDriver-WDM/SDV-FailDriver-WDM.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fail_driver1", "driver\fail_driver1.vcxproj", "{D993A00C-3449-4EA0-AB30-D76264170B45}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fail_driver1", "driver\fail_driver1.vcxproj", "{00B50311-24EF-44CE-B29E-A1A308EB2649}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +13,14 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {D993A00C-3449-4EA0-AB30-D76264170B45}.Debug|Win32.ActiveCfg = Debug|Win32 - {D993A00C-3449-4EA0-AB30-D76264170B45}.Debug|Win32.Build.0 = Debug|Win32 - {D993A00C-3449-4EA0-AB30-D76264170B45}.Release|Win32.ActiveCfg = Release|Win32 - {D993A00C-3449-4EA0-AB30-D76264170B45}.Release|Win32.Build.0 = Release|Win32 - {D993A00C-3449-4EA0-AB30-D76264170B45}.Debug|x64.ActiveCfg = Debug|x64 - {D993A00C-3449-4EA0-AB30-D76264170B45}.Debug|x64.Build.0 = Debug|x64 - {D993A00C-3449-4EA0-AB30-D76264170B45}.Release|x64.ActiveCfg = Release|x64 - {D993A00C-3449-4EA0-AB30-D76264170B45}.Release|x64.Build.0 = Release|x64 + {00B50311-24EF-44CE-B29E-A1A308EB2649}.Debug|Win32.ActiveCfg = Debug|Win32 + {00B50311-24EF-44CE-B29E-A1A308EB2649}.Debug|Win32.Build.0 = Debug|Win32 + {00B50311-24EF-44CE-B29E-A1A308EB2649}.Release|Win32.ActiveCfg = Release|Win32 + {00B50311-24EF-44CE-B29E-A1A308EB2649}.Release|Win32.Build.0 = Release|Win32 + {00B50311-24EF-44CE-B29E-A1A308EB2649}.Debug|x64.ActiveCfg = Debug|x64 + {00B50311-24EF-44CE-B29E-A1A308EB2649}.Debug|x64.Build.0 = Debug|x64 + {00B50311-24EF-44CE-B29E-A1A308EB2649}.Release|x64.ActiveCfg = Release|x64 + {00B50311-24EF-44CE-B29E-A1A308EB2649}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/tools/sdv/samples/SDV-FailDriver-WDM/driver/fail_driver1.vcxproj b/tools/sdv/samples/SDV-FailDriver-WDM/driver/fail_driver1.vcxproj index d4c6a8f3..21695ceb 100644 --- a/tools/sdv/samples/SDV-FailDriver-WDM/driver/fail_driver1.vcxproj +++ b/tools/sdv/samples/SDV-FailDriver-WDM/driver/fail_driver1.vcxproj @@ -19,12 +19,12 @@ - {D993A00C-3449-4EA0-AB30-D76264170B45} + {00B50311-24EF-44CE-B29E-A1A308EB2649} $(MSBuildProjectName) false Debug Win32 - {C9FF3F49-C214-4F1F-90F7-D8E603E8BF77} + {4FA3F9BE-9E15-4FA0-8518-AF89D4CDD6A6} diff --git a/tools/sdv/samples/SDV-FailDriver-WDM/driver/fail_driver1.vcxproj.Filters b/tools/sdv/samples/SDV-FailDriver-WDM/driver/fail_driver1.vcxproj.Filters index e1ce9005..e8ec8ea6 100644 --- a/tools/sdv/samples/SDV-FailDriver-WDM/driver/fail_driver1.vcxproj.Filters +++ b/tools/sdv/samples/SDV-FailDriver-WDM/driver/fail_driver1.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {97E7B21F-9D51-46F7-B682-3E296B783754} + {1D87B41B-F73A-4066-8327-6374BF51EFF4} h;hpp;hxx;hm;inl;inc;xsd - {865633FF-0974-4663-BC09-3D6BC8AA2F64} + {D83503F2-ED45-43A1-AF56-C95A9F884C09} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {E11DA589-E084-48A1-8E55-765AB4F1F52E} + {6C268FC9-0E60-4E55-978E-3DF74D73636F} inf;inv;inx;mof;mc; - {02E5F1C3-81C0-4CE8-ADC9-E767C0718594} + {4FC4D076-182A-4141-BDCF-91295FD9D821} diff --git a/usb/kmdf_enumswitches/kmdf_enumswitches.sln b/usb/kmdf_enumswitches/kmdf_enumswitches.sln index 0b3f4a9a..241354f4 100644 --- a/usb/kmdf_enumswitches/kmdf_enumswitches.sln +++ b/usb/kmdf_enumswitches/kmdf_enumswitches.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "kmdf_enumswitches", "sys\kmdf_enumswitches.vcxproj", "{6A32E70D-E961-4940-A1E8-AB1A7CED390D}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "kmdf_enumswitches", "sys\kmdf_enumswitches.vcxproj", "{2EE39DF5-47CC-427F-8C78-B7C1D9C3EF45}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +13,14 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {6A32E70D-E961-4940-A1E8-AB1A7CED390D}.Debug|Win32.ActiveCfg = Debug|Win32 - {6A32E70D-E961-4940-A1E8-AB1A7CED390D}.Debug|Win32.Build.0 = Debug|Win32 - {6A32E70D-E961-4940-A1E8-AB1A7CED390D}.Release|Win32.ActiveCfg = Release|Win32 - {6A32E70D-E961-4940-A1E8-AB1A7CED390D}.Release|Win32.Build.0 = Release|Win32 - {6A32E70D-E961-4940-A1E8-AB1A7CED390D}.Debug|x64.ActiveCfg = Debug|x64 - {6A32E70D-E961-4940-A1E8-AB1A7CED390D}.Debug|x64.Build.0 = Debug|x64 - {6A32E70D-E961-4940-A1E8-AB1A7CED390D}.Release|x64.ActiveCfg = Release|x64 - {6A32E70D-E961-4940-A1E8-AB1A7CED390D}.Release|x64.Build.0 = Release|x64 + {2EE39DF5-47CC-427F-8C78-B7C1D9C3EF45}.Debug|Win32.ActiveCfg = Debug|Win32 + {2EE39DF5-47CC-427F-8C78-B7C1D9C3EF45}.Debug|Win32.Build.0 = Debug|Win32 + {2EE39DF5-47CC-427F-8C78-B7C1D9C3EF45}.Release|Win32.ActiveCfg = Release|Win32 + {2EE39DF5-47CC-427F-8C78-B7C1D9C3EF45}.Release|Win32.Build.0 = Release|Win32 + {2EE39DF5-47CC-427F-8C78-B7C1D9C3EF45}.Debug|x64.ActiveCfg = Debug|x64 + {2EE39DF5-47CC-427F-8C78-B7C1D9C3EF45}.Debug|x64.Build.0 = Debug|x64 + {2EE39DF5-47CC-427F-8C78-B7C1D9C3EF45}.Release|x64.ActiveCfg = Release|x64 + {2EE39DF5-47CC-427F-8C78-B7C1D9C3EF45}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/usb/kmdf_enumswitches/sys/kmdf_enumswitches.vcxproj b/usb/kmdf_enumswitches/sys/kmdf_enumswitches.vcxproj index a8bde5c4..6b2eac58 100644 --- a/usb/kmdf_enumswitches/sys/kmdf_enumswitches.vcxproj +++ b/usb/kmdf_enumswitches/sys/kmdf_enumswitches.vcxproj @@ -19,12 +19,12 @@ - {6A32E70D-E961-4940-A1E8-AB1A7CED390D} + {2EE39DF5-47CC-427F-8C78-B7C1D9C3EF45} $(MSBuildProjectName) 1 Debug Win32 - {5F18CAB2-2FE2-4E6B-BA36-C0EFF928BB0E} + {629058BB-4E85-43D3-B519-FCEA0871305D} diff --git a/usb/kmdf_enumswitches/sys/kmdf_enumswitches.vcxproj.Filters b/usb/kmdf_enumswitches/sys/kmdf_enumswitches.vcxproj.Filters index f230f871..afc896f0 100644 --- a/usb/kmdf_enumswitches/sys/kmdf_enumswitches.vcxproj.Filters +++ b/usb/kmdf_enumswitches/sys/kmdf_enumswitches.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {8CFB48AC-E2E0-495E-B587-5D803D866819} + {D1F8A3E1-FDAA-4BB1-9ED5-5C2237B070A1} h;hpp;hxx;hm;inl;inc;xsd - {D29CD043-B947-42D0-8741-B8510E442021} + {63723244-91AD-468B-B2D5-C9720A362381} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {5A199DB9-BFEF-42C9-A546-9AA11B9322FE} + {F64A4E05-C5D3-41CE-9B8E-4B303D852777} inf;inv;inx;mof;mc; - {634C8B4D-FD4D-4D9D-9A2A-9A4C2E388164} + {ACD4D5C7-344D-4734-BF67-DF249474349A} diff --git a/usb/umdf2_fx2/ReadMe.md b/usb/umdf2_fx2/ReadMe.md index 74e1885e..2f89407e 100644 --- a/usb/umdf2_fx2/ReadMe.md +++ b/usb/umdf2_fx2/ReadMe.md @@ -9,12 +9,12 @@ This sample builds a Windows Universal driver. It uses only APIs and DDIs that a The sample can also be used with the CustomDeviceAccess MSDK sample. The sample demonstrates how to perform bulk and interrupt data transfers to an USB device. The specification for the device is at . The driver and sample device metadata also work with the [Custom driver access](http://go.microsoft.com/fwlink/p/?LinkID=248288) sample. Starting in Windows 8.1, the osrusbfx2 sample has been divided into these samples: +* [WDF Sample Driver Learning Lab for OSR USB-FX2](http://msdn.microsoft.com/en-us/library/windows/hardware/): This sample is a series of iterative drivers that demonstrate how to write a "Hello World" driver and adds additional features in each step. +* [kmdf\_fx2](gallery_samples.123a_gallery#1): This sample is the final version of kernel-mode [wdf\_osrfx2](http://msdn.microsoft.com/en-us/library/windows/hardware/) driver. The sample demonstrates KMDF methods. +* umdf\_fx2: This sample is the final version of the user-mode driver [wdf\_osrfx2](http://msdn.microsoft.com/en-us/library/windows/hardware/). The sample demonstrates UMDF methods. -- [WDF Sample Driver Learning Lab for OSR USB-FX2](http://msdn.microsoft.com/en-us/library/windows/hardware/): This sample is a series of iterative drivers that demonstrate how to write a "Hello World" driver and adds additional features in each step. - -- [kmdf\_fx2](gallery_samples.123a_gallery#1): This sample is the final version of kernel-mode [wdf\_osrfx2](http://msdn.microsoft.com/en-us/library/windows/hardware/) driver. The sample demonstrates KMDF methods. - -- umdf\_fx2: This sample is the final version of the user-mode driver [wdf\_osrfx2](http://msdn.microsoft.com/en-us/library/windows/hardware/). The sample demonstrates UMDF methods. +**Note** +Due to a known bug in the current Windows Driver Kit tools, when building this sample in Debug mode, the exe project may report some ApiValidator warnings. These can be safely ignored. Overview -------- diff --git a/usb/umdf2_fx2/driver/osrusbfx2um.inx b/usb/umdf2_fx2/driver/osrusbfx2um.inx index bd01bb16..ff535c15 100644 --- a/usb/umdf2_fx2/driver/osrusbfx2um.inx +++ b/usb/umdf2_fx2/driver/osrusbfx2um.inx @@ -48,18 +48,12 @@ osrusbfx2um.dll=1 [OsrUsb_Install.NT] CopyFiles=UMDriverCopy -Include=WINUSB.INF ; Import sections from WINUSB.INF -Needs=WINUSB.NT ; Run the CopyFiles & AddReg directives for WinUsb.INF - -[OsrUsb_Install.NT.hw] -AddReg=OsrUsb_Device_AddReg [OsrUsb_Install.NT.Services] AddService=WUDFRd,0x000001fa,WUDFRD_ServiceInstall ; flag 0x2 sets this as the service for the device -AddService=WinUsb,0x000001f8,WinUsb_ServiceInstall ; this service is installed because its a filter. [OsrUsb_Install.NT.Wdf] -UmdfDispatcher=WinUsb +UmdfDispatcher=NativeUSB UmdfService=WUDFOsrUsbFx2, WUDFOsrUsbFx2_Install UmdfServiceOrder=WUDFOsrUsbFx2 @@ -67,10 +61,6 @@ UmdfServiceOrder=WUDFOsrUsbFx2 UmdfLibraryVersion=$UMDFVERSION$ ServiceBinary="%12%\UMDF\osrusbfx2um.dll" -[OsrUsb_Device_AddReg] -HKR,,"LowerFilters",0x00010008,"WinUsb" ; FLG_ADDREG_TYPE_MULTI_SZ | FLG_ADDREG_APPEND -HKR,,"WinUsbPowerPolicyOwnershipDisabled",0x00010001,1 ; our driver takes ownership of power policy. Tell WINUSB not to - [WUDFRD_ServiceInstall] DisplayName = %WudfRdDisplayName% ServiceType = 1 @@ -78,13 +68,6 @@ StartType = 3 ErrorControl = 1 ServiceBinary = %12%\WUDFRd.sys -[WinUsb_ServiceInstall] -DisplayName = %WinUsb_SvcDesc% -ServiceType = 1 -StartType = 3 -ErrorControl = 1 -ServiceBinary = %12%\WinUSB.sys - [DestinationDirs] UMDriverCopy=12,UMDF ; copy to driversMdf CoInstallers_CopyFiles=11 @@ -99,5 +82,4 @@ MSFTUMDF="Microsoft Internal (WDF:UMDF)" MediaDescription="Microsoft Sample Driver Installation Media" ClassName="Sample Device" WudfRdDisplayName="Windows Driver Foundation - User-mode Driver Framework Reflector" -OsrUsbDeviceName="UMDF 2.0 Sample Driver for OSR USB Fx2 Learning Kit" -WinUsb_SvcDesc="WinUSB Driver" +OsrUsbDeviceName="UMDF v2 Sample Driver for OSR USB Fx2 Learning Kit with NativeUSB" diff --git a/usb/umdf2_fx2/driver/osrusbfx2um.vcxproj b/usb/umdf2_fx2/driver/osrusbfx2um.vcxproj index 44f6d46f..baa0a411 100644 --- a/usb/umdf2_fx2/driver/osrusbfx2um.vcxproj +++ b/usb/umdf2_fx2/driver/osrusbfx2um.vcxproj @@ -19,12 +19,12 @@ - {33535CCD-5A39-4FDC-9C3A-796896CE065B} + {6A48DB7E-DC78-493F-9923-DCB9321C7667} $(MSBuildProjectName) 2 Debug Win32 - {0818D84E-7C44-4668-BCC4-CBE4610E615B} + {7FB8FEE0-972F-4454-9A05-425221DC87B6} diff --git a/usb/umdf2_fx2/driver/osrusbfx2um.vcxproj.Filters b/usb/umdf2_fx2/driver/osrusbfx2um.vcxproj.Filters index e9fac5a4..160a48d9 100644 --- a/usb/umdf2_fx2/driver/osrusbfx2um.vcxproj.Filters +++ b/usb/umdf2_fx2/driver/osrusbfx2um.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {52B04D2F-A9FC-4C03-9A04-DF29F0A760BD} + {21B700F3-2B7F-4332-A55B-C436016AC536} h;hpp;hxx;hm;inl;inc;xsd - {0A38487D-5A95-4D22-856A-29C215B94BA6} + {B93FCB80-AF61-4C1D-9534-6B6EB29B526A} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {455882CC-7C61-4EF5-BA09-0B6A70C234A9} + {4C88E4BA-E0F4-45C9-852B-F96E9C9E5883} inf;inv;inx;mof;mc; - {FFADC7F2-84FB-45BC-BA65-1447A12B4727} + {3893D068-C2BA-4785-B0AE-9EF13A8DE5BB} diff --git a/usb/umdf2_fx2/exe/osrusbfx2.vcxproj b/usb/umdf2_fx2/exe/osrusbfx2.vcxproj index 3ac60333..0a26c683 100644 --- a/usb/umdf2_fx2/exe/osrusbfx2.vcxproj +++ b/usb/umdf2_fx2/exe/osrusbfx2.vcxproj @@ -19,17 +19,17 @@ - {020DB89E-97F7-43B1-BC5B-BD2A09EB070D} + {FAF22768-F07B-437A-BB6B-4CA77B19D705} $(MSBuildProjectName) Debug Win32 - {A62B86BA-B2B1-4059-959F-064A5F9D7C70} + {BD1E8570-B544-4A6C-BF30-70EBD4456E54} Windows10 False - Desktop + Universal WindowsApplicationForDrivers10.0 Application @@ -37,7 +37,7 @@ Windows10 True - Desktop + Universal WindowsApplicationForDrivers10.0 Application @@ -45,7 +45,7 @@ Windows10 False - Desktop + Universal WindowsApplicationForDrivers10.0 Application @@ -53,7 +53,7 @@ Windows10 True - Desktop + Universal WindowsApplicationForDrivers10.0 Application @@ -92,17 +92,20 @@ true Level4 %(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc;..\sys\inc + %(PreprocessorDefinitions);UNICODE;_UNICODE %(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc;..\sys\inc + %(PreprocessorDefinitions);UNICODE;_UNICODE %(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc;..\sys\inc + %(PreprocessorDefinitions);UNICODE;_UNICODE - %(AdditionalDependencies);setupapi.lib + %(AdditionalDependencies);mincore.lib @@ -110,17 +113,20 @@ true Level4 %(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc;..\sys\inc + %(PreprocessorDefinitions);UNICODE;_UNICODE %(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc;..\sys\inc + %(PreprocessorDefinitions);UNICODE;_UNICODE %(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc;..\sys\inc + %(PreprocessorDefinitions);UNICODE;_UNICODE - %(AdditionalDependencies);setupapi.lib + %(AdditionalDependencies);mincore.lib @@ -128,17 +134,20 @@ true Level4 %(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc;..\sys\inc + %(PreprocessorDefinitions);UNICODE;_UNICODE %(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc;..\sys\inc + %(PreprocessorDefinitions);UNICODE;_UNICODE %(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc;..\sys\inc + %(PreprocessorDefinitions);UNICODE;_UNICODE - %(AdditionalDependencies);setupapi.lib + %(AdditionalDependencies);mincore.lib @@ -146,17 +155,20 @@ true Level4 %(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc;..\sys\inc + %(PreprocessorDefinitions);UNICODE;_UNICODE %(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc;..\sys\inc + %(PreprocessorDefinitions);UNICODE;_UNICODE %(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc;..\sys\inc + %(PreprocessorDefinitions);UNICODE;_UNICODE - %(AdditionalDependencies);setupapi.lib + %(AdditionalDependencies);mincore.lib diff --git a/usb/umdf2_fx2/exe/osrusbfx2.vcxproj.Filters b/usb/umdf2_fx2/exe/osrusbfx2.vcxproj.Filters index 39d6f2be..f9eac4c7 100644 --- a/usb/umdf2_fx2/exe/osrusbfx2.vcxproj.Filters +++ b/usb/umdf2_fx2/exe/osrusbfx2.vcxproj.Filters @@ -3,15 +3,15 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {104452B2-CFF6-4BAD-8E54-179D97D98EF8} + {E08AB654-AE1F-42CF-AD59-772321BAD1ED} h;hpp;hxx;hm;inl;inc;xsd - {F8C6B699-E4D1-450D-A1F1-4D3A0670600A} + {60796E01-8594-4A2D-9395-F4D0D6B07875} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {64683058-E0C9-49C7-996C-E104FFA4D81B} + {D37B1ED9-9240-47CA-BF91-6FD1F6C8572F} diff --git a/usb/umdf2_fx2/exe/testapp.c b/usb/umdf2_fx2/exe/testapp.c index ab6f483f..a7d82915 100644 --- a/usb/umdf2_fx2/exe/testapp.c +++ b/usb/umdf2_fx2/exe/testapp.c @@ -37,7 +37,7 @@ _Analysis_mode_(_Analysis_code_type_user_code_) #pragma warning(disable:4201) // nameless struct/union #pragma warning(disable:4214) // bit field types other than int -#include +#include #include #include "usbdi.h" #include "public.h" @@ -86,127 +86,75 @@ typedef enum _INPUT_FUNCTION { _Success_(return) BOOL GetDevicePath( - IN LPGUID InterfaceGuid, - _Out_writes_z_(BufLen) PCHAR DevicePath, + _In_ LPGUID InterfaceGuid, + _Out_writes_z_(BufLen) PWCHAR 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; + CONFIGRET cr = CR_SUCCESS; + PWSTR deviceInterfaceList = NULL; + ULONG deviceInterfaceListLength = 0; + PWSTR nextInterface; + HRESULT hr = E_FAIL; + BOOL bRet = TRUE; + + cr = CM_Get_Device_Interface_List_Size( + &deviceInterfaceListLength, + InterfaceGuid, + NULL, + CM_GET_DEVICE_INTERFACE_LIST_PRESENT); + if (cr != CR_SUCCESS) { + printf("Error 0x%x retrieving device interface list size.\n", cr); + goto clean0; } - 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), - (LPSTR) &lpMsgBuf, - 0, - NULL - )) { - - printf("SetupDiEnumDeviceInterfaces failed: %s", (LPSTR)lpMsgBuf); - LocalFree(lpMsgBuf); - } + if (deviceInterfaceListLength <= 1) { + bRet = FALSE; + printf("Error: No active device interfaces found.\n" + " Is the sample driver loaded?"); + goto clean0; + } - SetupDiDestroyDeviceInfoList(HardwareDeviceInfo); - return FALSE; + deviceInterfaceList = (PWSTR)malloc(deviceInterfaceListLength * sizeof(WCHAR)); + if (deviceInterfaceList == NULL) { + printf("Error allocating memory for device interface list.\n"); + goto clean0; } + ZeroMemory(deviceInterfaceList, deviceInterfaceListLength * sizeof(WCHAR)); - SetupDiGetDeviceInterfaceDetail( - HardwareDeviceInfo, - &DeviceInterfaceData, + cr = CM_Get_Device_Interface_List( + InterfaceGuid, 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; + deviceInterfaceList, + deviceInterfaceListLength, + CM_GET_DEVICE_INTERFACE_LIST_PRESENT); + if (cr != CR_SUCCESS) { + printf("Error 0x%x retrieving device interface list.\n", cr); + goto clean0; } - DeviceInterfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); - - Length = RequiredLength; - - bResult = SetupDiGetDeviceInterfaceDetail( - HardwareDeviceInfo, - &DeviceInterfaceData, - DeviceInterfaceDetailData, - Length, - &RequiredLength, - NULL); - - 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), - (LPSTR) &lpMsgBuf, - 0, - NULL)) { - - printf("Error in SetupDiGetDeviceInterfaceDetail: %s\n", (LPSTR)lpMsgBuf); - LocalFree(lpMsgBuf); - } - - SetupDiDestroyDeviceInfoList(HardwareDeviceInfo); - LocalFree(DeviceInterfaceDetailData); - return FALSE; + nextInterface = deviceInterfaceList + wcslen(deviceInterfaceList) + 1; + if (*nextInterface != UNICODE_NULL) { + printf("Warning: More than one device interface instance found. \n" + "Selecting first matching device.\n\n"); } - hr = StringCchCopy(DevicePath, - BufLen, - DeviceInterfaceDetailData->DevicePath); + hr = StringCchCopy(DevicePath, BufLen, deviceInterfaceList); if (FAILED(hr)) { - SetupDiDestroyDeviceInfoList(HardwareDeviceInfo); - LocalFree(DeviceInterfaceDetailData); - return FALSE; + bRet = FALSE; + printf("Error: StringCchCopy failed with HRESULT 0x%x", hr); + goto clean0; } - SetupDiDestroyDeviceInfoList(HardwareDeviceInfo); - LocalFree(DeviceInterfaceDetailData); - - return TRUE; +clean0: + if (deviceInterfaceList != NULL) { + free(deviceInterfaceList); + } + if (CR_SUCCESS != cr) { + bRet = FALSE; + } + return bRet; } @@ -233,14 +181,14 @@ Return Value: { HANDLE hDev; - char completeDeviceName[MAX_DEVPATH_LENGTH]; + WCHAR completeDeviceName[MAX_DEVPATH_LENGTH]; if ( !GetDevicePath( (LPGUID) &GUID_DEVINTERFACE_OSRUSBFX2, completeDeviceName, - sizeof(completeDeviceName)) ) + sizeof(completeDeviceName)/sizeof(completeDeviceName[0])) ) { - return INVALID_HANDLE_VALUE; + return INVALID_HANDLE_VALUE; } printf("DeviceName = (%s)\n", completeDeviceName); diff --git a/usb/umdf2_fx2/umdf2_fx2.sln b/usb/umdf2_fx2/umdf2_fx2.sln index 8f165bef..780c0e7f 100644 --- a/usb/umdf2_fx2/umdf2_fx2.sln +++ b/usb/umdf2_fx2/umdf2_fx2.sln @@ -3,13 +3,13 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Driver", "Driver", "{A3ECF9EF-7A4E-4E3A-8B6C-F28831959DF5}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Driver", "Driver", "{CAFE3118-273C-43B1-9895-909D2132640C}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Exe", "Exe", "{1316F001-B1D6-4F04-9298-A553516BACF9}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Exe", "Exe", "{E1EEF412-A834-4B7C-B3CB-D22FA4FF52CC}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "osrusbfx2um", "driver\osrusbfx2um.vcxproj", "{33535CCD-5A39-4FDC-9C3A-796896CE065B}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "osrusbfx2um", "driver\osrusbfx2um.vcxproj", "{6A48DB7E-DC78-493F-9923-DCB9321C7667}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "osrusbfx2", "exe\osrusbfx2.vcxproj", "{020DB89E-97F7-43B1-BC5B-BD2A09EB070D}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "osrusbfx2", "exe\osrusbfx2.vcxproj", "{FAF22768-F07B-437A-BB6B-4CA77B19D705}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -19,28 +19,28 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {33535CCD-5A39-4FDC-9C3A-796896CE065B}.Debug|Win32.ActiveCfg = Debug|Win32 - {33535CCD-5A39-4FDC-9C3A-796896CE065B}.Debug|Win32.Build.0 = Debug|Win32 - {33535CCD-5A39-4FDC-9C3A-796896CE065B}.Release|Win32.ActiveCfg = Release|Win32 - {33535CCD-5A39-4FDC-9C3A-796896CE065B}.Release|Win32.Build.0 = Release|Win32 - {33535CCD-5A39-4FDC-9C3A-796896CE065B}.Debug|x64.ActiveCfg = Debug|x64 - {33535CCD-5A39-4FDC-9C3A-796896CE065B}.Debug|x64.Build.0 = Debug|x64 - {33535CCD-5A39-4FDC-9C3A-796896CE065B}.Release|x64.ActiveCfg = Release|x64 - {33535CCD-5A39-4FDC-9C3A-796896CE065B}.Release|x64.Build.0 = Release|x64 - {020DB89E-97F7-43B1-BC5B-BD2A09EB070D}.Debug|Win32.ActiveCfg = Debug|Win32 - {020DB89E-97F7-43B1-BC5B-BD2A09EB070D}.Debug|Win32.Build.0 = Debug|Win32 - {020DB89E-97F7-43B1-BC5B-BD2A09EB070D}.Release|Win32.ActiveCfg = Release|Win32 - {020DB89E-97F7-43B1-BC5B-BD2A09EB070D}.Release|Win32.Build.0 = Release|Win32 - {020DB89E-97F7-43B1-BC5B-BD2A09EB070D}.Debug|x64.ActiveCfg = Debug|x64 - {020DB89E-97F7-43B1-BC5B-BD2A09EB070D}.Debug|x64.Build.0 = Debug|x64 - {020DB89E-97F7-43B1-BC5B-BD2A09EB070D}.Release|x64.ActiveCfg = Release|x64 - {020DB89E-97F7-43B1-BC5B-BD2A09EB070D}.Release|x64.Build.0 = Release|x64 + {6A48DB7E-DC78-493F-9923-DCB9321C7667}.Debug|Win32.ActiveCfg = Debug|Win32 + {6A48DB7E-DC78-493F-9923-DCB9321C7667}.Debug|Win32.Build.0 = Debug|Win32 + {6A48DB7E-DC78-493F-9923-DCB9321C7667}.Release|Win32.ActiveCfg = Release|Win32 + {6A48DB7E-DC78-493F-9923-DCB9321C7667}.Release|Win32.Build.0 = Release|Win32 + {6A48DB7E-DC78-493F-9923-DCB9321C7667}.Debug|x64.ActiveCfg = Debug|x64 + {6A48DB7E-DC78-493F-9923-DCB9321C7667}.Debug|x64.Build.0 = Debug|x64 + {6A48DB7E-DC78-493F-9923-DCB9321C7667}.Release|x64.ActiveCfg = Release|x64 + {6A48DB7E-DC78-493F-9923-DCB9321C7667}.Release|x64.Build.0 = Release|x64 + {FAF22768-F07B-437A-BB6B-4CA77B19D705}.Debug|Win32.ActiveCfg = Debug|Win32 + {FAF22768-F07B-437A-BB6B-4CA77B19D705}.Debug|Win32.Build.0 = Debug|Win32 + {FAF22768-F07B-437A-BB6B-4CA77B19D705}.Release|Win32.ActiveCfg = Release|Win32 + {FAF22768-F07B-437A-BB6B-4CA77B19D705}.Release|Win32.Build.0 = Release|Win32 + {FAF22768-F07B-437A-BB6B-4CA77B19D705}.Debug|x64.ActiveCfg = Debug|x64 + {FAF22768-F07B-437A-BB6B-4CA77B19D705}.Debug|x64.Build.0 = Debug|x64 + {FAF22768-F07B-437A-BB6B-4CA77B19D705}.Release|x64.ActiveCfg = Release|x64 + {FAF22768-F07B-437A-BB6B-4CA77B19D705}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {33535CCD-5A39-4FDC-9C3A-796896CE065B} = {A3ECF9EF-7A4E-4E3A-8B6C-F28831959DF5} - {020DB89E-97F7-43B1-BC5B-BD2A09EB070D} = {1316F001-B1D6-4F04-9298-A553516BACF9} + {6A48DB7E-DC78-493F-9923-DCB9321C7667} = {CAFE3118-273C-43B1-9895-909D2132640C} + {FAF22768-F07B-437A-BB6B-4CA77B19D705} = {E1EEF412-A834-4B7C-B3CB-D22FA4FF52CC} EndGlobalSection EndGlobal diff --git a/usb/umdf_filter_kmdf/Package/package.VcxProj b/usb/umdf_filter_kmdf/Package/package.VcxProj deleted file mode 100644 index cbcac967..00000000 --- a/usb/umdf_filter_kmdf/Package/package.VcxProj +++ /dev/null @@ -1,91 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - WindowsKernelModeDriver10.0 - Utility - Package - true - Debug - - - - {3EF9240F-7E95-49A7-8B0D-5F7061655764} - {0CA520A9-E977-438B-8DC7-505D2B17D810} - $(MSBuildProjectName) - - - Windows10 - true - - - Windows10 - false - - - Windows10 - true - - - Windows10 - false - - - - - - - - - - - DbgengKernelDebugger - False - None - - - - - - %PathToInf% - False - False - True - - 133563 - - - - - - - - - - {23EAF474-B558-4457-B03C-164DA83B7575} - - - {0149B701-5356-434C-AC8C-07CAA1D9A4AA} - - - - - - \ No newline at end of file diff --git a/usb/umdf_filter_kmdf/Package/package.VcxProj.Filters b/usb/umdf_filter_kmdf/Package/package.VcxProj.Filters deleted file mode 100644 index cee9d105..00000000 --- a/usb/umdf_filter_kmdf/Package/package.VcxProj.Filters +++ /dev/null @@ -1,21 +0,0 @@ - - - - - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {11E4648F-825F-4166-A710-1F8405EB585C} - - - h;hpp;hxx;hm;inl;inc;xsd - {702820FE-A863-4886-A39F-1EF5E2CAEB24} - - - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {040C9EA5-697C-432B-B344-774708E72655} - - - inf;inv;inx;mof;mc; - {18B9CB91-2A87-4A72-ABFF-A1FB4EACD0AC} - - - \ No newline at end of file diff --git a/usb/umdf_filter_kmdf/ReadMe.md b/usb/umdf_filter_kmdf/ReadMe.md deleted file mode 100644 index cc12d391..00000000 --- a/usb/umdf_filter_kmdf/ReadMe.md +++ /dev/null @@ -1,38 +0,0 @@ -Sample UMDF Filter above KMDF Function Driver for OSR USB-FX2 (UMDF Version 1) -============================================================================== - -The umdf\_filter\_kmdf sample demonstrates how to load a UMDF filter driver as an upper filter driver above the kmdf\_fx2 sample driver. - -The sample includes Event Tracing for Windows (ETW) tracing support, and is written for the OSR USB-FX2 Learning Kit. The specification for the device is at . - -Overview --------- - -Here is the overview of the device: - -- The device is based on the development board supplied with the Cypress EZ-USB FX2 Development Kit (CY3681). -- It contains 1 interface and 3 endpoints (Interrupt IN, Bulk Out, Bulk IN). -- Firmware supports vendor commands to query or set LED Bar graph display and 7-segment LED display, and to query toggle switch states. -- Interrupt Endpoint: - - Sends an 8-bit value that represents the state of the switches. - - Sent on startup, resume from suspend, and whenever the switch pack setting changes. - - Firmware does not de-bounce the switch pack. - - One switch change can result in multiple bytes being sent. - - Bits are in the reverse order of the labels on the pack (for example, bit 0x80 is labeled 1 on the pack). -- Bulk Endpoints are configured for loopback: - - The device moves data from IN endpoint to OUT endpoint. - - The device does not change the values of the data it receives nor does it internally create any data. - - Endpoints are always double buffered. - - Maximum packet size depends on speed (64 full speed, 512 high speed). -- ETW events: - - Included osrusbfx2.man, which describes events added. - - Three events are targeted to the event log: - - Failure during the add device routine. - - Failure to start the OSR device on a USB 1.1 controller. - - Invocation of the “re-enumerate device†IOCTL. - - Read/write start/stop events can be used to measure the time taken. - -Testing the driver ------------------- - -You can test this sample either by using the [Custom driver access](http://go.microsoft.com/fwlink/p/?LinkID=248288) sample application, or by using the osrusbfx2.exe test application. For information on how to build and use the osrusbfx2.exe application, see the test instructions for the [kmdf\_fx2](http://msdn.microsoft.com/en-us/library/windows/hardware/) sample. diff --git a/usb/umdf_filter_kmdf/inc/WUDFOsrUsbPublic.h b/usb/umdf_filter_kmdf/inc/WUDFOsrUsbPublic.h deleted file mode 100644 index 6681fa14..00000000 --- a/usb/umdf_filter_kmdf/inc/WUDFOsrUsbPublic.h +++ /dev/null @@ -1,32 +0,0 @@ -/*++ - -Copyright (c) Microsoft Corporation, All Rights Reserved - -Module Name: - - WUDFOsrUsbPublic.h - -Abstract: - - This module contains the common declarations shared by driver - and user applications for the UMDF OSR device sample. - - Note that this driver does NOT use the same device interface GUID - as the KMDF OSR USB sample. - -Environment: - - user and kernel - ---*/ - -#pragma once - -// -// Define an Interface Guid so that app can find the device and talk to it. -// - -// {573E8C73-0CB4-4471-A1BF-FAB26C31D384} -DEFINE_GUID(GUID_DEVINTERFACE_OSRUSBFX2, - 0x573e8c73, 0xcb4, 0x4471, 0xa1, 0xbf, 0xfa, 0xb2, 0x6c, 0x31, 0xd3, 0x84); - diff --git a/usb/umdf_filter_kmdf/inc/list.h b/usb/umdf_filter_kmdf/inc/list.h deleted file mode 100644 index 38d0b1e9..00000000 --- a/usb/umdf_filter_kmdf/inc/list.h +++ /dev/null @@ -1,77 +0,0 @@ -/*++ - -Copyright (C) Microsoft Corporation, All Rights Reserved - -Module Name: - - list.h - -Abstract: - - This module contains doubly linked list macros - -Environment: - - Windows User-Mode Driver Framework (WUDF) - ---*/ - -#pragma once - - -FORCEINLINE -VOID -InitializeListHead( - IN PLIST_ENTRY ListHead - ) -{ - ListHead->Flink = ListHead->Blink = ListHead; -} - -FORCEINLINE -BOOLEAN -RemoveEntryList( - IN PLIST_ENTRY Entry - ) -{ - PLIST_ENTRY Blink; - PLIST_ENTRY Flink; - - Flink = Entry->Flink; - Blink = Entry->Blink; - Blink->Flink = Flink; - Flink->Blink = Blink; - return (BOOLEAN)(Flink == Blink); -} - -FORCEINLINE -VOID -InsertHeadList( - IN PLIST_ENTRY ListHead, - IN PLIST_ENTRY Entry - ) -{ - PLIST_ENTRY Flink; - - Flink = ListHead->Flink; - Entry->Flink = Flink; - Entry->Blink = ListHead; - Flink->Blink = Entry; - ListHead->Flink = Entry; -} - -FORCEINLINE -VOID -InsertTailList( - IN PLIST_ENTRY ListHead, - IN PLIST_ENTRY Entry - ) -{ - PLIST_ENTRY Blink; - - Blink = ListHead->Blink; - Entry->Flink = ListHead; - Entry->Blink = Blink; - Blink->Flink = Entry; - ListHead->Blink = Entry; -} diff --git a/usb/umdf_filter_kmdf/inc/public.h b/usb/umdf_filter_kmdf/inc/public.h deleted file mode 100644 index 22f6cb6d..00000000 --- a/usb/umdf_filter_kmdf/inc/public.h +++ /dev/null @@ -1,217 +0,0 @@ -/*++ - -Copyright (c) Microsoft Corporation. All rights reserved. - -Module Name: - - public.h - -Abstract: - - Public definitions for the OSR_FX2 device operations. - -Environment: - - User & Kernel mode - ---*/ - -#ifndef _PUBLIC_H -#define _PUBLIC_H - -#include - -#include "WudfOsrUsbPublic.h" - - -// -// Define the structures that will be used by the IOCTL -// interface to the driver -// - -// -// BAR_GRAPH_STATE -// -// BAR_GRAPH_STATE is a bit field structure with each -// bit corresponding to one of the bar graph on the -// OSRFX2 Development Board -// -#include - -#pragma warning( push ) -#pragma warning( disable : 4201 ) // nameless struct/union -#pragma warning( disable : 4214 ) // bit-field type other than int - -typedef struct _BAR_GRAPH_STATE { - - union { - - struct { - // - // Individual bars starting from the - // top of the stack of bars - // - // NOTE: There are actually 10 bars, - // but the very top two do not light - // and are not counted here - // - UCHAR Bar1 : 1; - UCHAR Bar2 : 1; - UCHAR Bar3 : 1; - UCHAR Bar4 : 1; - UCHAR Bar5 : 1; - UCHAR Bar6 : 1; - UCHAR Bar7 : 1; - UCHAR Bar8 : 1; - }; - - // - // The state of all the bar graph as a single - // UCHAR - // - UCHAR BarsAsUChar; - - }; - -}BAR_GRAPH_STATE, *PBAR_GRAPH_STATE; - -// -// SWITCH_STATE -// -// SWITCH_STATE is a bit field structure with each -// bit corresponding to one of the switches on the -// OSRFX2 Development Board -// -typedef struct _SWITCH_STATE { - - union { - struct { - // - // Individual switches starting from the - // left of the set of switches - // - UCHAR Switch1 : 1; - UCHAR Switch2 : 1; - UCHAR Switch3 : 1; - UCHAR Switch4 : 1; - UCHAR Switch5 : 1; - UCHAR Switch6 : 1; - UCHAR Switch7 : 1; - UCHAR Switch8 : 1; - }; - - // - // The state of all the switches as a single - // UCHAR - // - UCHAR SwitchesAsUChar; - - }; - - -}SWITCH_STATE, *PSWITCH_STATE; - -// -// Seven segment display bit values. -// - -// -// Undefine conflicting MFC constant -// -#undef SS_CENTER -#undef SS_LEFT -#undef SS_RIGHT - -#define SS_TOP 0x01 -#define SS_TOP_LEFT 0x40 -#define SS_TOP_RIGHT 0x02 -#define SS_CENTER 0x20 -#define SS_BOTTOM_LEFT 0x10 -#define SS_BOTTOM_RIGHT 0x04 -#define SS_BOTTOM 0x80 -#define SS_DOT 0x08 - -// -// FILE_PLAYBACK -// -// FILE_PLAYBACK structure contains the parameters for the PLAY_FILE I/O Control. -// - -typedef struct _FILE_PLAYBACK -{ - // - // The delay between changes in the display, in milliseconds. - // - - USHORT Delay; - - // - // The data file path. - // - - WCHAR Path[1]; -} FILE_PLAYBACK, *PFILE_PLAYBACK; - -#include - -#define IOCTL_INDEX 0x800 -#define FILE_DEVICE_OSRUSBFX2 0x65500 - -#define IOCTL_OSRUSBFX2_GET_CONFIG_DESCRIPTOR CTL_CODE(FILE_DEVICE_OSRUSBFX2, \ - IOCTL_INDEX, \ - METHOD_BUFFERED, \ - FILE_READ_ACCESS) - -#define IOCTL_OSRUSBFX2_RESET_DEVICE CTL_CODE(FILE_DEVICE_OSRUSBFX2, \ - IOCTL_INDEX + 1, \ - METHOD_BUFFERED, \ - FILE_WRITE_ACCESS) - -#define IOCTL_OSRUSBFX2_REENUMERATE_DEVICE CTL_CODE(FILE_DEVICE_OSRUSBFX2, \ - IOCTL_INDEX + 3, \ - METHOD_BUFFERED, \ - FILE_WRITE_ACCESS) - -#define IOCTL_OSRUSBFX2_GET_BAR_GRAPH_DISPLAY CTL_CODE(FILE_DEVICE_OSRUSBFX2,\ - IOCTL_INDEX + 4, \ - METHOD_BUFFERED, \ - FILE_READ_ACCESS) - - -#define IOCTL_OSRUSBFX2_SET_BAR_GRAPH_DISPLAY CTL_CODE(FILE_DEVICE_OSRUSBFX2,\ - IOCTL_INDEX + 5, \ - METHOD_BUFFERED, \ - FILE_WRITE_ACCESS) - - -#define IOCTL_OSRUSBFX2_READ_SWITCHES CTL_CODE(FILE_DEVICE_OSRUSBFX2, \ - IOCTL_INDEX + 6, \ - METHOD_BUFFERED, \ - FILE_READ_ACCESS) - - -#define IOCTL_OSRUSBFX2_GET_7_SEGMENT_DISPLAY CTL_CODE(FILE_DEVICE_OSRUSBFX2, \ - IOCTL_INDEX + 7, \ - METHOD_BUFFERED, \ - FILE_READ_ACCESS) - - -#define IOCTL_OSRUSBFX2_SET_7_SEGMENT_DISPLAY CTL_CODE(FILE_DEVICE_OSRUSBFX2, \ - IOCTL_INDEX + 8, \ - METHOD_BUFFERED, \ - FILE_WRITE_ACCESS) - -#define IOCTL_OSRUSBFX2_GET_INTERRUPT_MESSAGE CTL_CODE(FILE_DEVICE_OSRUSBFX2,\ - IOCTL_INDEX + 9, \ - METHOD_OUT_DIRECT, \ - FILE_READ_ACCESS) - -#define IOCTL_OSRUSBFX2_PLAY_FILE CTL_CODE(FILE_DEVICE_OSRUSBFX2, \ - IOCTL_INDEX + 10, \ - METHOD_BUFFERED, \ - FILE_WRITE_ACCESS) - -#pragma warning(pop) - -#endif - diff --git a/usb/umdf_filter_kmdf/inc/usb_hw.h b/usb/umdf_filter_kmdf/inc/usb_hw.h deleted file mode 100644 index d6e983f1..00000000 --- a/usb/umdf_filter_kmdf/inc/usb_hw.h +++ /dev/null @@ -1,233 +0,0 @@ -/*++ - -Copyright (c) Microsoft Corporation. All rights reserved. - -Module Name: - - Usb.h - -Abstract: - - Contains prototypes for interfacing with a USB connected device. These - are copied from the KMDF WDFUSB.H header file (but with the WDF specific - portions removed) - -Environment: - - kernel mode only - ---*/ - -#pragma once - -typedef enum _WINUSB_BMREQUEST_DIRECTION { - BmRequestHostToDevice = BMREQUEST_HOST_TO_DEVICE, - BmRequestDeviceToHost = BMREQUEST_DEVICE_TO_HOST, -} WINUSB_BMREQUEST_DIRECTION; - -typedef enum _WINUSB_BMREQUEST_TYPE { - BmRequestStandard = BMREQUEST_STANDARD, - BmRequestClass = BMREQUEST_CLASS, - BmRequestVendor = BMREQUEST_VENDOR, -} WINUSB_BMREQUEST_TYPE; - -typedef enum _WINUSB_BMREQUEST_RECIPIENT { - BmRequestToDevice = BMREQUEST_TO_DEVICE, - BmRequestToInterface = BMREQUEST_TO_INTERFACE, - BmRequestToEndpoint = BMREQUEST_TO_ENDPOINT, - BmRequestToOther = BMREQUEST_TO_OTHER, -} WINUSB_BMREQUEST_RECIPIENT; - -typedef enum _WINUSB_DEVICE_TRAITS { - WINUSB_DEVICE_TRAIT_SELF_POWERED = 0x00000001, - WINUSB_DEVICE_TRAIT_REMOTE_WAKE_CAPABLE = 0x00000002, - WINUSB_DEVICE_TRAIT_AT_HIGH_SPEED = 0x00000004, -} WINUSB_DEVICE_TRAITS; - -typedef enum _WdfUsbTargetDeviceSelectInterfaceType { - WdfUsbTargetDeviceSelectInterfaceTypeInterface = 0x10, - WdfUsbTargetDeviceSelectInterfaceTypeUrb = 0x11, -} WdfUsbTargetDeviceSelectInterfaceType; - - - -typedef union _WINUSB_CONTROL_SETUP_PACKET { - struct { - union { - #pragma warning(disable:4214) // bit field types other than int - struct { - // - // Valid values are BMREQUEST_TO_DEVICE, BMREQUEST_TO_INTERFACE, - // BMREQUEST_TO_ENDPOINT, BMREQUEST_TO_OTHER - // - BYTE Recipient:2; - - BYTE Reserved:3; - - // - // Valid values are BMREQUEST_STANDARD, BMREQUEST_CLASS, - // BMREQUEST_VENDOR - // - BYTE Type:2; - - // - // Valid values are BMREQUEST_HOST_TO_DEVICE, - // BMREQUEST_DEVICE_TO_HOST - // - BYTE Dir:1; - } Request; - #pragma warning(default:4214) // bit field types other than int - BYTE Byte; - } bm; - - BYTE bRequest; - - union { - struct { - BYTE LowByte; - BYTE HiByte; - } Bytes; - USHORT Value; - } wValue; - - union { - struct { - BYTE LowByte; - BYTE HiByte; - } Bytes; - USHORT Value; - } wIndex; - - USHORT wLength; - } Packet; - - struct { - BYTE Bytes[8]; - } Generic; - - WINUSB_SETUP_PACKET WinUsb; - -} WINUSB_CONTROL_SETUP_PACKET, *PWINUSB_CONTROL_SETUP_PACKET; - -VOID -FORCEINLINE -WINUSB_CONTROL_SETUP_PACKET_INIT( - PWINUSB_CONTROL_SETUP_PACKET Packet, - WINUSB_BMREQUEST_DIRECTION Direction, - WINUSB_BMREQUEST_RECIPIENT Recipient, - BYTE Request, - USHORT Value, - USHORT Index - ) -{ - RtlZeroMemory(Packet, sizeof(WINUSB_CONTROL_SETUP_PACKET)); - - Packet->Packet.bm.Request.Dir = (BYTE) Direction; - Packet->Packet.bm.Request.Type = (BYTE) BmRequestStandard; - Packet->Packet.bm.Request.Recipient = (BYTE) Recipient; - - Packet->Packet.bRequest = Request; - Packet->Packet.wValue.Value = Value; - Packet->Packet.wIndex.Value = Index; - - // Packet->Packet.wLength will be set by the formatting function -} - -VOID -FORCEINLINE -WINUSB_CONTROL_SETUP_PACKET_INIT_CLASS( - PWINUSB_CONTROL_SETUP_PACKET Packet, - WINUSB_BMREQUEST_DIRECTION Direction, - WINUSB_BMREQUEST_RECIPIENT Recipient, - BYTE Request, - USHORT Value, - USHORT Index - ) -{ - RtlZeroMemory(Packet, sizeof(WINUSB_CONTROL_SETUP_PACKET)); - - Packet->Packet.bm.Request.Dir = (BYTE) Direction; - Packet->Packet.bm.Request.Type = (BYTE) BmRequestClass; - Packet->Packet.bm.Request.Recipient = (BYTE) Recipient; - - Packet->Packet.bRequest = Request; - Packet->Packet.wValue.Value = Value; - Packet->Packet.wIndex.Value = Index; - - // Packet->Packet.wLength will be set by the formatting function -} - -VOID -FORCEINLINE -WINUSB_CONTROL_SETUP_PACKET_INIT_VENDOR( - PWINUSB_CONTROL_SETUP_PACKET Packet, - WINUSB_BMREQUEST_DIRECTION Direction, - WINUSB_BMREQUEST_RECIPIENT Recipient, - BYTE Request, - USHORT Value, - USHORT Index - ) -{ - RtlZeroMemory(Packet, sizeof(WINUSB_CONTROL_SETUP_PACKET)); - - Packet->Packet.bm.Request.Dir = (BYTE) Direction; - Packet->Packet.bm.Request.Type = (BYTE) BmRequestVendor; - Packet->Packet.bm.Request.Recipient = (BYTE) Recipient; - - Packet->Packet.bRequest = Request; - Packet->Packet.wValue.Value = Value; - Packet->Packet.wIndex.Value = Index; - - // Packet->Packet.wLength will be set by the formatting function -} - -VOID -FORCEINLINE -WINUSB_CONTROL_SETUP_PACKET_INIT_FEATURE( - PWINUSB_CONTROL_SETUP_PACKET Packet, - WINUSB_BMREQUEST_RECIPIENT BmRequestRecipient, - USHORT FeatureSelector, - USHORT Index, - BOOLEAN SetFeature - ) -{ - RtlZeroMemory(Packet, sizeof(WINUSB_CONTROL_SETUP_PACKET)); - - Packet->Packet.bm.Request.Dir = (BYTE) BmRequestHostToDevice; - Packet->Packet.bm.Request.Type = (BYTE) BmRequestStandard; - Packet->Packet.bm.Request.Recipient = (BYTE) BmRequestRecipient; - - if (SetFeature) { - Packet->Packet.bRequest = USB_REQUEST_SET_FEATURE; - } - else { - Packet->Packet.bRequest = USB_REQUEST_CLEAR_FEATURE; - } - - Packet->Packet.wValue.Value = FeatureSelector; - Packet->Packet.wIndex.Value = Index; - - // Packet->Packet.wLength will be set by the formatting function -} - -VOID -FORCEINLINE -WINUSB_CONTROL_SETUP_PACKET_INIT_GET_STATUS( - PWINUSB_CONTROL_SETUP_PACKET Packet, - WINUSB_BMREQUEST_RECIPIENT BmRequestRecipient, - USHORT Index - ) -{ - RtlZeroMemory(Packet, sizeof(WINUSB_CONTROL_SETUP_PACKET)); - - Packet->Packet.bm.Request.Dir = (BYTE) BmRequestDeviceToHost; - Packet->Packet.bm.Request.Type = (BYTE) BmRequestStandard; - Packet->Packet.bm.Request.Recipient = (BYTE) BmRequestRecipient; - - Packet->Packet.bRequest = USB_REQUEST_GET_STATUS; - Packet->Packet.wIndex.Value = Index; - Packet->Packet.wValue.Value = 0; - - // Packet->Packet.wLength will be set by the formatting function -} - diff --git a/usb/umdf_filter_kmdf/kmdf_driver/Device.c b/usb/umdf_filter_kmdf/kmdf_driver/Device.c deleted file mode 100644 index 87ead857..00000000 --- a/usb/umdf_filter_kmdf/kmdf_driver/Device.c +++ /dev/null @@ -1,1051 +0,0 @@ -/*++ - -Copyright (c) Microsoft Corporation. All rights reserved. - - THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY - KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR - PURPOSE. - -Module Name: - - Device.c - -Abstract: - - USB device driver for OSR USB-FX2 Learning Kit - -Environment: - - Kernel mode only - - ---*/ - -#include -#include - -#if defined(EVENT_TRACING) -#include "device.tmh" -#endif - -#ifdef ALLOC_PRAGMA -#pragma alloc_text(PAGE, OsrFxEvtDeviceAdd) -#pragma alloc_text(PAGE, OsrFxEvtDevicePrepareHardware) -#pragma alloc_text(PAGE, OsrFxEvtDeviceD0Exit) -#pragma alloc_text(PAGE, SelectInterfaces) -#pragma alloc_text(PAGE, OsrFxSetPowerPolicy) -#pragma alloc_text(PAGE, OsrFxReadFdoRegistryKeyValue) -#pragma alloc_text(PAGE, GetDeviceEventLoggingNames) -#pragma alloc_text(PAGE, OsrFxValidateConfigurationDescriptor) -#endif - - -NTSTATUS -OsrFxEvtDeviceAdd( - WDFDRIVER Driver, - PWDFDEVICE_INIT DeviceInit - ) -/*++ -Routine Description: - - EvtDeviceAdd is called by the framework in response to AddDevice - call from the PnP manager. We create and initialize a device object to - represent a new instance of the device. All the software resources - should be allocated in this callback. - -Arguments: - - Driver - Handle to a framework driver object created in DriverEntry - - DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure. - -Return Value: - - NTSTATUS - ---*/ -{ - WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks; - WDF_OBJECT_ATTRIBUTES attributes; - NTSTATUS status; - WDFDEVICE device; - WDF_DEVICE_PNP_CAPABILITIES pnpCaps; - WDF_IO_QUEUE_CONFIG ioQueueConfig; - PDEVICE_CONTEXT pDevContext; - WDFQUEUE queue; - GUID activity; - UNICODE_STRING symbolicLinkName; - WDFSTRING symbolicLinkString; - DEVPROP_BOOLEAN isRestricted; - - UNREFERENCED_PARAMETER(Driver); - - PAGED_CODE(); - - TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,"--> OsrFxEvtDeviceAdd routine\n"); - - // - // Initialize the pnpPowerCallbacks structure. Callback events for PNP - // and Power are specified here. If you don't supply any callbacks, - // the Framework will take appropriate default actions based on whether - // DeviceInit is initialized to be an FDO, a PDO or a filter device - // object. - // - - WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks); - // - // For usb devices, PrepareHardware callback is the to place select the - // interface and configure the device. - // - pnpPowerCallbacks.EvtDevicePrepareHardware = OsrFxEvtDevicePrepareHardware; - - // - // These two callbacks start and stop the wdfusb pipe continuous reader - // as we go in and out of the D0-working state. - // - - pnpPowerCallbacks.EvtDeviceD0Entry = OsrFxEvtDeviceD0Entry; - pnpPowerCallbacks.EvtDeviceD0Exit = OsrFxEvtDeviceD0Exit; - pnpPowerCallbacks.EvtDeviceSelfManagedIoFlush = OsrFxEvtDeviceSelfManagedIoFlush; - - WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks); - - WdfDeviceInitSetIoType(DeviceInit, WdfDeviceIoBuffered); - - // - // Now specify the size of device extension where we track per device - // context.DeviceInit is completely initialized. So call the framework - // to create the device and attach it to the lower stack. - // - WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, DEVICE_CONTEXT); - - status = WdfDeviceCreate(&DeviceInit, &attributes, &device); - if (!NT_SUCCESS(status)) { - TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, - "WdfDeviceCreate failed with Status code %!STATUS!\n", status); - return status; - } - - // - // Setup the activity ID so that we can log events using it. - // - - activity = DeviceToActivityId(device); - - // - // Get the DeviceObject context by using accessor function specified in - // the WDF_DECLARE_CONTEXT_TYPE_WITH_NAME macro for DEVICE_CONTEXT. - // - pDevContext = GetDeviceContext(device); - - // - // Get the device's friendly name and location so that we can use it in - // error logging. If this fails then it will setup dummy strings. - // - - GetDeviceEventLoggingNames(device); - - // - // Tell the framework to set the SurpriseRemovalOK in the DeviceCaps so - // that you don't get the popup in usermode when you surprise remove the device. - // - WDF_DEVICE_PNP_CAPABILITIES_INIT(&pnpCaps); - pnpCaps.SurpriseRemovalOK = WdfTrue; - - WdfDeviceSetPnpCapabilities(device, &pnpCaps); - - // - // Create a parallel default queue and register an event callback to - // receive ioctl requests. We will create separate queues for - // handling read and write requests. All other requests will be - // completed with error status automatically by the framework. - // - WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&ioQueueConfig, - WdfIoQueueDispatchParallel); - - ioQueueConfig.EvtIoDeviceControl = OsrFxEvtIoDeviceControl; - - // - // By default, Static Driver Verifier (SDV) displays a warning if it - // doesn't find the EvtIoStop callback on a power-managed queue. - // The 'assume' below causes SDV to suppress this warning. If the driver - // has not explicitly set PowerManaged to WdfFalse, the framework creates - // power-managed queues when the device is not a filter driver. Normally - // the EvtIoStop is required for power-managed queues, but for this driver - // it is not needed b/c the driver doesn't hold on to the requests for - // long time or forward them to other drivers. - // If the EvtIoStop callback is not implemented, the framework waits for - // all driver-owned requests to be done before moving in the Dx/sleep - // states or before removing the device, which is the correct behavior - // for this type of driver. If the requests were taking an indeterminate - // amount of time to complete, or if the driver forwarded the requests - // to a lower driver/another stack, the queue should have an - // EvtIoStop/EvtIoResume. - // - __analysis_assume(ioQueueConfig.EvtIoStop != 0); - status = WdfIoQueueCreate(device, - &ioQueueConfig, - WDF_NO_OBJECT_ATTRIBUTES, - &queue);// pointer to default queue - __analysis_assume(ioQueueConfig.EvtIoStop == 0); - - if (!NT_SUCCESS(status)) { - TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, - "WdfIoQueueCreate failed %!STATUS!\n", status); - goto Error; - } - - // - // We will create a separate sequential queue and configure it - // to receive read requests. We also need to register a EvtIoStop - // handler so that we can acknowledge requests that are pending - // at the target driver. - // - WDF_IO_QUEUE_CONFIG_INIT(&ioQueueConfig, WdfIoQueueDispatchSequential); - - ioQueueConfig.EvtIoRead = OsrFxEvtIoRead; - ioQueueConfig.EvtIoStop = OsrFxEvtIoStop; - - status = WdfIoQueueCreate( - device, - &ioQueueConfig, - WDF_NO_OBJECT_ATTRIBUTES, - &queue // queue handle - ); - - if (!NT_SUCCESS (status)) { - TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, - "WdfIoQueueCreate failed 0x%x\n", status); - goto Error; - } - - status = WdfDeviceConfigureRequestDispatching( - device, - queue, - WdfRequestTypeRead); - - if(!NT_SUCCESS (status)){ - NT_ASSERT(NT_SUCCESS(status)); - TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, - "WdfDeviceConfigureRequestDispatching failed 0x%x\n", status); - goto Error; - } - - - // - // We will create another sequential queue and configure it - // to receive write requests. - // - WDF_IO_QUEUE_CONFIG_INIT(&ioQueueConfig, WdfIoQueueDispatchSequential); - - ioQueueConfig.EvtIoWrite = OsrFxEvtIoWrite; - ioQueueConfig.EvtIoStop = OsrFxEvtIoStop; - - status = WdfIoQueueCreate( - device, - &ioQueueConfig, - WDF_NO_OBJECT_ATTRIBUTES, - &queue // queue handle - ); - - if (!NT_SUCCESS (status)) { - TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, - "WdfIoQueueCreate failed 0x%x\n", status); - goto Error; - } - - status = WdfDeviceConfigureRequestDispatching( - device, - queue, - WdfRequestTypeWrite); - - if(!NT_SUCCESS (status)){ - NT_ASSERT(NT_SUCCESS(status)); - TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, - "WdfDeviceConfigureRequestDispatching failed 0x%x\n", status); - goto Error; - } - - // - // Register a manual I/O queue for handling Interrupt Message Read Requests. - // This queue will be used for storing Requests that need to wait for an - // interrupt to occur before they can be completed. - // - WDF_IO_QUEUE_CONFIG_INIT(&ioQueueConfig, WdfIoQueueDispatchManual); - - // - // This queue is used for requests that dont directly access the device. The - // requests in this queue are serviced only when the device is in a fully - // powered state and sends an interrupt. So we can use a non-power managed - // queue to park the requests since we dont care whether the device is idle - // or fully powered up. - // - ioQueueConfig.PowerManaged = WdfFalse; - - status = WdfIoQueueCreate(device, - &ioQueueConfig, - WDF_NO_OBJECT_ATTRIBUTES, - &pDevContext->InterruptMsgQueue - ); - - if (!NT_SUCCESS(status)) { - TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, - "WdfIoQueueCreate failed 0x%x\n", status); - goto Error; - } - - // - // Register a device interface so that app can find our device and talk to it. - // - status = WdfDeviceCreateDeviceInterface(device, - (LPGUID) &GUID_DEVINTERFACE_OSRUSBFX2, - NULL); // Reference String - - if (!NT_SUCCESS(status)) { - TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, - "WdfDeviceCreateDeviceInterface failed %!STATUS!\n", status); - goto Error; - } - - // - // Create the lock that we use to serialize calls to ResetDevice(). As an - // alternative to using a WDFWAITLOCK to serialize the calls, a sequential - // WDFQUEUE can be created and reset IOCTLs would be forwarded to it. - // - WDF_OBJECT_ATTRIBUTES_INIT(&attributes); - attributes.ParentObject = device; - - status = WdfWaitLockCreate(&attributes, &pDevContext->ResetDeviceWaitLock); - if (!NT_SUCCESS(status)) { - TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, - "WdfWaitLockCreate failed %!STATUS!\n", status); - goto Error; - } - - // - // Get the string for the device interface and set the restricted - // property on it to allow applications bound with device metadata - // to access the interface. - // - if (g_pIoSetDeviceInterfacePropertyData != NULL) { - - status = WdfStringCreate(NULL, - WDF_NO_OBJECT_ATTRIBUTES, - &symbolicLinkString); - - if (!NT_SUCCESS(status)) { - TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, - "WdfStringCreate failed %!STATUS!\n", status); - goto Error; - } - - status = WdfDeviceRetrieveDeviceInterfaceString(device, - (LPGUID) &GUID_DEVINTERFACE_OSRUSBFX2, - NULL, - symbolicLinkString); - - if (!NT_SUCCESS(status)) { - TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, - "WdfDeviceRetrieveDeviceInterfaceString failed %!STATUS!\n", status); - goto Error; - } - - WdfStringGetUnicodeString(symbolicLinkString, &symbolicLinkName); - - isRestricted = DEVPROP_TRUE; - - status = g_pIoSetDeviceInterfacePropertyData(&symbolicLinkName, - &DEVPKEY_DeviceInterface_Restricted, - 0, - 0, - DEVPROP_TYPE_BOOLEAN, - sizeof(isRestricted), - &isRestricted ); - - WdfObjectDelete(symbolicLinkString); - - if (!NT_SUCCESS(status)) { - TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, - "IoSetDeviceInterfacePropertyData failed %!STATUS!\n", status); - goto Error; - } - } - - TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "<-- OsrFxEvtDeviceAdd\n"); - - return status; - -Error: - - // - // Log fail to add device to the event log - // - EventWriteFailAddDevice(&activity, - pDevContext->DeviceName, - pDevContext->Location, - status); - - return status; -} - -NTSTATUS -OsrFxEvtDevicePrepareHardware( - WDFDEVICE Device, - WDFCMRESLIST ResourceList, - WDFCMRESLIST ResourceListTranslated - ) -/*++ - -Routine Description: - - In this callback, the driver does whatever is necessary to make the - hardware ready to use. In the case of a USB device, this involves - reading and selecting descriptors. - -Arguments: - - Device - handle to a device - - ResourceList - handle to a resource-list object that identifies the - raw hardware resources that the PnP manager assigned - to the device - - ResourceListTranslated - handle to a resource-list object that - identifies the translated hardware resources - that the PnP manager assigned to the device - -Return Value: - - NT status value - ---*/ -{ - NTSTATUS status; - PDEVICE_CONTEXT pDeviceContext; - WDF_USB_DEVICE_INFORMATION deviceInfo; - ULONG waitWakeEnable; - - UNREFERENCED_PARAMETER(ResourceList); - UNREFERENCED_PARAMETER(ResourceListTranslated); - waitWakeEnable = FALSE; - PAGED_CODE(); - - TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "--> EvtDevicePrepareHardware\n"); - - pDeviceContext = GetDeviceContext(Device); - - // - // Create a USB device handle so that we can communicate with the - // underlying USB stack. The WDFUSBDEVICE handle is used to query, - // configure, and manage all aspects of the USB device. - // These aspects include device properties, bus properties, - // and I/O creation and synchronization. We only create device the first - // the PrepareHardware is called. If the device is restarted by pnp manager - // for resource rebalance, we will use the same device handle but then select - // the interfaces again because the USB stack could reconfigure the device on - // restart. - // - if (pDeviceContext->UsbDevice == NULL) { - WDF_USB_DEVICE_CREATE_CONFIG config; - - WDF_USB_DEVICE_CREATE_CONFIG_INIT(&config, - USBD_CLIENT_CONTRACT_VERSION_602); - - status = WdfUsbTargetDeviceCreateWithParameters(Device, - &config, - WDF_NO_OBJECT_ATTRIBUTES, - &pDeviceContext->UsbDevice); - - if (!NT_SUCCESS(status)) { - TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, - "WdfUsbTargetDeviceCreateWithParameters failed with Status code %!STATUS!\n", status); - return status; - } - - // - // TODO: If you are fetching configuration descriptor from device for - // selecting a configuration or to parse other descriptors, call OsrFxValidateConfigurationDescriptor - // to do basic validation on the descriptors before you access them . - // - } - - // - // Retrieve USBD version information, port driver capabilites and device - // capabilites such as speed, power, etc. - // - WDF_USB_DEVICE_INFORMATION_INIT(&deviceInfo); - - status = WdfUsbTargetDeviceRetrieveInformation( - pDeviceContext->UsbDevice, - &deviceInfo); - if (NT_SUCCESS(status)) { - TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "IsDeviceHighSpeed: %s\n", - (deviceInfo.Traits & WDF_USB_DEVICE_TRAIT_AT_HIGH_SPEED) ? "TRUE" : "FALSE"); - TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, - "IsDeviceSelfPowered: %s\n", - (deviceInfo.Traits & WDF_USB_DEVICE_TRAIT_SELF_POWERED) ? "TRUE" : "FALSE"); - - waitWakeEnable = deviceInfo.Traits & - WDF_USB_DEVICE_TRAIT_REMOTE_WAKE_CAPABLE; - - TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, - "IsDeviceRemoteWakeable: %s\n", - waitWakeEnable ? "TRUE" : "FALSE"); - // - // Save these for use later. - // - pDeviceContext->UsbDeviceTraits = deviceInfo.Traits; - } - else { - pDeviceContext->UsbDeviceTraits = 0; - } - - status = SelectInterfaces(Device); - if (!NT_SUCCESS(status)) { - TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, - "SelectInterfaces failed 0x%x\n", status); - return status; - } - - // - // Enable wait-wake and idle timeout if the device supports it - // - if (waitWakeEnable) { - status = OsrFxSetPowerPolicy(Device); - if (!NT_SUCCESS (status)) { - TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, - "OsrFxSetPowerPolicy failed %!STATUS!\n", status); - return status; - } - } - - status = OsrFxConfigContReaderForInterruptEndPoint(pDeviceContext); - - TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "<-- EvtDevicePrepareHardware\n"); - - return status; -} - - -NTSTATUS -OsrFxEvtDeviceD0Entry( - WDFDEVICE Device, - WDF_POWER_DEVICE_STATE PreviousState - ) -/*++ - -Routine Description: - - EvtDeviceD0Entry event callback must perform any operations that are - necessary before the specified device is used. It will be called every - time the hardware needs to be (re-)initialized. - - This function is not marked pageable because this function is in the - device power up path. When a function is marked pagable and the code - section is paged out, it will generate a page fault which could impact - the fast resume behavior because the client driver will have to wait - until the system drivers can service this page fault. - - This function runs at PASSIVE_LEVEL, even though it is not paged. A - driver can optionally make this function pageable if DO_POWER_PAGABLE - is set. Even if DO_POWER_PAGABLE isn't set, this function still runs - at PASSIVE_LEVEL. In this case, though, the function absolutely must - not do anything that will cause a page fault. - -Arguments: - - Device - Handle to a framework device object. - - PreviousState - Device power state which the device was in most recently. - If the device is being newly started, this will be - PowerDeviceUnspecified. - -Return Value: - - NTSTATUS - ---*/ -{ - PDEVICE_CONTEXT pDeviceContext; - NTSTATUS status; - BOOLEAN isTargetStarted; - - pDeviceContext = GetDeviceContext(Device); - isTargetStarted = FALSE; - - TraceEvents(TRACE_LEVEL_INFORMATION, DBG_POWER, - "-->OsrFxEvtEvtDeviceD0Entry - coming from %s\n", - DbgDevicePowerString(PreviousState)); - - // - // Since continuous reader is configured for this interrupt-pipe, we must explicitly start - // the I/O target to get the framework to post read requests. - // - status = WdfIoTargetStart(WdfUsbTargetPipeGetIoTarget(pDeviceContext->InterruptPipe)); - if (!NT_SUCCESS(status)) { - TraceEvents(TRACE_LEVEL_ERROR, DBG_POWER, "Failed to start interrupt pipe %!STATUS!\n", status); - goto End; - } - - isTargetStarted = TRUE; - -End: - - if (!NT_SUCCESS(status)) { - // - // Failure in D0Entry will lead to device being removed. So let us stop the continuous - // reader in preparation for the ensuing remove. - // - if (isTargetStarted) { - WdfIoTargetStop(WdfUsbTargetPipeGetIoTarget(pDeviceContext->InterruptPipe), WdfIoTargetCancelSentIo); - } - } - - TraceEvents(TRACE_LEVEL_INFORMATION, DBG_POWER, "<--OsrFxEvtEvtDeviceD0Entry\n"); - - return status; -} - - -NTSTATUS -OsrFxEvtDeviceD0Exit( - WDFDEVICE Device, - WDF_POWER_DEVICE_STATE TargetState - ) -/*++ - -Routine Description: - - This routine undoes anything done in EvtDeviceD0Entry. It is called - whenever the device leaves the D0 state, which happens when the device is - stopped, when it is removed, and when it is powered off. - - The device is still in D0 when this callback is invoked, which means that - the driver can still touch hardware in this routine. - - - EvtDeviceD0Exit event callback must perform any operations that are - necessary before the specified device is moved out of the D0 state. If the - driver needs to save hardware state before the device is powered down, then - that should be done here. - - This function runs at PASSIVE_LEVEL, though it is generally not paged. A - driver can optionally make this function pageable if DO_POWER_PAGABLE is set. - - Even if DO_POWER_PAGABLE isn't set, this function still runs at - PASSIVE_LEVEL. In this case, though, the function absolutely must not do - anything that will cause a page fault. - -Arguments: - - Device - Handle to a framework device object. - - TargetState - Device power state which the device will be put in once this - callback is complete. - -Return Value: - - Success implies that the device can be used. Failure will result in the - device stack being torn down. - ---*/ -{ - PDEVICE_CONTEXT pDeviceContext; - - PAGED_CODE(); - - TraceEvents(TRACE_LEVEL_INFORMATION, DBG_POWER, - "-->OsrFxEvtDeviceD0Exit - moving to %s\n", - DbgDevicePowerString(TargetState)); - - pDeviceContext = GetDeviceContext(Device); - - WdfIoTargetStop(WdfUsbTargetPipeGetIoTarget(pDeviceContext->InterruptPipe), WdfIoTargetCancelSentIo); - - TraceEvents(TRACE_LEVEL_INFORMATION, DBG_POWER, "<--OsrFxEvtDeviceD0Exit\n"); - - return STATUS_SUCCESS; -} - -VOID -OsrFxEvtDeviceSelfManagedIoFlush( - _In_ WDFDEVICE Device - ) -/*++ - -Routine Description: - - This routine handles flush activity for the device's - self-managed I/O operations. - -Arguments: - - Device - Handle to a framework device object. - -Return Value: - - None - ---*/ -{ - // Service the interrupt message queue to drain any outstanding - // requests - OsrUsbIoctlGetInterruptMessage(Device, STATUS_DEVICE_REMOVED); -} - -_IRQL_requires_(PASSIVE_LEVEL) -USBD_STATUS -OsrFxValidateConfigurationDescriptor( - _In_reads_bytes_(BufferLength) PUSB_CONFIGURATION_DESCRIPTOR ConfigDesc, - _In_ ULONG BufferLength, - _Inout_ PUCHAR *Offset - ) -/*++ - -Routine Description: - - Validates a USB Configuration Descriptor - -Parameters: - - ConfigDesc: Pointer to the entire USB Configuration descriptor returned by the device - - BufferLength: Known size of buffer pointed to by ConfigDesc (Not wTotalLength) - - Offset: if the USBD_STATUS returned is not USBD_STATUS_SUCCESS, offet will - be set to the address within the ConfigDesc buffer where the failure occured. - -Return Value: - - USBD_STATUS - Success implies the configuration descriptor is valid. - ---*/ -{ - - - USBD_STATUS status = USBD_STATUS_SUCCESS; - USHORT ValidationLevel = 3; - - PAGED_CODE(); - - // - // Call USBD_ValidateConfigurationDescriptor to validate the descriptors which are present in this supplied configuration descriptor. - // USBD_ValidateConfigurationDescriptor validates that all descriptors are completely contained within the configuration descriptor buffer. - // It also checks for interface numbers, number of endpoints in an interface etc. - // Please refer to msdn documentation for this function for more information. - // - - status = USBD_ValidateConfigurationDescriptor( ConfigDesc, BufferLength , ValidationLevel , Offset , POOL_TAG ); - if (!(NT_SUCCESS (status)) ){ - return status; - } - - // - // TODO: You should validate the correctness of other descriptors which are not taken care by USBD_ValidateConfigurationDescriptor - // Check that all such descriptors have size >= sizeof(the descriptor they point to) - // Check for any association between them if required - // - - return status; -} - - -_IRQL_requires_(PASSIVE_LEVEL) -NTSTATUS -OsrFxSetPowerPolicy( - _In_ WDFDEVICE Device - ) -{ - WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS idleSettings; - WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS wakeSettings; - NTSTATUS status = STATUS_SUCCESS; - - PAGED_CODE(); - - // - // Init the idle policy structure. - // - WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_INIT(&idleSettings, IdleUsbSelectiveSuspend); - idleSettings.IdleTimeout = 10000; // 10-sec - - status = WdfDeviceAssignS0IdleSettings(Device, &idleSettings); - if ( !NT_SUCCESS(status)) { - TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, - "WdfDeviceSetPowerPolicyS0IdlePolicy failed %x\n", status); - return status; - } - - // - // Init wait-wake policy structure. - // - WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_INIT(&wakeSettings); - - status = WdfDeviceAssignSxWakeSettings(Device, &wakeSettings); - if (!NT_SUCCESS(status)) { - TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, - "WdfDeviceAssignSxWakeSettings failed %x\n", status); - return status; - } - - return status; -} - - -_IRQL_requires_(PASSIVE_LEVEL) -NTSTATUS -SelectInterfaces( - _In_ WDFDEVICE Device - ) -/*++ - -Routine Description: - - This helper routine selects the configuration, interface and - creates a context for every pipe (end point) in that interface. - -Arguments: - - Device - Handle to a framework device - -Return Value: - - NT status value - ---*/ -{ - WDF_USB_DEVICE_SELECT_CONFIG_PARAMS configParams; - NTSTATUS status = STATUS_SUCCESS; - PDEVICE_CONTEXT pDeviceContext; - WDFUSBPIPE pipe; - WDF_USB_PIPE_INFORMATION pipeInfo; - UCHAR index; - UCHAR numberConfiguredPipes; - - PAGED_CODE(); - - pDeviceContext = GetDeviceContext(Device); - - WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_INIT_SINGLE_INTERFACE( &configParams); - - status = WdfUsbTargetDeviceSelectConfig(pDeviceContext->UsbDevice, - WDF_NO_OBJECT_ATTRIBUTES, - &configParams); - if(!NT_SUCCESS(status)) { - - TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, - "WdfUsbTargetDeviceSelectConfig failed %!STATUS! \n", - status); - - // - // Since the Osr USB fx2 device is capable of working at high speed, the only reason - // the device would not be working at high speed is if the port doesn't - // support it. If the port doesn't support high speed it is a 1.1 port - // - if ((pDeviceContext->UsbDeviceTraits & WDF_USB_DEVICE_TRAIT_AT_HIGH_SPEED) == 0) { - GUID activity = DeviceToActivityId(Device); - - TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, - " On a 1.1 USB port on Windows Vista" - " this is expected as the OSR USB Fx2 board's Interrupt EndPoint descriptor" - " doesn't conform to the USB specification. Windows Vista detects this and" - " returns an error. \n" - ); - EventWriteSelectConfigFailure( - &activity, - pDeviceContext->DeviceName, - pDeviceContext->Location, - status - ); - } - - return status; - } - - pDeviceContext->UsbInterface = - configParams.Types.SingleInterface.ConfiguredUsbInterface; - - numberConfiguredPipes = configParams.Types.SingleInterface.NumberConfiguredPipes; - - // - // Get pipe handles - // - for(index=0; index < numberConfiguredPipes; index++) { - - WDF_USB_PIPE_INFORMATION_INIT(&pipeInfo); - - pipe = WdfUsbInterfaceGetConfiguredPipe( - pDeviceContext->UsbInterface, - index, //PipeIndex, - &pipeInfo - ); - // - // Tell the framework that it's okay to read less than - // MaximumPacketSize - // - WdfUsbTargetPipeSetNoMaximumPacketSizeCheck(pipe); - - if(WdfUsbPipeTypeInterrupt == pipeInfo.PipeType) { - TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTL, - "Interrupt Pipe is 0x%p\n", pipe); - pDeviceContext->InterruptPipe = pipe; - } - - if(WdfUsbPipeTypeBulk == pipeInfo.PipeType && - WdfUsbTargetPipeIsInEndpoint(pipe)) { - TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTL, - "BulkInput Pipe is 0x%p\n", pipe); - pDeviceContext->BulkReadPipe = pipe; - } - - if(WdfUsbPipeTypeBulk == pipeInfo.PipeType && - WdfUsbTargetPipeIsOutEndpoint(pipe)) { - TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTL, - "BulkOutput Pipe is 0x%p\n", pipe); - pDeviceContext->BulkWritePipe = pipe; - } - - } - - // - // If we didn't find all the 3 pipes, fail the start. - // - if(!(pDeviceContext->BulkWritePipe - && pDeviceContext->BulkReadPipe && pDeviceContext->InterruptPipe)) { - status = STATUS_INVALID_DEVICE_STATE; - TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, - "Device is not configured properly %!STATUS!\n", - status); - - return status; - } - - return status; -} - -_IRQL_requires_(PASSIVE_LEVEL) -VOID -GetDeviceEventLoggingNames( - _In_ WDFDEVICE Device - ) -/*++ - -Routine Description: - - Retrieve the friendly name and the location string into WDFMEMORY objects - and store them in the device context. - -Arguments: - -Return Value: - - None - ---*/ -{ - PDEVICE_CONTEXT pDevContext = GetDeviceContext(Device); - - WDF_OBJECT_ATTRIBUTES objectAttributes; - - WDFMEMORY deviceNameMemory = NULL; - WDFMEMORY locationMemory = NULL; - - NTSTATUS status; - - PAGED_CODE(); - - // - // We want both memory objects to be children of the device so they will - // be deleted automatically when the device is removed. - // - - WDF_OBJECT_ATTRIBUTES_INIT(&objectAttributes); - objectAttributes.ParentObject = Device; - - // - // First get the length of the string. If the FriendlyName - // is not there then get the lenght of device description. - // - - status = WdfDeviceAllocAndQueryProperty(Device, - DevicePropertyFriendlyName, - NonPagedPool, - &objectAttributes, - &deviceNameMemory); - - if (!NT_SUCCESS(status)) - { - status = WdfDeviceAllocAndQueryProperty(Device, - DevicePropertyDeviceDescription, - NonPagedPool, - &objectAttributes, - &deviceNameMemory); - } - - if (NT_SUCCESS(status)) - { - pDevContext->DeviceNameMemory = deviceNameMemory; - pDevContext->DeviceName = WdfMemoryGetBuffer(deviceNameMemory, NULL); - } - else - { - pDevContext->DeviceNameMemory = NULL; - pDevContext->DeviceName = L"(error retrieving name)"; - } - - // - // Retrieve the device location string. - // - - status = WdfDeviceAllocAndQueryProperty(Device, - DevicePropertyLocationInformation, - NonPagedPool, - WDF_NO_OBJECT_ATTRIBUTES, - &locationMemory); - - if (NT_SUCCESS(status)) - { - pDevContext->LocationMemory = locationMemory; - pDevContext->Location = WdfMemoryGetBuffer(locationMemory, NULL); - } - else - { - pDevContext->LocationMemory = NULL; - pDevContext->Location = L"(error retrieving location)"; - } - - return; -} - -_IRQL_requires_(PASSIVE_LEVEL) -PCHAR -DbgDevicePowerString( - _In_ WDF_POWER_DEVICE_STATE Type - ) -{ - switch (Type) - { - case WdfPowerDeviceInvalid: - return "WdfPowerDeviceInvalid"; - case WdfPowerDeviceD0: - return "WdfPowerDeviceD0"; - case WdfPowerDeviceD1: - return "WdfPowerDeviceD1"; - case WdfPowerDeviceD2: - return "WdfPowerDeviceD2"; - case WdfPowerDeviceD3: - return "WdfPowerDeviceD3"; - case WdfPowerDeviceD3Final: - return "WdfPowerDeviceD3Final"; - case WdfPowerDevicePrepareForHibernation: - return "WdfPowerDevicePrepareForHibernation"; - case WdfPowerDeviceMaximum: - return "WdfPowerDeviceMaximum"; - default: - return "UnKnown Device Power State"; - } -} - - - diff --git a/usb/umdf_filter_kmdf/kmdf_driver/bulkrwr.c b/usb/umdf_filter_kmdf/kmdf_driver/bulkrwr.c deleted file mode 100644 index eabda192..00000000 --- a/usb/umdf_filter_kmdf/kmdf_driver/bulkrwr.c +++ /dev/null @@ -1,436 +0,0 @@ -/*++ - -Copyright (c) Microsoft Corporation. All rights reserved. - - THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY - KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR - PURPOSE. - -Module Name: - - bulkrwr.c - -Abstract: - - This file has routines to perform reads and writes. - The read and writes are targeted bulk to endpoints. - -Environment: - - Kernel mode - ---*/ - -#include - - -#if defined(EVENT_TRACING) -#include "bulkrwr.tmh" -#endif - -#pragma warning(disable:4267) - -VOID -OsrFxEvtIoRead( - _In_ WDFQUEUE Queue, - _In_ WDFREQUEST Request, - _In_ size_t Length - ) -/*++ - -Routine Description: - - Called by the framework when it receives Read or Write requests. - -Arguments: - - Queue - Default queue handle - Request - Handle to the read/write request - Lenght - Length of the data buffer associated with the request. - The default property of the queue is to not dispatch - zero lenght read & write requests to the driver and - complete is with status success. So we will never get - a zero length request. - -Return Value: - - ---*/ -{ - WDFUSBPIPE pipe; - NTSTATUS status; - WDFMEMORY reqMemory; - PDEVICE_CONTEXT pDeviceContext; - GUID activity = RequestToActivityId(Request); - - UNREFERENCED_PARAMETER(Queue); - - // - // Log read start event, using IRP activity ID if available or request - // handle otherwise. - // - - EventWriteReadStart(&activity, WdfIoQueueGetDevice(Queue), (ULONG)Length); - - TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ, "-->OsrFxEvtIoRead\n"); - - // - // First validate input parameters. - // - if (Length > TEST_BOARD_TRANSFER_BUFFER_SIZE) { - TraceEvents(TRACE_LEVEL_ERROR, DBG_READ, "Transfer exceeds %d\n", - TEST_BOARD_TRANSFER_BUFFER_SIZE); - status = STATUS_INVALID_PARAMETER; - goto Exit; - } - - pDeviceContext = GetDeviceContext(WdfIoQueueGetDevice(Queue)); - - pipe = pDeviceContext->BulkReadPipe; - - status = WdfRequestRetrieveOutputMemory(Request, &reqMemory); - if(!NT_SUCCESS(status)){ - TraceEvents(TRACE_LEVEL_ERROR, DBG_READ, - "WdfRequestRetrieveOutputMemory failed %!STATUS!\n", status); - goto Exit; - } - - // - // The format call validates to make sure that you are reading or - // writing to the right pipe type, sets the appropriate transfer flags, - // creates an URB and initializes the request. - // - status = WdfUsbTargetPipeFormatRequestForRead(pipe, - Request, - reqMemory, - NULL // Offsets - ); - if (!NT_SUCCESS(status)) { - TraceEvents(TRACE_LEVEL_ERROR, DBG_READ, - "WdfUsbTargetPipeFormatRequestForRead failed 0x%x\n", status); - goto Exit; - } - - WdfRequestSetCompletionRoutine( - Request, - EvtRequestReadCompletionRoutine, - pipe); - // - // Send the request asynchronously. - // - if (WdfRequestSend(Request, WdfUsbTargetPipeGetIoTarget(pipe), WDF_NO_SEND_OPTIONS) == FALSE) { - // - // Framework couldn't send the request for some reason. - // - TraceEvents(TRACE_LEVEL_ERROR, DBG_READ, "WdfRequestSend failed\n"); - status = WdfRequestGetStatus(Request); - goto Exit; - } - - -Exit: - if (!NT_SUCCESS(status)) { - // - // log event read failed - // - EventWriteReadFail(&activity, WdfIoQueueGetDevice(Queue), status); - WdfRequestCompleteWithInformation(Request, status, 0); - } - - TraceEvents(TRACE_LEVEL_INFORMATION, DBG_READ, "<-- OsrFxEvtIoRead\n"); - - return; -} - -VOID -EvtRequestReadCompletionRoutine( - _In_ WDFREQUEST Request, - _In_ WDFIOTARGET Target, - _In_ PWDF_REQUEST_COMPLETION_PARAMS CompletionParams, - _In_ WDFCONTEXT Context - ) -/*++ - -Routine Description: - - This is the completion routine for reads - If the irp completes with success, we check if we - need to recirculate this irp for another stage of - transfer. - -Arguments: - - Context - Driver supplied context - Device - Device handle - Request - Request handle - Params - request completion params - -Return Value: - None - ---*/ -{ - NTSTATUS status; - size_t bytesRead = 0; - GUID activity = RequestToActivityId(Request); - PWDF_USB_REQUEST_COMPLETION_PARAMS usbCompletionParams; - - UNREFERENCED_PARAMETER(Target); - UNREFERENCED_PARAMETER(Context); - - status = CompletionParams->IoStatus.Status; - - usbCompletionParams = CompletionParams->Parameters.Usb.Completion; - - bytesRead = usbCompletionParams->Parameters.PipeRead.Length; - - if (NT_SUCCESS(status)){ - TraceEvents(TRACE_LEVEL_INFORMATION, DBG_READ, - "Number of bytes read: %I64d\n", (INT64)bytesRead); - } else { - TraceEvents(TRACE_LEVEL_ERROR, DBG_READ, - "Read failed - request status 0x%x UsbdStatus 0x%x\n", - status, usbCompletionParams->UsbdStatus); - - } - - // - // Log read stop event, using IRP activity ID if available or request - // handle otherwise. - // - - EventWriteReadStop(&activity, - WdfIoQueueGetDevice(WdfRequestGetIoQueue(Request)), - bytesRead, - status, - usbCompletionParams->UsbdStatus); - - WdfRequestCompleteWithInformation(Request, status, bytesRead); - - return; -} - -VOID -OsrFxEvtIoWrite( - _In_ WDFQUEUE Queue, - _In_ WDFREQUEST Request, - _In_ size_t Length - ) -/*++ - -Routine Description: - - Called by the framework when it receives Read or Write requests. - -Arguments: - - Queue - Default queue handle - Request - Handle to the read/write request - Lenght - Length of the data buffer associated with the request. - The default property of the queue is to not dispatch - zero lenght read & write requests to the driver and - complete is with status success. So we will never get - a zero length request. - -Return Value: - - ---*/ -{ - NTSTATUS status; - WDFUSBPIPE pipe; - WDFMEMORY reqMemory; - PDEVICE_CONTEXT pDeviceContext; - GUID activity = RequestToActivityId(Request); - - UNREFERENCED_PARAMETER(Queue); - - - // - // Log write start event, using IRP activity ID if available or request - // handle otherwise. - // - EventWriteWriteStart(&activity, WdfIoQueueGetDevice(Queue), (ULONG)Length); - - TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE, "-->OsrFxEvtIoWrite\n"); - - // - // First validate input parameters. - // - if (Length > TEST_BOARD_TRANSFER_BUFFER_SIZE) { - TraceEvents(TRACE_LEVEL_ERROR, DBG_READ, "Transfer exceeds %d\n", - TEST_BOARD_TRANSFER_BUFFER_SIZE); - status = STATUS_INVALID_PARAMETER; - goto Exit; - } - - pDeviceContext = GetDeviceContext(WdfIoQueueGetDevice(Queue)); - - pipe = pDeviceContext->BulkWritePipe; - - status = WdfRequestRetrieveInputMemory(Request, &reqMemory); - if(!NT_SUCCESS(status)){ - TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, "WdfRequestRetrieveInputBuffer failed\n"); - goto Exit; - } - - status = WdfUsbTargetPipeFormatRequestForWrite(pipe, - Request, - reqMemory, - NULL); // Offset - - - if (!NT_SUCCESS(status)) { - TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, - "WdfUsbTargetPipeFormatRequestForWrite failed 0x%x\n", status); - goto Exit; - } - - WdfRequestSetCompletionRoutine( - Request, - EvtRequestWriteCompletionRoutine, - pipe); - - // - // Send the request asynchronously. - // - if (WdfRequestSend(Request, WdfUsbTargetPipeGetIoTarget(pipe), WDF_NO_SEND_OPTIONS) == FALSE) { - // - // Framework couldn't send the request for some reason. - // - TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, "WdfRequestSend failed\n"); - status = WdfRequestGetStatus(Request); - goto Exit; - } - -Exit: - - if (!NT_SUCCESS(status)) { - // - // log event write failed - // - EventWriteWriteFail(&activity, WdfIoQueueGetDevice(Queue), status); - - WdfRequestCompleteWithInformation(Request, status, 0); - } - - TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE, "<-- OsrFxEvtIoWrite\n"); - - return; -} - -VOID -EvtRequestWriteCompletionRoutine( - _In_ WDFREQUEST Request, - _In_ WDFIOTARGET Target, - _In_ PWDF_REQUEST_COMPLETION_PARAMS CompletionParams, - _In_ WDFCONTEXT Context - ) -/*++ - -Routine Description: - - This is the completion routine for writes - If the irp completes with success, we check if we - need to recirculate this irp for another stage of - transfer. - -Arguments: - - Context - Driver supplied context - Device - Device handle - Request - Request handle - Params - request completion params - -Return Value: - None - ---*/ -{ - NTSTATUS status; - size_t bytesWritten = 0; - GUID activity = RequestToActivityId(Request); - PWDF_USB_REQUEST_COMPLETION_PARAMS usbCompletionParams; - - UNREFERENCED_PARAMETER(Target); - UNREFERENCED_PARAMETER(Context); - - status = CompletionParams->IoStatus.Status; - - // - // For usb devices, we should look at the Usb.Completion param. - // - usbCompletionParams = CompletionParams->Parameters.Usb.Completion; - - bytesWritten = usbCompletionParams->Parameters.PipeWrite.Length; - - if (NT_SUCCESS(status)){ - TraceEvents(TRACE_LEVEL_INFORMATION, DBG_WRITE, - "Number of bytes written: %I64d\n", (INT64)bytesWritten); - } else { - TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, - "Write failed: request Status 0x%x UsbdStatus 0x%x\n", - status, usbCompletionParams->UsbdStatus); - } - - // - // Log write stop event, using IRP activtiy ID if available or request - // handle otherwise - // - EventWriteWriteStop(&activity, - WdfIoQueueGetDevice(WdfRequestGetIoQueue(Request)), - bytesWritten, - status, - usbCompletionParams->UsbdStatus); - - - WdfRequestCompleteWithInformation(Request, status, bytesWritten); - - return; -} - - -VOID -OsrFxEvtIoStop( - _In_ WDFQUEUE Queue, - _In_ WDFREQUEST Request, - _In_ ULONG ActionFlags - ) -/*++ - -Routine Description: - - This callback is invoked on every inflight request when the device - is suspended or removed. Since our inflight read and write requests - are actually pending in the target device, we will just acknowledge - its presence. Until we acknowledge, complete, or requeue the requests - framework will wait before allowing the device suspend or remove to - proceeed. When the underlying USB stack gets the request to suspend or - remove, it will fail all the pending requests. - -Arguments: - - Queue - handle to queue object that is associated with the I/O request - - Request - handle to a request object - - ActionFlags - bitwise OR of one or more WDF_REQUEST_STOP_ACTION_FLAGS flags - -Return Value: - None - ---*/ -{ - UNREFERENCED_PARAMETER(Queue); - UNREFERENCED_PARAMETER(ActionFlags); - - if (ActionFlags & WdfRequestStopActionSuspend ) { - WdfRequestStopAcknowledge(Request, FALSE); // Don't requeue - } else if(ActionFlags & WdfRequestStopActionPurge) { - WdfRequestCancelSentRequest(Request); - } - return; -} - - diff --git a/usb/umdf_filter_kmdf/kmdf_driver/driver.c b/usb/umdf_filter_kmdf/kmdf_driver/driver.c deleted file mode 100644 index d3b44573..00000000 --- a/usb/umdf_filter_kmdf/kmdf_driver/driver.c +++ /dev/null @@ -1,299 +0,0 @@ -/*++ - -Copyright (c) Microsoft Corporation. All rights reserved. - - THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY - KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR - PURPOSE. - -Module Name: - - Driver.c - -Abstract: - - Main module. - - This driver is for Open System Resources USB-FX2 Learning Kit designed - and built by OSR specifically for use in teaching software developers how to write - drivers for USB devices. - - The board supports a single configuration. The board automatically - detects the speed of the host controller, and supplies either the - high or full speed configuration based on the host controller's speed. - - The firmware supports 3 endpoints: - - Endpoint number 1 is used to indicate the state of the 8-switch - switch-pack on the OSR USB-FX2 board. A single byte representing - the switch state is sent (a) when the board is first started, - (b) when the board resumes after selective-suspend, - (c) whenever the state of the switches is changed. - - Endpoints 6 and 8 perform an internal loop-back function. - Data that is sent to the board at EP6 is returned to the host on EP8. - - For further information on the endpoints, please refer to the spec - http://www.osronline.com/hardware/OSRFX2_32.pdf. - - Vendor ID of the device is 0x4705 and Product ID is 0x210. - -Environment: - - Kernel mode only - ---*/ - -#include - -#if defined(EVENT_TRACING) -// -// The trace message header (.tmh) file must be included in a source file -// before any WPP macro calls and after defining a WPP_CONTROL_GUIDS -// macro (defined in trace.h). During the compilation, WPP scans the source -// files for DoTraceMessage() calls and builds a .tmh file which stores a unique -// data GUID for each message, the text resource string for each message, -// and the data types of the variables passed in for each message. This file -// is automatically generated and used during post-processing. -// -#include "driver.tmh" -#else -ULONG DebugLevel = TRACE_LEVEL_INFORMATION; -ULONG DebugFlag = 0xff; -#endif - -PFN_IO_GET_ACTIVITY_ID_IRP g_pIoGetActivityIdIrp; -PFN_IO_SET_DEVICE_INTERFACE_PROPERTY_DATA g_pIoSetDeviceInterfacePropertyData; - -#ifdef ALLOC_PRAGMA -#pragma alloc_text(INIT, DriverEntry) -#pragma alloc_text(PAGE, OsrFxEvtDriverContextCleanup) -#endif - -NTSTATUS -DriverEntry( - PDRIVER_OBJECT DriverObject, - PUNICODE_STRING RegistryPath - ) -/*++ - -Routine Description: - DriverEntry initializes the driver and is the first routine called by the - system after the driver is loaded. - -Parameters Description: - - DriverObject - represents the instance of the function driver that is loaded - into memory. DriverEntry must initialize members of DriverObject before it - returns to the caller. DriverObject is allocated by the system before the - driver is loaded, and it is released by the system after the system unloads - the function driver from memory. - - RegistryPath - represents the driver specific path in the Registry. - The function driver can use the path to store driver related data between - reboots. The path does not store hardware instance specific data. - -Return Value: - - STATUS_SUCCESS if successful, - STATUS_UNSUCCESSFUL or another NTSTATUS error code otherwise. - ---*/ -{ - WDF_DRIVER_CONFIG config; - NTSTATUS status; - WDF_OBJECT_ATTRIBUTES attributes; - UNICODE_STRING funcName; - - // - // Initialize WPP Tracing - // - WPP_INIT_TRACING( DriverObject, RegistryPath ); - - TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, - "OSRUSBFX2 Driver Sample - Driver Framework Edition.\n"); - - TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, - "Built %s %s\n", __DATE__, __TIME__); - - // - // IRP activity ID functions are available on some versions, save them into - // globals (or NULL if not available) - // - RtlInitUnicodeString(&funcName, L"IoGetActivityIdIrp"); - g_pIoGetActivityIdIrp = (PFN_IO_GET_ACTIVITY_ID_IRP) (ULONG_PTR) - MmGetSystemRoutineAddress(&funcName); - - // - // The Device interface property set is available on some version, save it - // into globals (or NULL if not available) - // - RtlInitUnicodeString(&funcName, L"IoSetDeviceInterfacePropertyData"); - g_pIoSetDeviceInterfacePropertyData = (PFN_IO_SET_DEVICE_INTERFACE_PROPERTY_DATA) (ULONG_PTR) - MmGetSystemRoutineAddress(&funcName); - - // - // Register with ETW (unified tracing) - // - EventRegisterOSRUSBFX2(); - - // - // Initiialize driver config to control the attributes that - // are global to the driver. Note that framework by default - // provides a driver unload routine. If you create any resources - // in the DriverEntry and want to be cleaned in driver unload, - // you can override that by manually setting the EvtDriverUnload in the - // config structure. In general xxx_CONFIG_INIT macros are provided to - // initialize most commonly used members. - // - - WDF_DRIVER_CONFIG_INIT( - &config, - OsrFxEvtDeviceAdd - ); - - // - // Register a cleanup callback so that we can call WPP_CLEANUP when - // the framework driver object is deleted during driver unload. - // - WDF_OBJECT_ATTRIBUTES_INIT(&attributes); - attributes.EvtCleanupCallback = OsrFxEvtDriverContextCleanup; - - // - // Create a framework driver object to represent our driver. - // - status = WdfDriverCreate( - DriverObject, - RegistryPath, - &attributes, // Driver Object Attributes - &config, // Driver Config Info - WDF_NO_HANDLE // hDriver - ); - - if (!NT_SUCCESS(status)) { - - TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, - "WdfDriverCreate failed with status 0x%x\n", status); - // - // Cleanup tracing here because DriverContextCleanup will not be called - // as we have failed to create WDFDRIVER object itself. - // Please note that if your return failure from DriverEntry after the - // WDFDRIVER object is created successfully, you don't have to - // call WPP cleanup because in those cases DriverContextCleanup - // will be executed when the framework deletes the DriverObject. - // - WPP_CLEANUP(DriverObject); - EventUnregisterOSRUSBFX2(); - } - - return status; -} - -VOID -OsrFxEvtDriverContextCleanup( - WDFOBJECT Driver - ) -/*++ -Routine Description: - - Free resources allocated in DriverEntry that are not automatically - cleaned up by the framework. - -Arguments: - - Driver - handle to a WDF Driver object. - -Return Value: - - VOID. - ---*/ -{ - PAGED_CODE (); - - TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, - "--> OsrFxEvtDriverContextCleanup\n"); - - WPP_CLEANUP( WdfDriverWdmGetDriverObject( (WDFDRIVER)Driver )); - - UNREFERENCED_PARAMETER(Driver); // For the case when WPP is not being used. - - EventUnregisterOSRUSBFX2(); -} - -#if !defined(EVENT_TRACING) - -VOID -TraceEvents ( - _In_ ULONG DebugPrintLevel, - _In_ ULONG DebugPrintFlag, - _Printf_format_string_ - _In_ PCSTR DebugMessage, - ... - ) - -/*++ - -Routine Description: - - Debug print for the sample driver. - -Arguments: - - DebugPrintLevel - print level between 0 and 3, with 3 the most verbose - DebugPrintFlag - message mask - DebugMessage - format string of the message to print - ... - values used by the format string - -Return Value: - - None. - - --*/ - { -#if DBG -#define TEMP_BUFFER_SIZE 1024 - va_list list; - CHAR debugMessageBuffer[TEMP_BUFFER_SIZE]; - NTSTATUS status; - - va_start(list, DebugMessage); - - if (DebugMessage) { - - // - // Using new safe string functions instead of _vsnprintf. - // This function takes care of NULL terminating if the message - // is longer than the buffer. - // - status = RtlStringCbVPrintfA( debugMessageBuffer, - sizeof(debugMessageBuffer), - DebugMessage, - list ); - if(!NT_SUCCESS(status)) { - - DbgPrint (_DRIVER_NAME_": RtlStringCbVPrintfA failed 0x%x\n", status); - return; - } - if (DebugPrintLevel <= TRACE_LEVEL_ERROR || - (DebugPrintLevel <= DebugLevel && - ((DebugPrintFlag & DebugFlag) == DebugPrintFlag))) { - DbgPrint("%s %s", _DRIVER_NAME_, debugMessageBuffer); - } - } - va_end(list); - - return; -#else - UNREFERENCED_PARAMETER(DebugPrintLevel); - UNREFERENCED_PARAMETER(DebugPrintFlag); - UNREFERENCED_PARAMETER(DebugMessage); -#endif -} - -#endif - - - - diff --git a/usb/umdf_filter_kmdf/kmdf_driver/interrupt.c b/usb/umdf_filter_kmdf/kmdf_driver/interrupt.c deleted file mode 100644 index 00ea3550..00000000 --- a/usb/umdf_filter_kmdf/kmdf_driver/interrupt.c +++ /dev/null @@ -1,184 +0,0 @@ -/*++ - -Copyright (c) Microsoft Corporation. All rights reserved. - - THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY - KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR - PURPOSE. - -Module Name: - - Interrupt.c - -Abstract: - - This modules has routines configure a continuous reader on an - interrupt pipe to asynchronously read toggle switch states. - -Environment: - - Kernel mode - ---*/ - -#include - -#if defined(EVENT_TRACING) -#include "interrupt.tmh" -#endif - - -_IRQL_requires_(PASSIVE_LEVEL) -NTSTATUS -OsrFxConfigContReaderForInterruptEndPoint( - _In_ PDEVICE_CONTEXT DeviceContext - ) -/*++ - -Routine Description: - - This routine configures a continuous reader on the - interrupt endpoint. It's called from the PrepareHarware event. - -Arguments: - - -Return Value: - - NT status value - ---*/ -{ - WDF_USB_CONTINUOUS_READER_CONFIG contReaderConfig; - NTSTATUS status; - - WDF_USB_CONTINUOUS_READER_CONFIG_INIT(&contReaderConfig, - OsrFxEvtUsbInterruptPipeReadComplete, - DeviceContext, // Context - sizeof(UCHAR)); // TransferLength - - contReaderConfig.EvtUsbTargetPipeReadersFailed = OsrFxEvtUsbInterruptReadersFailed; - - // - // Reader requests are not posted to the target automatically. - // Driver must explictly call WdfIoTargetStart to kick start the - // reader. In this sample, it's done in D0Entry. - // By defaut, framework queues two requests to the target - // endpoint. Driver can configure up to 10 requests with CONFIG macro. - // - status = WdfUsbTargetPipeConfigContinuousReader(DeviceContext->InterruptPipe, - &contReaderConfig); - - if (!NT_SUCCESS(status)) { - TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, - "OsrFxConfigContReaderForInterruptEndPoint failed %x\n", - status); - return status; - } - - return status; -} - -VOID -OsrFxEvtUsbInterruptPipeReadComplete( - WDFUSBPIPE Pipe, - WDFMEMORY Buffer, - size_t NumBytesTransferred, - WDFCONTEXT Context - ) -/*++ - -Routine Description: - - This the completion routine of the continour reader. This can - called concurrently on multiprocessor system if there are - more than one readers configured. So make sure to protect - access to global resources. - -Arguments: - - Buffer - This buffer is freed when this call returns. - If the driver wants to delay processing of the buffer, it - can take an additional referrence. - - Context - Provided in the WDF_USB_CONTINUOUS_READER_CONFIG_INIT macro - -Return Value: - - NT status value - ---*/ -{ - PUCHAR switchState = NULL; - WDFDEVICE device; - PDEVICE_CONTEXT pDeviceContext = Context; - - UNREFERENCED_PARAMETER(Pipe); - - device = WdfObjectContextGetObject(pDeviceContext); - - // - // Make sure that there is data in the read packet. Depending on the device - // specification, it is possible for it to return a 0 length read in - // certain conditions. - // - - if (NumBytesTransferred == 0) { - TraceEvents(TRACE_LEVEL_WARNING, DBG_INIT, - "OsrFxEvtUsbInterruptPipeReadComplete Zero length read " - "occured on the Interrupt Pipe's Continuous Reader\n" - ); - return; - } - - - NT_ASSERT(NumBytesTransferred == sizeof(UCHAR)); - - switchState = WdfMemoryGetBuffer(Buffer, NULL); - - TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, - "OsrFxEvtUsbInterruptPipeReadComplete SwitchState %x\n", - *switchState); - - pDeviceContext->CurrentSwitchState = *switchState; - - // - // Handle any pending Interrupt Message IOCTLs. Note that the OSR USB device - // will generate an interrupt message when the the device resumes from a low - // power state. So if the Interrupt Message IOCTL was sent after the device - // has gone to a low power state, the pending Interrupt Message IOCTL will - // get completed in the function call below, before the user twiddles the - // dip switches on the OSR USB device. If this is not the desired behavior - // for your driver, then you could handle this condition by maintaining a - // state variable on D0Entry to track interrupt messages caused by power up. - // - OsrUsbIoctlGetInterruptMessage(device, STATUS_SUCCESS); - -} - -BOOLEAN -OsrFxEvtUsbInterruptReadersFailed( - _In_ WDFUSBPIPE Pipe, - _In_ NTSTATUS Status, - _In_ USBD_STATUS UsbdStatus - ) -{ - WDFDEVICE device = WdfIoTargetGetDevice(WdfUsbTargetPipeGetIoTarget(Pipe)); - PDEVICE_CONTEXT pDeviceContext = GetDeviceContext(device); - - UNREFERENCED_PARAMETER(UsbdStatus); - - // - // Clear the current switch state. - // - pDeviceContext->CurrentSwitchState = 0; - - // - // Service the pending interrupt switch change request - // - OsrUsbIoctlGetInterruptMessage(device, Status); - - return TRUE; -} - diff --git a/usb/umdf_filter_kmdf/kmdf_driver/ioctl.c b/usb/umdf_filter_kmdf/kmdf_driver/ioctl.c deleted file mode 100644 index 0f29dc8c..00000000 --- a/usb/umdf_filter_kmdf/kmdf_driver/ioctl.c +++ /dev/null @@ -1,1057 +0,0 @@ -/*++ - -Copyright (c) Microsoft Corporation. All rights reserved. - - THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY - KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR - PURPOSE. - -Module Name: - - Ioctl.c - -Abstract: - - USB device driver for OSR USB-FX2 Learning Kit - -Environment: - - Kernel mode only - ---*/ - -#include - -#if defined(EVENT_TRACING) -#include "ioctl.tmh" -#endif - -#pragma alloc_text(PAGE, OsrFxEvtIoDeviceControl) -#pragma alloc_text(PAGE, ResetPipe) -#pragma alloc_text(PAGE, ResetDevice) -#pragma alloc_text(PAGE, ReenumerateDevice) -#pragma alloc_text(PAGE, GetBarGraphState) -#pragma alloc_text(PAGE, SetBarGraphState) -#pragma alloc_text(PAGE, GetSevenSegmentState) -#pragma alloc_text(PAGE, SetSevenSegmentState) -#pragma alloc_text(PAGE, GetSwitchState) - -VOID -OsrFxEvtIoDeviceControl( - _In_ WDFQUEUE Queue, - _In_ WDFREQUEST Request, - _In_ size_t OutputBufferLength, - _In_ size_t InputBufferLength, - _In_ ULONG IoControlCode - ) -/*++ - -Routine Description: - - This event is called when the framework receives IRP_MJ_DEVICE_CONTROL - requests from the system. - -Arguments: - - Queue - Handle to the framework queue object that is associated - with the I/O request. - Request - Handle to a framework request object. - - OutputBufferLength - length of the request's output buffer, - if an output buffer is available. - InputBufferLength - length of the request's input buffer, - if an input buffer is available. - - IoControlCode - the driver-defined or system-defined I/O control code - (IOCTL) that is associated with the request. -Return Value: - - VOID - ---*/ -{ - WDFDEVICE device; - PDEVICE_CONTEXT pDevContext; - size_t bytesReturned = 0; - PBAR_GRAPH_STATE barGraphState = NULL; - PSWITCH_STATE switchState = NULL; - PUCHAR sevenSegment = NULL; - BOOLEAN requestPending = FALSE; - NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST; - - UNREFERENCED_PARAMETER(InputBufferLength); - UNREFERENCED_PARAMETER(OutputBufferLength); - - PAGED_CODE(); - - TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTL, "--> OsrFxEvtIoDeviceControl\n"); - // - // initialize variables - // - device = WdfIoQueueGetDevice(Queue); - pDevContext = GetDeviceContext(device); - - switch(IoControlCode) { - - case IOCTL_OSRUSBFX2_GET_CONFIG_DESCRIPTOR: { - - PUSB_CONFIGURATION_DESCRIPTOR configurationDescriptor = NULL; - USHORT requiredSize = 0; - - // - // First get the size of the config descriptor - // - status = WdfUsbTargetDeviceRetrieveConfigDescriptor( - pDevContext->UsbDevice, - NULL, - &requiredSize); - - if (status != STATUS_BUFFER_TOO_SMALL) { - TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, - "WdfUsbTargetDeviceRetrieveConfigDescriptor failed 0x%x\n", status); - break; - } - - // - // Get the buffer - make sure the buffer is big enough - // - status = WdfRequestRetrieveOutputBuffer(Request, - (size_t)requiredSize, // MinimumRequired - &configurationDescriptor, - NULL); - if(!NT_SUCCESS(status)){ - TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, - "WdfRequestRetrieveOutputBuffer failed 0x%x\n", status); - break; - } - - status = WdfUsbTargetDeviceRetrieveConfigDescriptor( - pDevContext->UsbDevice, - configurationDescriptor, - &requiredSize); - if (!NT_SUCCESS(status)) { - TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, - "WdfUsbTargetDeviceRetrieveConfigDescriptor failed 0x%x\n", status); - break; - } - - bytesReturned = requiredSize; - - } - break; - - case IOCTL_OSRUSBFX2_RESET_DEVICE: - - status = ResetDevice(device); - break; - - case IOCTL_OSRUSBFX2_REENUMERATE_DEVICE: - - // - // Otherwise, call our function to reenumerate the - // device - // - status = ReenumerateDevice(pDevContext); - - bytesReturned = 0; - break; - - case IOCTL_OSRUSBFX2_GET_BAR_GRAPH_DISPLAY: - - // - // Make sure the caller's output buffer is large enough - // to hold the state of the bar graph - // - status = WdfRequestRetrieveOutputBuffer(Request, - sizeof(BAR_GRAPH_STATE), - &barGraphState, - NULL); - - if (!NT_SUCCESS(status)) { - TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, - "User's output buffer is too small for this IOCTL, expecting an BAR_GRAPH_STATE\n"); - break; - } - // - // Call our function to get the bar graph state - // - status = GetBarGraphState(pDevContext, barGraphState); - - // - // If we succeeded return the user their data - // - if (NT_SUCCESS(status)) { - - bytesReturned = sizeof(BAR_GRAPH_STATE); - - } else { - - bytesReturned = 0; - - } - break; - - case IOCTL_OSRUSBFX2_SET_BAR_GRAPH_DISPLAY: - - status = WdfRequestRetrieveInputBuffer(Request, - sizeof(BAR_GRAPH_STATE), - &barGraphState, - NULL); - if (!NT_SUCCESS(status)) { - TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, - "User's input buffer is too small for this IOCTL, expecting an BAR_GRAPH_STATE\n"); - break; - } - - // - // Call our routine to set the bar graph state - // - status = SetBarGraphState(pDevContext, barGraphState); - - // - // There's no data returned for this call - // - bytesReturned = 0; - break; - - case IOCTL_OSRUSBFX2_GET_7_SEGMENT_DISPLAY: - - status = WdfRequestRetrieveOutputBuffer(Request, - sizeof(UCHAR), - &sevenSegment, - NULL); - - if (!NT_SUCCESS(status)) { - TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, - "User's output buffer is too small for this IOCTL, expecting an UCHAR\n"); - break; - } - - // - // Call our function to get the 7 segment state - // - status = GetSevenSegmentState(pDevContext, sevenSegment); - - // - // If we succeeded return the user their data - // - if (NT_SUCCESS(status)) { - - bytesReturned = sizeof(UCHAR); - - } else { - - bytesReturned = 0; - - } - break; - - case IOCTL_OSRUSBFX2_SET_7_SEGMENT_DISPLAY: - - status = WdfRequestRetrieveInputBuffer(Request, - sizeof(UCHAR), - &sevenSegment, - NULL); - if (!NT_SUCCESS(status)) { - TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, - "User's input buffer is too small for this IOCTL, expecting an UCHAR\n"); - bytesReturned = sizeof(UCHAR); - break; - } - - // - // Call our routine to set the 7 segment state - // - status = SetSevenSegmentState(pDevContext, sevenSegment); - - // - // There's no data returned for this call - // - bytesReturned = 0; - break; - - case IOCTL_OSRUSBFX2_READ_SWITCHES: - - status = WdfRequestRetrieveOutputBuffer(Request, - sizeof(SWITCH_STATE), - &switchState, - NULL);// BufferLength - - if (!NT_SUCCESS(status)) { - TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, - "User's output buffer is too small for this IOCTL, expecting a SWITCH_STATE\n"); - bytesReturned = sizeof(SWITCH_STATE); - break; - - } - - // - // Call our routine to get the state of the switches - // - status = GetSwitchState(pDevContext, switchState); - - // - // If successful, return the user their data - // - if (NT_SUCCESS(status)) { - - bytesReturned = sizeof(SWITCH_STATE); - - } else { - // - // Don't return any data - // - bytesReturned = 0; - } - break; - - case IOCTL_OSRUSBFX2_GET_INTERRUPT_MESSAGE: - - // - // Forward the request to an interrupt message queue and dont complete - // the request until an interrupt from the USB device occurs. - // - status = WdfRequestForwardToIoQueue(Request, pDevContext->InterruptMsgQueue); - if (NT_SUCCESS(status)) { - requestPending = TRUE; - } - - break; - - default : - status = STATUS_INVALID_DEVICE_REQUEST; - break; - } - - if (requestPending == FALSE) { - WdfRequestCompleteWithInformation(Request, status, bytesReturned); - } - - TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTL, "<-- OsrFxEvtIoDeviceControl\n"); - - return; -} - -_IRQL_requires_(PASSIVE_LEVEL) -NTSTATUS -ResetPipe( - _In_ WDFUSBPIPE Pipe - ) -/*++ - -Routine Description: - - This routine resets the pipe. - -Arguments: - - Pipe - framework pipe handle - -Return Value: - - NT status value - ---*/ -{ - NTSTATUS status; - - PAGED_CODE(); - - // - // This routine synchronously submits a URB_FUNCTION_RESET_PIPE - // request down the stack. - // - status = WdfUsbTargetPipeResetSynchronously(Pipe, - WDF_NO_HANDLE, // WDFREQUEST - NULL // PWDF_REQUEST_SEND_OPTIONS - ); - - if (NT_SUCCESS(status)) { - TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTL, "ResetPipe - success\n"); - status = STATUS_SUCCESS; - } - else { - TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, "ResetPipe - failed\n"); - } - - return status; -} - -VOID -StopAllPipes( - IN PDEVICE_CONTEXT DeviceContext - ) -{ - WdfIoTargetStop(WdfUsbTargetPipeGetIoTarget(DeviceContext->InterruptPipe), - WdfIoTargetCancelSentIo); - WdfIoTargetStop(WdfUsbTargetPipeGetIoTarget(DeviceContext->BulkReadPipe), - WdfIoTargetCancelSentIo); - WdfIoTargetStop(WdfUsbTargetPipeGetIoTarget(DeviceContext->BulkWritePipe), - WdfIoTargetCancelSentIo); -} - -NTSTATUS -StartAllPipes( - IN PDEVICE_CONTEXT DeviceContext - ) -{ - NTSTATUS status; - - status = WdfIoTargetStart(WdfUsbTargetPipeGetIoTarget(DeviceContext->InterruptPipe)); - if (!NT_SUCCESS(status)) { - return status; - } - - status = WdfIoTargetStart(WdfUsbTargetPipeGetIoTarget(DeviceContext->BulkReadPipe)); - if (!NT_SUCCESS(status)) { - return status; - } - - status = WdfIoTargetStart(WdfUsbTargetPipeGetIoTarget(DeviceContext->BulkWritePipe)); - if (!NT_SUCCESS(status)) { - return status; - } - - return status; -} - -_IRQL_requires_(PASSIVE_LEVEL) -NTSTATUS -ResetDevice( - _In_ WDFDEVICE Device - ) -/*++ - -Routine Description: - - This routine calls WdfUsbTargetDeviceResetPortSynchronously to reset the device if it's still - connected. - -Arguments: - - Device - Handle to a framework device - -Return Value: - - NT status value - ---*/ -{ - PDEVICE_CONTEXT pDeviceContext; - NTSTATUS status; - - PAGED_CODE(); - - TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTL, "--> ResetDevice\n"); - - pDeviceContext = GetDeviceContext(Device); - - // - // A NULL timeout indicates an infinite wake - // - status = WdfWaitLockAcquire(pDeviceContext->ResetDeviceWaitLock, NULL); - if (!NT_SUCCESS(status)) { - TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, "ResetDevice - could not acquire lock\n"); - return status; - } - - StopAllPipes(pDeviceContext); - - status = WdfUsbTargetDeviceResetPortSynchronously(pDeviceContext->UsbDevice); - if (!NT_SUCCESS(status)) { - TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, "ResetDevice failed - 0x%x\n", status); - } - - status = StartAllPipes(pDeviceContext); - if (!NT_SUCCESS(status)) { - TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, "Failed to start all pipes - 0x%x\n", status); - } - - WdfWaitLockRelease(pDeviceContext->ResetDeviceWaitLock); - - TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTL, "<-- ResetDevice\n"); - return status; -} - -_IRQL_requires_(PASSIVE_LEVEL) -NTSTATUS -ReenumerateDevice( - _In_ PDEVICE_CONTEXT DevContext - ) -/*++ - -Routine Description - - This routine re-enumerates the USB device. - -Arguments: - - pDevContext - One of our device extensions - -Return Value: - - NT status value - ---*/ -{ - NTSTATUS status; - WDF_USB_CONTROL_SETUP_PACKET controlSetupPacket; - WDF_REQUEST_SEND_OPTIONS sendOptions; - GUID activity; - - PAGED_CODE(); - - TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL,"--> ReenumerateDevice\n"); - - WDF_REQUEST_SEND_OPTIONS_INIT( - &sendOptions, - WDF_REQUEST_SEND_OPTION_TIMEOUT - ); - - WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT( - &sendOptions, - DEFAULT_CONTROL_TRANSFER_TIMEOUT - ); - - WDF_USB_CONTROL_SETUP_PACKET_INIT_VENDOR(&controlSetupPacket, - BmRequestHostToDevice, - BmRequestToDevice, - USBFX2LK_REENUMERATE, // Request - 0, // Value - 0); // Index - - - status = WdfUsbTargetDeviceSendControlTransferSynchronously( - DevContext->UsbDevice, - WDF_NO_HANDLE, // Optional WDFREQUEST - &sendOptions, - &controlSetupPacket, - NULL, // MemoryDescriptor - NULL); // BytesTransferred - - if(!NT_SUCCESS(status)) { - TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, - "ReenumerateDevice: Failed to Reenumerate - 0x%x \n", status); - } - - TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL,"<-- ReenumerateDevice\n"); - - // - // Send event to eventlog - // - - activity = DeviceToActivityId(WdfObjectContextGetObject(DevContext)); - EventWriteDeviceReenumerated(&activity, - DevContext->DeviceName, - DevContext->Location, - status); - - return status; - -} - -_IRQL_requires_(PASSIVE_LEVEL) -NTSTATUS -GetBarGraphState( - _In_ PDEVICE_CONTEXT DevContext, - _Out_ PBAR_GRAPH_STATE BarGraphState - ) -/*++ - -Routine Description - - This routine gets the state of the bar graph on the board - -Arguments: - - DevContext - One of our device extensions - - BarGraphState - Struct that receives the bar graph's state - -Return Value: - - NT status value - ---*/ -{ - NTSTATUS status; - WDF_USB_CONTROL_SETUP_PACKET controlSetupPacket; - WDF_REQUEST_SEND_OPTIONS sendOptions; - WDF_MEMORY_DESCRIPTOR memDesc; - ULONG bytesTransferred; - - PAGED_CODE(); - - TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "--> GetBarGraphState\n"); - - WDF_REQUEST_SEND_OPTIONS_INIT( - &sendOptions, - WDF_REQUEST_SEND_OPTION_TIMEOUT - ); - - WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT( - &sendOptions, - DEFAULT_CONTROL_TRANSFER_TIMEOUT - ); - - WDF_USB_CONTROL_SETUP_PACKET_INIT_VENDOR(&controlSetupPacket, - BmRequestDeviceToHost, - BmRequestToDevice, - USBFX2LK_READ_BARGRAPH_DISPLAY, // Request - 0, // Value - 0); // Index - - // - // Set the buffer to 0, the board will OR in everything that is set - // - BarGraphState->BarsAsUChar = 0; - - - WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&memDesc, - BarGraphState, - sizeof(BAR_GRAPH_STATE)); - - status = WdfUsbTargetDeviceSendControlTransferSynchronously( - DevContext->UsbDevice, - WDF_NO_HANDLE, // Optional WDFREQUEST - &sendOptions, - &controlSetupPacket, - &memDesc, - &bytesTransferred); - - if(!NT_SUCCESS(status)) { - - TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, - "GetBarGraphState: Failed to GetBarGraphState - 0x%x \n", status); - - } else { - - TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, - "GetBarGraphState: LED mask is 0x%x\n", BarGraphState->BarsAsUChar); - } - - TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "<-- GetBarGraphState\n"); - - return status; - -} - -_IRQL_requires_(PASSIVE_LEVEL) -NTSTATUS -SetBarGraphState( - _In_ PDEVICE_CONTEXT DevContext, - _In_ PBAR_GRAPH_STATE BarGraphState - ) -/*++ - -Routine Description - - This routine sets the state of the bar graph on the board - -Arguments: - - DevContext - One of our device extensions - - BarGraphState - Struct that describes the bar graph's desired state - -Return Value: - - NT status value - ---*/ -{ - NTSTATUS status; - WDF_USB_CONTROL_SETUP_PACKET controlSetupPacket; - WDF_REQUEST_SEND_OPTIONS sendOptions; - WDF_MEMORY_DESCRIPTOR memDesc; - ULONG bytesTransferred; - - PAGED_CODE(); - - TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "--> SetBarGraphState\n"); - - WDF_REQUEST_SEND_OPTIONS_INIT( - &sendOptions, - WDF_REQUEST_SEND_OPTION_TIMEOUT - ); - - WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT( - &sendOptions, - DEFAULT_CONTROL_TRANSFER_TIMEOUT - ); - - WDF_USB_CONTROL_SETUP_PACKET_INIT_VENDOR(&controlSetupPacket, - BmRequestHostToDevice, - BmRequestToDevice, - USBFX2LK_SET_BARGRAPH_DISPLAY, // Request - 0, // Value - 0); // Index - - WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&memDesc, - BarGraphState, - sizeof(BAR_GRAPH_STATE)); - - status = WdfUsbTargetDeviceSendControlTransferSynchronously( - DevContext->UsbDevice, - NULL, // Optional WDFREQUEST - &sendOptions, - &controlSetupPacket, - &memDesc, - &bytesTransferred); - - if(!NT_SUCCESS(status)) { - - TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, - "SetBarGraphState: Failed - 0x%x \n", status); - - } else { - - TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, - "SetBarGraphState: LED mask is 0x%x\n", BarGraphState->BarsAsUChar); - } - - TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "<-- SetBarGraphState\n"); - - return status; - -} - -_IRQL_requires_(PASSIVE_LEVEL) -NTSTATUS -GetSevenSegmentState( - _In_ PDEVICE_CONTEXT DevContext, - _Out_ PUCHAR SevenSegment - ) -/*++ - -Routine Description - - This routine gets the state of the 7 segment display on the board - by sending a synchronous control command. - - NOTE: It's not a good practice to send a synchronous request in the - context of the user thread because if the transfer takes long - time to complete, you end up holding the user thread. - - I'm choosing to do synchronous transfer because a) I know this one - completes immediately b) and for demonstration. - -Arguments: - - DevContext - One of our device extensions - - SevenSegment - receives the state of the 7 segment display - -Return Value: - - NT status value - ---*/ -{ - NTSTATUS status; - WDF_USB_CONTROL_SETUP_PACKET controlSetupPacket; - WDF_REQUEST_SEND_OPTIONS sendOptions; - - WDF_MEMORY_DESCRIPTOR memDesc; - ULONG bytesTransferred; - - TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "GetSetSevenSegmentState: Enter\n"); - - PAGED_CODE(); - - WDF_REQUEST_SEND_OPTIONS_INIT( - &sendOptions, - WDF_REQUEST_SEND_OPTION_TIMEOUT - ); - - WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT( - &sendOptions, - DEFAULT_CONTROL_TRANSFER_TIMEOUT - ); - - WDF_USB_CONTROL_SETUP_PACKET_INIT_VENDOR(&controlSetupPacket, - BmRequestDeviceToHost, - BmRequestToDevice, - USBFX2LK_READ_7SEGMENT_DISPLAY, // Request - 0, // Value - 0); // Index - - // - // Set the buffer to 0, the board will OR in everything that is set - // - *SevenSegment = 0; - - WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&memDesc, - SevenSegment, - sizeof(UCHAR)); - - status = WdfUsbTargetDeviceSendControlTransferSynchronously( - DevContext->UsbDevice, - NULL, // Optional WDFREQUEST - &sendOptions, - &controlSetupPacket, - &memDesc, - &bytesTransferred); - - if(!NT_SUCCESS(status)) { - - TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, - "GetSevenSegmentState: Failed to get 7 Segment state - 0x%x \n", status); - } else { - - TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, - "GetSevenSegmentState: 7 Segment mask is 0x%x\n", *SevenSegment); - } - - TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "GetSetSevenSegmentState: Exit\n"); - - return status; - -} - -_IRQL_requires_(PASSIVE_LEVEL) -NTSTATUS -SetSevenSegmentState( - _In_ PDEVICE_CONTEXT DevContext, - _In_ PUCHAR SevenSegment - ) -/*++ - -Routine Description - - This routine sets the state of the 7 segment display on the board - -Arguments: - - DevContext - One of our device extensions - - SevenSegment - desired state of the 7 segment display - -Return Value: - - NT status value - ---*/ -{ - NTSTATUS status; - WDF_USB_CONTROL_SETUP_PACKET controlSetupPacket; - WDF_REQUEST_SEND_OPTIONS sendOptions; - WDF_MEMORY_DESCRIPTOR memDesc; - ULONG bytesTransferred; - - PAGED_CODE(); - - TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "--> SetSevenSegmentState\n"); - - WDF_REQUEST_SEND_OPTIONS_INIT( - &sendOptions, - WDF_REQUEST_SEND_OPTION_TIMEOUT - ); - - WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT( - &sendOptions, - DEFAULT_CONTROL_TRANSFER_TIMEOUT - ); - - WDF_USB_CONTROL_SETUP_PACKET_INIT_VENDOR(&controlSetupPacket, - BmRequestHostToDevice, - BmRequestToDevice, - USBFX2LK_SET_7SEGMENT_DISPLAY, // Request - 0, // Value - 0); // Index - - WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&memDesc, - SevenSegment, - sizeof(UCHAR)); - - status = WdfUsbTargetDeviceSendControlTransferSynchronously( - DevContext->UsbDevice, - NULL, // Optional WDFREQUEST - &sendOptions, - &controlSetupPacket, - &memDesc, - &bytesTransferred); - - if(!NT_SUCCESS(status)) { - - TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, - "SetSevenSegmentState: Failed to set 7 Segment state - 0x%x \n", status); - - } else { - - TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, - "SetSevenSegmentState: 7 Segment mask is 0x%x\n", *SevenSegment); - - } - - TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "<-- SetSevenSegmentState\n"); - - return status; - -} - -_IRQL_requires_(PASSIVE_LEVEL) -NTSTATUS -GetSwitchState( - _In_ PDEVICE_CONTEXT DevContext, - _In_ PSWITCH_STATE SwitchState - ) -/*++ - -Routine Description - - This routine gets the state of the switches on the board - -Arguments: - - DevContext - One of our device extensions - -Return Value: - - NT status value - ---*/ -{ - NTSTATUS status; - WDF_USB_CONTROL_SETUP_PACKET controlSetupPacket; - WDF_REQUEST_SEND_OPTIONS sendOptions; - WDF_MEMORY_DESCRIPTOR memDesc; - ULONG bytesTransferred; - - TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "--> GetSwitchState\n"); - - PAGED_CODE(); - - WDF_REQUEST_SEND_OPTIONS_INIT( - &sendOptions, - WDF_REQUEST_SEND_OPTION_TIMEOUT - ); - - WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT( - &sendOptions, - DEFAULT_CONTROL_TRANSFER_TIMEOUT - ); - - WDF_USB_CONTROL_SETUP_PACKET_INIT_VENDOR(&controlSetupPacket, - BmRequestDeviceToHost, - BmRequestToDevice, - USBFX2LK_READ_SWITCHES, // Request - 0, // Value - 0); // Index - - SwitchState->SwitchesAsUChar = 0; - - WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&memDesc, - SwitchState, - sizeof(SWITCH_STATE)); - - status = WdfUsbTargetDeviceSendControlTransferSynchronously( - DevContext->UsbDevice, - NULL, // Optional WDFREQUEST - &sendOptions, - &controlSetupPacket, - &memDesc, - &bytesTransferred); - - if(!NT_SUCCESS(status)) { - TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, - "GetSwitchState: Failed to Get switches - 0x%x \n", status); - - } else { - TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, - "GetSwitchState: Switch mask is 0x%x\n", SwitchState->SwitchesAsUChar); - } - - TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "<-- GetSwitchState\n"); - - return status; - -} - - -VOID -OsrUsbIoctlGetInterruptMessage( - _In_ WDFDEVICE Device, - _In_ NTSTATUS ReaderStatus - ) -/*++ - -Routine Description - - This method handles the completion of the pended request for the IOCTL - IOCTL_OSRUSBFX2_GET_INTERRUPT_MESSAGE. - -Arguments: - - Device - Handle to a framework device. - -Return Value: - - None. - ---*/ -{ - NTSTATUS status; - WDFREQUEST request; - PDEVICE_CONTEXT pDevContext; - size_t bytesReturned = 0; - PSWITCH_STATE switchState = NULL; - - pDevContext = GetDeviceContext(Device); - - do { - - // - // Check if there are any pending requests in the Interrupt Message Queue. - // If a request is found then complete the pending request. - // - status = WdfIoQueueRetrieveNextRequest(pDevContext->InterruptMsgQueue, &request); - - if (NT_SUCCESS(status)) { - status = WdfRequestRetrieveOutputBuffer(request, - sizeof(SWITCH_STATE), - &switchState, - NULL);// BufferLength - - if (!NT_SUCCESS(status)) { - - TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, - "User's output buffer is too small for this IOCTL, expecting a SWITCH_STATE\n"); - bytesReturned = sizeof(SWITCH_STATE); - - } else { - - // - // Copy the state information saved by the continuous reader. - // - if (NT_SUCCESS(ReaderStatus)) { - switchState->SwitchesAsUChar = pDevContext->CurrentSwitchState; - bytesReturned = sizeof(SWITCH_STATE); - } else { - bytesReturned = 0; - } - } - - // - // Complete the request. If we failed to get the output buffer then - // complete with that status. Otherwise complete with the status from the reader. - // - WdfRequestCompleteWithInformation(request, - NT_SUCCESS(status) ? ReaderStatus : status, - bytesReturned); - status = STATUS_SUCCESS; - - } else if (status != STATUS_NO_MORE_ENTRIES) { - KdPrint(("WdfIoQueueRetrieveNextRequest status %08x\n", status)); - } - - request = NULL; - - } while (status == STATUS_SUCCESS); - - return; - -} - - diff --git a/usb/umdf_filter_kmdf/kmdf_driver/osrusbfx2.h b/usb/umdf_filter_kmdf/kmdf_driver/osrusbfx2.h deleted file mode 100644 index 909e347d..00000000 --- a/usb/umdf_filter_kmdf/kmdf_driver/osrusbfx2.h +++ /dev/null @@ -1,335 +0,0 @@ -/*++ - -Copyright (c) Microsoft Corporation. All rights reserved. - - THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY - KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR - PURPOSE. - -Module Name: - - private.h - -Abstract: - - Contains structure definitions and function prototypes private to - the driver. - -Environment: - - Kernel mode - ---*/ - -#include -#include -#include "usbdi.h" -#include "usbdlib.h" -#include "public.h" -#include "driverspecs.h" -#include -#include -#define NTSTRSAFE_LIB -#include - -#include "trace.h" - -// -// Include auto-generated ETW event functions (created by MC.EXE from -// osrusbfx2.man) -// -#include "fx2Events.h" - -#ifndef _PRIVATE_H -#define _PRIVATE_H - -#define POOL_TAG (ULONG) 'FRSO' -#define _DRIVER_NAME_ "OSRUSBFX2" - -#define TEST_BOARD_TRANSFER_BUFFER_SIZE (64*1024) -#define DEVICE_DESC_LENGTH 256 - -extern const __declspec(selectany) LONGLONG DEFAULT_CONTROL_TRANSFER_TIMEOUT = 5 * -1 * WDF_TIMEOUT_TO_SEC; - -// -// Define the vendor commands supported by our device -// -#define USBFX2LK_READ_7SEGMENT_DISPLAY 0xD4 -#define USBFX2LK_READ_SWITCHES 0xD6 -#define USBFX2LK_READ_BARGRAPH_DISPLAY 0xD7 -#define USBFX2LK_SET_BARGRAPH_DISPLAY 0xD8 -#define USBFX2LK_IS_HIGH_SPEED 0xD9 -#define USBFX2LK_REENUMERATE 0xDA -#define USBFX2LK_SET_7SEGMENT_DISPLAY 0xDB - -// -// Define the features that we can clear -// and set on our device -// -#define USBFX2LK_FEATURE_EPSTALL 0x00 -#define USBFX2LK_FEATURE_WAKE 0x01 - -// -// Order of endpoints in the interface descriptor -// -#define INTERRUPT_IN_ENDPOINT_INDEX 0 -#define BULK_OUT_ENDPOINT_INDEX 1 -#define BULK_IN_ENDPOINT_INDEX 2 - -// -// A structure representing the instance information associated with -// this particular device. -// - -typedef struct _DEVICE_CONTEXT { - - WDFUSBDEVICE UsbDevice; - - WDFUSBINTERFACE UsbInterface; - - WDFUSBPIPE BulkReadPipe; - - WDFUSBPIPE BulkWritePipe; - - WDFUSBPIPE InterruptPipe; - - WDFWAITLOCK ResetDeviceWaitLock; - - UCHAR CurrentSwitchState; - - WDFQUEUE InterruptMsgQueue; - - ULONG UsbDeviceTraits; - - // - // The following fields are used during event logging to - // report the events relative to this specific instance - // of the device. - // - - WDFMEMORY DeviceNameMemory; - PCWSTR DeviceName; - - WDFMEMORY LocationMemory; - PCWSTR Location; - -} DEVICE_CONTEXT, *PDEVICE_CONTEXT; - -WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(DEVICE_CONTEXT, GetDeviceContext) - -extern ULONG DebugLevel; - -typedef -NTSTATUS -(*PFN_IO_GET_ACTIVITY_ID_IRP) ( - _In_ PIRP Irp, - _Out_ LPGUID Guid - ); - -typedef -NTSTATUS -(*PFN_IO_SET_DEVICE_INTERFACE_PROPERTY_DATA) ( - _In_ PUNICODE_STRING SymbolicLinkName, - _In_ CONST DEVPROPKEY *PropertyKey, - _In_ LCID Lcid, - _In_ ULONG Flags, - _In_ DEVPROPTYPE Type, - _In_ ULONG Size, - _In_opt_ PVOID Data - ); - -// -// Global function pointer set in DriverEntry -// Check for NULL before using -// -extern PFN_IO_GET_ACTIVITY_ID_IRP g_pIoGetActivityIdIrp; - -extern PFN_IO_SET_DEVICE_INTERFACE_PROPERTY_DATA g_pIoSetDeviceInterfacePropertyData; - -DRIVER_INITIALIZE DriverEntry; - -EVT_WDF_OBJECT_CONTEXT_CLEANUP OsrFxEvtDriverContextCleanup; - -EVT_WDF_DRIVER_DEVICE_ADD OsrFxEvtDeviceAdd; - -EVT_WDF_DEVICE_PREPARE_HARDWARE OsrFxEvtDevicePrepareHardware; - -EVT_WDF_IO_QUEUE_IO_READ OsrFxEvtIoRead; - -EVT_WDF_IO_QUEUE_IO_WRITE OsrFxEvtIoWrite; - -EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL OsrFxEvtIoDeviceControl; - -EVT_WDF_REQUEST_COMPLETION_ROUTINE EvtRequestReadCompletionRoutine; - -EVT_WDF_REQUEST_COMPLETION_ROUTINE EvtRequestWriteCompletionRoutine; - -_IRQL_requires_(PASSIVE_LEVEL) -NTSTATUS -ResetPipe( - _In_ WDFUSBPIPE Pipe - ); - -_IRQL_requires_(PASSIVE_LEVEL) -NTSTATUS -ResetDevice( - _In_ WDFDEVICE Device - ); - -_IRQL_requires_(PASSIVE_LEVEL) -NTSTATUS -SelectInterfaces( - _In_ WDFDEVICE Device - ); - -_IRQL_requires_(PASSIVE_LEVEL) -NTSTATUS -ReenumerateDevice( - _In_ PDEVICE_CONTEXT DevContext - ); - -_IRQL_requires_(PASSIVE_LEVEL) -NTSTATUS -GetBarGraphState( - _In_ PDEVICE_CONTEXT DevContext, - _Out_ PBAR_GRAPH_STATE BarGraphState - ); - -_IRQL_requires_(PASSIVE_LEVEL) -NTSTATUS -SetBarGraphState( - _In_ PDEVICE_CONTEXT DevContext, - _In_ PBAR_GRAPH_STATE BarGraphState - ); - -_IRQL_requires_(PASSIVE_LEVEL) -NTSTATUS -GetSevenSegmentState( - _In_ PDEVICE_CONTEXT DevContext, - _Out_ PUCHAR SevenSegment - ); - -_IRQL_requires_(PASSIVE_LEVEL) -NTSTATUS -SetSevenSegmentState( - _In_ PDEVICE_CONTEXT DevContext, - _In_ PUCHAR SevenSegment - ); - -_IRQL_requires_(PASSIVE_LEVEL) -NTSTATUS -GetSwitchState( - _In_ PDEVICE_CONTEXT DevContext, - _In_ PSWITCH_STATE SwitchState - ); - -VOID -OsrUsbIoctlGetInterruptMessage( - _In_ WDFDEVICE Device, - _In_ NTSTATUS ReaderStatus - ); - -_IRQL_requires_(PASSIVE_LEVEL) -NTSTATUS -OsrFxSetPowerPolicy( - _In_ WDFDEVICE Device - ); - -_IRQL_requires_(PASSIVE_LEVEL) -NTSTATUS -OsrFxConfigContReaderForInterruptEndPoint( - _In_ PDEVICE_CONTEXT DeviceContext - ); - -EVT_WDF_USB_READER_COMPLETION_ROUTINE OsrFxEvtUsbInterruptPipeReadComplete; - -EVT_WDF_USB_READERS_FAILED OsrFxEvtUsbInterruptReadersFailed; - -EVT_WDF_IO_QUEUE_IO_STOP OsrFxEvtIoStop; - -EVT_WDF_DEVICE_D0_ENTRY OsrFxEvtDeviceD0Entry; - -EVT_WDF_DEVICE_D0_EXIT OsrFxEvtDeviceD0Exit; - -EVT_WDF_DEVICE_SELF_MANAGED_IO_FLUSH OsrFxEvtDeviceSelfManagedIoFlush; - -_IRQL_requires_(PASSIVE_LEVEL) -BOOLEAN -OsrFxReadFdoRegistryKeyValue( - _In_ PWDFDEVICE_INIT DeviceInit, - _In_ PWCHAR Name, - _Out_ PULONG Value - ); - -_IRQL_requires_max_(DISPATCH_LEVEL) -VOID -OsrFxEnumerateChildren( - _In_ WDFDEVICE Device - ); - -_IRQL_requires_(PASSIVE_LEVEL) -VOID -GetDeviceEventLoggingNames( - _In_ WDFDEVICE Device - ); - -_IRQL_requires_(PASSIVE_LEVEL) -PCHAR -DbgDevicePowerString( - _In_ WDF_POWER_DEVICE_STATE Type - ); - - -_IRQL_requires_(PASSIVE_LEVEL) -USBD_STATUS -OsrFxValidateConfigurationDescriptor( - _In_reads_bytes_(BufferLength) PUSB_CONFIGURATION_DESCRIPTOR ConfigDesc, - _In_ ULONG BufferLength, - _Inout_ PUCHAR *Offset - ); - -FORCEINLINE -GUID -RequestToActivityId( - _In_ WDFREQUEST Request - ) -{ - GUID activity = {0}; - NTSTATUS status = STATUS_SUCCESS; - - if (g_pIoGetActivityIdIrp != NULL) { - - // - // Use activity ID generated by application (or IO manager) - // - status = g_pIoGetActivityIdIrp(WdfRequestWdmGetIrp(Request), &activity); - } - - if (g_pIoGetActivityIdIrp == NULL || !NT_SUCCESS(status)) { - - // - // Fall back to using the WDFREQUEST handle as the activity ID - // - RtlCopyMemory(&activity, &Request, sizeof(WDFREQUEST)); - } - - - return activity; -} - -FORCEINLINE -GUID -DeviceToActivityId( - _In_ WDFDEVICE Device - ) -{ - GUID activity = {0}; - RtlCopyMemory(&activity, &Device, sizeof(WDFDEVICE)); - return activity; -} - - -#endif - - diff --git a/usb/umdf_filter_kmdf/kmdf_driver/osrusbfx2.man b/usb/umdf_filter_kmdf/kmdf_driver/osrusbfx2.man deleted file mode 100644 index 176dfc89..00000000 --- a/usb/umdf_filter_kmdf/kmdf_driver/osrusbfx2.man +++ /dev/null @@ -1,309 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/usb/umdf_filter_kmdf/kmdf_driver/osrusbfx2.rc b/usb/umdf_filter_kmdf/kmdf_driver/osrusbfx2.rc deleted file mode 100644 index 092ec195..00000000 --- a/usb/umdf_filter_kmdf/kmdf_driver/osrusbfx2.rc +++ /dev/null @@ -1,18 +0,0 @@ -#include - -#include - -#define VER_FILETYPE VFT_DRV -#define VER_FILESUBTYPE VFT2_DRV_SYSTEM -#define VER_FILEDESCRIPTION_STR "WDF Sample Driver for OSR USB-FX2 Learning Kit" -#define VER_INTERNALNAME_STR "osrusbfx2.sys" -#define VER_ORIGINALFILENAME_STR "osrusbfx2.sys" - -#include "common.ver" - -// -// Include auto-generated string resources (created by MC.EXE from -// osrusbfx2.man) -// - -#include "fx2Events.rc" diff --git a/usb/umdf_filter_kmdf/kmdf_driver/osrusbfx2.vcxproj b/usb/umdf_filter_kmdf/kmdf_driver/osrusbfx2.vcxproj deleted file mode 100644 index 187c5aba..00000000 --- a/usb/umdf_filter_kmdf/kmdf_driver/osrusbfx2.vcxproj +++ /dev/null @@ -1,245 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - {23EAF474-B558-4457-B03C-164DA83B7575} - $(MSBuildProjectName) - 1 - false - true - Debug - Win32 - {634111FB-6184-4A00-8450-38992AB88BED} - - - - Windows10 - False - Desktop - KMDF - WindowsKernelModeDriver10.0 - Driver - - - Windows10 - True - Desktop - KMDF - WindowsKernelModeDriver10.0 - Driver - - - Windows10 - False - Desktop - KMDF - WindowsKernelModeDriver10.0 - Driver - - - Windows10 - True - Desktop - KMDF - WindowsKernelModeDriver10.0 - Driver - - - - $(IntDir) - - - - - - - - - - - - - - - - true - true - TraceEvents(LEVEL,FLAGS,MSG,...) - {km-WdfDefault.tpl}*.tmh - - - true - true - .\$(IntDir) - true - .\$(IntDir) - true - fx2Events - true - - - true - true - TraceEvents(LEVEL,FLAGS,MSG,...) - {km-WdfDefault.tpl}*.tmh - - - - osrusbfx2 - - - osrusbfx2 - - - osrusbfx2 - - - osrusbfx2 - - - - %(AdditionalIncludeDirectories);..\inc - %(PreprocessorDefinitions);EVENT_TRACING - - - %(AdditionalIncludeDirectories);..\inc - true - Level4 - %(PreprocessorDefinitions);EVENT_TRACING - - - %(AdditionalIncludeDirectories);..\inc - %(PreprocessorDefinitions);EVENT_TRACING - - - %(AdditionalDependencies);$(DDK_LIB_PATH)\ntstrsafe.lib;$(DDK_LIB_PATH)\usbd.lib - - - - - %(AdditionalIncludeDirectories);..\inc - %(PreprocessorDefinitions);EVENT_TRACING - - - %(AdditionalIncludeDirectories);..\inc - true - Level4 - %(PreprocessorDefinitions);EVENT_TRACING - - - %(AdditionalIncludeDirectories);..\inc - %(PreprocessorDefinitions);EVENT_TRACING - - - %(AdditionalDependencies);$(DDK_LIB_PATH)\ntstrsafe.lib;$(DDK_LIB_PATH)\usbd.lib - - - - - %(AdditionalIncludeDirectories);..\inc - %(PreprocessorDefinitions);EVENT_TRACING - - - %(AdditionalIncludeDirectories);..\inc - true - Level4 - %(PreprocessorDefinitions);EVENT_TRACING - - - %(AdditionalIncludeDirectories);..\inc - %(PreprocessorDefinitions);EVENT_TRACING - - - %(AdditionalDependencies);$(DDK_LIB_PATH)\ntstrsafe.lib;$(DDK_LIB_PATH)\usbd.lib - - - - - %(AdditionalIncludeDirectories);..\inc - %(PreprocessorDefinitions);EVENT_TRACING - - - %(AdditionalIncludeDirectories);..\inc - true - Level4 - %(PreprocessorDefinitions);EVENT_TRACING - - - %(AdditionalIncludeDirectories);..\inc - %(PreprocessorDefinitions);EVENT_TRACING - - - %(AdditionalDependencies);$(DDK_LIB_PATH)\ntstrsafe.lib;$(DDK_LIB_PATH)\usbd.lib - - - - 1 - - - 1 - - - 1 - - - 1 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/usb/umdf_filter_kmdf/kmdf_driver/osrusbfx2.vcxproj.Filters b/usb/umdf_filter_kmdf/kmdf_driver/osrusbfx2.vcxproj.Filters deleted file mode 100644 index 2b60d58b..00000000 --- a/usb/umdf_filter_kmdf/kmdf_driver/osrusbfx2.vcxproj.Filters +++ /dev/null @@ -1,46 +0,0 @@ - - - - - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {5B33A1A5-0088-41DD-B8DD-CB322223AFD2} - - - h;hpp;hxx;hm;inl;inc;xsd - {5E63DCDC-A400-4A86-8C33-C6C83D50CC49} - - - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {F97C10AC-837D-4657-B682-DD6E00ADE8A6} - - - inf;inv;inx;mof;mc; - {E7563CE1-E6A4-4746-87FA-4C8E3981C313} - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Resource Files - - - Resource Files - - - \ No newline at end of file diff --git a/usb/umdf_filter_kmdf/kmdf_driver/trace.h b/usb/umdf_filter_kmdf/kmdf_driver/trace.h deleted file mode 100644 index 518ff5f1..00000000 --- a/usb/umdf_filter_kmdf/kmdf_driver/trace.h +++ /dev/null @@ -1,115 +0,0 @@ -/*++ - -Copyright (c) Microsoft Corporation. All rights reserved. - - THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY - KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR - PURPOSE. - -Module Name: - - TRACE.h - -Abstract: - - Header file for the debug tracing related function defintions and macros. - -Environment: - - Kernel mode - ---*/ - -#include // For TRACE_LEVEL definitions - -#if !defined(EVENT_TRACING) - -// -// TODO: These defines are missing in evntrace.h -// in some DDK build environments (XP). -// -#if !defined(TRACE_LEVEL_NONE) - #define TRACE_LEVEL_NONE 0 - #define TRACE_LEVEL_CRITICAL 1 - #define TRACE_LEVEL_FATAL 1 - #define TRACE_LEVEL_ERROR 2 - #define TRACE_LEVEL_WARNING 3 - #define TRACE_LEVEL_INFORMATION 4 - #define TRACE_LEVEL_VERBOSE 5 - #define TRACE_LEVEL_RESERVED6 6 - #define TRACE_LEVEL_RESERVED7 7 - #define TRACE_LEVEL_RESERVED8 8 - #define TRACE_LEVEL_RESERVED9 9 -#endif - - -// -// Define Debug Flags -// -#define DBG_INIT 0x00000001 -#define DBG_PNP 0x00000002 -#define DBG_POWER 0x00000004 -#define DBG_WMI 0x00000008 -#define DBG_CREATE_CLOSE 0x00000010 -#define DBG_IOCTL 0x00000020 -#define DBG_WRITE 0x00000040 -#define DBG_READ 0x00000080 - - -VOID -TraceEvents ( - _In_ ULONG DebugPrintLevel, - _In_ ULONG DebugPrintFlag, - _Printf_format_string_ - _In_ PCSTR DebugMessage, - ... - ); - -#define WPP_INIT_TRACING(DriverObject, RegistryPath) -#define WPP_CLEANUP(DriverObject) - -#else -// -// If software tracing is defined in the sources file.. -// WPP_DEFINE_CONTROL_GUID specifies the GUID used for this driver. -// *** REPLACE THE GUID WITH YOUR OWN UNIQUE ID *** -// WPP_DEFINE_BIT allows setting debug bit masks to selectively print. -// The names defined in the WPP_DEFINE_BIT call define the actual names -// that are used to control the level of tracing for the control guid -// specified. -// -// NOTE: If you are adopting this sample for your driver, please generate -// a new guid, using tools\other\i386\guidgen.exe present in the -// DDK. -// -// Name of the logger is OSRUSBFX2 and the guid is -// {D23A0C5A-D307-4f0e-AE8E-E2A355AD5DAB} -// (0xd23a0c5a, 0xd307, 0x4f0e, 0xae, 0x8e, 0xe2, 0xa3, 0x55, 0xad, 0x5d, 0xab); -// - -#define WPP_CHECK_FOR_NULL_STRING //to prevent exceptions due to NULL strings - -#define WPP_CONTROL_GUIDS \ - WPP_DEFINE_CONTROL_GUID(OsrUsbFxTraceGuid,(d23a0c5a,d307,4f0e,ae8e,E2A355AD5DAB), \ - WPP_DEFINE_BIT(DBG_INIT) /* bit 0 = 0x00000001 */ \ - WPP_DEFINE_BIT(DBG_PNP) /* bit 1 = 0x00000002 */ \ - WPP_DEFINE_BIT(DBG_POWER) /* bit 2 = 0x00000004 */ \ - WPP_DEFINE_BIT(DBG_WMI) /* bit 3 = 0x00000008 */ \ - WPP_DEFINE_BIT(DBG_CREATE_CLOSE) /* bit 4 = 0x00000010 */ \ - WPP_DEFINE_BIT(DBG_IOCTL) /* bit 5 = 0x00000020 */ \ - WPP_DEFINE_BIT(DBG_WRITE) /* bit 6 = 0x00000040 */ \ - WPP_DEFINE_BIT(DBG_READ) /* bit 7 = 0x00000080 */ \ - /* You can have up to 32 defines. If you want more than that,\ - you have to provide another trace control GUID */\ - ) - - -#define WPP_LEVEL_FLAGS_LOGGER(lvl,flags) WPP_LEVEL_LOGGER(flags) -#define WPP_LEVEL_FLAGS_ENABLED(lvl, flags) (WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level >= lvl) - - -#endif - - - diff --git a/usb/umdf_filter_kmdf/umdf_filter/OsrUsbFilter.rc b/usb/umdf_filter_kmdf/umdf_filter/OsrUsbFilter.rc deleted file mode 100644 index cec032d9..00000000 --- a/usb/umdf_filter_kmdf/umdf_filter/OsrUsbFilter.rc +++ /dev/null @@ -1,17 +0,0 @@ -//--------------------------------------------------------------------------- -// OsrUsbFilter.rc -// -// Copyright (c) Microsoft Corporation, All Rights Reserved -//--------------------------------------------------------------------------- - - -#include -#include - -#define VER_FILETYPE VFT_DLL -#define VER_FILESUBTYPE VFT_UNKNOWN -#define VER_FILEDESCRIPTION_STR "WDF:UMDF OsrUsbFilter User-Mode Driver Sample" -#define VER_INTERNALNAME_STR "OsrUsbFilter" -#define VER_ORIGINALFILENAME_STR "OsrUsbFilter.dll" - -#include "common.ver" diff --git a/usb/umdf_filter_kmdf/umdf_filter/WUDFOsrUsbFilter.vcxproj b/usb/umdf_filter_kmdf/umdf_filter/WUDFOsrUsbFilter.vcxproj deleted file mode 100644 index bf1103dd..00000000 --- a/usb/umdf_filter_kmdf/umdf_filter/WUDFOsrUsbFilter.vcxproj +++ /dev/null @@ -1,287 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - {0149B701-5356-434C-AC8C-07CAA1D9A4AA} - $(MSBuildProjectName) - 1 - 1 - false - true - Debug - Win32 - {AD8E5857-7AEF-4A01-8436-7748CEF29EC4} - - - - Windows10 - False - Desktop - UMDF - WindowsUserModeDriver10.0 - DynamicLibrary - - - Windows10 - True - Desktop - UMDF - WindowsUserModeDriver10.0 - DynamicLibrary - - - Windows10 - False - Desktop - UMDF - WindowsUserModeDriver10.0 - DynamicLibrary - - - Windows10 - True - Desktop - UMDF - WindowsUserModeDriver10.0 - DynamicLibrary - - - - $(IntDir) - - - - - - - - - - - - - - - - true - true - internal.h - - - $(InfArch) - true - .\$(IntDir)\WUDFOsrUsbFilterOnKmDriver.Inf - - - true - true - internal.h - - - - WUDFOsrUsbFilter - - - WUDFOsrUsbFilter - - - WUDFOsrUsbFilter - - - WUDFOsrUsbFilter - - - - %(PreprocessorDefinitions);_UNICODE;UNICODE - - - %(PreprocessorDefinitions);_UNICODE;UNICODE - - - %(PreprocessorDefinitions);_UNICODE;UNICODE - - - - - %(PreprocessorDefinitions);_UNICODE;UNICODE - - - %(PreprocessorDefinitions);_UNICODE;UNICODE - - - %(PreprocessorDefinitions);_UNICODE;UNICODE - - - - - %(PreprocessorDefinitions);_UNICODE;UNICODE - - - %(PreprocessorDefinitions);_UNICODE;UNICODE - - - %(PreprocessorDefinitions);_UNICODE;UNICODE - - - - - %(PreprocessorDefinitions);_UNICODE;UNICODE - - - %(PreprocessorDefinitions);_UNICODE;UNICODE - - - %(PreprocessorDefinitions);_UNICODE;UNICODE - - - - 0x0A00 - 0x0A000000 - - - 0x0A00 - 0x0A000000 - - - 0x0A00 - 0x0A000000 - - - 0x0A00 - 0x0A000000 - - - - _DllMainCRTStartup@12 - _DllMainCRTStartup - - - - - _DllMainCRTStartup@12 - _DllMainCRTStartup - - - - - _DllMainCRTStartup@12 - _DllMainCRTStartup - - - - - _DllMainCRTStartup@12 - _DllMainCRTStartup - - - - - %(AdditionalIncludeDirectories);..\..\..\inc - - - %(AdditionalIncludeDirectories);..\..\..\inc - true - Level4 - - - - - %(AdditionalIncludeDirectories);..\..\..\inc - - - %(AdditionalDependencies);$(SDK_LIB_PATH)\strsafe.lib;$(SDK_LIB_PATH)\kernel32.lib;$(SDK_LIB_PATH)\advapi32.lib - exports.def - - - - - %(AdditionalIncludeDirectories);..\..\..\inc - - - %(AdditionalIncludeDirectories);..\..\..\inc - true - Level4 - - - - - %(AdditionalIncludeDirectories);..\..\..\inc - - - %(AdditionalDependencies);$(SDK_LIB_PATH)\strsafe.lib;$(SDK_LIB_PATH)\kernel32.lib;$(SDK_LIB_PATH)\advapi32.lib - exports.def - - - - - %(AdditionalIncludeDirectories);..\..\..\inc - - - %(AdditionalIncludeDirectories);..\..\..\inc - true - Level4 - - - - - %(AdditionalIncludeDirectories);..\..\..\inc - - - %(AdditionalDependencies);$(SDK_LIB_PATH)\strsafe.lib;$(SDK_LIB_PATH)\kernel32.lib;$(SDK_LIB_PATH)\advapi32.lib - exports.def - - - - - %(AdditionalIncludeDirectories);..\..\..\inc - - - %(AdditionalIncludeDirectories);..\..\..\inc - true - Level4 - - - - - %(AdditionalIncludeDirectories);..\..\..\inc - - - %(AdditionalDependencies);$(SDK_LIB_PATH)\strsafe.lib;$(SDK_LIB_PATH)\kernel32.lib;$(SDK_LIB_PATH)\advapi32.lib - exports.def - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/usb/umdf_filter_kmdf/umdf_filter/WUDFOsrUsbFilter.vcxproj.Filters b/usb/umdf_filter_kmdf/umdf_filter/WUDFOsrUsbFilter.vcxproj.Filters deleted file mode 100644 index 6c035c03..00000000 --- a/usb/umdf_filter_kmdf/umdf_filter/WUDFOsrUsbFilter.vcxproj.Filters +++ /dev/null @@ -1,51 +0,0 @@ - - - - - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {33CB427D-970A-48D7-9257-328CC86ACBDA} - - - h;hpp;hxx;hm;inl;inc;xsd - {3107D133-7EB4-4E28-8B1B-13EF0595395D} - - - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {90D3C591-7FB6-4F06-9CDB-1F008F0CD090} - - - inf;inv;inx;mof;mc; - {1440CBCB-215A-492F-906D-F0ABE90BA456} - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Driver Files - - - - - Resource Files - - - \ No newline at end of file diff --git a/usb/umdf_filter_kmdf/umdf_filter/WUDFOsrUsbFilterOnKmDriver.inx b/usb/umdf_filter_kmdf/umdf_filter/WUDFOsrUsbFilterOnKmDriver.inx deleted file mode 100644 index 429b5afa..00000000 --- a/usb/umdf_filter_kmdf/umdf_filter/WUDFOsrUsbFilterOnKmDriver.inx +++ /dev/null @@ -1,123 +0,0 @@ -; -; INF for installing OSR USB user-mode filter driver on top of OSR USB KMDF (final) sample driver -; You will need to have the user-mode filter driver and KMDF function driver in one install location -; The KMDF files needed are: -; osrusbfx2.sys (final version) -; WdfCoInstallerxxxx.dll (the KMDF coinstaller) -; - -[Version] -Signature="$WINDOWS NT$" -Class=Sample -ClassGuid={78A1C341-4539-11d3-B88D-00C04FAD5171} -Provider=%MSFT% -DriverVer=10/01/2002,6.0.5058.0 -CatalogFile=wudf.cat - - -; ================= Class section ===================== - -[ClassInstall32] -Addreg=SampleClassReg - -[SampleClassReg] -HKR,,,0,%ClassName% -HKR,,Icon,,-5 - - -; ================= Device section ===================== - -[Manufacturer] -%MfgName%=Microsoft,NT$ARCH$ - -; For XP and later -[Microsoft.NT$ARCH$] -%USB\VID_045E&PID_930A.DeviceDesc%=osrusbfx2, USB\VID_0547&PID_1002 - -[osrusbfx2.NT] -CopyFiles=osrusbfx2.Files.Ext,UMDriverCopy - -[osrusbfx2.NT.hw] -AddReg=OsrUsb_AddReg - - -[osrusbfx2.NT.CoInstallers] -AddReg=CoInstaller_AddReg -CopyFiles=CoInstaller_CopyFiles - -[osrusbfx2.NT.Services] -AddService=WUDFRd,0x000001f8,WUDFRD_ServiceInstall -AddService=osrusbfx2, 0x000001fa, osrusbfx2.AddService ;flag 0x2 sets this as the service for the device - -[osrusbfx2.NT.Wdf] -KmdfService=osrusbfx2, osrusbfx2_wdfsect -UmdfService="WUDFOsrUsbFilter", WudfOsrUsbFilter_Install -UmdfServiceOrder=WUDFOsrUsbFilter - -[OsrUsb_AddReg] -HKR,,"UpperFilters",0x00010008,"WUDFRd" ; FLG_ADDREG_TYPE_MULTI_SZ | FLG_ADDREG_APPEND - - -[WudfOsrUsbFilter_Install] -UmdfLibraryVersion=$UMDFVERSION$ -DriverCLSID = "{422d8dbc-520d-4d7e-8f53-920e5c867e6c}" -ServiceBinary = "%12%\UMDF\WUDFOsrUsbFilter.dll" - -[osrusbfx2_wdfsect] -KmdfLibraryVersion=$KMDFVERSION$ - -[WUDFRD_ServiceInstall] -DisplayName = %WudfRdDisplayName% -ServiceType = 1 -StartType = 3 -ErrorControl = 1 -ServiceBinary = %12%\WUDFRd.sys - -[osrusbfx2.AddService] -DisplayName = %osrusbfx2.SvcDesc% -ServiceType = 1 ; SERVICE_KERNEL_DRIVER -StartType = 3 ; SERVICE_DEMAND_START -ErrorControl = 1 ; SERVICE_ERROR_NORMAL -ServiceBinary = %10%\System32\Drivers\osrusbfx2.sys -AddReg = osrusbfx2_AddReg - -[osrusbfx2.Files.Ext] -osrusbfx2.sys - -[UMDriverCopy] -WudfOsrUsbFilter.dll - -[SourceDisksNames] -1=%Disk_Description%,,, - -[SourceDisksFiles] -osrusbfx2.sys = 1 -WudfOsrUsbFilter.dll=1 -WudfUpdate_$UMDFCOINSTALLERVERSION$.dll=1 - -[DestinationDirs] -UMDriverCopy=12,UMDF ; copy to drivers\umdf -DefaultDestDir = 12 - -;-------------- WDF Coinstaller installation - -[DestinationDirs] -CoInstaller_CopyFiles = 11 - -[CoInstaller_CopyFiles] -WudfUpdate_$UMDFCOINSTALLERVERSION$.dll - -[CoInstaller_AddReg] -HKR,,CoInstallers32,0x00010000,"WudfUpdate_$UMDFCOINSTALLERVERSION$.dll" - -;---------------------------------------------------------------; - -[Strings] -MSFT="Microsoft" -MfgName="OSR" -Disk_Description="OSRUSBFX2 Installation Disk" -USB\VID_045E&PID_930A.DeviceDesc="Microsoft UMDF OSR Usb Sample Device With Filter on kernel-mode Driver" -osrusbfx2.SvcDesc="WDF Sample Driver for OSR USB-FX2 Learning Kit" -ClassName = "Sample Device" -WudfRdDisplayName="Windows Driver Foundation - User-mode Driver Framework Reflector" - diff --git a/usb/umdf_filter_kmdf/umdf_filter/comsup.cpp b/usb/umdf_filter_kmdf/umdf_filter/comsup.cpp deleted file mode 100644 index 31257f31..00000000 --- a/usb/umdf_filter_kmdf/umdf_filter/comsup.cpp +++ /dev/null @@ -1,351 +0,0 @@ -/*++ - -Copyright (C) Microsoft Corporation, All Rights Reserved - -Module Name: - - ComSup.cpp - -Abstract: - - This module contains implementations for the functions and methods - used for providing COM support. - -Environment: - - Windows User-Mode Driver Framework (WUDF) - ---*/ - -#include "internal.h" - -#include "comsup.tmh" - -// -// This is the number of characters in a GUID string including the trailing -// NULL. -// - -#define GUID_STRING_CCH (sizeof("{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}")) - -// -// Implementation of CUnknown methods. -// - -CUnknown::CUnknown( - VOID - ) : m_ReferenceCount(1) -/*++ - - Routine Description: - - Constructor for an instance of the CUnknown class. This simply initializes - the reference count of the object to 1. The caller is expected to - call Release() if it wants to delete the object once it has been allocated. - - Arguments: - - None - - Return Value: - - None - ---*/ -{ - // do nothing. -} - -HRESULT -STDMETHODCALLTYPE -CUnknown::QueryInterface( - _In_ REFIID InterfaceId, - _Out_ PVOID *Object - ) -/*++ - - Routine Description: - - This method provides the basic support for query interface on CUnknown. - If the interface requested is IUnknown it references the object and - returns an interface pointer. Otherwise it returns an error. - - Arguments: - - InterfaceId - the IID being requested - - Object - a location to store the interface pointer to return. - - Return Value: - - S_OK or E_NOINTERFACE - ---*/ -{ - if (IsEqualIID(InterfaceId, __uuidof(IUnknown))) - { - *Object = QueryIUnknown(); - return S_OK; - } - else - { - *Object = NULL; - return E_NOINTERFACE; - } -} - -IUnknown * -CUnknown::QueryIUnknown( - VOID - ) -/*++ - - Routine Description: - - This helper method references the object and returns a pointer to the - object's IUnknown interface. - - This allows other methods to convert a CUnknown pointer into an IUnknown - pointer without a typecast and without calling QueryInterface and dealing - with the return value. - - Arguments: - - None - - Return Value: - - A pointer to the object's IUnknown interface. - ---*/ -{ - AddRef(); - return static_cast(this); -} - -ULONG -STDMETHODCALLTYPE -CUnknown::AddRef( - VOID - ) -/*++ - - Routine Description: - - This method adds one to the object's reference count. - - Arguments: - - None - - Return Value: - - The new reference count. The caller should only use this for debugging - as the object's actual reference count can change while the caller - examines the return value. - ---*/ -{ - return InterlockedIncrement(&m_ReferenceCount); -} - -ULONG -STDMETHODCALLTYPE -CUnknown::Release( - VOID - ) -/*++ - - Routine Description: - - This method subtracts one to the object's reference count. If the count - goes to zero, this method deletes the object. - - Arguments: - - None - - Return Value: - - The new reference count. If the caller uses this value it should only be - to check for zero (i.e. this call caused or will cause deletion) or - non-zero (i.e. some other call may have caused deletion, but this one - didn't). - ---*/ -{ - ULONG count = InterlockedDecrement(&m_ReferenceCount); - - if (count == 0) - { - delete this; - } - return count; -} - -// -// Implementation of CClassFactory methods. -// - -// -// Define storage for the factory's static lock count variable. -// - -LONG CClassFactory::s_LockCount = 0; - -IClassFactory * -CClassFactory::QueryIClassFactory( - VOID - ) -/*++ - - Routine Description: - - This helper method references the object and returns a pointer to the - object's IClassFactory interface. - - This allows other methods to convert a CClassFactory pointer into an - IClassFactory pointer without a typecast and without dealing with the - return value QueryInterface. - - Arguments: - - None - - Return Value: - - A referenced pointer to the object's IClassFactory interface. - ---*/ -{ - AddRef(); - return static_cast(this); -} - -HRESULT -CClassFactory::QueryInterface( - _In_ REFIID InterfaceId, - _Out_ PVOID *Object - ) -/*++ - - Routine Description: - - This method attempts to retrieve the requested interface from the object. - - If the interface is found then the reference count on that interface (and - thus the object itself) is incremented. - - Arguments: - - InterfaceId - the interface the caller is requesting. - - Object - a location to store the interface pointer. - - Return Value: - - S_OK or E_NOINTERFACE - ---*/ -{ - // - // This class only supports IClassFactory so check for that. - // - - if (IsEqualIID(InterfaceId, __uuidof(IClassFactory))) - { - *Object = QueryIClassFactory(); - return S_OK; - } - else - { - // - // See if the base class supports the interface. - // - - return CUnknown::QueryInterface(InterfaceId, Object); - } -} - -HRESULT -STDMETHODCALLTYPE -CClassFactory::CreateInstance( - _In_opt_ IUnknown * /* OuterObject */, - _In_ REFIID InterfaceId, - _Out_ PVOID *Object - ) -/*++ - - Routine Description: - - This COM method is the factory routine - it creates instances of the driver - callback class and returns the specified interface on them. - - Arguments: - - OuterObject - only used for aggregation, which our driver callback class - does not support. - - InterfaceId - the interface ID the caller would like to get from our - new object. - - Object - a location to store the referenced interface pointer to the new - object. - - Return Value: - - Status. - ---*/ -{ - HRESULT hr; - - PCMyDriver driver; - - *Object = NULL; - - hr = CMyDriver::CreateInstance(&driver); - - if (SUCCEEDED(hr)) - { - hr = driver->QueryInterface(InterfaceId, Object); - driver->Release(); - } - - return hr; -} - -HRESULT -STDMETHODCALLTYPE -CClassFactory::LockServer( - _In_ BOOL Lock - ) -/*++ - - Routine Description: - - This COM method can be used to keep the DLL in memory. However since the - driver's DllCanUnloadNow function always returns false, this has little - effect. Still it tracks the number of lock and unlock operations. - - Arguments: - - Lock - Whether the caller wants to lock or unlock the "server" - - Return Value: - - S_OK - ---*/ -{ - if (Lock) - { - InterlockedIncrement(&s_LockCount); - } - else - { - InterlockedDecrement(&s_LockCount); - } - return S_OK; -} - diff --git a/usb/umdf_filter_kmdf/umdf_filter/comsup.h b/usb/umdf_filter_kmdf/umdf_filter/comsup.h deleted file mode 100644 index b96fd982..00000000 --- a/usb/umdf_filter_kmdf/umdf_filter/comsup.h +++ /dev/null @@ -1,215 +0,0 @@ -/*++ - -Copyright (C) Microsoft Corporation, All Rights Reserved - -Module Name: - - ComSup.h - -Abstract: - - This module contains classes and functions use for providing COM support - code. - -Environment: - - Windows User-Mode Driver Framework (WUDF) - ---*/ - -#pragma once - -// -// Forward type declarations. They are here rather than in internal.h as -// you only need them if you choose to use these support classes. -// - -typedef class CUnknown *PCUnknown; -typedef class CClassFactory *PCClassFactory; - -// -// Base class to implement IUnknown. You can choose to derive your COM -// classes from this class, or simply implement IUnknown in each of your -// classes. -// - -class CUnknown : public IUnknown -{ - -// -// Private data members and methods. These are only accessible by the methods -// of this class. -// -private: - - // - // The reference count for this object. Initialized to 1 in the - // constructor. - // - - LONG m_ReferenceCount; - -// -// Protected data members and methods. These are accessible by the subclasses -// but not by other classes. -// -protected: - - // - // The constructor and destructor are protected to ensure that only the - // subclasses of CUnknown can create and destroy instances. - // - - CUnknown( - VOID - ); - - // - // The destructor MUST be virtual. Since any instance of a CUnknown - // derived class should only be deleted from within CUnknown::Release, - // the destructor MUST be virtual or only CUnknown::~CUnknown will get - // invoked on deletion. - // - // If you see that your CMyDevice specific destructor is never being - // called, make sure you haven't deleted the virtual destructor here. - // - - virtual - ~CUnknown( - VOID - ) - { - // Do nothing - } - -// -// Public Methods. These are accessible by any class. -// -public: - - IUnknown * - QueryIUnknown( - VOID - ); - -// -// COM Methods. -// -public: - - // - // IUnknown methods - // - - virtual - ULONG - STDMETHODCALLTYPE - AddRef( - VOID - ); - - virtual - ULONG - STDMETHODCALLTYPE - Release( - VOID - ); - - virtual - HRESULT - STDMETHODCALLTYPE - QueryInterface( - _In_ REFIID InterfaceId, - _Out_ PVOID *Object - ); -}; - -// -// Class factory support class. Create an instance of this from your -// DllGetClassObject method and modify the implementation to create -// an instance of your driver event handler class. -// - -class CClassFactory : public CUnknown, public IClassFactory -{ -// -// Private data members and methods. These are only accessible by the methods -// of this class. -// -private: - - // - // The lock count. This is shared across all instances of IClassFactory - // and can be queried through the public IsLocked method. - // - - static LONG s_LockCount; - -// -// Public Methods. These are accessible by any class. -// -public: - - IClassFactory * - QueryIClassFactory( - VOID - ); - -// -// COM Methods. -// -public: - - // - // IUnknown methods - // - - virtual - ULONG - STDMETHODCALLTYPE - AddRef( - VOID - ) - { - return __super::AddRef(); - } - - _At_(this, __drv_freesMem(object)) - virtual - ULONG - STDMETHODCALLTYPE - Release( - VOID - ) - { - return __super::Release(); - } - - virtual - HRESULT - STDMETHODCALLTYPE - QueryInterface( - _In_ REFIID InterfaceId, - _Out_ PVOID *Object - ); - - // - // IClassFactory methods. - // - - virtual - HRESULT - STDMETHODCALLTYPE - CreateInstance( - _In_opt_ IUnknown *OuterObject, - _In_ REFIID InterfaceId, - _Out_ PVOID *Object - ); - - virtual - HRESULT - STDMETHODCALLTYPE - LockServer( - _In_ BOOL Lock - ); -}; diff --git a/usb/umdf_filter_kmdf/umdf_filter/device.cpp b/usb/umdf_filter_kmdf/umdf_filter/device.cpp deleted file mode 100644 index 126637ce..00000000 --- a/usb/umdf_filter_kmdf/umdf_filter/device.cpp +++ /dev/null @@ -1,243 +0,0 @@ -/*++ - -Copyright (C) Microsoft Corporation, All Rights Reserved. - -Module Name: - - Device.cpp - -Abstract: - - This module contains the implementation of the UMDF OSR USB Sample Filter driver's - device callback object. - -Environment: - - Windows User-Mode Driver Framework (WUDF) - ---*/ - -#include "internal.h" -#include "device.tmh" - -HRESULT -CMyDevice::CreateInstance( - _In_ IWDFDriver *FxDriver, - _In_ IWDFDeviceInitialize * FxDeviceInit, - _Out_ PCMyDevice *Device - ) -/*++ - - Routine Description: - - This method creates and initializs an instance of the OSR USB Sample Filter driver's - device callback object. - - Arguments: - - FxDeviceInit - the settings for the device. - - Device - a location to store the referenced pointer to the device object. - - Return Value: - - Status - ---*/ -{ - PCMyDevice device; - HRESULT hr; - - // - // Allocate a new instance of the device class. - // - - device = new CMyDevice(); - - if (NULL == device) - { - return E_OUTOFMEMORY; - } - - // - // Initialize the instance. - // - - hr = device->Initialize(FxDriver, FxDeviceInit); - - if (SUCCEEDED(hr)) - { - *Device = device; - } - else - { - device->Release(); - } - - return hr; -} - -HRESULT -CMyDevice::Initialize( - _In_ IWDFDriver * FxDriver, - _In_ IWDFDeviceInitialize * FxDeviceInit - ) -/*++ - - Routine Description: - - This method initializes the device callback object and creates the - partner device object. - - The method should perform any device-specific configuration that: - * could fail (these can't be done in the constructor) - * must be done before the partner object is created -or- - * can be done after the partner object is created and which aren't - influenced by any device-level parameters the parent (the driver - in this case) might set. - - Arguments: - - FxDeviceInit - the settings for this device. - - Return Value: - - status. - ---*/ -{ - IWDFDevice *fxDevice; - HRESULT hr; - - // - // Configure things like the locking model before we go to create our - // partner device. - // - - // - // We don't need device level locking since we do not keep any state - // across the requests - // - - FxDeviceInit->SetLockingConstraint(None); - - // - // Mark ourselves as a filter - // - - FxDeviceInit->SetFilter(); - - - // - // We are a filter; we don't want to be the power policy owner - // - - FxDeviceInit->SetPowerPolicyOwnership(FALSE); - - // - // QueryIUnknown references the IUnknown interface that it returns - // (which is the same as referencing the device). We pass that to - // CreateDevice, which takes its own reference if everything works. - // - - { - IUnknown *unknown = this->QueryIUnknown(); - - hr = FxDriver->CreateDevice(FxDeviceInit, unknown, &fxDevice); - - unknown->Release(); - } - - // - // If that succeeded then set our FxDevice member variable. - // - - if (SUCCEEDED(hr)) - { - m_FxDevice = fxDevice; - - // - // Drop the reference we got from CreateDevice. Since this object - // is partnered with the framework object they have the same - // lifespan - there is no need for an additional reference. - // - - fxDevice->Release(); - } - - return hr; -} - -HRESULT -CMyDevice::Configure( - VOID - ) -/*++ - - Routine Description: - - This method is called after the device callback object has been initialized - and returned to the driver. It would setup the device's queues and their - corresponding callback objects. - - Arguments: - - FxDevice - the framework device object for which we're handling events. - - Return Value: - - status - ---*/ -{ - PCMyQueue defaultQueue; - - HRESULT hr; - - hr = CMyQueue::CreateInstance(m_FxDevice, &defaultQueue); - - if (FAILED(hr)) - { - return hr; - } - - hr = defaultQueue->Configure(); - - defaultQueue->Release(); - - return hr; -} - -HRESULT -CMyDevice::QueryInterface( - _In_ REFIID InterfaceId, - _Out_ PVOID *Object - ) -/*++ - - Routine Description: - - This method is called to get a pointer to one of the object's callback - interfaces. - - Since the OSR USB Sample Filter driver doesn't support any of the device events, this - method simply calls the base class's BaseQueryInterface. - - If OSR USB Sample Filter is extended to include device event interfaces then this - method must be changed to check the IID and return pointers to them as - appropriate. - - Arguments: - - InterfaceId - the interface being requested - - Object - a location to store the interface pointer if successful - - Return Value: - - S_OK or E_NOINTERFACE - ---*/ -{ - return CUnknown::QueryInterface(InterfaceId, Object); -} diff --git a/usb/umdf_filter_kmdf/umdf_filter/device.h b/usb/umdf_filter_kmdf/umdf_filter/device.h deleted file mode 100644 index f7a50b1d..00000000 --- a/usb/umdf_filter_kmdf/umdf_filter/device.h +++ /dev/null @@ -1,114 +0,0 @@ -/*++ - -Copyright (C) Microsoft Corporation, All Rights Reserved - -Module Name: - - Device.h - -Abstract: - - This module contains the type definitions for the UMDF OSR USB Sample Filter - driver's device callback class. - -Environment: - - Windows User-Mode Driver Framework (WUDF) - ---*/ - -#pragma once - -// -// Class for the iotrace driver. -// - -class CMyDevice : public CUnknown -{ - -// -// Private data members. -// -private: - - IWDFDevice *m_FxDevice; - -// -// Private methods. -// - -private: - - CMyDevice( - VOID - ) - { - m_FxDevice = NULL; - } - - HRESULT - Initialize( - _In_ IWDFDriver *FxDriver, - _In_ IWDFDeviceInitialize *FxDeviceInit - ); - -// -// Public methods -// -public: - - // - // The factory method used to create an instance of this driver. - // - - static - HRESULT - CreateInstance( - _In_ IWDFDriver *FxDriver, - _In_ IWDFDeviceInitialize *FxDeviceInit, - _Out_ PCMyDevice *Device - ); - - HRESULT - Configure( - VOID - ); - -// -// COM methods -// -public: - - // - // IUnknown methods. - // - - virtual - ULONG - STDMETHODCALLTYPE - AddRef( - VOID - ) - { - return __super::AddRef(); - } - - _At_(this, __drv_freesMem(object)) - virtual - ULONG - STDMETHODCALLTYPE - Release( - VOID - ) - { - return __super::Release(); - } - - virtual - HRESULT - STDMETHODCALLTYPE - QueryInterface( - _In_ REFIID InterfaceId, - _Out_ PVOID *Object - ); -}; diff --git a/usb/umdf_filter_kmdf/umdf_filter/dllsup.cpp b/usb/umdf_filter_kmdf/umdf_filter/dllsup.cpp deleted file mode 100644 index 10ef8a78..00000000 --- a/usb/umdf_filter_kmdf/umdf_filter/dllsup.cpp +++ /dev/null @@ -1,183 +0,0 @@ -/*++ - -Copyright (C) Microsoft Corporation, All Rights Reserved. - -Module Name: - - dllsup.cpp - -Abstract: - - This module contains the implementation of the OSR USB Sample Filter - Driver's entry point and its exported functions for providing COM support. - - This module can be copied without modification to a new UMDF driver. It - depends on some of the code in comsup.cpp & comsup.h to handle DLL - registration and creating the first class factory. - - This module is dependent on the following defines: - - MYDRIVER_TRACING_ID - A wide string passed to WPP when initializing - tracing. For example the skeleton uses - L"Microsoft\\UMDF\\Skeleton" - - MYDRIVER_CLASS_ID - A GUID encoded in struct format used to - initialize the driver's ClassID. - - These are defined in internal.h for the OSR USB Sample Filter sample. If - you choose to use a different primary include file, you should ensure - they are defined there as well. - -Environment: - - WDF User-Mode Driver Framework (WDF:UMDF) - ---*/ - -#include "internal.h" -#include "dllsup.tmh" - -const GUID CLSID_MyDriverCoClass = MYDRIVER_CLASS_ID; - -// -// Global variable to hold the module handle for this DLL. Initialized during -// DllMain and never cleared. This is used when registering and unregistering -// the driver's COM information. -// - -HINSTANCE g_ModuleHandle = NULL; - -BOOL -WINAPI -DllMain( - HINSTANCE /* ModuleHandle */, - DWORD Reason, - PVOID /* Reserved */ - ) -/*++ - - Routine Description: - - This is the entry point and exit point for the I/O trace driver. This - does very little as the I/O trace driver has minimal global data. - - This method initializes tracing. - - Arguments: - - ModuleHandle - the DLL handle for this module. - - Reason - the reason this entry point was called. - - Reserved - unused - - Return Value: - - TRUE - ---*/ -{ - - if (DLL_PROCESS_ATTACH == Reason) - { - // - // Initialize tracing. - // - - WPP_INIT_TRACING(MYDRIVER_TRACING_ID); - } - else if (DLL_PROCESS_DETACH == Reason) - { - // - // Cleanup tracing. - // - - WPP_CLEANUP(); - } - - return TRUE; -} - -HRESULT -STDAPICALLTYPE -DllGetClassObject( - _In_ REFCLSID ClassId, - _In_ REFIID InterfaceId, - _Outptr_ LPVOID *Interface - ) -/*++ - - Routine Description: - - This routine is called by COM in order to instantiate the OSR USB Sample - Filter driver callback object and do an initial query interface on it. - - This method only creates an instance of the driver's class factory, as this - is the minimum required to support UMDF. - - Arguments: - - ClassId - the CLSID of the object being "gotten" - - InterfaceId - the interface the caller wants from that object. - - Interface - a location to store the referenced interface pointer - - Return Value: - - S_OK if the function succeeds or error indicating the cause of the - failure. - ---*/ -{ - PCClassFactory factory; - - HRESULT hr = S_OK; - - *Interface = NULL; - - // - // If the CLSID doesn't match that of our "coclass" (defined in the IDL - // file) then we can't create the object the caller wants. This may - // indicate that the COM registration is incorrect, and another CLSID - // is referencing this drvier. - // - - if (IsEqualCLSID(ClassId, CLSID_MyDriverCoClass) == false) - { - Trace( - TRACE_LEVEL_ERROR, - L"ERROR: Called to create instance of unrecognized class (%!GUID!)", - &ClassId - ); - - return CLASS_E_CLASSNOTAVAILABLE; - } - - // - // Create an instance of the class factory for the caller. - // - - factory = new CClassFactory(); - - if (NULL == factory) - { - hr = E_OUTOFMEMORY; - } - - // - // Query the object we created for the interface the caller wants. After - // that we release the object. This will drive the reference count to - // 1 (if the QI succeeded an referenced the object) or 0 (if the QI failed). - // In the later case the object is automatically deleted. - // - - if (SUCCEEDED(hr)) - { - hr = factory->QueryInterface(InterfaceId, Interface); - factory->Release(); - } - - return hr; -} - diff --git a/usb/umdf_filter_kmdf/umdf_filter/driver.cpp b/usb/umdf_filter_kmdf/umdf_filter/driver.cpp deleted file mode 100644 index c5910c05..00000000 --- a/usb/umdf_filter_kmdf/umdf_filter/driver.cpp +++ /dev/null @@ -1,207 +0,0 @@ -/*++ - -Copyright (C) Microsoft Corporation, All Rights Reserved. - -Module Name: - - Driver.cpp - -Abstract: - - This module contains the implementation of the UMDF OSR USB Sample Filter - driver's core driver callback object. - -Environment: - - Windows User-Mode Driver Framework (WUDF) - ---*/ - -#include "internal.h" -#include "driver.tmh" - -HRESULT -CMyDriver::CreateInstance( - _Out_ PCMyDriver *Driver - ) -/*++ - - Routine Description: - - This static method is invoked in order to create and initialize a new - instance of the driver class. The caller should arrange for the object - to be released when it is no longer in use. - - Arguments: - - Driver - a location to store a referenced pointer to the new instance - - Return Value: - - S_OK if successful, or error otherwise. - ---*/ -{ - PCMyDriver driver; - HRESULT hr; - - // - // Allocate the callback object. - // - - driver = new CMyDriver(); - - if (NULL == driver) - { - return E_OUTOFMEMORY; - } - - // - // Initialize the callback object. - // - - hr = driver->Initialize(); - - if (SUCCEEDED(hr)) - { - // - // Store a pointer to the new, initialized object in the output - // parameter. - // - - *Driver = driver; - } - else - { - - // - // Release the reference on the driver object to get it to delete - // itself. - // - - driver->Release(); - } - - return hr; -} - -HRESULT -CMyDriver::Initialize( - VOID - ) -/*++ - - Routine Description: - - This method is called to initialize a newly created driver callback object - before it is returned to the creator. Unlike the constructor, the - Initialize method contains operations which could potentially fail. - - Arguments: - - None - - Return Value: - - None - ---*/ -{ - return S_OK; -} - -HRESULT -CMyDriver::QueryInterface( - _In_ REFIID InterfaceId, - _Out_ PVOID *Interface - ) -/*++ - - Routine Description: - - This method returns a pointer to the requested interface on the callback - object.. - - Arguments: - - InterfaceId - the IID of the interface to query/reference - - Interface - a location to store the interface pointer. - - Return Value: - - S_OK if the interface is supported. - E_NOINTERFACE if it is not supported. - ---*/ -{ - if (IsEqualIID(InterfaceId, __uuidof(IDriverEntry))) - { - *Interface = QueryIDriverEntry(); - return S_OK; - } - else - { - return CUnknown::QueryInterface(InterfaceId, Interface); - } -} - -HRESULT -CMyDriver::OnDeviceAdd( - _In_ IWDFDriver *FxWdfDriver, - _In_ IWDFDeviceInitialize *FxDeviceInit - ) -/*++ - - Routine Description: - - The FX invokes this method when it wants to install our driver on a device - stack. This method creates a device callback object, then calls the Fx - to create an Fx device object and associate the new callback object with - it. - - Arguments: - - FxWdfDriver - the Fx driver object. - - FxDeviceInit - the initialization information for the device. - - Return Value: - - status - ---*/ -{ - HRESULT hr; - - PCMyDevice device = NULL; - - // - // Create a new instance of our device callback object - // - - hr = CMyDevice::CreateInstance(FxWdfDriver, FxDeviceInit, &device); - - // - // If that succeeded then call the device's construct method. This - // allows the device to create any queues or other structures that it - // needs now that the corresponding fx device object has been created. - // - - if (SUCCEEDED(hr)) - { - hr = device->Configure(); - } - - // - // Release the reference on the device callback object now that it's been - // associated with an fx device object. - // - - if (NULL != device) - { - device->Release(); - } - - return hr; -} diff --git a/usb/umdf_filter_kmdf/umdf_filter/driver.h b/usb/umdf_filter_kmdf/umdf_filter/driver.h deleted file mode 100644 index 08f36a71..00000000 --- a/usb/umdf_filter_kmdf/umdf_filter/driver.h +++ /dev/null @@ -1,145 +0,0 @@ -/*++ - -Copyright (C) Microsoft Corporation, All Rights Reserved - -Module Name: - - Driver.h - -Abstract: - - This module contains the type definitions for the UMDF OSR USB Sample Filter - driver's callback class. - -Environment: - - Windows User-Mode Driver Framework (WUDF) - ---*/ - -#pragma once - -// -// This class handles driver events for the OSR USB Sample Filter driver. In particular -// it supports the OnDeviceAdd event, which occurs when the driver is called -// to setup per-device handlers for a new device stack. -// - -class CMyDriver : public CUnknown, public IDriverEntry -{ -// -// Private data members. -// -private: - -// -// Private methods. -// -private: - - // - // Returns a refernced pointer to the IDriverEntry interface. - // - - IDriverEntry * - QueryIDriverEntry( - VOID - ) - { - AddRef(); - return static_cast(this); - } - - HRESULT - Initialize( - VOID - ); - -// -// Public methods -// -public: - - // - // The factory method used to create an instance of this driver. - // - - static - HRESULT - CreateInstance( - _Out_ PCMyDriver *Driver - ); - -// -// COM methods -// -public: - - // - // IDriverEntry methods - // - - virtual - HRESULT - STDMETHODCALLTYPE - OnInitialize( - _In_ IWDFDriver* /*FxWdfDriver*/ - ) - { - return S_OK; - } - - virtual - HRESULT - STDMETHODCALLTYPE - OnDeviceAdd( - _In_ IWDFDriver *FxWdfDriver, - _In_ IWDFDeviceInitialize *FxDeviceInit - ); - - virtual - VOID - STDMETHODCALLTYPE - OnDeinitialize( - _In_ IWDFDriver * /*FxWdfDriver*/ - ) - { - return; - } - - // - // IUnknown methods. - // - // We have to implement basic ones here that redirect to the - // base class becuase of the multiple inheritance. - // - - virtual - ULONG - STDMETHODCALLTYPE - AddRef( - VOID - ) - { - return __super::AddRef(); - } - - _At_(this, __drv_freesMem(object)) - virtual - ULONG - STDMETHODCALLTYPE - Release( - VOID - ) - { - return __super::Release(); - } - - virtual - HRESULT - STDMETHODCALLTYPE - QueryInterface( - _In_ REFIID InterfaceId, - _Out_ PVOID *Object - ); -}; diff --git a/usb/umdf_filter_kmdf/umdf_filter/exports.def b/usb/umdf_filter_kmdf/umdf_filter/exports.def deleted file mode 100644 index 0fc42817..00000000 --- a/usb/umdf_filter_kmdf/umdf_filter/exports.def +++ /dev/null @@ -1,4 +0,0 @@ -; Skeleton.def : Declares the module parameters. - -EXPORTS - DllGetClassObject PRIVATE diff --git a/usb/umdf_filter_kmdf/umdf_filter/internal.h b/usb/umdf_filter_kmdf/umdf_filter/internal.h deleted file mode 100644 index 516f6d7f..00000000 --- a/usb/umdf_filter_kmdf/umdf_filter/internal.h +++ /dev/null @@ -1,111 +0,0 @@ -/*++ - -Copyright (C) Microsoft Corporation, All Rights Reserved - -Module Name: - - Internal.h - -Abstract: - - This module contains the local type definitions for the UMDF OSR USB Sample Filter - driver. - -Environment: - - Windows User-Mode Driver Framework (WUDF) - ---*/ - -#pragma once - -#ifndef ARRAY_SIZE -#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) -#endif - -// -// Include the WUDF headers -// - -#include "wudfddi.h" - -// -// Use specstrings for in/out annotation of function parameters. -// - -#include "specstrings.h" - -// -// Forward definitions of classes in the other header files. -// - -typedef class CMyDriver *PCMyDriver; -typedef class CMyDevice *PCMyDevice; -typedef class CMyQueue *PCMyQueue; - -// -// Define the tracing flags. -// - -#define WPP_CONTROL_GUIDS \ - WPP_DEFINE_CONTROL_GUID( \ - MyDriverTraceControl, (73cdcaa5,ce52,43f2,aa2d,5f5a84e22213), \ - \ - WPP_DEFINE_BIT(MYDRIVER_ALL_INFO) \ - ) - -#define WPP_FLAG_LEVEL_LOGGER(flag, level) \ - WPP_LEVEL_LOGGER(flag) - -#define WPP_FLAG_LEVEL_ENABLED(flag, level) \ - (WPP_LEVEL_ENABLED(flag) && \ - WPP_CONTROL(WPP_BIT_ ## flag).Level >= level) - -// -// This comment block is scanned by the trace preprocessor to define our -// Trace function. -// -// begin_wpp config -// FUNC Trace{FLAG=MYDRIVER_ALL_INFO}(LEVEL, MSG, ...); -// end_wpp -// - -// -// Driver specific #defines -// - -#define MYDRIVER_TRACING_ID L"Microsoft\\UMDF\\OsrUsbFilter" -#define MYDRIVER_COM_DESCRIPTION L"UMDF OSR USB Sample Filter Driver" -#define MYDRIVER_CLASS_ID {0x422d8dbc, 0x520d, 0x4d7e, {0x8f, 0x53, 0x92, 0x0e, 0x5c, 0x86, 0x7e, 0x6c}} - -// -// Include the type specific headers. -// - -#include "comsup.h" -#include "driver.h" -#include "device.h" -#include "queue.h" - -__forceinline -#ifdef _PREFAST_ -__declspec(noreturn) -#endif -VOID -WdfTestNoReturn( - VOID - ) -{ - // do nothing. -} - -#define WUDF_SAMPLE_DRIVER_ASSERT(p) \ -{ \ - if ( !(p) ) \ - { \ - DebugBreak(); \ - WdfTestNoReturn(); \ - } \ -} - -#define SAFE_RELEASE(p) {if ((p)) { (p)->Release(); (p) = NULL; }} diff --git a/usb/umdf_filter_kmdf/umdf_filter/queue.cpp b/usb/umdf_filter_kmdf/umdf_filter/queue.cpp deleted file mode 100644 index 5642ec74..00000000 --- a/usb/umdf_filter_kmdf/umdf_filter/queue.cpp +++ /dev/null @@ -1,538 +0,0 @@ -/*++ - -Copyright (C) Microsoft Corporation, All Rights Reserved. - -Module Name: - - Queue.cpp - -Abstract: - - This module contains the implementation of the OSR USB Filter Sample driver's - queue callback object. - -Environment: - - Windows User-Mode Driver Framework (WUDF) - ---*/ - -#include "internal.h" -#include "queue.h" - -#include "queue.tmh" - -HRESULT -CMyQueue::CreateInstance( - _In_ IWDFDevice * FxDevice, - _Out_ CMyQueue **Queue - ) -/*++ - - Routine Description: - - This method creates and initializs an instance of the OSR USB Filter Sample driver's - device callback object. - - Arguments: - - FxDeviceInit - the settings for the device. - - Device - a location to store the referenced pointer to the device object. - - Return Value: - - Status - ---*/ -{ - CMyQueue *queue; - - HRESULT hr = S_OK; - - // - // Allocate a new instance of the device class. - // - - queue = new CMyQueue(); - - if (NULL == queue) - { - hr = E_OUTOFMEMORY; - } - - // - // Initialize the instance. - // - - if (SUCCEEDED(hr)) - { - hr = queue->Initialize(FxDevice); - } - - if (SUCCEEDED(hr)) - { - queue->AddRef(); - *Queue = queue; - } - - if (NULL != queue) - { - queue->Release(); - } - - return hr; -} - -HRESULT -CMyQueue::QueryInterface( - _In_ REFIID InterfaceId, - _Out_ PVOID *Object - ) -/*++ - - Routine Description: - - This method is called to get a pointer to one of the object's callback - interfaces. - - Arguments: - - InterfaceId - the interface being requested - - Object - a location to store the interface pointer if successful - - Return Value: - - S_OK or E_NOINTERFACE - ---*/ -{ - HRESULT hr; - - - if(IsEqualIID(InterfaceId, __uuidof(IQueueCallbackDefaultIoHandler))) - { - hr = S_OK; - *Object = QueryIQueueCallbackDefaultIoHandler(); - } - else if (IsEqualIID(InterfaceId, __uuidof(IQueueCallbackWrite))) - { - hr = S_OK; - *Object = QueryIQueueCallbackWrite(); - } - else if (IsEqualIID(InterfaceId, __uuidof(IRequestCallbackRequestCompletion))) - { - hr = S_OK; - *Object = QueryIRequestCallbackRequestCompletion(); - - } - else - { - hr = CUnknown::QueryInterface(InterfaceId, Object); - } - - return hr; -} - -HRESULT -CMyQueue::Initialize( - _In_ IWDFDevice *FxDevice - ) -/*++ - - Routine Description: - - This method initializes the device callback object. Any operations which - need to be performed before the caller can use the callback object, but - which couldn't be done in the constructor becuase they could fail would - be placed here. - - Arguments: - - FxDevice - the device which this Queue is for. - - Return Value: - - status. - ---*/ -{ - IWDFIoQueue *fxQueue; - HRESULT hr; - - // - // Create the framework queue - // - - IUnknown *unknown = QueryIUnknown(); - hr = FxDevice->CreateIoQueue( - unknown, - TRUE, // bDefaultQueue - WdfIoQueueDispatchParallel, - FALSE, // bPowerManaged - TRUE, // bAllowZeroLengthRequests - &fxQueue - ); - if (FAILED(hr)) - { - Trace( - TRACE_LEVEL_ERROR, - "%!FUNC!: Could not create default I/O queue, %!hresult!", - hr - ); - } - - unknown->Release(); - - if (SUCCEEDED(hr)) - { - m_FxQueue = fxQueue; - - // - // m_FxQueue is kept as a Weak reference to framework Queue object to avoid - // circular reference. This object's lifetime is contained within - // framework Queue object's lifetime - // - - fxQueue->Release(); - } - - if (SUCCEEDED(hr)) - { - FxDevice->GetDefaultIoTarget(&m_FxIoTarget); - } - - return hr; -} - -void -CMyQueue::InvertBits( - _Inout_ IWDFMemory* FxMemory, - _In_ SIZE_T NumBytes - ) -/*++ - - Routine Description: - - This helper method inverts bits in the buffer of an FxMemory object - - Arguments: - - FxMemory - Framework memory object whose buffer's bits are to be inverted - - NumBytes - Number of bytes for which bits are to be inverted - - Return Value: - - None - ---*/ -{ - PBYTE Buffer = (PBYTE) - FxMemory->GetDataBuffer(NULL); - - for (SIZE_T i = 0; i < NumBytes; i++) - { - memset(Buffer + i, ~(Buffer[i]), sizeof(*Buffer)); - } -} - -void -CMyQueue::OnWrite( - _In_ IWDFIoQueue* FxQueue, - _In_ IWDFIoRequest* FxRequest, - _In_ SIZE_T NumOfBytesToWrite - ) -/*++ - - Routine Description: - - This method is called by Framework Queue object to deliver the Write request - This method inverts the bits in write buffer and forwards the request down the device stack - In case of any failure prior to ForwardRequest, it completets the request with failure - - Arguments: - - pWdfQueue - Framework Queue which is delivering the request - - pWdfRequest - Framework Request - - Return Value: - - None - ---*/ -{ - UNREFERENCED_PARAMETER(FxQueue); - - IWDFMemory * FxInputMemory = NULL; - - FxRequest->GetInputMemory(&FxInputMemory); - - // - // Invert bits of the buffer to be written to device - // - - InvertBits(FxInputMemory, NumOfBytesToWrite); - - // - // Forward request down the stack - // When the device below completes the request we will get notified in OnComplete - // and then we will complete the request - // - - ForwardRequest(FxRequest); - - FxInputMemory->Release(); -} - -// -// IQueueCallbackDefaultIoHandler method -// - -void -CMyQueue::OnDefaultIoHandler( - _In_ IWDFIoQueue* FxQueue, - _In_ IWDFIoRequest* FxRequest - ) -/*++ - - Routine Description: - - This method is called by Framework Queue object to deliver all the I/O - Requests for which we do not have a specific handler - (In our case anything other than Write) - - Arguments: - - pWdfQueue - Framework Queue which is delivering the request - - pWdfRequest - Framework Request - - Return Value: - - None - ---*/ -{ - UNREFERENCED_PARAMETER(FxQueue); - - // - // We just forward the request down the stack - // When the device below completes the request we will get notified in OnComplete - // and then we will complete the request - // - - ForwardRequest(FxRequest); -} - -void -CMyQueue::ForwardRequest( - _In_ IWDFIoRequest* FxRequest - ) -/*++ - - Routine Description: - - This helper method forwards the request down the stack - - Arguments: - - pWdfRequest - Request to be forwarded - - Return Value: - - None - - Remarks: - - The request gets forwarded to the next device in the stack which can be: - 1. Next device in user-mode stack - 2. Top device in kernel-mode stack (Redirector's Down Device) - - In this routine we: - 1. Set a completion callback - 2. Copy request parameters to next stack location - 3. Asynchronously send the request without any timeout - - When the lower request gets completed we will be notified via the - completion callback, where we will complete our request - - In case of failure this routine completes the request - ---*/ -{ - // - //First set the completion callback - // - - IRequestCallbackRequestCompletion *completionCallback = - QueryIRequestCallbackRequestCompletion(); - - FxRequest->SetCompletionCallback( - completionCallback, - NULL //pContext - ); - - completionCallback->Release(); - - // - //Copy current i/o stack locations parameters to the next stack location - // - - FxRequest->FormatUsingCurrentType( - ); - - // - //Send down the request - // - HRESULT hrSend = S_OK; - - hrSend = FxRequest->Send( - m_FxIoTarget, - 0, //No flag - 0 //No timeout - ); - - if (FAILED(hrSend)) - { - // - //If send failed we need to complete the request with failure - // - FxRequest->CompleteWithInformation(hrSend, 0); - } - - return; -} - -void -CMyQueue::HandleReadRequestCompletion( - IWDFIoRequest* FxRequest, - IWDFIoRequestCompletionParams* CompletionParams - ) -/*++ - - Routine Description: - - This helper method is called by OnCompletion method to complete Read request - We invert the bits in the read buffer - This is so that the client reads back the data it wrote since - we inverted bits during write to device - - Arguments: - - FxRequest - Request object of our layer - - CompletionParams - Parameters with which the lower Request got completed - - Return Value: - - None - - Remarks: - - This method always completes the request since no one else would get a chance to - complete the request - In case of failure it completes the request with failure - ---*/ -{ - HRESULT hrCompletion = CompletionParams->GetCompletionStatus(); - ULONG_PTR BytesRead = CompletionParams->GetInformation(); - - // - // Check - // 1. whether the lower device succeeded the Request (otherwise we will just complete - // the Request with failure - // 2. If data read is of non-zero length, for us to bother to invert its bits - // - - if (SUCCEEDED(hrCompletion) && - (0 != BytesRead) - ) - { - IWDFMemory *FxOutputMemory; - - FxRequest->GetOutputMemory(&FxOutputMemory ); - - InvertBits(FxOutputMemory, BytesRead); - - FxOutputMemory->Release(); - } - - // - // Complete the request - // - - FxRequest->CompleteWithInformation( - hrCompletion, - BytesRead - ); -} - - -void -CMyQueue::OnCompletion( - IWDFIoRequest* FxRequest, - IWDFIoTarget* FxIoTarget, - IWDFRequestCompletionParams* CompletionParams, - PVOID Context - ) -/*++ - - Routine Description: - - This method is called by Framework I/O Target object when - the lower device completets the Request - - Arguments: - - pWdfRequest - Request object of our layer - - pIoTarget - I/O Target object invoking this callback - - pParams - Parameters with which the lower Request got completed - - Return Value: - - None - ---*/ -{ - UNREFERENCED_PARAMETER(FxIoTarget); - UNREFERENCED_PARAMETER(Context); - - // - // If it is a read request, we invert the bits read since we inverted them during write - // so that application would read the same data as it wrote - // - - if (WdfRequestRead == FxRequest->GetType()) - { - IWDFIoRequestCompletionParams * IoCompletionParams = NULL; - HRESULT hrQI = CompletionParams->QueryInterface(IID_PPV_ARGS(&IoCompletionParams)); - WUDF_SAMPLE_DRIVER_ASSERT(SUCCEEDED(hrQI)); - - HandleReadRequestCompletion( - FxRequest, - IoCompletionParams - ); - - SAFE_RELEASE(IoCompletionParams); - } - else - { - - // - // Otherwise we just complete our Request object with the same parameters - // with which the lower Request got completed - // - - FxRequest->CompleteWithInformation( - CompletionParams->GetCompletionStatus(), - CompletionParams->GetInformation() - ); - } -} - diff --git a/usb/umdf_filter_kmdf/umdf_filter/queue.h b/usb/umdf_filter_kmdf/umdf_filter/queue.h deleted file mode 100644 index 216264e9..00000000 --- a/usb/umdf_filter_kmdf/umdf_filter/queue.h +++ /dev/null @@ -1,253 +0,0 @@ -/*++ - -Copyright (C) Microsoft Corporation, All Rights Reserved - -Module Name: - - Queue.h - -Abstract: - - This module contains the type definitions for the OSR USB Filter Sample - driver's queue callback class. - -Environment: - - Windows User-Mode Driver Framework (WUDF) - ---*/ - -#pragma once - -// -// Class for the queue callbacks. -// It implements -// IQueueCallbackDeviceIoControl -// IRequestCallbackRequestCompletion -// Queue callbacks -// -// This class also implements IRequestCallbackRequestCompletion callback -// to get the request completion notification when request is sent down the -// stack. This callback can be implemented on a separate object as well. -// This callback is implemented here only for conenience. -// -class CMyQueue : - public CUnknown, - public IQueueCallbackWrite, - public IQueueCallbackDefaultIoHandler, - public IRequestCallbackRequestCompletion -{ - -// -// Private data members. -// -private: - - // - // Weak reference to framework Queue object which this object implements callbacks for - // This is kept as a weak reference to avoid circular reference - // This object's lifetime is contained within framework Queue object's lifetime - // - - IWDFIoQueue *m_FxQueue; - - // - // I/O Target to which we forward requests. Represents next device in the - // device stack - // - - IWDFIoTarget *m_FxIoTarget; - -// -// Private methods. -// - -private: - - CMyQueue() : - m_FxQueue(NULL), - m_FxIoTarget(NULL) - { - } - - virtual ~CMyQueue() - { - if (NULL != m_FxIoTarget) - { - m_FxIoTarget->Release(); - } - } - - // - // QueryInterface helpers - // - - IRequestCallbackRequestCompletion * - QueryIRequestCallbackRequestCompletion( - VOID - ) - { - AddRef(); - return static_cast(this); - } - - IQueueCallbackWrite * - QueryIQueueCallbackWrite( - VOID - ) - { - AddRef(); - return static_cast(this); - } - - IQueueCallbackDefaultIoHandler * - QueryIQueueCallbackDefaultIoHandler( - VOID - ) - { - AddRef(); - return static_cast(this); - } - - // - // Initialize - // - - HRESULT - Initialize( - _In_ IWDFDevice *FxDevice - ); - - // - // Helper method to forward request down the stack - // - - void - ForwardRequest( - _In_ IWDFIoRequest *pWdfRequest - ); - - // - // Helper method to inverts bits in the buffer of a framework Memory object - // - - void - InvertBits( - _Inout_ IWDFMemory* FxMemory, - _In_ SIZE_T NumBytes - ); - - // - // Helper method to handle Read request completion - // - - void - HandleReadRequestCompletion( - IWDFIoRequest* FxRequest, - IWDFIoRequestCompletionParams* CompletionParams - ); - -// -// Public methods -// -public: - - // - // The factory method used to create an instance of this class - // - - static - HRESULT - CreateInstance( - _In_ IWDFDevice *FxDevice, - _Out_ CMyQueue **Queue - ); - - - HRESULT - Configure( - VOID - ) - { - return S_OK; - } - -// -// COM methods -// -public: - - // - // IUnknown methods. - // - - virtual - ULONG - STDMETHODCALLTYPE - AddRef( - VOID - ) - { - return __super::AddRef(); - } - - _At_(this, __drv_freesMem(object)) - virtual - ULONG - STDMETHODCALLTYPE - Release( - VOID - ) - { - return __super::Release(); - } - - virtual - HRESULT - STDMETHODCALLTYPE - QueryInterface( - _In_ REFIID InterfaceId, - _Out_ PVOID *Object - ); - - // - // IQueueCallbackWrite method - // - - virtual - void - STDMETHODCALLTYPE - OnWrite( - _In_ IWDFIoQueue* FxQueue, - _In_ IWDFIoRequest* FxRequest, - _In_ SIZE_T NumOfBytesToWrite - ); - - - // - // IQueueCallbackDefaultIoHandler method - // - - virtual - void - STDMETHODCALLTYPE - OnDefaultIoHandler( - _In_ IWDFIoQueue* FxQueue, - _In_ IWDFIoRequest* FxRequest - ); - - // - //IRequestCallbackRequestCompletion - // - - virtual - void - STDMETHODCALLTYPE - OnCompletion( - IWDFIoRequest* FxRequest, - IWDFIoTarget* FxIoTarget, - IWDFRequestCompletionParams* CompletionParams, - PVOID Context - ); -}; - diff --git a/usb/umdf_filter_kmdf/umdf_filter_kmdf.sln b/usb/umdf_filter_kmdf/umdf_filter_kmdf.sln deleted file mode 100644 index 610e5fe9..00000000 --- a/usb/umdf_filter_kmdf/umdf_filter_kmdf.sln +++ /dev/null @@ -1,59 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2013 -VisualStudioVersion = 12.0 -MinimumVisualStudioVersion = 12.0 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Package", "Package", "{C5684CA0-69C7-44A5-9993-99687939133F}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Umdf_filter", "Umdf_filter", "{EECFA720-E287-4CEE-A8AA-6BF3777F68B3}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Kmdf_driver", "Kmdf_driver", "{A0A8D15D-A7A6-4170-AAFA-753B7E798AF4}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "package", "Package\package.VcxProj", "{3EF9240F-7E95-49A7-8B0D-5F7061655764}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WUDFOsrUsbFilter", "umdf_filter\WUDFOsrUsbFilter.vcxproj", "{0149B701-5356-434C-AC8C-07CAA1D9A4AA}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "osrusbfx2", "kmdf_driver\osrusbfx2.vcxproj", "{23EAF474-B558-4457-B03C-164DA83B7575}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Release|Win32 = Release|Win32 - Debug|x64 = Debug|x64 - Release|x64 = Release|x64 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {3EF9240F-7E95-49A7-8B0D-5F7061655764}.Debug|Win32.ActiveCfg = Debug|Win32 - {3EF9240F-7E95-49A7-8B0D-5F7061655764}.Debug|Win32.Build.0 = Debug|Win32 - {3EF9240F-7E95-49A7-8B0D-5F7061655764}.Release|Win32.ActiveCfg = Release|Win32 - {3EF9240F-7E95-49A7-8B0D-5F7061655764}.Release|Win32.Build.0 = Release|Win32 - {3EF9240F-7E95-49A7-8B0D-5F7061655764}.Debug|x64.ActiveCfg = Debug|x64 - {3EF9240F-7E95-49A7-8B0D-5F7061655764}.Debug|x64.Build.0 = Debug|x64 - {3EF9240F-7E95-49A7-8B0D-5F7061655764}.Release|x64.ActiveCfg = Release|x64 - {3EF9240F-7E95-49A7-8B0D-5F7061655764}.Release|x64.Build.0 = Release|x64 - {0149B701-5356-434C-AC8C-07CAA1D9A4AA}.Debug|Win32.ActiveCfg = Debug|Win32 - {0149B701-5356-434C-AC8C-07CAA1D9A4AA}.Debug|Win32.Build.0 = Debug|Win32 - {0149B701-5356-434C-AC8C-07CAA1D9A4AA}.Release|Win32.ActiveCfg = Release|Win32 - {0149B701-5356-434C-AC8C-07CAA1D9A4AA}.Release|Win32.Build.0 = Release|Win32 - {0149B701-5356-434C-AC8C-07CAA1D9A4AA}.Debug|x64.ActiveCfg = Debug|x64 - {0149B701-5356-434C-AC8C-07CAA1D9A4AA}.Debug|x64.Build.0 = Debug|x64 - {0149B701-5356-434C-AC8C-07CAA1D9A4AA}.Release|x64.ActiveCfg = Release|x64 - {0149B701-5356-434C-AC8C-07CAA1D9A4AA}.Release|x64.Build.0 = Release|x64 - {23EAF474-B558-4457-B03C-164DA83B7575}.Debug|Win32.ActiveCfg = Debug|Win32 - {23EAF474-B558-4457-B03C-164DA83B7575}.Debug|Win32.Build.0 = Debug|Win32 - {23EAF474-B558-4457-B03C-164DA83B7575}.Release|Win32.ActiveCfg = Release|Win32 - {23EAF474-B558-4457-B03C-164DA83B7575}.Release|Win32.Build.0 = Release|Win32 - {23EAF474-B558-4457-B03C-164DA83B7575}.Debug|x64.ActiveCfg = Debug|x64 - {23EAF474-B558-4457-B03C-164DA83B7575}.Debug|x64.Build.0 = Debug|x64 - {23EAF474-B558-4457-B03C-164DA83B7575}.Release|x64.ActiveCfg = Release|x64 - {23EAF474-B558-4457-B03C-164DA83B7575}.Release|x64.Build.0 = Release|x64 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {3EF9240F-7E95-49A7-8B0D-5F7061655764} = {C5684CA0-69C7-44A5-9993-99687939133F} - {0149B701-5356-434C-AC8C-07CAA1D9A4AA} = {EECFA720-E287-4CEE-A8AA-6BF3777F68B3} - {23EAF474-B558-4457-B03C-164DA83B7575} = {A0A8D15D-A7A6-4170-AAFA-753B7E798AF4} - EndGlobalSection -EndGlobal diff --git a/usb/umdf_filter_umdf/Package/package.VcxProj b/usb/umdf_filter_umdf/Package/package.VcxProj index b9b377e9..9ce9102a 100644 --- a/usb/umdf_filter_umdf/Package/package.VcxProj +++ b/usb/umdf_filter_umdf/Package/package.VcxProj @@ -27,8 +27,8 @@ - {92A41A0C-EC0F-4D98-B4DE-4899B375FD49} - {ECED2BAF-D334-46B0-A7A9-734224614A21} + {8D2391A3-43B4-4B9F-89E2-A4024B35FBAD} + {41DDE172-7368-4C23-A7CC-B858DDD69598} $(MSBuildProjectName) @@ -79,10 +79,10 @@
- {0D3781C2-2236-46B0-806D-387999E500AB} + {81B31960-3EA8-4F43-B79A-5A851EC49CE8} - {E62A4AAA-870E-4D58-AA10-D9604A2E52E8} + {F7387F7F-59AF-4963-9D6E-8626E9E4D2EF} diff --git a/usb/umdf_filter_umdf/Package/package.VcxProj.Filters b/usb/umdf_filter_umdf/Package/package.VcxProj.Filters index a96565c8..16a8f2b2 100644 --- a/usb/umdf_filter_umdf/Package/package.VcxProj.Filters +++ b/usb/umdf_filter_umdf/Package/package.VcxProj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {4E330348-D3BC-4378-9E28-1C0E89913E9C} + {B88534C0-78F8-4BDC-8C08-67199D9AA05A} h;hpp;hxx;hm;inl;inc;xsd - {F5D9FE78-6B2A-4C19-91B7-49A3D081DA74} + {5F6982F6-3AF9-4722-83E0-A9D98AE5B91F} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {32502152-33D3-42BC-8DC3-DBCEC24AAC1F} + {14281D5C-7E16-4447-BBF8-E89022F25A64} inf;inv;inx;mof;mc; - {82F51BD2-E3F4-4E26-9787-497F73C1EC82} + {EC6EE142-CF05-44A4-9FDC-01D842258F31} \ No newline at end of file diff --git a/usb/umdf_filter_umdf/umdf_driver/WUDFOsrUsbFx2.vcxproj b/usb/umdf_filter_umdf/umdf_driver/WUDFOsrUsbFx2.vcxproj index e5b2d207..278a29ee 100644 --- a/usb/umdf_filter_umdf/umdf_driver/WUDFOsrUsbFx2.vcxproj +++ b/usb/umdf_filter_umdf/umdf_driver/WUDFOsrUsbFx2.vcxproj @@ -19,7 +19,7 @@
- {0D3781C2-2236-46B0-806D-387999E500AB} + {81B31960-3EA8-4F43-B79A-5A851EC49CE8} $(MSBuildProjectName) 1 1 @@ -27,7 +27,7 @@ true Debug Win32 - {C4216905-C3FE-44F7-A5AD-0987922D565E} + {2B42915F-EE92-4D87-A546-B050A53BCCB6} diff --git a/usb/umdf_filter_umdf/umdf_driver/WUDFOsrUsbFx2.vcxproj.Filters b/usb/umdf_filter_umdf/umdf_driver/WUDFOsrUsbFx2.vcxproj.Filters index d0c54d1b..62f00807 100644 --- a/usb/umdf_filter_umdf/umdf_driver/WUDFOsrUsbFx2.vcxproj.Filters +++ b/usb/umdf_filter_umdf/umdf_driver/WUDFOsrUsbFx2.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {ABA4E4AE-18A0-4313-819F-B0D9DDB54C2E} + {48ABB0A1-2EEB-4A52-A63E-E2CAAF57DDA7} h;hpp;hxx;hm;inl;inc;xsd - {E4C135BD-DEBF-4561-8E32-CA099824DFF6} + {80693C76-07E2-41A9-BA81-3F4FC6E25DE9} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {2CBEC65A-B61D-4E62-9582-AA80C3C538D0} + {46C21426-AD2F-493A-A1FA-BDD65A5BB6AF} inf;inv;inx;mof;mc; - {8597CA67-53BC-423A-BF33-07316F805E89} + {05DE7331-93CD-4B4C-8212-3510CFF88BC8} diff --git a/usb/umdf_filter_umdf/umdf_filter/WUDFOsrUsbFilter.vcxproj b/usb/umdf_filter_umdf/umdf_filter/WUDFOsrUsbFilter.vcxproj index 4968db88..e7d128d9 100644 --- a/usb/umdf_filter_umdf/umdf_filter/WUDFOsrUsbFilter.vcxproj +++ b/usb/umdf_filter_umdf/umdf_filter/WUDFOsrUsbFilter.vcxproj @@ -19,7 +19,7 @@ - {E62A4AAA-870E-4D58-AA10-D9604A2E52E8} + {F7387F7F-59AF-4963-9D6E-8626E9E4D2EF} $(MSBuildProjectName) 1 1 @@ -27,7 +27,7 @@ true Debug Win32 - {A09CF05A-0501-47A9-98B5-48C0A9487ECA} + {1A27CDB5-8D3E-47CE-B9F3-6A9C3E964175} diff --git a/usb/umdf_filter_umdf/umdf_filter/WUDFOsrUsbFilter.vcxproj.Filters b/usb/umdf_filter_umdf/umdf_filter/WUDFOsrUsbFilter.vcxproj.Filters index f92d33fa..054dcbea 100644 --- a/usb/umdf_filter_umdf/umdf_filter/WUDFOsrUsbFilter.vcxproj.Filters +++ b/usb/umdf_filter_umdf/umdf_filter/WUDFOsrUsbFilter.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {AFBD23B1-572F-4E48-B155-B32902A4661E} + {5D7700E9-F17B-412A-AD01-7ABC0A91FC45} h;hpp;hxx;hm;inl;inc;xsd - {A72AB5BE-0993-4901-8D44-E3AC062578E8} + {6163CCCD-5DFB-441F-A144-DFAF53F65869} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {3D0316D0-D4C5-4718-8634-6072A187C604} + {C5FC49C2-D442-4645-9D78-BC6B98C60BBC} inf;inv;inx;mof;mc; - {10BE8A0E-56B7-4329-8582-2BB1E16F94E1} + {EE04D080-B627-4CBB-AD4E-2A9A70CEDE94} diff --git a/usb/umdf_filter_umdf/umdf_filter/WUDFOsrUsbFilterOnUmFx2Driver.inx b/usb/umdf_filter_umdf/umdf_filter/WUDFOsrUsbFilterOnUmFx2Driver.inx index fd920e03..db242508 100644 --- a/usb/umdf_filter_umdf/umdf_filter/WUDFOsrUsbFilterOnUmFx2Driver.inx +++ b/usb/umdf_filter_umdf/umdf_filter/WUDFOsrUsbFilterOnUmFx2Driver.inx @@ -58,8 +58,9 @@ UmdfDispatcher=WinUsb AddReg = CoInstallers_AddReg CopyFiles = CoInstallers_CopyFiles +; Needed for Win7 support [WinUsb_Install] -KmdfLibraryVersion=$KMDFVERSION$ +KmdfLibraryVersion=1.9 [WudfOsrUsbFilter_Install] UmdfLibraryVersion=$UMDFVERSION$ diff --git a/usb/umdf_filter_umdf/umdf_filter_umdf.sln b/usb/umdf_filter_umdf/umdf_filter_umdf.sln index 50055acd..0bdd1b1d 100644 --- a/usb/umdf_filter_umdf/umdf_filter_umdf.sln +++ b/usb/umdf_filter_umdf/umdf_filter_umdf.sln @@ -3,17 +3,17 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Package", "Package", "{531B99DD-B7DB-431D-A028-6843337B1B2E}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Package", "Package", "{E1970392-D253-4054-9859-047E430EAF95}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Umdf_filter", "Umdf_filter", "{C76583EA-D923-45F8-B74B-A08226D64DE4}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Umdf_filter", "Umdf_filter", "{DEE88039-9FB9-401D-B13D-727CBF613BCB}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Umdf_driver", "Umdf_driver", "{BA612164-8359-46AB-8A21-D2AD9B9EDCA5}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Umdf_driver", "Umdf_driver", "{2E02C638-E773-463D-918E-3A1FBA040E1D}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "package", "Package\package.VcxProj", "{92A41A0C-EC0F-4D98-B4DE-4899B375FD49}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "package", "Package\package.VcxProj", "{8D2391A3-43B4-4B9F-89E2-A4024B35FBAD}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WUDFOsrUsbFilter", "umdf_filter\WUDFOsrUsbFilter.vcxproj", "{E62A4AAA-870E-4D58-AA10-D9604A2E52E8}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WUDFOsrUsbFilter", "umdf_filter\WUDFOsrUsbFilter.vcxproj", "{F7387F7F-59AF-4963-9D6E-8626E9E4D2EF}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WUDFOsrUsbFx2", "umdf_driver\WUDFOsrUsbFx2.vcxproj", "{0D3781C2-2236-46B0-806D-387999E500AB}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WUDFOsrUsbFx2", "umdf_driver\WUDFOsrUsbFx2.vcxproj", "{81B31960-3EA8-4F43-B79A-5A851EC49CE8}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -23,37 +23,37 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {92A41A0C-EC0F-4D98-B4DE-4899B375FD49}.Debug|Win32.ActiveCfg = Debug|Win32 - {92A41A0C-EC0F-4D98-B4DE-4899B375FD49}.Debug|Win32.Build.0 = Debug|Win32 - {92A41A0C-EC0F-4D98-B4DE-4899B375FD49}.Release|Win32.ActiveCfg = Release|Win32 - {92A41A0C-EC0F-4D98-B4DE-4899B375FD49}.Release|Win32.Build.0 = Release|Win32 - {92A41A0C-EC0F-4D98-B4DE-4899B375FD49}.Debug|x64.ActiveCfg = Debug|x64 - {92A41A0C-EC0F-4D98-B4DE-4899B375FD49}.Debug|x64.Build.0 = Debug|x64 - {92A41A0C-EC0F-4D98-B4DE-4899B375FD49}.Release|x64.ActiveCfg = Release|x64 - {92A41A0C-EC0F-4D98-B4DE-4899B375FD49}.Release|x64.Build.0 = Release|x64 - {E62A4AAA-870E-4D58-AA10-D9604A2E52E8}.Debug|Win32.ActiveCfg = Debug|Win32 - {E62A4AAA-870E-4D58-AA10-D9604A2E52E8}.Debug|Win32.Build.0 = Debug|Win32 - {E62A4AAA-870E-4D58-AA10-D9604A2E52E8}.Release|Win32.ActiveCfg = Release|Win32 - {E62A4AAA-870E-4D58-AA10-D9604A2E52E8}.Release|Win32.Build.0 = Release|Win32 - {E62A4AAA-870E-4D58-AA10-D9604A2E52E8}.Debug|x64.ActiveCfg = Debug|x64 - {E62A4AAA-870E-4D58-AA10-D9604A2E52E8}.Debug|x64.Build.0 = Debug|x64 - {E62A4AAA-870E-4D58-AA10-D9604A2E52E8}.Release|x64.ActiveCfg = Release|x64 - {E62A4AAA-870E-4D58-AA10-D9604A2E52E8}.Release|x64.Build.0 = Release|x64 - {0D3781C2-2236-46B0-806D-387999E500AB}.Debug|Win32.ActiveCfg = Debug|Win32 - {0D3781C2-2236-46B0-806D-387999E500AB}.Debug|Win32.Build.0 = Debug|Win32 - {0D3781C2-2236-46B0-806D-387999E500AB}.Release|Win32.ActiveCfg = Release|Win32 - {0D3781C2-2236-46B0-806D-387999E500AB}.Release|Win32.Build.0 = Release|Win32 - {0D3781C2-2236-46B0-806D-387999E500AB}.Debug|x64.ActiveCfg = Debug|x64 - {0D3781C2-2236-46B0-806D-387999E500AB}.Debug|x64.Build.0 = Debug|x64 - {0D3781C2-2236-46B0-806D-387999E500AB}.Release|x64.ActiveCfg = Release|x64 - {0D3781C2-2236-46B0-806D-387999E500AB}.Release|x64.Build.0 = Release|x64 + {8D2391A3-43B4-4B9F-89E2-A4024B35FBAD}.Debug|Win32.ActiveCfg = Debug|Win32 + {8D2391A3-43B4-4B9F-89E2-A4024B35FBAD}.Debug|Win32.Build.0 = Debug|Win32 + {8D2391A3-43B4-4B9F-89E2-A4024B35FBAD}.Release|Win32.ActiveCfg = Release|Win32 + {8D2391A3-43B4-4B9F-89E2-A4024B35FBAD}.Release|Win32.Build.0 = Release|Win32 + {8D2391A3-43B4-4B9F-89E2-A4024B35FBAD}.Debug|x64.ActiveCfg = Debug|x64 + {8D2391A3-43B4-4B9F-89E2-A4024B35FBAD}.Debug|x64.Build.0 = Debug|x64 + {8D2391A3-43B4-4B9F-89E2-A4024B35FBAD}.Release|x64.ActiveCfg = Release|x64 + {8D2391A3-43B4-4B9F-89E2-A4024B35FBAD}.Release|x64.Build.0 = Release|x64 + {F7387F7F-59AF-4963-9D6E-8626E9E4D2EF}.Debug|Win32.ActiveCfg = Debug|Win32 + {F7387F7F-59AF-4963-9D6E-8626E9E4D2EF}.Debug|Win32.Build.0 = Debug|Win32 + {F7387F7F-59AF-4963-9D6E-8626E9E4D2EF}.Release|Win32.ActiveCfg = Release|Win32 + {F7387F7F-59AF-4963-9D6E-8626E9E4D2EF}.Release|Win32.Build.0 = Release|Win32 + {F7387F7F-59AF-4963-9D6E-8626E9E4D2EF}.Debug|x64.ActiveCfg = Debug|x64 + {F7387F7F-59AF-4963-9D6E-8626E9E4D2EF}.Debug|x64.Build.0 = Debug|x64 + {F7387F7F-59AF-4963-9D6E-8626E9E4D2EF}.Release|x64.ActiveCfg = Release|x64 + {F7387F7F-59AF-4963-9D6E-8626E9E4D2EF}.Release|x64.Build.0 = Release|x64 + {81B31960-3EA8-4F43-B79A-5A851EC49CE8}.Debug|Win32.ActiveCfg = Debug|Win32 + {81B31960-3EA8-4F43-B79A-5A851EC49CE8}.Debug|Win32.Build.0 = Debug|Win32 + {81B31960-3EA8-4F43-B79A-5A851EC49CE8}.Release|Win32.ActiveCfg = Release|Win32 + {81B31960-3EA8-4F43-B79A-5A851EC49CE8}.Release|Win32.Build.0 = Release|Win32 + {81B31960-3EA8-4F43-B79A-5A851EC49CE8}.Debug|x64.ActiveCfg = Debug|x64 + {81B31960-3EA8-4F43-B79A-5A851EC49CE8}.Debug|x64.Build.0 = Debug|x64 + {81B31960-3EA8-4F43-B79A-5A851EC49CE8}.Release|x64.ActiveCfg = Release|x64 + {81B31960-3EA8-4F43-B79A-5A851EC49CE8}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {92A41A0C-EC0F-4D98-B4DE-4899B375FD49} = {531B99DD-B7DB-431D-A028-6843337B1B2E} - {E62A4AAA-870E-4D58-AA10-D9604A2E52E8} = {C76583EA-D923-45F8-B74B-A08226D64DE4} - {0D3781C2-2236-46B0-806D-387999E500AB} = {BA612164-8359-46AB-8A21-D2AD9B9EDCA5} + {8D2391A3-43B4-4B9F-89E2-A4024B35FBAD} = {E1970392-D253-4054-9859-047E430EAF95} + {F7387F7F-59AF-4963-9D6E-8626E9E4D2EF} = {DEE88039-9FB9-401D-B13D-727CBF613BCB} + {81B31960-3EA8-4F43-B79A-5A851EC49CE8} = {2E02C638-E773-463D-918E-3A1FBA040E1D} EndGlobalSection EndGlobal diff --git a/usb/umdf_fx2/ReadMe.md b/usb/umdf_fx2/ReadMe.md new file mode 100644 index 00000000..e27415cc --- /dev/null +++ b/usb/umdf_fx2/ReadMe.md @@ -0,0 +1,343 @@ +Sample UMDF Function Driver for OSR USB-FX2 (UMDF Version 1) +============================================================ + +The umdf\_fx2 sample is a User-Mode Driver Framework (UMDF) driver for the OSR USB-FX2 device. It includes a test app and sample device metadata, and supports impersonation and idle power down. + +The sample can also be used with the CustomDeviceAccess MSDK sample. The sample demonstrates how to perform bulk and interrupt data transfers to an USB device. The specification for the device is at . The driver and sample device metadata also work with the [Custom driver access](http://go.microsoft.com/fwlink/p/?LinkID=248288) sample. + +Starting in Windows 8.1, the osrusbfx2 sample has been divided into these samples: + +- [WDF Sample Driver Learning Lab for OSR USB-FX2](http://msdn.microsoft.com/en-us/library/windows/hardware/): This sample is a series of iterative drivers that demonstrate how to write a "Hello World" driver and adds additional features in each step. + +- [kmdf\_fx2](gallery_samples.123a_gallery#1): This sample is the final version of kernel-mode [wdf\_osrfx2](http://msdn.microsoft.com/en-us/library/windows/hardware/) driver. The sample demonstrates KMDF methods. + +- umdf\_fx2: This sample is the final version of the user-mode driver [wdf\_osrfx2](http://msdn.microsoft.com/en-us/library/windows/hardware/). The sample demonstrates UMDF methods. + +Related topics +-------------- + +**** + +[kmdf\_fx2](http://msdn.microsoft.com/en-us/library/windows/hardware/) + + +Build the sample +---------------- + +The default Solution build configuration is Windows 8.1 Debug and Win32. You can change the default configuration to build for Windows 8 or Windows 7 version of the operating system. + +**To select a configuration and build a driver** + +1. Open the driver project or solution in Visual Studio 2013 (find *filtername*.sln or *filtername*.vcxproj). +2. Right-click the solution in the **Solutions Explorer** and select **Configuration Manager**. +3. From the **Configuration Manager**, select the **Active Solution Configuration** (for example, Windows 8.1 Debug or Windows 8.1 Release) and the **Active Solution Platform** (for example, Win32) that correspond to the type of build you are interested in. +4. From the **Build** menu, click **Build Solution** (Ctrl+Shift+B). + +Overview +-------- + +Here is the overview of the device: + +- The device is based on the development board supplied with the Cypress EZ-USB FX2 Development Kit (CY3681). +- It contains 1 interface and 3 endpoints (Interrupt IN, Bulk Out, Bulk IN). +- Firmware supports vendor commands to query or set LED Bar graph display and 7-segment LED display, and to query toggle switch states. +- Interrupt Endpoint: + - Sends an 8-bit value that represents the state of the switches. + - Sent on startup, resume from suspend, and whenever the switch pack setting changes. + - Firmware does not de-bounce the switch pack. + - One switch change can result in multiple bytes being sent. + - Bits are in the reverse order of the labels on the pack (for example, bit 0x80 is labeled 1 on the pack). +- Bulk Endpoints are configured for loopback: + - The device moves data from IN endpoint to OUT endpoint. + - The device does not change the values of the data it receives nor does it internally create any data. + - Endpoints are always double buffered. + - Maximum packet size depends on speed (64 full speed, 512 high speed). + +Testing the driver +------------------ + +You can use the [Custom driver access](http://go.microsoft.com/fwlink/p/?LinkID=248288) sample to test the umdf\_fx2 sample. + +This sample also includes a test application, osrusbfx2.exe, that you can use to test the device. This console application enumerates the interface registered by the driver and opens the device to send read, write, or IOCTL requests based on the command line options. + +Usage for Read/Write test: + +- -r [*n*], where *n* is number of bytes to read. +- -w [*n*], where *n* is number of bytes to write. +- -c [*n*], where *n* is number of iterations (default = 1). +- -v, shows verbose read data. +- -p, plays with Bar Display, Dip Switch, 7-Segment Display. +- -a, performs asynchronous I/O operation. +- -u, dumps USB configuration and pipe information. +- -f \<*filename*\> [*interval-seconds*], where *interval-seconds* is a delay in milliseconds, to send a text file to the seven-segment display (UMDF only) + +**Playing with the 7 segment display, toggle switches, and bar graph display** + +Use the command **osrusbfx2.exe -p** with options 1 through 9 to set and clear bar graph display, set and get 7 segment state, and read the toggle switch states. The following shows the function options: + +1. Light Bar +2. Clear Bar +3. Light entire Bar graph +4. Clear entire Bar graph +5. Get bar graph state +6. Get Switch state +7. Get Switch Interrupt Message +8. Get 7 segment state +9. Set 7 segment state +10. Reset the device +11. Re-enumerate the device + +0. Exit + +Selection: + +**Reset and re-enumerate the device** + +Use the command **osrusbfx2.exe -p** with options 10 and 11 to either reset the device or re-enumerate the device. + +**Read and write to bulk endpoints** + +The following commands send read and write requests to the device's bulk endpoint. + +- `osrusbfx2.exe -r 64` + + The preceding command reads 64 bytes to the bulk IN endpoint. + +- `osrusbfx2.exe -w 64 ` + + The preceding command writes 64 bytes to the bulk OUT endpoint. + +- `osrusbfx2.exe -r 64 -w 64 -c 100 -v` + + The preceding command first writes 64 bytes of data to bulk OUT endpoint (Pipe 1), then reads 64 bytes from bulk IN endpoint (Pipe 2), and then compares the read buffer with write buffer to see if they match. If the buffer contents match, it repeats this operation 100 times. + +- `osrusbfx2.exe -a` + + The preceding command reads and writes to the device asynchronously in an infinite loop. + +The bulk endpoints are double buffered. Depending on the operational speed (full or high), the buffer size is either 64 bytes or 512 bytes, respectively. A request to read data does not complete if the buffers are empty. If the buffers are full, a request to write data does not complete until the buffers are emptied. When you are doing a synchronous read, make sure the endpoint buffer has data (for example, when you send 512 bytes write request to the device operating in full speed mode). Because the endpoints are double buffered, the total buffer capacity is 256 bytes. The first 256 bytes fills the buffer and the write request waits in the USB stack until the buffers are emptied. If you run another instance of the application to read 512 bytes of data, both write and read requests complete successfully. + +**Displaying descriptors** + +The following command displays all the descriptors and endpoint information. + +**osrusbfx2.exe -u** + +If the device is operating in high speed mode, you get the following information: + +`===================` + +`USB_CONFIGURATION_DESCRIPTOR` + +`bLength = 0x9, decimal 9` + +`bDescriptorType = 0x2 ( USB_CONFIGURATION_DESCRIPTOR_TYPE )` + +`wTotalLength = 0x27, decimal 39` + +`bNumInterfaces = 0x1, decimal 1` + +`bConfigurationValue = 0x1, decimal 1` + +`iConfiguration = 0x4, decimal 4` + +`bmAttributes = 0xa0 ( USB_CONFIG_BUS_POWERED )` + +`MaxPower = 0x32, decimal 50` + +`-----------------------------` + +`USB_INTERFACE_DESCRIPTOR #0` + +`bLength = 0x9` + +`bDescriptorType = 0x4 ( USB_INTERFACE_DESCRIPTOR_TYPE )` + +`bInterfaceNumber = 0x0` + +`bAlternateSetting = 0x0` + +`bNumEndpoints = 0x3` + +`bInterfaceClass = 0xff` + +`bInterfaceSubClass = 0x0` + +`bInterfaceProtocol = 0x0` + +`bInterface = 0x0` + +`------------------------------` + +`USB_ENDPOINT_DESCRIPTOR for Pipe00` + +`bLength = 0x7` + +`bDescriptorType = 0x5 ( USB_ENDPOINT_DESCRIPTOR_TYPE )` + +`bEndpointAddress= 0x81 ( INPUT )` + +`bmAttributes= 0x3 ( USB_ENDPOINT_TYPE_INTERRUPT )` + +`wMaxPacketSize= 0x49, decimal 73` + +`bInterval = 0x1, decimal 1` + +`------------------------------` + +`USB_ENDPOINT_DESCRIPTOR for Pipe01` + +`bLength = 0x7` + +`bDescriptorType = 0x5 ( USB_ENDPOINT_DESCRIPTOR_TYPE )` + +`bEndpointAddress= 0x6 ( OUTPUT )` + +`bmAttributes= 0x2 ( USB_ENDPOINT_TYPE_BULK )` + +`wMaxPacketSize= 0x200, ` + +`decimal 512 bInterval = 0x0, ` + +`decimal 0` + +`------------------------------` + +`USB_ENDPOINT_DESCRIPTOR for Pipe02` + +`bLength = 0x7` + +`bDescriptorType = 0x5 ( USB_ENDPOINT_DESCRIPTOR_TYPE )` + +`bEndpointAddress= 0x88 ( INPUT )` + +`bmAttributes= 0x2 ( USB_ENDPOINT_TYPE_BULK )` + +`wMaxPacketSize= 0x200, decimal 512` + +`bInterval = 0x0, decimal 0` + +If the device is operating in low speed mode, you will get the following information: + +`===================` + +`USB_CONFIGURATION_DESCRIPTOR` + +`bLength = 0x9, decimal 9` + +`bDescriptorType = 0x2 ( USB_CONFIGURATION_DESCRIPTOR_TYPE )` + +`wTotalLength = 0x27, decimal 39` + +`bNumInterfaces = 0x1, decimal 1` + +`bConfigurationValue = 0x1, decimal 1` + +`iConfiguration = 0x3, decimal 3` + +`bmAttributes = 0xa0 ( USB_CONFIG_BUS_POWERED )` + +`MaxPower = 0x32, decimal 50 ` + +`-----------------------------` + +`USB_INTERFACE_DESCRIPTOR #0` + +`bLength = 0x9` + +`bDescriptorType = 0x4 ( USB_INTERFACE_DESCRIPTOR_TYPE )` + +`bInterfaceNumber = 0x0 bAlternateSetting = 0x0` + +`bNumEndpoints = 0x3` + +`bInterfaceClass = 0xff` + +`bInterfaceSubClass = 0x0` + +`bInterfaceProtocol = 0x0` + +`bInterface = 0x0` + +`------------------------------` + +`USB_ENDPOINT_DESCRIPTOR for Pipe00` + +`bLength = 0x7` + +`bDescriptorType = 0x5 ( USB_ENDPOINT_DESCRIPTOR_TYPE )` + +`bEndpointAddress= 0x81 ( INPUT )` + +`bmAttributes= 0x3 ( USB_ENDPOINT_TYPE_INTERRUPT )` + +`wMaxPacketSize= 0x49, decimal 73` + +`bInterval = 0x1, decimal 1` + +`------- -----------------------` + +`USB_ENDPOINT_DESCRIPTOR for Pipe01` + +`bLength = 0x7` + +`bDescriptorType = 0x5 ( USB_ENDPOINT_DESCRIPTOR_TYPE )` + +`bEndpointAddress= 0x6 ( OUTPUT )` + +`bmAttributes= 0x2 ( USB_ENDPOINT_TYPE_BULK )` + +`wMaxPacketSize= 0x40, decimal 64` + +`bInterval = 0x0, decimal 0` + +`------------------------------` + +`USB_ENDPOINT_DESCRIPTOR for Pipe02` + +`bLength = 0x7` + +`bDescriptorType = 0x5 ( USB_ENDPOINT_DESCRIPTOR_TYPE )` + +`bEndpointAddress= 0x88 ( INPUT )` + +`bmAttributes= 0x2 ( USB_ENDPOINT_TYPE_BULK )` + +`wMaxPacketSize= 0x40, decimal 64` + +`bInterval = 0x0, decimal 0 ` + +Sample Contents +--------------- + +Folder + +Description + +usb\\umdf\_fx2\\driver + +This directory contains driver code that demonstrates the following functionality: + +- Loads the driver and responds to PnP and Power events. You can install, uninstall, disable, enable, suspend, and resume the system. +- Registers a PnP device interface so that application can open a handle to the device. +- Implements **IPnpCallbackHardware** interface and initializes USB I/O targets in **IPnpCallbackHardware::OnPrepareHardware** method. +- Creates a sequential queue for handling IOCTL requests. +- Adds code to handle the IOCTL to set bar graph display. +- Creates a parallel queue for handling read and write requests. +- Retrieves memory from read and write requests, format the requests, and sends them to a USB target. +- Supports additional IOCTLs to get and set the 7-segment display, get bar graph display, and get config descriptor. +- Sets power policy for the device. +- Adds code to indicate that the device is ready by lighting up the period on 7-segment display. +- Calls **SetupDi** functions to determine the "BusTypeGUID" of the device, and uses impersonation to access resources that only the caller has access to. +- Shows how to implement idle and wake functionality to make the driver the power policy owner (PPO). The sample achieves this using power-managed queues and UMDF DDIs, AssignS0IdleSettings, and AssignSxWakeSettings. +- Demonstrates implementation of a continuous reader. +- Demonstrates the use of impersonation. + +usb\\umdf\_fx2\\exe + +This directory contains a test application that can be used to drive the UMDF driver and FX2 device. This is a modified version of the test application for the KMDF Fx2 driver. + +usb\\umdf\_fx2\\deviceMetadata + +This directory contains the device metadata package for the sample. You must copy the device metadata to the system before installing the device. For information on how to update and deploy device metadata, see [Custom driver access sample](http://go.microsoft.com/fwlink/p/?LinkID=248288). + diff --git a/usb/umdf_fx2/deviceMetadata/B4D697F5-1C56-4807-ACCD-B28C09D37FF0.devicemetadata-ms b/usb/umdf_fx2/deviceMetadata/B4D697F5-1C56-4807-ACCD-B28C09D37FF0.devicemetadata-ms new file mode 100644 index 00000000..5f8e82ee Binary files /dev/null and b/usb/umdf_fx2/deviceMetadata/B4D697F5-1C56-4807-ACCD-B28C09D37FF0.devicemetadata-ms differ diff --git a/usb/umdf_fx2/driver/ControlQueue.cpp b/usb/umdf_fx2/driver/ControlQueue.cpp new file mode 100644 index 00000000..f4058941 --- /dev/null +++ b/usb/umdf_fx2/driver/ControlQueue.cpp @@ -0,0 +1,564 @@ +/*++ + +Copyright (c) Microsoft Corporation, All Rights Reserved + +Module Name: + + ControlQueue.cpp + +Abstract: + + This file implements the I/O queue interface and performs + the ioctl operations. + +Environment: + + Windows User-Mode Driver Framework (WUDF) + +--*/ + +#include "internal.h" + +#include "winioctl.h" + +#include "ControlQueue.tmh" + +CMyControlQueue::CMyControlQueue( + _In_ PCMyDevice Device + ) : CMyQueue(Device) +{ + +} + +HRESULT +STDMETHODCALLTYPE +CMyControlQueue::QueryInterface( + _In_ REFIID InterfaceId, + _Out_ PVOID *Object + ) +/*++ + +Routine Description: + + + Query Interface + +Aruments: + + Follows COM specifications + +Return Value: + + HRESULT indicatin success or failure + +--*/ +{ + HRESULT hr; + + + if (IsEqualIID(InterfaceId, __uuidof(IQueueCallbackDeviceIoControl))) + { + hr = S_OK; + *Object = QueryIQueueCallbackDeviceIoControl(); + + } + else + { + hr = CMyQueue::QueryInterface(InterfaceId, Object); + } + + return hr; +} + +// +// Initialize +// + +HRESULT +CMyControlQueue::CreateInstance( + _In_ PCMyDevice Device, + _Out_ PCMyControlQueue *Queue + ) +/*++ + +Routine Description: + + + CreateInstance creates an instance of the queue object. + +Aruments: + + ppUkwn - OUT parameter is an IUnknown interface to the queue object + +Return Value: + + HRESULT indicatin success or failure + +--*/ +{ + PCMyControlQueue queue = NULL; + HRESULT hr = S_OK; + + queue = new CMyControlQueue(Device); + + if (NULL == queue) + { + hr = E_OUTOFMEMORY; + } + + // + // Call the queue callback object to initialize itself. This will create + // its partner queue framework object. + // + + if (SUCCEEDED(hr)) + { + hr = queue->Initialize(); + } + + if (SUCCEEDED(hr)) + { + *Queue = queue; + } + else + { + SAFE_RELEASE(queue); + } + + return hr; +} + +HRESULT +CMyControlQueue::Initialize( + VOID + ) +{ + HRESULT hr; + + // + // First initialize the base class. This will create the partner FxIoQueue + // object and setup automatic forwarding of I/O controls. + // + + // + // The framework (UMDF) will not deliver a + // request to the driver that arrives on a power-managed queue, unless + // the device is in a powered-up state. If you receive a request on a + // power-managed queue after the device has idled out, + // the framework will not be able to power-up and present the request + // to the driver unless it is the power policy owner (PPO). + // Since this driver is the PPO it can use power managed queues + // + + hr = __super::Initialize(WdfIoQueueDispatchSequential, + false, + true /* use power managed queue */); + + // + // return the status. + // + + return hr; +} + +VOID +STDMETHODCALLTYPE +CMyControlQueue::OnDeviceIoControl( + _In_ IWDFIoQueue *FxQueue, + _In_ IWDFIoRequest *FxRequest, + _In_ ULONG ControlCode, + _In_ SIZE_T InputBufferSizeInBytes, + _In_ SIZE_T OutputBufferSizeInBytes + ) +/*++ + +Routine Description: + + + DeviceIoControl dispatch routine + +Aruments: + + FxQueue - Framework Queue instance + FxRequest - Framework Request instance + ControlCode - IO Control Code + InputBufferSizeInBytes - Lenth of input buffer + OutputBufferSizeInBytes - Lenth of output buffer + + Always succeeds DeviceIoIoctl +Return Value: + + VOID + +--*/ +{ + UNREFERENCED_PARAMETER(FxQueue); + + IWDFMemory *memory = NULL; + PVOID buffer; + + SIZE_T bigBufferCb; + + ULONG information = 0; + + bool completeRequest = true; + + HRESULT hr = S_OK; + + switch (ControlCode) + { + case IOCTL_OSRUSBFX2_GET_CONFIG_DESCRIPTOR: + { + // + // Get the output buffer. + // + + FxRequest->GetOutputMemory(&memory ); + + // + // request the descriptor. + // + + ULONG bufferCb; + + // + // Get the buffer address then release the memory object. + // The memory object remains valid until the request is + // completed. + // + + buffer = memory->GetDataBuffer(&bigBufferCb); + memory->Release(); + + if (bigBufferCb > ULONG_MAX) + { + hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); + break; + } + else + { + bufferCb = (ULONG) bigBufferCb; + } + + hr = m_Device->GetUsbTargetDevice()->RetrieveDescriptor( + USB_CONFIGURATION_DESCRIPTOR_TYPE, + 0, + 0, + &bufferCb, + (PUCHAR) buffer + ); + + if (SUCCEEDED(hr)) + { + information = bufferCb; + } + + break; + } + + case IOCTL_OSRUSBFX2_GET_BAR_GRAPH_DISPLAY: + { + // + // Make sure the buffer is big enough to hold the result of the + // control transfer. + // + + if (OutputBufferSizeInBytes < sizeof(BAR_GRAPH_STATE)) + { + hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); + } + else + { + FxRequest->GetOutputMemory(&memory ); + } + + if (SUCCEEDED(hr)) + { + buffer = memory->GetDataBuffer(&bigBufferCb); + memory->Release(); + + hr = m_Device->GetBarGraphDisplay((PBAR_GRAPH_STATE) buffer); + } + + // + // If that worked then record how many bytes of data we're + // returning. + // + + if (SUCCEEDED(hr)) + { + information = sizeof(BAR_GRAPH_STATE); + } + + break; + } + + case IOCTL_OSRUSBFX2_SET_BAR_GRAPH_DISPLAY: + { + // + // Make sure the buffer is big enough to hold the input for the + // control transfer. + // + + if (InputBufferSizeInBytes < sizeof(BAR_GRAPH_STATE)) + { + hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); + } + else + { + FxRequest->GetInputMemory(&memory); + } + + // + // Get the data buffer and use it to set the bar graph on the + // device. + // + + if (SUCCEEDED(hr)) + { + buffer = memory->GetDataBuffer(&bigBufferCb); + memory->Release(); + + hr = m_Device->SetBarGraphDisplay((PBAR_GRAPH_STATE) buffer); + } + + break; + } + + case IOCTL_OSRUSBFX2_GET_7_SEGMENT_DISPLAY: + { + // + // Make sure the buffer is big enough to hold the result of the + // control transfer. + // + + if (OutputBufferSizeInBytes < sizeof(SEVEN_SEGMENT)) + { + hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); + } + else + { + FxRequest->GetOutputMemory(&memory ); + } + + if (SUCCEEDED(hr)) + { + buffer = memory->GetDataBuffer(&bigBufferCb); + memory->Release(); + hr = m_Device->GetSevenSegmentDisplay((PSEVEN_SEGMENT) buffer); + } + + // + // If that worked then record how many bytes of data we're + // returning. + // + + if (SUCCEEDED(hr)) + { + information = sizeof(SEVEN_SEGMENT); + } + + break; + } + + case IOCTL_OSRUSBFX2_SET_7_SEGMENT_DISPLAY: + { + // + // Make sure the buffer is big enough to hold the input for the + // control transfer. + // + + if (InputBufferSizeInBytes < sizeof(SEVEN_SEGMENT)) + { + hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); + } + else + { + FxRequest->GetInputMemory(&memory ); + } + + // + // Get the data buffer and use it to set the bar graph on the + // device. + // + + if (SUCCEEDED(hr)) + { + buffer = memory->GetDataBuffer(&bigBufferCb); + memory->Release(); + + hr = m_Device->SetSevenSegmentDisplay((PSEVEN_SEGMENT) buffer); + } + break; + } + + case IOCTL_OSRUSBFX2_READ_SWITCHES: + { + // + // Make sure the buffer is big enough to hold the input for the + // control transfer. + // + + if (OutputBufferSizeInBytes < sizeof(SWITCH_STATE)) + { + hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); + } + else + { + FxRequest->GetOutputMemory(&memory ); + } + + // + // Get the data buffer and use it to set the bar graph on the + // device. + // + + if (SUCCEEDED(hr)) + { + buffer = memory->GetDataBuffer(&bigBufferCb); + memory->Release(); + + hr = m_Device->ReadSwitchState((PSWITCH_STATE) buffer); + } + + if (SUCCEEDED(hr)) + { + information = sizeof(SWITCH_STATE); + } + + break; + } + + case IOCTL_OSRUSBFX2_GET_INTERRUPT_MESSAGE: + { + // + // Make sure the buffer is big enough to hold the switch + // state. + // + + if (OutputBufferSizeInBytes < sizeof(SWITCH_STATE)) + { + hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); + } + else + { + // + // Forward the request to the switch state change queue. + // + + hr = FxRequest->ForwardToIoQueue( + m_Device->GetSwitchChangeQueue() + ); + + if (SUCCEEDED(hr)) + { + completeRequest = false; + } + } + + break; + } + + case IOCTL_OSRUSBFX2_RESET_DEVICE: + case IOCTL_OSRUSBFX2_REENUMERATE_DEVICE: + { + // + // WinUSB does not allow us to reset or re-enumerate the device. + // Return not-supported for the error in both of these cases. + // + + hr = HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); + break; + } + + case IOCTL_OSRUSBFX2_PLAY_FILE: + { + // + // This IOCTL demonstrates how to use impersonation to access + // resources using the credentials provided by the client. Note + // that for impersonation to work it has to be enabled in the device + // INF and the client must allow impersonation when they open the + // device. + // + // This IOCTL opens a file using the path provided by the client + // and then plays the characters in that file out to the seven segment + // display in a worker thread. + // + + PFILE_PLAYBACK playback; + SIZE_T playbackCb; + size_t realPlaybackCb; + + FxRequest->GetInputMemory(&memory); + + if (memory == NULL) + { + hr = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER); + break; + } + + // + // Get the playback structure from the input buffer. + // + + playback = (PFILE_PLAYBACK) memory->GetDataBuffer(&playbackCb); + + memory->Release(); + + // + // Make sure the length is at least as big as the fixed portion + // of the input structure. + // + + if (playbackCb < (FIELD_OFFSET(FILE_PLAYBACK, Path))) + { + hr = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER); + break; + } + + // + // Make sure the file name is at least one character long. + // + + playbackCb -= FIELD_OFFSET(FILE_PLAYBACK, Path); + + if (playbackCb < sizeof(WCHAR)) + { + hr = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER); + break; + } + + // + // Verify that the string provided is valid. + // + + hr = StringCbLength(playback->Path, + min(playbackCb, (STRSAFE_MAX_CCH * sizeof(WCHAR))), + &realPlaybackCb); + + if (FAILED(hr)) + { + break; + } + + hr = m_Device->PlaybackFile(playback, FxRequest); + + break; + } + + + + default: + { + hr = HRESULT_FROM_WIN32(ERROR_INVALID_FUNCTION); + break; + } + } + + if (completeRequest) + { + FxRequest->CompleteWithInformation(hr, information); + } + + return; +} diff --git a/usb/umdf_fx2/driver/ControlQueue.h b/usb/umdf_fx2/driver/ControlQueue.h new file mode 100644 index 00000000..251521e1 --- /dev/null +++ b/usb/umdf_fx2/driver/ControlQueue.h @@ -0,0 +1,101 @@ +/*++ + +Copyright (c) Microsoft Corporation, All Rights Reserved + +Module Name: + + ControlQueue.h + +Abstract: + + This file defines the queue callback object for handling device I/O + control requests. This is a serialized queue. + +Environment: + + Windows User-Mode Driver Framework (WUDF) + +--*/ + +#pragma once + +// +// Queue Callback Object. +// + +class CMyControlQueue : public IQueueCallbackDeviceIoControl, + public CMyQueue +{ + HRESULT + Initialize( + VOID + ); + +public: + + CMyControlQueue( + _In_ PCMyDevice Device + ); + + virtual + ~CMyControlQueue( + VOID + ) + { + return; + } + + static + HRESULT + CreateInstance( + _In_ PCMyDevice Device, + _Out_ PCMyControlQueue *Queue + ); + + HRESULT + Configure( + VOID + ) + { + return S_OK; + } + + IQueueCallbackDeviceIoControl * + QueryIQueueCallbackDeviceIoControl( + VOID + ) + { + AddRef(); + return static_cast(this); + } + + // + // IUnknown + // + + STDMETHOD_(ULONG,AddRef) (VOID) {return CUnknown::AddRef();} + + _At_(this, __drv_freesMem(object)) + STDMETHOD_(ULONG,Release) (VOID) {return CUnknown::Release();} + + STDMETHOD_(HRESULT, QueryInterface)( + _In_ REFIID InterfaceId, + _Out_ PVOID *Object + ); + + // + // Wdf Callbacks + // + + // + // IQueueCallbackDeviceIoControl + // + STDMETHOD_ (void, OnDeviceIoControl)( + _In_ IWDFIoQueue *pWdfQueue, + _In_ IWDFIoRequest *pWdfRequest, + _In_ ULONG ControlCode, + _In_ SIZE_T InputBufferSizeInBytes, + _In_ SIZE_T OutputBufferSizeInBytes + ); +}; + diff --git a/usb/umdf_fx2/driver/Device.cpp b/usb/umdf_fx2/driver/Device.cpp new file mode 100644 index 00000000..2ebf4079 --- /dev/null +++ b/usb/umdf_fx2/driver/Device.cpp @@ -0,0 +1,2087 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved. + +Module Name: + + Device.cpp + +Abstract: + + This module contains the implementation of the UMDF OSR Fx2 driver's + device callback object. + +Environment: + + Windows User-Mode Driver Framework (WUDF) + +--*/ +#include "internal.h" +#include "initguid.h" +#include "usb_hw.h" +#include + +#include "device.tmh" +#define CONCURRENT_READS 2 + +CMyDevice::~CMyDevice( + ) +{ + SAFE_RELEASE(m_pIoTargetInterruptPipeStateMgmt); +} + +HRESULT +CMyDevice::CreateInstance( + _In_ IWDFDriver *FxDriver, + _In_ IWDFDeviceInitialize * FxDeviceInit, + _Out_ PCMyDevice *Device + ) +/*++ + + Routine Description: + + This method creates and initializs an instance of the OSR Fx2 driver's + device callback object. + + Arguments: + + FxDeviceInit - the settings for the device. + + Device - a location to store the referenced pointer to the device object. + + Return Value: + + Status + +--*/ +{ + PCMyDevice device; + HRESULT hr; + + // + // Allocate a new instance of the device class. + // + + device = new CMyDevice(); + + if (NULL == device) + { + return E_OUTOFMEMORY; + } + + // + // Initialize the instance. + // + + hr = device->Initialize(FxDriver, FxDeviceInit); + + if (SUCCEEDED(hr)) + { + *Device = device; + } + else + { + device->Release(); + } + + return hr; +} + +HRESULT +CMyDevice::Initialize( + _In_ IWDFDriver * FxDriver, + _In_ IWDFDeviceInitialize * FxDeviceInit + ) +/*++ + + Routine Description: + + This method initializes the device callback object and creates the + partner device object. + + The method should perform any device-specific configuration that: + * could fail (these can't be done in the constructor) + * must be done before the partner object is created -or- + * can be done after the partner object is created and which aren't + influenced by any device-level parameters the parent (the driver + in this case) might set. + + Arguments: + + FxDeviceInit - the settings for this device. + + Return Value: + + status. + +--*/ +{ + IWDFDevice2 *fxDevice = NULL; + + HRESULT hr = S_OK; + + // + // TODO: Any per-device initialization which must be done before + // creating the partner object. + // + + // + // Set no locking unless you need an automatic callbacks synchronization + // + + FxDeviceInit->SetLockingConstraint(None); + + // + // TODO: If you're writing a filter driver then indicate that here. + // And then don't claim power policy ownership below + // + // FxDeviceInit->SetFilter(); + // + + // + // Set the Fx2 driver as the power policy owner. + // + + FxDeviceInit->SetPowerPolicyOwnership(TRUE); + + // + // Create a new FX device object and assign the new callback object to + // handle any device level events that occur. + // + + // + // QueryIUnknown references the IUnknown interface that it returns + // (which is the same as referencing the device). We pass that to + // CreateDevice, which takes its own reference if everything works. + // + + if (SUCCEEDED(hr)) + { + IUnknown *unknown = this->QueryIUnknown(); + IWDFDevice* device1; + + hr = FxDriver->CreateDevice(FxDeviceInit, unknown, &device1); + + // + // Convert the interface to version 2 + // + + if (SUCCEEDED(hr)) { + device1->QueryInterface(IID_PPV_ARGS(&fxDevice)); + _Analysis_assume_(fxDevice != NULL); + device1->Release(); + } + + unknown->Release(); + } + + // + // If that succeeded then set our FxDevice member variable. + // + + if (SUCCEEDED(hr)) + { + m_FxDevice = fxDevice; + + // + // Drop the reference we got from CreateDevice. Since this object + // is partnered with the framework object they have the same + // lifespan - there is no need for an additional reference. + // + + fxDevice->Release(); + } + + return hr; +} + +HRESULT +CMyDevice::Configure( + VOID + ) +/*++ + + Routine Description: + + This method is called after the device callback object has been initialized + and returned to the driver. It would setup the device's queues and their + corresponding callback objects. + + Arguments: + + FxDevice - the framework device object for which we're handling events. + + Return Value: + + status + +--*/ +{ + HRESULT hr = S_OK; + + // + // Get the bus type GUID for the device and confirm that we're attached to + // USB. + // + // NOTE: Since this device only supports USB we'd normally trust our INF + // to ensure this. + // + // But if the device also supported 1394 then we could + // use this to determine which type of bus we were attached to. + // + + hr = GetBusTypeGuid(); + + if (FAILED(hr)) + { + return hr; + } + + // + // Create the read-write queue. + // + + hr = CMyReadWriteQueue::CreateInstance(this, &m_ReadWriteQueue); + + if (FAILED(hr)) + { + return hr; + } + + // + // We use default queue for read/write + // + + hr = m_ReadWriteQueue->Configure(); + + m_ReadWriteQueue->Release(); + + // + // Create the control queue and configure forwarding for IOCTL requests. + // + + if (SUCCEEDED(hr)) + { + hr = CMyControlQueue::CreateInstance(this, &m_ControlQueue); + + if (SUCCEEDED(hr)) + { + hr = m_ControlQueue->Configure(); + if (SUCCEEDED(hr)) + { + m_FxDevice->ConfigureRequestDispatching( + m_ControlQueue->GetFxQueue(), + WdfRequestDeviceIoControl, + true + ); + } + m_ControlQueue->Release(); + } + } + + // + // Create a manual I/O queue to hold requests for notification when + // the switch state changes. + // + + hr = m_FxDevice->CreateIoQueue(NULL, + FALSE, + WdfIoQueueDispatchManual, + FALSE, + FALSE, + &m_SwitchChangeQueue); + + + // + // Release creation reference as object tree will keep a reference + // + + m_SwitchChangeQueue->Release(); + + if (SUCCEEDED(hr)) + { + hr = m_FxDevice->CreateDeviceInterface(&GUID_DEVINTERFACE_OSRUSBFX2, + NULL); + } + + // + // Mark the interface as restricted to allow access to applications bound + // using device metadata. Failures here are not fatal so we log them but + // ignore them otherwise. + // + if (SUCCEEDED(hr)) + { + WDF_PROPERTY_STORE_ROOT RootSpecifier; + IWDFUnifiedPropertyStoreFactory * pUnifiedPropertyStoreFactory = NULL; + IWDFUnifiedPropertyStore * pUnifiedPropertyStore = NULL; + DEVPROP_BOOLEAN isRestricted = DEVPROP_TRUE; + HRESULT hrSetProp; + + hrSetProp = m_FxDevice->QueryInterface(IID_PPV_ARGS(&pUnifiedPropertyStoreFactory)); + + WUDF_TEST_DRIVER_ASSERT(SUCCEEDED(hrSetProp)); + + RootSpecifier.LengthCb = sizeof(RootSpecifier); + RootSpecifier.RootClass = WdfPropertyStoreRootClassDeviceInterfaceKey; + RootSpecifier.Qualifier.DeviceInterfaceKey.InterfaceGUID = &GUID_DEVINTERFACE_OSRUSBFX2; + RootSpecifier.Qualifier.DeviceInterfaceKey.ReferenceString = NULL; + + hrSetProp = pUnifiedPropertyStoreFactory->RetrieveUnifiedDevicePropertyStore(&RootSpecifier, + &pUnifiedPropertyStore); + + if (SUCCEEDED(hrSetProp)) + { + hrSetProp = pUnifiedPropertyStore->SetPropertyData(&DEVPKEY_DeviceInterface_Restricted, + 0, // Lcid + 0, // Flags + DEVPROP_TYPE_BOOLEAN, + sizeof(isRestricted), + &isRestricted); + } + + if (FAILED(hrSetProp)) + { + TraceEvents(TRACE_LEVEL_ERROR, + TEST_TRACE_DEVICE, + "%!FUNC! Could not set restricted property %!HRESULT!", + hrSetProp + ); + } + + SAFE_RELEASE(pUnifiedPropertyStoreFactory); + SAFE_RELEASE(pUnifiedPropertyStore); + } + + return hr; +} + +HRESULT +CMyDevice::QueryInterface( + _In_ REFIID InterfaceId, + _Outptr_ PVOID *Object + ) +/*++ + + Routine Description: + + This method is called to get a pointer to one of the object's callback + interfaces. + + Arguments: + + InterfaceId - the interface being requested + + Object - a location to store the interface pointer if successful + + Return Value: + + S_OK or E_NOINTERFACE + +--*/ +{ + HRESULT hr; + + if (IsEqualIID(InterfaceId, __uuidof(IPnpCallbackHardware))) + { + *Object = QueryIPnpCallbackHardware(); + hr = S_OK; + } + else if (IsEqualIID(InterfaceId, __uuidof(IPnpCallback))) + { + *Object = QueryIPnpCallback(); + hr = S_OK; + } + else if (IsEqualIID(InterfaceId, __uuidof(IPnpCallbackSelfManagedIo))) + { + *Object = QueryIPnpCallbackSelfManagedIo(); + hr = S_OK; + } + else if(IsEqualIID(InterfaceId, __uuidof(IUsbTargetPipeContinuousReaderCallbackReadersFailed))) + { + *Object = QueryContinousReaderFailureCompletion(); + hr = S_OK; + } + else if(IsEqualIID(InterfaceId, __uuidof(IUsbTargetPipeContinuousReaderCallbackReadComplete))) + { + *Object = QueryContinousReaderCompletion(); + hr = S_OK; + } + else + { + hr = CUnknown::QueryInterface(InterfaceId, Object); + } + + return hr; +} + +HRESULT +CMyDevice::OnPrepareHardware( + _In_ IWDFDevice * /* FxDevice */ + ) +/*++ + +Routine Description: + + This routine is invoked to ready the driver + to talk to hardware. It opens the handle to the + device and talks to it using the WINUSB interface. + It invokes WINUSB to discver the interfaces and stores + the information related to bulk endpoints. + +Arguments: + + FxDevice : Pointer to the WDF device interface + +Return Value: + + HRESULT + +--*/ +{ + PWSTR deviceName = NULL; + DWORD deviceNameCch = 0; + + HRESULT hr; + + // + // Get the device name. + // Get the length to allocate first + // + + hr = m_FxDevice->RetrieveDeviceName(NULL, &deviceNameCch); + + if (FAILED(hr)) + { + TraceEvents(TRACE_LEVEL_ERROR, + TEST_TRACE_DEVICE, + "%!FUNC! Cannot get device name %!HRESULT!", + hr + ); + } + + // + // Allocate the buffer + // + + if (SUCCEEDED(hr)) + { + deviceName = new WCHAR[deviceNameCch]; + + if (deviceName == NULL) + { + hr = E_OUTOFMEMORY; + } + } + + // + // Get the actual name + // + + if (SUCCEEDED(hr)) + { + hr = m_FxDevice->RetrieveDeviceName(deviceName, &deviceNameCch); + + if (FAILED(hr)) + { + TraceEvents(TRACE_LEVEL_ERROR, + TEST_TRACE_DEVICE, + "%!FUNC! Cannot get device name %!HRESULT!", + hr + ); + } + } + + if (SUCCEEDED(hr)) + { + TraceEvents(TRACE_LEVEL_INFORMATION, + TEST_TRACE_DEVICE, + "%!FUNC! Device name %S", + deviceName + ); + } + + // + // Create USB I/O Targets and configure them + // + + if (SUCCEEDED(hr)) + { + hr = CreateUsbIoTargets(); + } + + if (SUCCEEDED(hr)) + { + ULONG length = sizeof(m_Speed); + + hr = m_pIUsbTargetDevice->RetrieveDeviceInformation(DEVICE_SPEED, + &length, + &m_Speed); + if (FAILED(hr)) + { + TraceEvents(TRACE_LEVEL_ERROR, + TEST_TRACE_DEVICE, + "%!FUNC! Cannot get usb device speed information %!HRESULT!", + hr + ); + } + } + + if (SUCCEEDED(hr)) + { + TraceEvents(TRACE_LEVEL_INFORMATION, + TEST_TRACE_DEVICE, + "%!FUNC! Speed - %x\n", + m_Speed + ); + } + + if (SUCCEEDED(hr)) + { + hr = ConfigureUsbPipes(); + } + + // Setup power-management settings on the device. + // + + if (SUCCEEDED(hr)) + { + hr = SetPowerManagement(); + } + + // + // + // Clear the seven segement display to indicate that we're done with + // prepare hardware. + // + + if (SUCCEEDED(hr)) + { + hr = IndicateDeviceReady(); + } + + if (SUCCEEDED(hr)) + { + hr = ConfigContReaderForInterruptEndPoint(); + } + + delete[] deviceName; + + return hr; +} + +HRESULT +CMyDevice::OnReleaseHardware( + _In_ IWDFDevice * /* FxDevice */ + ) +/*++ + +Routine Description: + + This routine is invoked when the device is being removed or stopped + It releases all resources allocated for this device. + +Arguments: + + FxDevice - Pointer to the Device object. + +Return Value: + + HRESULT - Always succeeds. + +--*/ +{ + // + // Delete USB Target Device WDF Object, this will in turn + // delete all the children - interface and the pipe objects + // + // This makes sure that + // 1. We drain the the pending read which does not come from an I/O queue + // 2. We remove USB target objects from object tree (and thereby free them) + // before any potential subsequent OnPrepareHardware creates new ones + // + // m_pIUsbTargetDevice could be NULL if OnPrepareHardware failed so we need + // to guard against that + // + + if (m_pIUsbTargetDevice) + { + m_pIUsbTargetDevice->DeleteWdfObject(); + } + + return S_OK; +} + +HRESULT +CMyDevice::CreateUsbIoTargets( + ) +/*++ + +Routine Description: + + This routine creates Usb device, interface and pipe objects + +Arguments: + + None + +Return Value: + + HRESULT +--*/ +{ + HRESULT hr; + UCHAR NumEndPoints = 0; + IWDFUsbTargetFactory * pIUsbTargetFactory = NULL; + IWDFUsbTargetDevice * pIUsbTargetDevice = NULL; + IWDFUsbInterface * pIUsbInterface = NULL; + IWDFUsbTargetPipe * pIUsbPipe = NULL; + + hr = m_FxDevice->QueryInterface(IID_PPV_ARGS(&pIUsbTargetFactory)); + + if (FAILED(hr)) + { + TraceEvents(TRACE_LEVEL_ERROR, + TEST_TRACE_DEVICE, + "%!FUNC! Cannot get usb target factory %!HRESULT!", + hr + ); + } + + if (SUCCEEDED(hr)) + { + hr = pIUsbTargetFactory->CreateUsbTargetDevice( + &pIUsbTargetDevice); + if (FAILED(hr)) + { + TraceEvents(TRACE_LEVEL_ERROR, + TEST_TRACE_DEVICE, + "%!FUNC! Unable to create USB Device I/O Target %!HRESULT!", + hr + ); + } + else + { + m_pIUsbTargetDevice = pIUsbTargetDevice; + + // + // Release the creation reference as object tree will maintain a reference + // + + pIUsbTargetDevice->Release(); + } + } + + if (SUCCEEDED(hr)) + { + UCHAR NumInterfaces = pIUsbTargetDevice->GetNumInterfaces(); + + WUDF_TEST_DRIVER_ASSERT(1 == NumInterfaces); + + hr = pIUsbTargetDevice->RetrieveUsbInterface(0, &pIUsbInterface); + if (FAILED(hr)) + { + TraceEvents(TRACE_LEVEL_ERROR, + TEST_TRACE_DEVICE, + "%!FUNC! Unable to retrieve USB interface from USB Device I/O Target %!HRESULT!", + hr + ); + } + else + { + m_pIUsbInterface = pIUsbInterface; + + pIUsbInterface->Release(); //release creation reference + } + } + + if (SUCCEEDED(hr)) + { + NumEndPoints = pIUsbInterface->GetNumEndPoints(); + + if (NumEndPoints != NUM_OSRUSB_ENDPOINTS) { + hr = E_UNEXPECTED; + TraceEvents(TRACE_LEVEL_ERROR, + TEST_TRACE_DEVICE, + "%!FUNC! Has %d endpoints, expected %d, returning %!HRESULT! ", + NumEndPoints, + NUM_OSRUSB_ENDPOINTS, + hr + ); + } + } + + if (SUCCEEDED(hr)) + { + for (UCHAR PipeIndex = 0; PipeIndex < NumEndPoints; PipeIndex++) + { + hr = pIUsbInterface->RetrieveUsbPipeObject(PipeIndex, + &pIUsbPipe); + + if (FAILED(hr)) + { + TraceEvents(TRACE_LEVEL_ERROR, + TEST_TRACE_DEVICE, + "%!FUNC! Unable to retrieve USB Pipe for PipeIndex %d, %!HRESULT!", + PipeIndex, + hr + ); + } + else + { + if ( pIUsbPipe->IsInEndPoint() ) + { + if ( UsbdPipeTypeInterrupt == pIUsbPipe->GetType() ) + { + m_pIUsbInterruptPipe = pIUsbPipe; + + WUDF_TEST_DRIVER_ASSERT (m_pIoTargetInterruptPipeStateMgmt == NULL); + + hr = m_pIUsbInterruptPipe->QueryInterface(__uuidof( + IWDFIoTargetStateManagement), + reinterpret_cast(&m_pIoTargetInterruptPipeStateMgmt) + ); + if (FAILED(hr)) + { + m_pIoTargetInterruptPipeStateMgmt = NULL; + } + } + else if ( UsbdPipeTypeBulk == pIUsbPipe->GetType() ) + { + m_pIUsbInputPipe = pIUsbPipe; + } + else + { + pIUsbPipe->DeleteWdfObject(); + } + } + else if ( pIUsbPipe->IsOutEndPoint() && (UsbdPipeTypeBulk == pIUsbPipe->GetType()) ) + { + m_pIUsbOutputPipe = pIUsbPipe; + } + else + { + pIUsbPipe->DeleteWdfObject(); + } + + SAFE_RELEASE(pIUsbPipe); //release creation reference + } + } + + if (NULL == m_pIUsbInputPipe || NULL == m_pIUsbOutputPipe) + { + hr = E_UNEXPECTED; + TraceEvents(TRACE_LEVEL_ERROR, + TEST_TRACE_DEVICE, + "%!FUNC! Input or output pipe not found, returning %!HRESULT!", + hr + ); + } + } + + SAFE_RELEASE(pIUsbTargetFactory); + + return hr; +} + +HRESULT +CMyDevice::ConfigureUsbPipes( + ) +/*++ + +Routine Description: + + This routine retrieves the IDs for the bulk end points of the USB device. + +Arguments: + + None + +Return Value: + + HRESULT +--*/ +{ + HRESULT hr = S_OK; + LONG timeout; + + // + // Set timeout policies for input/output pipes + // + + if (SUCCEEDED(hr)) + { + timeout = ENDPOINT_TIMEOUT; + + hr = m_pIUsbInputPipe->SetPipePolicy(PIPE_TRANSFER_TIMEOUT, + sizeof(timeout), + &timeout); + if (FAILED(hr)) + { + TraceEvents(TRACE_LEVEL_ERROR, + TEST_TRACE_DEVICE, + "%!FUNC! Unable to set timeout policy for input pipe %!HRESULT!", + hr + ); + } + } + + if (SUCCEEDED(hr)) + { + timeout = ENDPOINT_TIMEOUT; + + hr = m_pIUsbOutputPipe->SetPipePolicy(PIPE_TRANSFER_TIMEOUT, + sizeof(timeout), + &timeout); + if (FAILED(hr)) + { + TraceEvents(TRACE_LEVEL_ERROR, + TEST_TRACE_DEVICE, + "%!FUNC! Unable to set timeout policy for output pipe %!HRESULT!", + hr + ); + } + } + + return hr; +} + +HRESULT +CMyDevice::IndicateDeviceReady( + VOID + ) +/*++ + + Routine Description: + + This method lights the period on the device's seven-segment display to + indicate that the driver's PrepareHardware method has completed. + + Arguments: + + None + + Return Value: + + Status + +--*/ +{ + SEVEN_SEGMENT display = {0}; + + HRESULT hr; + + // + // First read the contents of the seven segment display. + // + + hr = GetSevenSegmentDisplay(&display); + + if (SUCCEEDED(hr)) + { + display.Segments |= 0x08; + + hr = SetSevenSegmentDisplay(&display); + } + + return hr; +} + +HRESULT +CMyDevice::GetBarGraphDisplay( + _In_ PBAR_GRAPH_STATE BarGraphState + ) +/*++ + + Routine Description: + + This method synchronously retrieves the bar graph display information + from the OSR USB-FX2 device. It uses the buffers in the FxRequest + to hold the data it retrieves. + + Arguments: + + FxRequest - the request for the bar-graph info. + + Return Value: + + Status + +--*/ +{ + WINUSB_CONTROL_SETUP_PACKET setupPacket; + + ULONG bytesReturned; + + HRESULT hr = S_OK; + + // + // Zero the contents of the buffer - the controller OR's in every + // light that's set. + // + + BarGraphState->BarsAsUChar = 0; + + // + // Setup the control packet. + // + + WINUSB_CONTROL_SETUP_PACKET_INIT( &setupPacket, + BmRequestDeviceToHost, + BmRequestToDevice, + USBFX2LK_READ_BARGRAPH_DISPLAY, + 0, + 0 ); + + // + // Issue the request to WinUsb. + // + + hr = SendControlTransferSynchronously( + &(setupPacket.WinUsb), + (PUCHAR) BarGraphState, + sizeof(BAR_GRAPH_STATE), + &bytesReturned + ); + + return hr; +} + +HRESULT +CMyDevice::SetBarGraphDisplay( + _In_ PBAR_GRAPH_STATE BarGraphState + ) +/*++ + + Routine Description: + + This method synchronously sets the bar graph display on the OSR USB-FX2 + device using the buffers in the FxRequest as input. + + Arguments: + + FxRequest - the request to set the bar-graph info. + + Return Value: + + Status + +--*/ +{ + WINUSB_CONTROL_SETUP_PACKET setupPacket; + + ULONG bytesTransferred; + + HRESULT hr = S_OK; + + // + // Setup the control packet. + // + + WINUSB_CONTROL_SETUP_PACKET_INIT( &setupPacket, + BmRequestHostToDevice, + BmRequestToDevice, + USBFX2LK_SET_BARGRAPH_DISPLAY, + 0, + 0 ); + + // + // Issue the request to WinUsb. + // + + hr = SendControlTransferSynchronously( + &(setupPacket.WinUsb), + (PUCHAR) BarGraphState, + sizeof(BAR_GRAPH_STATE), + &bytesTransferred + ); + + + return hr; +} + +HRESULT +CMyDevice::GetSevenSegmentDisplay( + _In_ PSEVEN_SEGMENT SevenSegment + ) +/*++ + + Routine Description: + + This method synchronously retrieves the bar graph display information + from the OSR USB-FX2 device. It uses the buffers in the FxRequest + to hold the data it retrieves. + + Arguments: + + FxRequest - the request for the bar-graph info. + + Return Value: + + Status + +--*/ +{ + WINUSB_CONTROL_SETUP_PACKET setupPacket; + + ULONG bytesReturned; + + HRESULT hr = S_OK; + + // + // Zero the output buffer - the device will or in the bits for + // the lights that are set. + // + + SevenSegment->Segments = 0; + + // + // Setup the control packet. + // + + WINUSB_CONTROL_SETUP_PACKET_INIT( &setupPacket, + BmRequestDeviceToHost, + BmRequestToDevice, + USBFX2LK_READ_7SEGMENT_DISPLAY, + 0, + 0 ); + + // + // Issue the request to WinUsb. + // + + hr = SendControlTransferSynchronously( + &(setupPacket.WinUsb), + (PUCHAR) SevenSegment, + sizeof(SEVEN_SEGMENT), + &bytesReturned + ); + + return hr; +} + +HRESULT +CMyDevice::SetSevenSegmentDisplay( + _In_ PSEVEN_SEGMENT SevenSegment + ) +/*++ + + Routine Description: + + This method synchronously sets the bar graph display on the OSR USB-FX2 + device using the buffers in the FxRequest as input. + + Arguments: + + FxRequest - the request to set the bar-graph info. + + Return Value: + + Status + +--*/ +{ + WINUSB_CONTROL_SETUP_PACKET setupPacket; + + ULONG bytesTransferred; + + HRESULT hr = S_OK; + + // + // Setup the control packet. + // + + WINUSB_CONTROL_SETUP_PACKET_INIT( &setupPacket, + BmRequestHostToDevice, + BmRequestToDevice, + USBFX2LK_SET_7SEGMENT_DISPLAY, + 0, + 0 ); + + // + // Issue the request to WinUsb. + // + + hr = SendControlTransferSynchronously( + &(setupPacket.WinUsb), + (PUCHAR) SevenSegment, + sizeof(SEVEN_SEGMENT), + &bytesTransferred + ); + + return hr; +} + +HRESULT +CMyDevice::ReadSwitchState( + _In_ PSWITCH_STATE SwitchState + ) +/*++ + + Routine Description: + + This method synchronously retrieves the bar graph display information + from the OSR USB-FX2 device. It uses the buffers in the FxRequest + to hold the data it retrieves. + + Arguments: + + FxRequest - the request for the bar-graph info. + + Return Value: + + Status + +--*/ +{ + WINUSB_CONTROL_SETUP_PACKET setupPacket; + + ULONG bytesReturned; + + HRESULT hr = S_OK; + + // + // Zero the output buffer - the device will or in the bits for + // the lights that are set. + // + + SwitchState->SwitchesAsUChar = 0; + + // + // Setup the control packet. + // + + WINUSB_CONTROL_SETUP_PACKET_INIT( &setupPacket, + BmRequestDeviceToHost, + BmRequestToDevice, + USBFX2LK_READ_SWITCHES, + 0, + 0 ); + + // + // Issue the request to WinUsb. + // + + hr = SendControlTransferSynchronously( + &(setupPacket.WinUsb), + (PUCHAR) SwitchState, + sizeof(SWITCH_STATE), + &bytesReturned + ); + + return hr; +} + +HRESULT +CMyDevice::SendControlTransferSynchronously( + _In_ PWINUSB_SETUP_PACKET SetupPacket, + _Inout_updates_(BufferLength) PBYTE Buffer, + _In_ ULONG BufferLength, + _Out_ PULONG LengthTransferred + ) +{ + HRESULT hr = S_OK; + HRESULT hrRequest = S_OK; + IWDFIoRequest *pWdfRequest = NULL; + IWDFDriver * FxDriver = NULL; + IWDFMemory * FxMemory = NULL; + IWDFRequestCompletionParams * FxComplParams = NULL; + IWDFUsbRequestCompletionParams * FxUsbComplParams = NULL; + + *LengthTransferred = 0; + + hr = m_FxDevice->CreateRequest( NULL, //pCallbackInterface + NULL, //pParentObject + &pWdfRequest); + hrRequest = hr; + + if (SUCCEEDED(hr)) + { + m_FxDevice->GetDriver(&FxDriver); + + hr = FxDriver->CreatePreallocatedWdfMemory( Buffer, + BufferLength, + NULL, //pCallbackInterface + pWdfRequest, //pParetObject + &FxMemory ); + } + + if (SUCCEEDED(hr)) + { + hr = m_pIUsbTargetDevice->FormatRequestForControlTransfer( pWdfRequest, + SetupPacket, + FxMemory, + NULL); //TransferOffset + } + + if (SUCCEEDED(hr)) + { + hr = pWdfRequest->Send( m_pIUsbTargetDevice, + WDF_REQUEST_SEND_OPTION_SYNCHRONOUS, + 0); //Timeout + } + + if (SUCCEEDED(hr)) + { + pWdfRequest->GetCompletionParams(&FxComplParams); + + hr = FxComplParams->GetCompletionStatus(); + } + + if (SUCCEEDED(hr)) + { + HRESULT hrQI = FxComplParams->QueryInterface(IID_PPV_ARGS(&FxUsbComplParams)); + WUDF_TEST_DRIVER_ASSERT(SUCCEEDED(hrQI)); + + WUDF_TEST_DRIVER_ASSERT( WdfUsbRequestTypeDeviceControlTransfer == + FxUsbComplParams->GetCompletedUsbRequestType() ); + + FxUsbComplParams->GetDeviceControlTransferParameters( NULL, + LengthTransferred, + NULL, + NULL ); + } + + SAFE_RELEASE(FxUsbComplParams); + SAFE_RELEASE(FxComplParams); + SAFE_RELEASE(FxMemory); + + if (SUCCEEDED(hrRequest)) + { + pWdfRequest->DeleteWdfObject(); + } + SAFE_RELEASE(pWdfRequest); + + SAFE_RELEASE(FxDriver); + + return hr; +} + +WDF_IO_TARGET_STATE +CMyDevice::GetTargetState( + IWDFIoTarget * pTarget + ) +{ + IWDFIoTargetStateManagement * pStateMgmt = NULL; + WDF_IO_TARGET_STATE state; + + HRESULT hrQI = pTarget->QueryInterface(IID_PPV_ARGS(&pStateMgmt)); + WUDF_TEST_DRIVER_ASSERT((SUCCEEDED(hrQI) && pStateMgmt)); + + state = pStateMgmt->GetState(); + + SAFE_RELEASE(pStateMgmt); + + return state; +} + +VOID +CMyDevice::ServiceSwitchChangeQueue( + _In_ SWITCH_STATE NewState, + _In_ HRESULT CompletionStatus, + _In_opt_ IWDFFile *SpecificFile + ) +/*++ + + Routine Description: + + This method processes switch-state change notification requests as + part of reading the OSR device's interrupt pipe. As each read completes + this pulls all pending I/O off the switch change queue and completes + each request with the current switch state. + + Arguments: + + NewState - the state of the switches + + CompletionStatus - all pending operations are completed with this status. + + SpecificFile - if provided only requests for this file object will get + completed. + + Return Value: + + None + +--*/ +{ + IWDFIoRequest *fxRequest; + + HRESULT enumHr = S_OK; + + do + { + HRESULT hr; + + // + // Get the next request. + // + + if (NULL != SpecificFile) + { + enumHr = m_SwitchChangeQueue->RetrieveNextRequestByFileObject( + SpecificFile, + &fxRequest + ); + } + else + { + enumHr = m_SwitchChangeQueue->RetrieveNextRequest(&fxRequest); + } + + // + // if we got one then complete it. + // + + if (SUCCEEDED(enumHr)) + { + if (SUCCEEDED(CompletionStatus)) + { + IWDFMemory *fxMemory; + + // + // First copy the result to the request buffer. + // + + fxRequest->GetOutputMemory(&fxMemory ); + + hr = fxMemory->CopyFromBuffer(0, + &NewState, + sizeof(SWITCH_STATE)); + fxMemory->Release(); + } + else + { + hr = CompletionStatus; + } + + // + // Complete the request with the status of the copy (or the completion + // status if that was an error). + // + + if (SUCCEEDED(hr)) + { + fxRequest->CompleteWithInformation(hr, sizeof(SWITCH_STATE)); + } + else + { + fxRequest->Complete(hr); + } + + fxRequest->Release(); + } + } + while (SUCCEEDED(enumHr)); +} + +HRESULT +CMyDevice::SetPowerManagement( + VOID + ) +/*++ + + Routine Description: + + This method enables the idle and wake functionality + using UMDF. UMDF has been set as the power policy + owner (PPO) for the device stack and we are using power + managed queues. + + Arguments: + + None + + Return Value: + + Status + +--*/ +{ + HRESULT hr; + + // + // Enable USB selective suspend on the device. + // + + hr = m_FxDevice->AssignS0IdleSettings( IdleUsbSelectiveSuspend, + PowerDeviceMaximum, + IDLE_TIMEOUT_IN_MSEC, + IdleAllowUserControl, + WdfUseDefault); + + if (FAILED(hr)) + { + TraceEvents(TRACE_LEVEL_ERROR, + TEST_TRACE_DEVICE, + "%!FUNC! Unable to assign S0 idle settings for the device %!HRESULT!", + hr + ); + } + + // + // Enable Sx wake settings + // + + if (SUCCEEDED(hr)) + { + hr = m_FxDevice->AssignSxWakeSettings( PowerDeviceMaximum, + WakeAllowUserControl, + WdfUseDefault); + + if (FAILED(hr)) + { + TraceEvents(TRACE_LEVEL_ERROR, + TEST_TRACE_DEVICE, + "%!FUNC! Unable to set Sx Wake Settings for the device %!HRESULT!", + hr + ); + } + + } + + + return hr; +} + +HRESULT +CMyDevice::OnD0Entry( + _In_ IWDFDevice* pWdfDevice, + _In_ WDF_POWER_DEVICE_STATE previousState + ) +{ + UNREFERENCED_PARAMETER(pWdfDevice); + UNREFERENCED_PARAMETER(previousState); + + // + // Start/Stop the I/O target if you support a continuous reader. + // The rest of the I/O is fed through power managed queues. The queue + // itself will stop feeding I/O to targets (and will wait for any pending + // I/O to complete before going into low power state), hence targets + // don’t need to be stopped/started. The continuous reader I/O is outside + // of power managed queues so we need to Stop the I/O target on D0Exit and + // start it on D0Entry. Please note that bulk pipe target doesn't need to + // be stopped/started because I/O submitted to this pipe comes from power + // managed I/O queue, which delivers I/O only in power on state. + // + + m_pIoTargetInterruptPipeStateMgmt->Start(); + + return S_OK; +} + +HRESULT +CMyDevice::OnD0Exit( + _In_ IWDFDevice* pWdfDevice, + _In_ WDF_POWER_DEVICE_STATE previousState + ) +{ + UNREFERENCED_PARAMETER(pWdfDevice); + UNREFERENCED_PARAMETER(previousState); + + // + // Stop the I/O target always succeedes. + // + m_pIoTargetInterruptPipeStateMgmt->Stop(WdfIoTargetCancelSentIo); + return S_OK; +} + +void +CMyDevice::OnSurpriseRemoval( + _In_ IWDFDevice* pWdfDevice + ) +{ + UNREFERENCED_PARAMETER(pWdfDevice); + return; +} + +HRESULT +CMyDevice::OnQueryRemove( + _In_ IWDFDevice* pWdfDevice + ) +{ + UNREFERENCED_PARAMETER(pWdfDevice); + return S_OK; +} + +HRESULT +CMyDevice::OnQueryStop( + _In_ IWDFDevice* pWdfDevice + ) +{ + UNREFERENCED_PARAMETER(pWdfDevice); + return S_OK; +} + +// +// Self Managed Io Callbacks +// + +VOID +CMyDevice::OnSelfManagedIoCleanup( + _In_ IWDFDevice* pWdfDevice + ) +{ + UNREFERENCED_PARAMETER(pWdfDevice); + return; +} + +VOID +CMyDevice::OnSelfManagedIoFlush( + _In_ IWDFDevice* pWdfDevice + ) +{ + UNREFERENCED_PARAMETER(pWdfDevice); + + // + // Complete every switch change operation with an error. + // + ServiceSwitchChangeQueue(m_SwitchState, + HRESULT_FROM_WIN32(ERROR_DEVICE_REMOVED), + NULL); + + return; +} + +HRESULT +CMyDevice::OnSelfManagedIoInit( + _In_ IWDFDevice* pWdfDevice + ) +{ + UNREFERENCED_PARAMETER(pWdfDevice); + return S_OK; +} + +HRESULT +CMyDevice::OnSelfManagedIoRestart( + _In_ IWDFDevice* pWdfDevice + ) +{ + UNREFERENCED_PARAMETER(pWdfDevice); + return S_OK; +} + +HRESULT +CMyDevice::OnSelfManagedIoStop( + _In_ IWDFDevice* pWdfDevice + ) +{ + UNREFERENCED_PARAMETER(pWdfDevice); + return S_OK; +} + +HRESULT +CMyDevice::OnSelfManagedIoSuspend( + _In_ IWDFDevice* pWdfDevice + ) +{ + UNREFERENCED_PARAMETER(pWdfDevice); + return S_OK; +} + + + +HRESULT +CMyDevice::ConfigContReaderForInterruptEndPoint( + VOID + ) +/*++ + +Routine Description: + + This routine configures a continuous reader on the + interrupt endpoint. It's called from the PrepareHarware event. + +Arguments: + + +Return Value: + + HRESULT value + +--*/ +{ + HRESULT hr, hrQI; + IUsbTargetPipeContinuousReaderCallbackReadComplete *pOnCompletionCallback = NULL; + IUsbTargetPipeContinuousReaderCallbackReadersFailed *pOnFailureCallback= NULL; + IWDFUsbTargetPipe2 * pIUsbInterruptPipe2; + + hrQI = this->QueryInterface(IID_PPV_ARGS(&pOnCompletionCallback)); + WUDF_TEST_DRIVER_ASSERT((SUCCEEDED(hrQI) && pOnCompletionCallback)); + + hrQI = this->QueryInterface(IID_PPV_ARGS(&pOnFailureCallback)); + WUDF_TEST_DRIVER_ASSERT((SUCCEEDED(hrQI) && pOnFailureCallback)); + + hrQI = m_pIUsbInterruptPipe->QueryInterface(IID_PPV_ARGS(&pIUsbInterruptPipe2)); + WUDF_TEST_DRIVER_ASSERT((SUCCEEDED(hrQI) && pIUsbInterruptPipe2)); + + // + // Reader requests are not posted to the target automatically. + // Driver must explictly call WdfIoTargetStart to kick start the + // reader. In this sample, it's done in D0Entry. + // By defaut, framework queues two requests to the target + // endpoint. Driver can configure up to 10 requests with the + // parameter CONCURRENT_READS + // + hr = pIUsbInterruptPipe2->ConfigureContinuousReader( sizeof(m_SwitchStateBuffer), + 0,//header + 0,//trailer + CONCURRENT_READS, + NULL, + pOnCompletionCallback, + m_pIUsbInterruptPipe, + pOnFailureCallback + ); + + if (FAILED(hr)) { + TraceEvents(TRACE_LEVEL_ERROR, TEST_TRACE_DEVICE, + "OsrFxConfigContReaderForInterruptEndPoint failed %!HRESULT!", + hr); + } + + SAFE_RELEASE(pOnCompletionCallback); + SAFE_RELEASE(pOnFailureCallback); + SAFE_RELEASE(pIUsbInterruptPipe2); + + return hr; +} + + +BOOL +CMyDevice::OnReaderFailure( + IWDFUsbTargetPipe * pPipe, + HRESULT hrCompletion + ) +{ + UNREFERENCED_PARAMETER(pPipe); + + m_InterruptReadProblem = hrCompletion; + TraceEvents(TRACE_LEVEL_INFORMATION, + TEST_TRACE_DEVICE, + "%!FUNC! Failure completed with %!HRESULT!", + hrCompletion + ); + + ServiceSwitchChangeQueue(m_SwitchState, + hrCompletion, + NULL); + + return TRUE; +} + +VOID +CMyDevice::OnReaderCompletion( + IWDFUsbTargetPipe * pPipe, + IWDFMemory * pMemory, + SIZE_T NumBytesTransferred, + PVOID Context + ) +{ + WUDF_TEST_DRIVER_ASSERT(pPipe == (IWDFUsbTargetPipe *)Context); + + // + // Make sure that there is data in the read packet. Depending on the device + // specification, it is possible for it to return a 0 length read in + // certain conditions. + // + + if (NumBytesTransferred == 0) { + TraceEvents(TRACE_LEVEL_INFORMATION, + TEST_TRACE_DEVICE, + "%!FUNC! Zero length read occured on the Interrupt Pipe's " + "Continuous Reader\n" + ); + return; + } + + WUDF_TEST_DRIVER_ASSERT(NumBytesTransferred == sizeof(m_SwitchState)); + + // + // Get the switch state + // + + PVOID pBuff = pMemory->GetDataBuffer(NULL); + + CopyMemory(&m_SwitchState, pBuff, sizeof(m_SwitchState)); + + + // + // Satisfy application request for switch change notification + // + + ServiceSwitchChangeQueue(m_SwitchState, + S_OK, + NULL); + + // + // Make sure that the request that got completed is the one that we reuse + // Don't Delete the request because it gets reused + // +} + + +HRESULT +CMyDevice::GetBusTypeGuid( + VOID + ) +/*++ + + Routine Description: + + This routine gets the device instance ID then invokes SetupDi to + retrieve the bus type guid for the device. The bus type guid is + stored in object. + + Arguments: + + None + + Return Value: + + Status + +--*/ +{ + ULONG instanceIdCch = 0; + PWSTR instanceId = NULL; + + HDEVINFO deviceInfoSet = NULL; + SP_DEVINFO_DATA deviceInfo = {sizeof(SP_DEVINFO_DATA)}; + + HRESULT hr; + + // + // Retrieve the device instance ID. + // + + hr = m_FxDevice->RetrieveDeviceInstanceId(NULL, &instanceIdCch); + + if (FAILED(hr)) + { + goto Exit; + } + + instanceId = new WCHAR[instanceIdCch]; + + if (instanceId == NULL) + { + hr = E_OUTOFMEMORY; + goto Exit; + } + + hr = m_FxDevice->RetrieveDeviceInstanceId(instanceId, &instanceIdCch); + + if (FAILED(hr)) + { + goto Exit2; + } + + // + // Call SetupDI to open the device info. + // + + deviceInfoSet = SetupDiCreateDeviceInfoList(NULL, NULL); + + if (deviceInfoSet == INVALID_HANDLE_VALUE) + { + hr = HRESULT_FROM_WIN32(GetLastError()); + goto Exit2; + } + + if (SetupDiOpenDeviceInfo(deviceInfoSet, + instanceId, + NULL, + 0, + &deviceInfo) == FALSE) + { + hr = HRESULT_FROM_WIN32(GetLastError()); + goto Exit3; + } + + if (SetupDiGetDeviceRegistryProperty(deviceInfoSet, + &deviceInfo, + SPDRP_BUSTYPEGUID, + NULL, + (PBYTE) &m_BusTypeGuid, + sizeof(m_BusTypeGuid), + NULL) == FALSE) + { + hr = HRESULT_FROM_WIN32(GetLastError()); + goto Exit3; + } + +Exit3: + SetupDiDestroyDeviceInfoList(deviceInfoSet); + +Exit2: + + delete[] instanceId; + +Exit: + + return hr; +} + +HRESULT +CMyDevice::PlaybackFile( + _In_ PFILE_PLAYBACK PlayInfo, + _In_ IWDFIoRequest *FxRequest + ) +/*++ + + Routine Description: + + This method impersonates the caller, opens the file and prints each + character to the seven segement display. + + Arguments: + + PlayInfo - the playback info from the request. + + FxRequest - the request (used for impersonation) + + Return Value: + + Status + +--*/ + +{ + PLAYBACK_IMPERSONATION_CONTEXT context = {PlayInfo, NULL, S_OK}; + IWDFIoRequest2* fxRequest2; + + HRESULT hr; + + // Convert FxRequest to FxRequest2. No error can occur here. + FxRequest->QueryInterface(IID_PPV_ARGS(&fxRequest2)); + _Analysis_assume_(fxRequest2 != NULL); + + // + // Impersonate and open the playback file. + // + + hr = FxRequest->Impersonate( + SecurityImpersonation, + this->QueryIImpersonateCallback(), + &context + ); + if (FAILED(hr)) + { + goto exit; + } + + // + // Release the reference that was added in QueryIImpersonateCallback() + // + this->Release(); + + hr = context.Hr; + + if (FAILED(hr)) + { + goto exit; + } + + // + // The impersonation callback succeeded - tell code analysis that the + // file handle is non-null + // + + _Analysis_assume_(context.FileHandle != NULL); + + // + // Read from the file one character at a time until we hit + // EOF or the request is cancelled. + // + + do + { + UCHAR c; + ULONG bytesRead; + + // + // Check for cancellation. + // + + if (fxRequest2->IsCanceled()) + { + hr = HRESULT_FROM_WIN32(ERROR_CANCELLED); + } + else + { + BOOL result; + + // + // Read a character from the file and see if we can + // encode it on the display. + // + + result = ReadFile(context.FileHandle, + &c, + sizeof(c), + &bytesRead, + NULL); + + if (result) + { + SEVEN_SEGMENT segment; + BAR_GRAPH_STATE barGraph; + + if (bytesRead > 0) + { + #pragma prefast(suppress:__WARNING_USING_UNINIT_VAR,"Above this->Release() method does not actually free 'this'") + if(EncodeSegmentValue(c, &segment) == true) + { + barGraph.BarsAsUChar = c; + + SetSevenSegmentDisplay(&segment); + SetBarGraphDisplay(&barGraph); + } + + Sleep(PlayInfo->Delay); + } + else + { + hr = S_OK; + break; + } + } + else + { + hr = HRESULT_FROM_WIN32(GetLastError()); + } + } + + } while(SUCCEEDED(hr)); + + CloseHandle(context.FileHandle); + +exit: + + fxRequest2->Release(); + return hr; +} + +VOID +CMyDevice::OnImpersonate( + _In_ PVOID Context + ) +/*++ + + Routine Description: + + This routine handles the impersonation for the PLAY FILE I/O control. + + Arguments: + + Context - pointer to the impersonation context + + Return Value: + + None + +--*/ +{ + PPLAYBACK_IMPERSONATION_CONTEXT context; + + context = (PPLAYBACK_IMPERSONATION_CONTEXT) Context; + + context->FileHandle = CreateFile(context->PlaybackInfo->Path, + GENERIC_READ, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + + if (context->FileHandle == INVALID_HANDLE_VALUE) + { + DWORD error = GetLastError(); + context->Hr = HRESULT_FROM_WIN32(error); + } + else + { + context->Hr = S_OK; + } + + return; +} + +#define SS_LEFT (SS_TOP_LEFT | SS_BOTTOM_LEFT) +#define SS_RIGHT (SS_TOP_RIGHT | SS_BOTTOM_RIGHT) + +bool +CMyDevice::EncodeSegmentValue( + _In_ UCHAR Character, + _Out_ SEVEN_SEGMENT *SevenSegment + ) +{ + UCHAR letterMap[] = { + (SS_TOP | SS_BOTTOM_LEFT | SS_RIGHT | SS_CENTER | SS_BOTTOM), // a + (SS_LEFT | SS_CENTER | SS_BOTTOM | SS_BOTTOM_RIGHT), // b + (SS_CENTER | SS_BOTTOM_LEFT | SS_BOTTOM), // c + (SS_BOTTOM_LEFT | SS_CENTER | SS_BOTTOM | SS_RIGHT), // d + (SS_LEFT | SS_TOP | SS_CENTER | SS_BOTTOM), // e + (SS_LEFT | SS_TOP | SS_CENTER), // f + (SS_TOP | SS_TOP_LEFT | SS_CENTER | SS_BOTTOM | SS_RIGHT), // g + (SS_LEFT | SS_RIGHT | SS_CENTER), // h + (SS_BOTTOM_LEFT), // i + (SS_BOTTOM | SS_RIGHT), // j + (SS_LEFT | SS_CENTER | SS_BOTTOM), // k + (SS_LEFT | SS_BOTTOM), // l + (SS_LEFT | SS_TOP | SS_RIGHT), // m + (SS_BOTTOM_LEFT | SS_CENTER | SS_BOTTOM_RIGHT), // n + (SS_BOTTOM_LEFT | SS_BOTTOM_RIGHT | SS_CENTER | SS_BOTTOM), // o + (SS_LEFT | SS_TOP | SS_CENTER | SS_TOP_RIGHT), // p + (SS_TOP_LEFT | SS_TOP | SS_CENTER | SS_RIGHT), // q + (SS_BOTTOM_LEFT | SS_CENTER), // r + (SS_TOP_LEFT | + SS_TOP | SS_CENTER | SS_BOTTOM | + SS_BOTTOM_RIGHT), // s + (SS_TOP | SS_RIGHT), // t + (SS_LEFT | SS_RIGHT | SS_BOTTOM), // u + (SS_BOTTOM_LEFT | SS_BOTTOM | SS_BOTTOM_RIGHT), // v + (SS_LEFT | SS_BOTTOM | SS_BOTTOM_RIGHT), // w + (SS_LEFT | SS_CENTER | SS_RIGHT), // x + (SS_TOP_LEFT | SS_CENTER | SS_RIGHT), // y + (SS_TOP_RIGHT | + SS_TOP | SS_CENTER | SS_BOTTOM | + SS_BOTTOM_LEFT), // z + }; + + UCHAR numberMap[] = { + (SS_LEFT | SS_TOP | SS_BOTTOM | SS_RIGHT | SS_DOT), // 0 + (SS_RIGHT | SS_DOT), // 1 + (SS_TOP | + SS_TOP_RIGHT | SS_CENTER | SS_BOTTOM_LEFT | + SS_BOTTOM | SS_DOT), // 2 + (SS_TOP | SS_CENTER | SS_BOTTOM | SS_RIGHT | SS_DOT), // 3 + (SS_TOP_LEFT | SS_CENTER | SS_RIGHT | SS_DOT), // 4 + (SS_TOP_LEFT | + SS_TOP | SS_CENTER | SS_BOTTOM | + SS_BOTTOM_RIGHT | SS_DOT), // 5 + (SS_TOP | SS_CENTER | SS_BOTTOM | + SS_LEFT | SS_BOTTOM_RIGHT | SS_DOT), // 6 + (SS_TOP | SS_RIGHT | SS_DOT), // 7 + (SS_TOP | SS_BOTTOM | SS_CENTER | + SS_LEFT | SS_RIGHT | SS_DOT), // 8 + (SS_TOP_LEFT | SS_TOP | SS_CENTER | SS_RIGHT | SS_DOT), // 9 + }; + + if (((Character >= 'a') && (Character <= 'z')) || + ((Character >= 'A') && (Character <= 'Z'))) + { + SevenSegment->Segments = letterMap[tolower(Character) - 'a']; + return true; + } + else if ((Character >= '0') && (Character <= '9')) + { + SevenSegment->Segments = numberMap[Character - '0']; + return true; + } + else + { + SevenSegment->Segments = 0; + return false; + } +} + diff --git a/usb/umdf_fx2/driver/Device.h b/usb/umdf_fx2/driver/Device.h new file mode 100644 index 00000000..641a04de --- /dev/null +++ b/usb/umdf_fx2/driver/Device.h @@ -0,0 +1,604 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved + +Module Name: + + Device.h + +Abstract: + + This module contains the type definitions for the UMDF OSR Fx2 sample + driver's device callback class. + +Environment: + + Windows User-Mode Driver Framework (WUDF) + +--*/ + +#pragma once +#include "internal.h" + +#define ENDPOINT_TIMEOUT 10000 +#define NUM_OSRUSB_ENDPOINTS 3 + +// +// Define the vendor commands supported by our device +// +#define USBFX2LK_READ_7SEGMENT_DISPLAY 0xD4 +#define USBFX2LK_READ_SWITCHES 0xD6 +#define USBFX2LK_READ_BARGRAPH_DISPLAY 0xD7 +#define USBFX2LK_SET_BARGRAPH_DISPLAY 0xD8 +#define USBFX2LK_IS_HIGH_SPEED 0xD9 +#define USBFX2LK_REENUMERATE 0xDA +#define USBFX2LK_SET_7SEGMENT_DISPLAY 0xDB + +typedef struct { + UCHAR Segments; +} SEVEN_SEGMENT, *PSEVEN_SEGMENT; + +// +// Context for the impersonation callback. +// + +typedef struct +{ + PFILE_PLAYBACK PlaybackInfo; + + HANDLE FileHandle; + + HRESULT Hr; +} PLAYBACK_IMPERSONATION_CONTEXT, *PPLAYBACK_IMPERSONATION_CONTEXT; + +// +// Class for the driver. +// + +class CMyDevice : + public CUnknown, + public IPnpCallbackHardware, + public IPnpCallback, + public IPnpCallbackSelfManagedIo, + public IUsbTargetPipeContinuousReaderCallbackReadersFailed, + public IUsbTargetPipeContinuousReaderCallbackReadComplete, + public IImpersonateCallback +{ +// +// Private data members. +// +private: + // + // Weak reference to framework device + // Use IWDFDevice2 so we can set power policy settings + // + IWDFDevice2 *m_FxDevice; + + // + // Weak reference to the control queue + // + PCMyReadWriteQueue m_ReadWriteQueue; + + // + // Weak reference to the control queue + // + PCMyControlQueue m_ControlQueue; + + // + // The bus type for this device (used here for + // illustrative purposes only) + // + + GUID m_BusTypeGuid; + + // + // USB Device I/O Target + // + IWDFUsbTargetDevice * m_pIUsbTargetDevice; + + // + // USB Interface + // + IWDFUsbInterface * m_pIUsbInterface; + + // + // USB Input pipe for Reads + // + IWDFUsbTargetPipe * m_pIUsbInputPipe; + + // + // USB Output pipe for writes + // + IWDFUsbTargetPipe * m_pIUsbOutputPipe; + + // + // USB interrupt pipe + // + IWDFUsbTargetPipe * m_pIUsbInterruptPipe; + + // + // Use I/O target state management interfaces if you are going to + // support a continuous reader. + // + + // + // USB interrupt pipe state management + // + IWDFIoTargetStateManagement * m_pIoTargetInterruptPipeStateMgmt; + + // + // Device Speed (Low, Full, High) + // + UCHAR m_Speed; + + // + // Current switch state + // + SWITCH_STATE m_SwitchState; + + // + // Request to be used for pending reads from interrupt pipe + // (to get switch state change notifications) + // + + IWDFIoRequest * m_RequestForPendingRead; + + // + // If reads stopped because of a transient problem, the error status + // is stored here. + // + + HRESULT m_InterruptReadProblem; + + // + // Switch state buffer - this might hold the transient value + // m_SwitchState holds stable value of the switch state + // + SWITCH_STATE m_SwitchStateBuffer; + + // + // A manual queue to hold requests for changes in the I/O switch state. + // + + IWDFIoQueue * m_SwitchChangeQueue; + +// +// Private methods. +// + +private: + + CMyDevice( + VOID + ) : + m_FxDevice(NULL), + m_ControlQueue(NULL), + m_ReadWriteQueue(NULL), + m_SwitchChangeQueue(NULL), + m_pIUsbTargetDevice(NULL), + m_pIUsbInterface(NULL), + m_pIUsbInputPipe(NULL), + m_pIUsbOutputPipe(NULL), + m_pIUsbInterruptPipe(NULL), + m_Speed(0), + m_InterruptReadProblem(S_OK), + m_RequestForPendingRead(NULL), + m_pIoTargetInterruptPipeStateMgmt(NULL) + { + ZeroMemory(&m_BusTypeGuid, sizeof(m_BusTypeGuid)); + } + + ~CMyDevice( + ); + + HRESULT + Initialize( + _In_ IWDFDriver *FxDriver, + _In_ IWDFDeviceInitialize *FxDeviceInit + ); + + // + // Helper methods + // + + HRESULT + GetBusTypeGuid( + VOID + ); + + HRESULT + CreateUsbIoTargets( + VOID + ); + + + HRESULT + ConfigureUsbPipes( + ); + + HRESULT + SetPowerManagement( + VOID + ); + + HRESULT + IndicateDeviceReady( + VOID + ); + + // + // Helper functions + // + + HRESULT + SendControlTransferSynchronously( + _In_ PWINUSB_SETUP_PACKET SetupPacket, + _Inout_updates_(BufferLength) PBYTE Buffer, + _In_ ULONG BufferLength, + _Out_ PULONG LengthTransferred + ); + + static + WDF_IO_TARGET_STATE + GetTargetState( + IWDFIoTarget * pTarget + ); + + VOID + ServiceSwitchChangeQueue( + _In_ SWITCH_STATE NewState, + _In_ HRESULT CompletionStatus, + _In_opt_ IWDFFile *SpecificFile + ); + +// +// Public methods +// +public: + + // + // The factory method used to create an instance of this driver. + // + + static + HRESULT + CreateInstance( + _In_ IWDFDriver *FxDriver, + _In_ IWDFDeviceInitialize *FxDeviceInit, + _Out_ PCMyDevice *Device + ); + + IWDFDevice * + GetFxDevice( + VOID + ) + { + return m_FxDevice; + } + + HRESULT + Configure( + VOID + ); + + IPnpCallback * + QueryIPnpCallback( + VOID + ) + { + AddRef(); + return static_cast(this); + } + + IPnpCallbackHardware * + QueryIPnpCallbackHardware( + VOID + ) + { + AddRef(); + return static_cast(this); + } + + IPnpCallbackSelfManagedIo * + QueryIPnpCallbackSelfManagedIo( + VOID + ) + { + AddRef(); + return static_cast(this); + } + + + IUsbTargetPipeContinuousReaderCallbackReadersFailed * + QueryContinousReaderFailureCompletion( + VOID + ) + { + AddRef(); + return static_cast(this); + } + + IUsbTargetPipeContinuousReaderCallbackReadComplete * + QueryContinousReaderCompletion( + VOID + ) + { + AddRef(); + return static_cast(this); + } + + IImpersonateCallback * + QueryIImpersonateCallback( + VOID + ) + { + AddRef(); + return static_cast(this); + } + + HRESULT + GetBarGraphDisplay( + _In_ PBAR_GRAPH_STATE BarGraphState + ); + + HRESULT + SetBarGraphDisplay( + _In_ PBAR_GRAPH_STATE BarGraphState + ); + + HRESULT + GetSevenSegmentDisplay( + _In_ PSEVEN_SEGMENT SevenSegment + ); + + HRESULT + SetSevenSegmentDisplay( + _In_ PSEVEN_SEGMENT SevenSegment + ); + + HRESULT + ReadSwitchState( + _In_ PSWITCH_STATE SwitchState + ); + + bool + EncodeSegmentValue( + _In_ UCHAR Character, + _Out_ SEVEN_SEGMENT *SevenSegment + ); + + HRESULT + PlaybackFile( + _In_ PFILE_PLAYBACK PlaybackInfo, + _In_ IWDFIoRequest *FxRequest + ); + + // + //returns a weak reference to the target USB device + //DO NOT release it + // + IWDFUsbTargetDevice * + GetUsbTargetDevice( + ) + { + return m_pIUsbTargetDevice; + } + + // + //returns a weak reference to input pipe + //DO NOT release it + // + IWDFUsbTargetPipe * + GetInputPipe( + ) + { + return m_pIUsbInputPipe; + } + + // + //returns a weak reference to output pipe + //DO NOT release it + // + IWDFUsbTargetPipe * + GetOutputPipe( + ) + { + return m_pIUsbOutputPipe; + } + + IWDFIoQueue * + GetSwitchChangeQueue( + VOID + ) + { + return m_SwitchChangeQueue; + } + + PSWITCH_STATE + GetCurrentSwitchState( + VOID + ) + { + return &m_SwitchState; + } + + + HRESULT + ConfigContReaderForInterruptEndPoint( + VOID + ); +// +// COM methods +// +public: + + // + // IUnknown methods. + // + + virtual + ULONG + STDMETHODCALLTYPE + AddRef( + VOID + ) + { + return __super::AddRef(); + } + + _At_(this, __drv_freesMem(object)) + virtual + ULONG + STDMETHODCALLTYPE + Release( + VOID + ) + { + return __super::Release(); + } + + virtual + HRESULT + STDMETHODCALLTYPE + QueryInterface( + _In_ REFIID InterfaceId, + _Outptr_ PVOID *Object + ); + + // + // IPnpCallbackHardware + // + + virtual + HRESULT + STDMETHODCALLTYPE + OnPrepareHardware( + _In_ IWDFDevice *FxDevice + ); + + virtual + HRESULT + STDMETHODCALLTYPE + OnReleaseHardware( + _In_ IWDFDevice *FxDevice + ); + + + // + // IPnpCallback + // + virtual + HRESULT + STDMETHODCALLTYPE + OnD0Entry( + _In_ IWDFDevice* pWdfDevice, + _In_ WDF_POWER_DEVICE_STATE previousState + ); + + virtual + HRESULT + STDMETHODCALLTYPE + OnD0Exit( + _In_ IWDFDevice* pWdfDevice, + _In_ WDF_POWER_DEVICE_STATE previousState + ); + + virtual + void + STDMETHODCALLTYPE + OnSurpriseRemoval( + _In_ IWDFDevice* pWdfDevice + ); + + virtual + HRESULT + STDMETHODCALLTYPE + OnQueryRemove( + _In_ IWDFDevice* pWdfDevice + ); + + virtual + HRESULT + STDMETHODCALLTYPE + OnQueryStop( + _In_ IWDFDevice* pWdfDevice + ); + + // + // IPnpCallbackSelfManagedIo + // + virtual + VOID + STDMETHODCALLTYPE + OnSelfManagedIoCleanup( + _In_ IWDFDevice* pWdfDevice + ); + + virtual + VOID + STDMETHODCALLTYPE + OnSelfManagedIoFlush( + _In_ IWDFDevice* pWdfDevice + ); + + virtual + HRESULT + STDMETHODCALLTYPE + OnSelfManagedIoInit( + _In_ IWDFDevice* pWdfDevice + ); + + virtual + HRESULT + STDMETHODCALLTYPE + OnSelfManagedIoRestart( + _In_ IWDFDevice* pWdfDevice + ); + + virtual + HRESULT + STDMETHODCALLTYPE + OnSelfManagedIoStop( + _In_ IWDFDevice* pWdfDevice + ); + + virtual + HRESULT + STDMETHODCALLTYPE + OnSelfManagedIoSuspend( + _In_ IWDFDevice* pWdfDevice + ); + + // + // IUsbTargetPipeContinuousReaderCallbackReadersFailed + // + virtual + BOOL + STDMETHODCALLTYPE + OnReaderFailure( + IWDFUsbTargetPipe * pPipe, + HRESULT hrCompletion + ); + + // + // IUsbTargetPipeContinuousReaderCallbackReadComplete + // + virtual + VOID + STDMETHODCALLTYPE + OnReaderCompletion( + IWDFUsbTargetPipe * pPipe, + IWDFMemory * pMemory, + SIZE_T NumBytesTransferred, + PVOID Context + ); + + // IImpersonateCallback + virtual + VOID + STDMETHODCALLTYPE + OnImpersonate( + _In_ PVOID Context + ); +}; + diff --git a/usb/umdf_fx2/driver/Driver.cpp b/usb/umdf_fx2/driver/Driver.cpp new file mode 100644 index 00000000..d6635242 --- /dev/null +++ b/usb/umdf_fx2/driver/Driver.cpp @@ -0,0 +1,220 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved. + +Module Name: + + Driver.cpp + +Abstract: + + This module contains the implementation of the UMDF OSR Fx2 driver's + core driver callback object. + +Environment: + + Windows User-Mode Driver Framework (WUDF) + +--*/ + +#include "internal.h" +#include "driver.tmh" + +HRESULT +CMyDriver::CreateInstance( + _Out_ PCMyDriver *Driver + ) +/*++ + + Routine Description: + + This static method is invoked in order to create and initialize a new + instance of the driver class. The caller should arrange for the object + to be released when it is no longer in use. + + Arguments: + + Driver - a location to store a referenced pointer to the new instance + + Return Value: + + S_OK if successful, or error otherwise. + +--*/ +{ + PCMyDriver driver; + HRESULT hr; + + // + // Allocate the callback object. + // + + driver = new CMyDriver(); + + if (NULL == driver) + { + return E_OUTOFMEMORY; + } + + // + // Initialize the callback object. + // + + hr = driver->Initialize(); + + if (SUCCEEDED(hr)) + { + // + // Store a pointer to the new, initialized object in the output + // parameter. + // + + *Driver = driver; + } + else + { + + // + // Release the reference on the driver object to get it to delete + // itself. + // + + driver->Release(); + } + + return hr; +} + +HRESULT +CMyDriver::Initialize( + VOID + ) +/*++ + + Routine Description: + + This method is called to initialize a newly created driver callback object + before it is returned to the creator. Unlike the constructor, the + Initialize method contains operations which could potentially fail. + + Arguments: + + None + + Return Value: + + None + +--*/ +{ + return S_OK; +} + +HRESULT +CMyDriver::QueryInterface( + _In_ REFIID InterfaceId, + _Outptr_ PVOID *Interface + ) +/*++ + + Routine Description: + + This method returns a pointer to the requested interface on the callback + object.. + + Arguments: + + InterfaceId - the IID of the interface to query/reference + + Interface - a location to store the interface pointer. + + Return Value: + + S_OK if the interface is supported. + E_NOINTERFACE if it is not supported. + +--*/ +{ + if (IsEqualIID(InterfaceId, __uuidof(IDriverEntry))) + { + *Interface = QueryIDriverEntry(); + return S_OK; + } + else + { + return CUnknown::QueryInterface(InterfaceId, Interface); + } +} + +HRESULT +CMyDriver::OnDeviceAdd( + _In_ IWDFDriver *FxWdfDriver, + _In_ IWDFDeviceInitialize *FxDeviceInit + ) +/*++ + + Routine Description: + + The FX invokes this method when it wants to install our driver on a device + stack. This method creates a device callback object, then calls the Fx + to create an Fx device object and associate the new callback object with + it. + + Arguments: + + FxWdfDriver - the Fx driver object. + + FxDeviceInit - the initialization information for the device. + + Return Value: + + status + +--*/ +{ + HRESULT hr; + + PCMyDevice device = NULL; + + // + // TODO: Do any per-device initialization (reading settings from the + // registry for example) that's necessary before creating your + // device callback object here. Otherwise you can leave such + // initialization to the initialization of the device event + // handler. + // + + // + // Create a new instance of our device callback object + // + + hr = CMyDevice::CreateInstance(FxWdfDriver, FxDeviceInit, &device); + + // + // TODO: Change any per-device settings that the object exposes before + // calling Configure to let it complete its initialization. + // + + // + // If that succeeded then call the device's construct method. This + // allows the device to create any queues or other structures that it + // needs now that the corresponding fx device object has been created. + // + + if (SUCCEEDED(hr)) + { + hr = device->Configure(); + } + + // + // Release the reference on the device callback object now that it's been + // associated with an fx device object. + // + + if (NULL != device) + { + device->Release(); + } + + return hr; +} diff --git a/usb/umdf_fx2/driver/Driver.h b/usb/umdf_fx2/driver/Driver.h new file mode 100644 index 00000000..d9cafb4e --- /dev/null +++ b/usb/umdf_fx2/driver/Driver.h @@ -0,0 +1,149 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved + +Module Name: + + Driver.h + +Abstract: + + This module contains the type definitions for the UMDF OSR Fx2 sample's + driver callback class. + +Environment: + + Windows User-Mode Driver Framework (WUDF) + +--*/ + +#pragma once + +// +// This class handles driver events for the OSR Fx2 sample. In particular +// it supports the OnDeviceAdd event, which occurs when the driver is called +// to setup per-device handlers for a new device stack. +// + +class CMyDriver : public CUnknown, public IDriverEntry +{ +// +// Private data members. +// +private: + +// +// Private methods. +// +private: + + // + // Returns a refernced pointer to the IDriverEntry interface. + // + + IDriverEntry * + QueryIDriverEntry( + VOID + ) + { + AddRef(); + return static_cast(this); + } + + HRESULT + Initialize( + VOID + ); + +// +// Public methods +// +public: + + // + // The factory method used to create an instance of this driver. + // + + static + HRESULT + CreateInstance( + _Out_ PCMyDriver *Driver + ); + +// +// COM methods +// +public: + + // + // IDriverEntry methods + // + + virtual + HRESULT + STDMETHODCALLTYPE + OnInitialize( + _In_ IWDFDriver *FxWdfDriver + ) + { + UNREFERENCED_PARAMETER(FxWdfDriver); + + return S_OK; + } + + virtual + HRESULT + STDMETHODCALLTYPE + OnDeviceAdd( + _In_ IWDFDriver *FxWdfDriver, + _In_ IWDFDeviceInitialize *FxDeviceInit + ); + + virtual + VOID + STDMETHODCALLTYPE + OnDeinitialize( + _In_ IWDFDriver *FxWdfDriver + ) + { + UNREFERENCED_PARAMETER(FxWdfDriver); + + return; + } + + // + // IUnknown methods. + // + // We have to implement basic ones here that redirect to the + // base class becuase of the multiple inheritance. + // + + virtual + ULONG + STDMETHODCALLTYPE + AddRef( + VOID + ) + { + return __super::AddRef(); + } + + _At_(this, __drv_freesMem(object)) + virtual + ULONG + STDMETHODCALLTYPE + Release( + VOID + ) + { + return __super::Release(); + } + + virtual + HRESULT + STDMETHODCALLTYPE + QueryInterface( + _In_ REFIID InterfaceId, + _Outptr_ PVOID *Object + ); +}; diff --git a/usb/umdf_fx2/driver/OsrUsbFx2.ctl b/usb/umdf_fx2/driver/OsrUsbFx2.ctl new file mode 100644 index 00000000..4dab56ae --- /dev/null +++ b/usb/umdf_fx2/driver/OsrUsbFx2.ctl @@ -0,0 +1 @@ +da5fbdfd-1eae-4ecf-b426-a3818f325ddb WudfOsrUsbFx2TraceGuid diff --git a/usb/umdf_fx2/driver/OsrUsbFx2.rc b/usb/umdf_fx2/driver/OsrUsbFx2.rc new file mode 100644 index 00000000..36f10ea9 --- /dev/null +++ b/usb/umdf_fx2/driver/OsrUsbFx2.rc @@ -0,0 +1,21 @@ +//--------------------------------------------------------------------------- +// OsrUsbDevice.rc +// +// Copyright (c) Microsoft Corporation, All Rights Reserved +//--------------------------------------------------------------------------- + + +#include +#include + +// +// TODO: Change the file description and file names to match your binary. +// + +#define VER_FILETYPE VFT_DLL +#define VER_FILESUBTYPE VFT_UNKNOWN +#define VER_FILEDESCRIPTION_STR "WDF:UMDF OSR USB Fx2 User-Mode Driver Sample" +#define VER_INTERNALNAME_STR "WUDFOsrUsbFx2" +#define VER_ORIGINALFILENAME_STR "WUDFOsrUsbFx2.dll" + +#include "common.ver" diff --git a/usb/umdf_fx2/driver/ReadWriteQueue.cpp b/usb/umdf_fx2/driver/ReadWriteQueue.cpp new file mode 100644 index 00000000..46144829 --- /dev/null +++ b/usb/umdf_fx2/driver/ReadWriteQueue.cpp @@ -0,0 +1,425 @@ +/*++ + +Copyright (c) Microsoft Corporation, All Rights Reserved + +Module Name: + + queue.cpp + +Abstract: + + This file implements the I/O queue interface and performs + the read/write/ioctl operations. + +Environment: + + Windows User-Mode Driver Framework (WUDF) + +--*/ + +#include "internal.h" +#include "ReadWriteQueue.tmh" + +VOID +CMyReadWriteQueue::OnCompletion( + _In_ IWDFIoRequest* pWdfRequest, + _In_ IWDFIoTarget* pIoTarget, + _In_ IWDFRequestCompletionParams* pParams, + _In_ PVOID pContext + ) +{ + UNREFERENCED_PARAMETER(pIoTarget); + UNREFERENCED_PARAMETER(pContext); + + pWdfRequest->CompleteWithInformation( + pParams->GetCompletionStatus(), + pParams->GetInformation() + ); +} + +void +CMyReadWriteQueue::ForwardFormattedRequest( + _In_ IWDFIoRequest* pRequest, + _In_ IWDFIoTarget* pIoTarget + ) +{ + // + //First set the completion callback + // + + IRequestCallbackRequestCompletion * pCompletionCallback = NULL; + HRESULT hrQI = this->QueryInterface(IID_PPV_ARGS(&pCompletionCallback)); + WUDF_TEST_DRIVER_ASSERT(SUCCEEDED(hrQI) && (NULL != pCompletionCallback)); + + pRequest->SetCompletionCallback( + pCompletionCallback, + NULL + ); + + pCompletionCallback->Release(); + pCompletionCallback = NULL; + + // + //Send down the request + // + + HRESULT hrSend = S_OK; + hrSend = pRequest->Send(pIoTarget, + 0, //flags + 0); //timeout + + if (FAILED(hrSend)) + { + pRequest->CompleteWithInformation(hrSend, 0); + } + + return; +} + + +CMyReadWriteQueue::CMyReadWriteQueue( + _In_ PCMyDevice Device + ) : + CMyQueue(Device) +{ +} + +// +// Queue destructor. +// Free up the buffer, wait for thread to terminate and +// + +CMyReadWriteQueue::~CMyReadWriteQueue( + VOID + ) +/*++ + +Routine Description: + + + IUnknown implementation of Release + +Aruments: + + +Return Value: + + ULONG (reference count after Release) + +--*/ +{ + TraceEvents(TRACE_LEVEL_INFORMATION, + TEST_TRACE_QUEUE, + "%!FUNC! Entry" + ); + +} + + +HRESULT +STDMETHODCALLTYPE +CMyReadWriteQueue::QueryInterface( + _In_ REFIID InterfaceId, + _Outptr_ PVOID *Object + ) +/*++ + +Routine Description: + + + Query Interface + +Aruments: + + Follows COM specifications + +Return Value: + + HRESULT indicatin success or failure + +--*/ +{ + HRESULT hr; + + + if (IsEqualIID(InterfaceId, __uuidof(IQueueCallbackWrite))) + { + hr = S_OK; + *Object = QueryIQueueCallbackWrite(); + } + else if (IsEqualIID(InterfaceId, __uuidof(IQueueCallbackRead))) + { + hr = S_OK; + *Object = QueryIQueueCallbackRead(); + } + else if (IsEqualIID(InterfaceId, __uuidof(IRequestCallbackRequestCompletion))) + { + hr = S_OK; + *Object = QueryIRequestCallbackRequestCompletion(); + } + else if (IsEqualIID(InterfaceId, __uuidof(IQueueCallbackIoStop))) + { + hr = S_OK; + *Object = QueryIQueueCallbackIoStop(); + } + else + { + hr = CMyQueue::QueryInterface(InterfaceId, Object); + } + + return hr; +} + +// +// Initialize +// + +HRESULT +CMyReadWriteQueue::CreateInstance( + _In_ PCMyDevice Device, + _Out_ PCMyReadWriteQueue *Queue + ) +/*++ + +Routine Description: + + + CreateInstance creates an instance of the queue object. + +Aruments: + + ppUkwn - OUT parameter is an IUnknown interface to the queue object + +Return Value: + + HRESULT indicatin success or failure + +--*/ +{ + PCMyReadWriteQueue queue; + HRESULT hr = S_OK; + + queue = new CMyReadWriteQueue(Device); + + if (NULL == queue) + { + hr = E_OUTOFMEMORY; + } + + // + // Call the queue callback object to initialize itself. This will create + // its partner queue framework object. + // + + if (SUCCEEDED(hr)) + { + hr = queue->Initialize(); + } + + if (SUCCEEDED(hr)) + { + *Queue = queue; + } + else + { + SAFE_RELEASE(queue); + } + + return hr; +} + +HRESULT +CMyReadWriteQueue::Initialize( + ) +{ + HRESULT hr; + + // + // First initialize the base class. This will create the partner FxIoQueue + // object and setup automatic forwarding of I/O controls. + // + + hr = __super::Initialize(WdfIoQueueDispatchParallel, + true, + true); + + // + // return the status. + // + + return hr; +} + +STDMETHODIMP_ (void) +CMyReadWriteQueue::OnWrite( + _In_ IWDFIoQueue *pWdfQueue, + _In_ IWDFIoRequest *pWdfRequest, + _In_ SIZE_T BytesToWrite + ) +/*++ + +Routine Description: + + + Write dispatch routine + IQueueCallbackWrite + +Aruments: + + pWdfQueue - Framework Queue instance + pWdfRequest - Framework Request instance + BytesToWrite - Lenth of bytes in the write buffer + + Allocate and copy data to local buffer +Return Value: + + VOID + +--*/ +{ + UNREFERENCED_PARAMETER(pWdfQueue); + + TraceEvents(TRACE_LEVEL_INFORMATION, + TEST_TRACE_QUEUE, + "%!FUNC!: Queue %p Request %p BytesToTransfer %d\n", + this, + pWdfRequest, + (ULONG)(ULONG_PTR)BytesToWrite + ); + + HRESULT hr = S_OK; + IWDFMemory * pInputMemory = NULL; + IWDFUsbTargetPipe * pOutputPipe = m_Device->GetOutputPipe(); + + pWdfRequest->GetInputMemory(&pInputMemory); + + hr = pOutputPipe->FormatRequestForWrite( + pWdfRequest, + NULL, //pFile + pInputMemory, + NULL, //Memory offset + NULL //DeviceOffset + ); + + if (FAILED(hr)) + { + pWdfRequest->Complete(hr); + } + else + { + ForwardFormattedRequest(pWdfRequest, pOutputPipe); + } + + SAFE_RELEASE(pInputMemory); + + return; +} + +STDMETHODIMP_ (void) +CMyReadWriteQueue::OnRead( + _In_ IWDFIoQueue *pWdfQueue, + _In_ IWDFIoRequest *pWdfRequest, + _In_ SIZE_T BytesToRead + ) +/*++ + +Routine Description: + + + Read dispatch routine + IQueueCallbackRead + +Aruments: + + pWdfQueue - Framework Queue instance + pWdfRequest - Framework Request instance + BytesToRead - Lenth of bytes in the read buffer + + Copy available data into the read buffer +Return Value: + + VOID + +--*/ +{ + UNREFERENCED_PARAMETER(pWdfQueue); + + TraceEvents(TRACE_LEVEL_INFORMATION, + TEST_TRACE_QUEUE, + "%!FUNC!: Queue %p Request %p BytesToTransfer %d\n", + this, + pWdfRequest, + (ULONG)(ULONG_PTR)BytesToRead + ); + + HRESULT hr = S_OK; + IWDFMemory * pOutputMemory = NULL; + + pWdfRequest->GetOutputMemory(&pOutputMemory); + + hr = m_Device->GetInputPipe()->FormatRequestForRead( + pWdfRequest, + NULL, //pFile + pOutputMemory, + NULL, //Memory offset + NULL //DeviceOffset + ); + + if (FAILED(hr)) + { + pWdfRequest->Complete(hr); + } + else + { + ForwardFormattedRequest(pWdfRequest, m_Device->GetInputPipe()); + } + + SAFE_RELEASE(pOutputMemory); + + return; +} + +STDMETHODIMP_ (void) +CMyReadWriteQueue::OnIoStop( + _In_ IWDFIoQueue * pWdfQueue, + _In_ IWDFIoRequest * pWdfRequest, + _In_ ULONG ActionFlags + ) +{ + UNREFERENCED_PARAMETER(pWdfQueue); + + + // + // The driver owns the request and no locking constraint is safe for + // the queue callbacks + // + if (ActionFlags == WdfRequestStopActionSuspend ) + { + IWDFIoRequest2 * request2 = NULL; + HRESULT hr; + + hr = pWdfRequest->QueryInterface(IID_PPV_ARGS(&request2)); + if (FAILED(hr)) + { + TraceEvents(TRACE_LEVEL_INFORMATION, + TEST_TRACE_QUEUE, + "%!FUNC!: Failed to QI for IWDFIoRequest2: %!hresult!", + hr); + return; + } + + request2->StopAcknowledge(FALSE); //don't requeue + SAFE_RELEASE(request2); + } + else if(ActionFlags == WdfRequestStopActionPurge) + { + // + // Cancel the sent request since we are asked to purge the request + // + + pWdfRequest->CancelSentRequest(); + } + + return; +} + diff --git a/usb/umdf_fx2/driver/ReadWriteQueue.h b/usb/umdf_fx2/driver/ReadWriteQueue.h new file mode 100644 index 00000000..4f1a98c1 --- /dev/null +++ b/usb/umdf_fx2/driver/ReadWriteQueue.h @@ -0,0 +1,163 @@ +/*++ + +Copyright (c) Microsoft Corporation, All Rights Reserved + +Module Name: + + queue.h + +Abstract: + + This file defines the queue callback interface. + +Environment: + + Windows User-Mode Driver Framework (WUDF) + +--*/ + +#pragma once + + +#define MAX_TRANSFER_SIZE(x) 64*1024*1024 + +// +// Queue Callback Object. +// + +class CMyReadWriteQueue : + public IQueueCallbackRead, + public IQueueCallbackWrite, + public IRequestCallbackRequestCompletion, + public IQueueCallbackIoStop, + public CMyQueue +{ +protected: + HRESULT + Initialize( + ); + + void + ForwardFormattedRequest( + _In_ IWDFIoRequest* pRequest, + _In_ IWDFIoTarget* pIoTarget + ); + +public: + + CMyReadWriteQueue( + _In_ PCMyDevice Device + ); + + virtual ~CMyReadWriteQueue(); + + static + HRESULT + CreateInstance( + _In_ PCMyDevice Device, + _Out_ PCMyReadWriteQueue *Queue + ); + + HRESULT + Configure( + VOID + ) + { + return CMyQueue::Configure(); + } + + IQueueCallbackWrite * + QueryIQueueCallbackWrite( + VOID + ) + { + AddRef(); + return static_cast(this); + } + + IQueueCallbackRead * + QueryIQueueCallbackRead( + VOID + ) + { + AddRef(); + return static_cast(this); + } + + IRequestCallbackRequestCompletion * + QueryIRequestCallbackRequestCompletion( + VOID + ) + { + AddRef(); + return static_cast(this); + } + + IQueueCallbackIoStop* + QueryIQueueCallbackIoStop( + VOID + ) + { + AddRef(); + return static_cast(this); + } + + // + // IUnknown + // + + STDMETHOD_(ULONG,AddRef) (VOID) {return CUnknown::AddRef();} + + _At_(this, __drv_freesMem(object)) + STDMETHOD_(ULONG,Release) (VOID) {return CUnknown::Release();} + + STDMETHOD_(HRESULT, QueryInterface)( + _In_ REFIID InterfaceId, + _Outptr_ PVOID *Object + ); + + + // + // Wdf Callbacks + // + + // + // IQueueCallbackWrite + // + STDMETHOD_ (void, OnWrite)( + _In_ IWDFIoQueue *pWdfQueue, + _In_ IWDFIoRequest *pWdfRequest, + _In_ SIZE_T NumOfBytesToWrite + ); + + // + // IQueueCallbackRead + // + STDMETHOD_ (void, OnRead)( + _In_ IWDFIoQueue *pWdfQueue, + _In_ IWDFIoRequest *pWdfRequest, + _In_ SIZE_T NumOfBytesToRead + ); + + // + //IRequestCallbackRequestCompletion + // + + STDMETHOD_ (void, OnCompletion)( + _In_ IWDFIoRequest* pWdfRequest, + _In_ IWDFIoTarget* pIoTarget, + _In_ IWDFRequestCompletionParams* pParams, + _In_ PVOID pContext + ); + + // + //IQueueCallbackIoStop + // + + STDMETHOD_ (void, OnIoStop)( + _In_ IWDFIoQueue * pWdfQueue, + _In_ IWDFIoRequest * pWdfRequest, + _In_ ULONG ActionFlags + ); + +}; diff --git a/usb/umdf_fx2/driver/WUDFOsrUsbFx2.inx b/usb/umdf_fx2/driver/WUDFOsrUsbFx2.inx new file mode 100644 index 00000000..1ade7da6 --- /dev/null +++ b/usb/umdf_fx2/driver/WUDFOsrUsbFx2.inx @@ -0,0 +1,115 @@ +; +; WUDFOsrUsbFx2.inf - Install the OSR USB user-mode driver +; + +[Version] +Signature="$Windows NT$" +Class=Sample +ClassGuid={78A1C341-4539-11d3-B88D-00C04FAD5171} +Provider=%MSFTUMDF% +DriverVer=03/25/2005,0.0.0.1 +CatalogFile=wudf.cat + +[Manufacturer] +%MSFTUMDF%=Microsoft,NT$ARCH$ + +[Microsoft.NT$ARCH$] +%OsrUsbDeviceName%=OsrUsb_Install, USB\Vid_045e&Pid_94aa&mi_00 +%OsrUsbDeviceName%=OsrUsb_Install, USB\VID_0547&PID_1002 + +[ClassInstall32] +AddReg=SampleClass_RegistryAdd + +[SampleClass_RegistryAdd] +HKR,,,,%ClassName% +HKR,,Icon,,"-10" + +[SourceDisksFiles] +WUDFOsrUsbFx2.dll=1 +WudfUpdate_$UMDFCOINSTALLERVERSION$.dll=1 + +[SourceDisksNames] +1 = %MediaDescription% + +; =================== UMDF OsrUsb Device ================================== + +[OsrUsb_Install.NT] +CopyFiles=UMDriverCopy +Include=WINUSB.INF ; Import sections from WINUSB.INF +Needs=WINUSB.NT ; Run the CopyFiles & AddReg directives for WinUsb.INF + + +[OsrUsb_Install.NT.hw] +AddReg=OsrUsb_Device_AddReg + +[OsrUsb_Install.NT.Services] +AddService=WUDFRd,0x000001fa,WUDFRD_ServiceInstall ; flag 0x2 sets this as the service for the device +AddService=WinUsb,0x000001f8,WinUsb_ServiceInstall ; this service is installed because its a filter. + +[OsrUsb_Install.NT.Wdf] +KmdfService=WINUSB, WinUsb_Install +UmdfDispatcher=WinUsb +UmdfService=WUDFOsrUsbFx2, WUDFOsrUsbFx2_Install +UmdfServiceOrder=WUDFOsrUsbFx2 + +; Enable impersonation for the PLAY_FILE IOCTL +UmdfImpersonationLevel=Impersonation + +[OsrUsb_Install.NT.CoInstallers] +AddReg=CoInstallers_AddReg +CopyFiles=CoInstallers_CopyFiles + +; Needed for Win7 support +[WinUsb_Install] +KmdfLibraryVersion = 1.9 + +[WUDFOsrUsbFx2_Install] +UmdfLibraryVersion=$UMDFVERSION$ +DriverCLSID = "{0865b2b0-6b73-428f-a3ea-2172832d6bfc}" +ServiceBinary = "%12%\UMDF\WUDFOsrUsbFx2.dll" + +[OsrUsb_Device_AddReg] +HKR,,"LowerFilters",0x00010008,"WinUsb" ; FLG_ADDREG_TYPE_MULTI_SZ | FLG_ADDREG_APPEND +HKR,,"WinUsbPowerPolicyOwnershipDisabled",0x00010001,1 ; our driver takes ownership of power policy. Tell WINUSB not to + +; When the UMDF Idle/Wake APIs are called with WdfDefault setting +; These keys tell UMDF to enable idle and wake by default +HKR,WudfPowerPolicySettings,"WdfDefaultIdleInWorkingState",0x00010001,1 +HKR,WudfPowerPolicySettings,"WdfDefaultWakeFromSleepState",0x00010001,1 + +[WUDFRD_ServiceInstall] +DisplayName = %WudfRdDisplayName% +ServiceType = 1 +StartType = 3 +ErrorControl = 1 +ServiceBinary = %12%\WUDFRd.sys + +[WinUsb_ServiceInstall] +DisplayName = %WinUsb_SvcDesc% +ServiceType = 1 +StartType = 3 +ErrorControl = 1 +ServiceBinary = %12%\WinUSB.sys + +[CoInstallers_AddReg] +HKR,,CoInstallers32,0x00010000,"WudfUpdate_$UMDFCOINSTALLERVERSION$.dll" + +[CoInstallers_CopyFiles] +WudfUpdate_$UMDFCOINSTALLERVERSION$.dll + +[DestinationDirs] +UMDriverCopy=12,UMDF ; copy to driversMdf +CoInstallers_CopyFiles=11 + +[UMDriverCopy] +WUDFOsrUsbFx2.dll,,,0x00004000 ; COPYFLG_IN_USE_RENAME + +; =================== Generic ================================== + +[Strings] +MSFTUMDF="Microsoft Internal (WDF:UMDF)" +MediaDescription="Microsoft Sample Driver Installation Media" +ClassName="Sample Device" +WudfRdDisplayName="Windows Driver Foundation - User-mode Driver Framework Reflector" +OsrUsbDeviceName="UMDF Sample Driver for OSR USB Fx2 Learning Kit" +WinUsb_SvcDesc="WinUSB Driver" diff --git a/usb/umdf_fx2/driver/WUDFOsrUsbFx2.vcxproj b/usb/umdf_fx2/driver/WUDFOsrUsbFx2.vcxproj new file mode 100644 index 00000000..78e68710 --- /dev/null +++ b/usb/umdf_fx2/driver/WUDFOsrUsbFx2.vcxproj @@ -0,0 +1,319 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {6C6B5C2D-F192-4C22-B8ED-A90C10FB9A1E} + $(MSBuildProjectName) + 1 + 1 + Debug + Win32 + {DD1D49D1-69A2-4BF2-9EE8-34692D0104FB} + + + + Windows10 + False + Desktop + UMDF + WindowsUserModeDriver10.0 + DynamicLibrary + + + Windows10 + True + Desktop + UMDF + WindowsUserModeDriver10.0 + DynamicLibrary + + + Windows10 + False + Desktop + UMDF + WindowsUserModeDriver10.0 + DynamicLibrary + + + Windows10 + True + Desktop + UMDF + WindowsUserModeDriver10.0 + DynamicLibrary + + + + $(IntDir) + + + + + + + + + + + + + + + + true + true + internal.h + + + $(InfArch) + true + .\$(IntDir)\WUDFOsrUsbFx2.inf + + + true + true + internal.h + + + + WUDFOsrUsbFx2 + 0x0A00 + 0x0A000000 + + + WUDFOsrUsbFx2 + 0x0A00 + 0x0A000000 + + + WUDFOsrUsbFx2 + 0x0A00 + 0x0A000000 + + + WUDFOsrUsbFx2 + 0x0A00 + 0x0A000000 + + + + true + Level4 + %(DisableSpecificWarnings);4201 + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + _DllMainCRTStartup@12 + _DllMainCRTStartup + + + + + true + Level4 + %(DisableSpecificWarnings);4201 + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + _DllMainCRTStartup@12 + _DllMainCRTStartup + + + + + true + Level4 + %(DisableSpecificWarnings);4201 + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + _DllMainCRTStartup@12 + _DllMainCRTStartup + + + + + true + Level4 + %(DisableSpecificWarnings);4201 + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + %(PreprocessorDefinitions);_UNICODE;UNICODE + + + _DllMainCRTStartup@12 + _DllMainCRTStartup + + + + + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc;..\..\inc + + + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc;..\..\inc + + + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc;..\..\inc + + + %(AdditionalDependencies);$(SDK_LIB_PATH)\strsafe.lib;$(SDK_LIB_PATH)\kernel32.lib;$(SDK_LIB_PATH)\advapi32.lib;$(SDK_LIB_PATH)\setupapi.lib + + + + + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc;..\..\inc + + + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc;..\..\inc + + + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc;..\..\inc + + + %(AdditionalDependencies);$(SDK_LIB_PATH)\strsafe.lib;$(SDK_LIB_PATH)\kernel32.lib;$(SDK_LIB_PATH)\advapi32.lib;$(SDK_LIB_PATH)\setupapi.lib + + + + + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc;..\..\inc + + + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc;..\..\inc + + + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc;..\..\inc + + + %(AdditionalDependencies);$(SDK_LIB_PATH)\strsafe.lib;$(SDK_LIB_PATH)\kernel32.lib;$(SDK_LIB_PATH)\advapi32.lib;$(SDK_LIB_PATH)\setupapi.lib + + + + + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc;..\..\inc + + + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc;..\..\inc + + + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc;..\..\inc + + + %(AdditionalDependencies);$(SDK_LIB_PATH)\strsafe.lib;$(SDK_LIB_PATH)\kernel32.lib;$(SDK_LIB_PATH)\advapi32.lib;$(SDK_LIB_PATH)\setupapi.lib + + + + + + + + + exports.def + + + + + + + + + exports.def + + + + + + + + + exports.def + + + + + + + + + exports.def + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/usb/umdf_fx2/driver/WUDFOsrUsbFx2.vcxproj.Filters b/usb/umdf_fx2/driver/WUDFOsrUsbFx2.vcxproj.Filters new file mode 100644 index 00000000..1e50204c --- /dev/null +++ b/usb/umdf_fx2/driver/WUDFOsrUsbFx2.vcxproj.Filters @@ -0,0 +1,60 @@ + + + + + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* + {23E0CA5E-560F-46BF-8A5D-0C9892A60610} + + + h;hpp;hxx;hm;inl;inc;xsd + {DE2D9516-18E4-493F-8E49-245A3A552F1A} + + + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml + {0D7905F4-200D-4439-A264-543F6CC50803} + + + inf;inv;inx;mof;mc; + {622540FC-F451-4D00-B0A6-DED0A2B5BDBA} + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Driver Files + + + Driver Files + + + + + Resource Files + + + \ No newline at end of file diff --git a/usb/umdf_fx2/driver/comsup.cpp b/usb/umdf_fx2/driver/comsup.cpp new file mode 100644 index 00000000..9c9aec3b --- /dev/null +++ b/usb/umdf_fx2/driver/comsup.cpp @@ -0,0 +1,344 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved + +Module Name: + + ComSup.cpp + +Abstract: + + This module contains implementations for the functions and methods + used for providing COM support. + +Environment: + + Windows User-Mode Driver Framework (WUDF) + +--*/ + +#include "internal.h" + +#include "comsup.tmh" + +// +// Implementation of CUnknown methods. +// + +CUnknown::CUnknown( + VOID + ) : m_ReferenceCount(1) +/*++ + + Routine Description: + + Constructor for an instance of the CUnknown class. This simply initializes + the reference count of the object to 1. The caller is expected to + call Release() if it wants to delete the object once it has been allocated. + + Arguments: + + None + + Return Value: + + None + +--*/ +{ + // do nothing. +} + +HRESULT +STDMETHODCALLTYPE +CUnknown::QueryInterface( + _In_ REFIID InterfaceId, + _Outptr_ PVOID *Object + ) +/*++ + + Routine Description: + + This method provides the basic support for query interface on CUnknown. + If the interface requested is IUnknown it references the object and + returns an interface pointer. Otherwise it returns an error. + + Arguments: + + InterfaceId - the IID being requested + + Object - a location to store the interface pointer to return. + + Return Value: + + S_OK or E_NOINTERFACE + +--*/ +{ + if (IsEqualIID(InterfaceId, __uuidof(IUnknown))) + { + *Object = QueryIUnknown(); + return S_OK; + } + else + { + *Object = NULL; + return E_NOINTERFACE; + } +} + +IUnknown * +CUnknown::QueryIUnknown( + VOID + ) +/*++ + + Routine Description: + + This helper method references the object and returns a pointer to the + object's IUnknown interface. + + This allows other methods to convert a CUnknown pointer into an IUnknown + pointer without a typecast and without calling QueryInterface and dealing + with the return value. + + Arguments: + + None + + Return Value: + + A pointer to the object's IUnknown interface. + +--*/ +{ + AddRef(); + return static_cast(this); +} + +ULONG +STDMETHODCALLTYPE +CUnknown::AddRef( + VOID + ) +/*++ + + Routine Description: + + This method adds one to the object's reference count. + + Arguments: + + None + + Return Value: + + The new reference count. The caller should only use this for debugging + as the object's actual reference count can change while the caller + examines the return value. + +--*/ +{ + return InterlockedIncrement(&m_ReferenceCount); +} + +ULONG +STDMETHODCALLTYPE +CUnknown::Release( + VOID + ) +/*++ + + Routine Description: + + This method subtracts one to the object's reference count. If the count + goes to zero, this method deletes the object. + + Arguments: + + None + + Return Value: + + The new reference count. If the caller uses this value it should only be + to check for zero (i.e. this call caused or will cause deletion) or + non-zero (i.e. some other call may have caused deletion, but this one + didn't). + +--*/ +{ + ULONG count = InterlockedDecrement(&m_ReferenceCount); + + if (count == 0) + { + delete this; + } + return count; +} + +// +// Implementation of CClassFactory methods. +// + +// +// Define storage for the factory's static lock count variable. +// + +LONG CClassFactory::s_LockCount = 0; + +IClassFactory * +CClassFactory::QueryIClassFactory( + VOID + ) +/*++ + + Routine Description: + + This helper method references the object and returns a pointer to the + object's IClassFactory interface. + + This allows other methods to convert a CClassFactory pointer into an + IClassFactory pointer without a typecast and without dealing with the + return value QueryInterface. + + Arguments: + + None + + Return Value: + + A referenced pointer to the object's IClassFactory interface. + +--*/ +{ + AddRef(); + return static_cast(this); +} + +HRESULT +CClassFactory::QueryInterface( + _In_ REFIID InterfaceId, + _Outptr_ PVOID *Object + ) +/*++ + + Routine Description: + + This method attempts to retrieve the requested interface from the object. + + If the interface is found then the reference count on that interface (and + thus the object itself) is incremented. + + Arguments: + + InterfaceId - the interface the caller is requesting. + + Object - a location to store the interface pointer. + + Return Value: + + S_OK or E_NOINTERFACE + +--*/ +{ + // + // This class only supports IClassFactory so check for that. + // + + if (IsEqualIID(InterfaceId, __uuidof(IClassFactory))) + { + *Object = QueryIClassFactory(); + return S_OK; + } + else + { + // + // See if the base class supports the interface. + // + + return CUnknown::QueryInterface(InterfaceId, Object); + } +} + +HRESULT +STDMETHODCALLTYPE +CClassFactory::CreateInstance( + _In_opt_ IUnknown * /* OuterObject */, + _In_ REFIID InterfaceId, + _Out_ PVOID *Object + ) +/*++ + + Routine Description: + + This COM method is the factory routine - it creates instances of the driver + callback class and returns the specified interface on them. + + Arguments: + + OuterObject - only used for aggregation, which our driver callback class + does not support. + + InterfaceId - the interface ID the caller would like to get from our + new object. + + Object - a location to store the referenced interface pointer to the new + object. + + Return Value: + + Status. + +--*/ +{ + HRESULT hr; + + PCMyDriver driver; + + *Object = NULL; + + hr = CMyDriver::CreateInstance(&driver); + + if (SUCCEEDED(hr)) + { + hr = driver->QueryInterface(InterfaceId, Object); + driver->Release(); + } + + return hr; +} + +HRESULT +STDMETHODCALLTYPE +CClassFactory::LockServer( + _In_ BOOL Lock + ) +/*++ + + Routine Description: + + This COM method can be used to keep the DLL in memory. However since the + driver's DllCanUnloadNow function always returns false, this has little + effect. Still it tracks the number of lock and unlock operations. + + Arguments: + + Lock - Whether the caller wants to lock or unlock the "server" + + Return Value: + + S_OK + +--*/ +{ + if (Lock) + { + InterlockedIncrement(&s_LockCount); + } + else + { + InterlockedDecrement(&s_LockCount); + } + return S_OK; +} + diff --git a/usb/umdf_fx2/driver/comsup.h b/usb/umdf_fx2/driver/comsup.h new file mode 100644 index 00000000..dedf78c8 --- /dev/null +++ b/usb/umdf_fx2/driver/comsup.h @@ -0,0 +1,215 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved + +Module Name: + + ComSup.h + +Abstract: + + This module contains classes and functions use for providing COM support + code. + +Environment: + + Windows User-Mode Driver Framework (WUDF) + +--*/ + +#pragma once + +// +// Forward type declarations. They are here rather than in internal.h as +// you only need them if you choose to use these support classes. +// + +typedef class CUnknown *PCUnknown; +typedef class CClassFactory *PCClassFactory; + +// +// Base class to implement IUnknown. You can choose to derive your COM +// classes from this class, or simply implement IUnknown in each of your +// classes. +// + +class CUnknown : public IUnknown +{ + +// +// Private data members and methods. These are only accessible by the methods +// of this class. +// +private: + + // + // The reference count for this object. Initialized to 1 in the + // constructor. + // + + LONG m_ReferenceCount; + +// +// Protected data members and methods. These are accessible by the subclasses +// but not by other classes. +// +protected: + + // + // The constructor and destructor are protected to ensure that only the + // subclasses of CUnknown can create and destroy instances. + // + + CUnknown( + VOID + ); + + // + // The destructor MUST be virtual. Since any instance of a CUnknown + // derived class should only be deleted from within CUnknown::Release, + // the destructor MUST be virtual or only CUnknown::~CUnknown will get + // invoked on deletion. + // + // If you see that your CMyDevice specific destructor is never being + // called, make sure you haven't deleted the virtual destructor here. + // + + virtual + ~CUnknown( + VOID + ) + { + // Do nothing + } + +// +// Public Methods. These are accessible by any class. +// +public: + + IUnknown * + QueryIUnknown( + VOID + ); + +// +// COM Methods. +// +public: + + // + // IUnknown methods + // + + virtual + ULONG + STDMETHODCALLTYPE + AddRef( + VOID + ); + + virtual + ULONG + STDMETHODCALLTYPE + Release( + VOID + ); + + virtual + HRESULT + STDMETHODCALLTYPE + QueryInterface( + _In_ REFIID InterfaceId, + _Outptr_ PVOID *Object + ); +}; + +// +// Class factory support class. Create an instance of this from your +// DllGetClassObject method and modify the implementation to create +// an instance of your driver event handler class. +// + +class CClassFactory : public CUnknown, public IClassFactory +{ +// +// Private data members and methods. These are only accessible by the methods +// of this class. +// +private: + + // + // The lock count. This is shared across all instances of IClassFactory + // and can be queried through the public IsLocked method. + // + + static LONG s_LockCount; + +// +// Public Methods. These are accessible by any class. +// +public: + + IClassFactory * + QueryIClassFactory( + VOID + ); + +// +// COM Methods. +// +public: + + // + // IUnknown methods + // + + virtual + ULONG + STDMETHODCALLTYPE + AddRef( + VOID + ) + { + return __super::AddRef(); + } + + _At_(this, __drv_freesMem(object)) + virtual + ULONG + STDMETHODCALLTYPE + Release( + VOID + ) + { + return __super::Release(); + } + + virtual + HRESULT + STDMETHODCALLTYPE + QueryInterface( + _In_ REFIID InterfaceId, + _Outptr_ PVOID *Object + ); + + // + // IClassFactory methods. + // + + virtual + HRESULT + STDMETHODCALLTYPE + CreateInstance( + _In_opt_ IUnknown *OuterObject, + _In_ REFIID InterfaceId, + _Out_ PVOID *Object + ); + + virtual + HRESULT + STDMETHODCALLTYPE + LockServer( + _In_ BOOL Lock + ); +}; diff --git a/usb/umdf_fx2/driver/dllsup.cpp b/usb/umdf_fx2/driver/dllsup.cpp new file mode 100644 index 00000000..22dfb3b0 --- /dev/null +++ b/usb/umdf_fx2/driver/dllsup.cpp @@ -0,0 +1,202 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved. + +Module Name: + + dllsup.cpp + +Abstract: + + This module contains the implementation of the UMDF OSR Fx2 + Driver's entry point and its exported functions for providing COM support. + + This module can be copied without modification to a new UMDF driver. It + depends on some of the code in comsup.cpp & comsup.h to handle DLL + registration and creating the first class factory. + + This module is dependent on the following defines: + + MYDRIVER_TRACING_ID - A wide string passed to WPP when initializing + tracing. For example the driver uses + L"Microsoft\\UMDF\\OsrUsb" + + MYDRIVER_CLASS_ID - A GUID encoded in struct format used to + initialize the driver's ClassID. + + These are defined in internal.h for this sample. If you choose + to use a different primary include file, you should ensure they are + defined there as well. + +Environment: + + WDF User-Mode Driver Framework (WDF:UMDF) + +--*/ + +#include "internal.h" +#include "dllsup.tmh" + +const GUID CLSID_MyDriverCoClass = MYDRIVER_CLASS_ID; + +BOOL +WINAPI +DllMain( + HINSTANCE ModuleHandle, + DWORD Reason, + PVOID /* Reserved */ + ) +/*++ + + Routine Description: + + This is the entry point and exit point for the I/O trace driver. This + does very little as the I/O trace driver has minimal global data. + + This method initializes tracing, and saves the module handle away in a + global variable so that it can be referenced should the COM registration + code (Dll[Un]RegisterServer) be called. + + Arguments: + + ModuleHandle - the DLL handle for this module. + + Reason - the reason this entry point was called. + + Reserved - unused + + Return Value: + + TRUE + +--*/ +{ + UNREFERENCED_PARAMETER(ModuleHandle); + + if (DLL_PROCESS_ATTACH == Reason) + { + // + // Initialize tracing. + // + + WPP_INIT_TRACING(MYDRIVER_TRACING_ID); + } + else if (DLL_PROCESS_DETACH == Reason) + { + // + // Cleanup tracing. + // + + WPP_CLEANUP(); + } + + return TRUE; +} + +HRESULT +STDAPICALLTYPE +DllCanUnloadNow( + VOID + ) +/*++ + + Routine Description: + + Called by the COM runtime when determining whether or not this module + can be unloaded. Our answer is always "no". + + Arguments: + + None + + Return Value: + + S_FALSE + +--*/ +{ + return S_FALSE; +} + +HRESULT +STDAPICALLTYPE +DllGetClassObject( + _In_ REFCLSID ClassId, + _In_ REFIID InterfaceId, + _Outptr_ LPVOID *Interface + ) +/*++ + + Routine Description: + + This routine is called by COM in order to instantiate the + OSR Fx2 driver callback object and do an initial query interface on it. + + This method only creates an instance of the driver's class factory, as this + is the minimum required to support UMDF. + + Arguments: + + ClassId - the CLSID of the object being "gotten" + + InterfaceId - the interface the caller wants from that object. + + Interface - a location to store the referenced interface pointer + + Return Value: + + S_OK if the function succeeds or error indicating the cause of the + failure. + +--*/ +{ + PCClassFactory factory; + + HRESULT hr = S_OK; + + *Interface = NULL; + + // + // If the CLSID doesn't match that of our "coclass" (defined in the IDL + // file) then we can't create the object the caller wants. This may + // indicate that the COM registration is incorrect, and another CLSID + // is referencing this drvier. + // + + if (IsEqualCLSID(ClassId, CLSID_MyDriverCoClass) == false) + { + Trace( + TRACE_LEVEL_ERROR, + L"ERROR: Called to create instance of unrecognized class (%!GUID!)", + &ClassId + ); + + return CLASS_E_CLASSNOTAVAILABLE; + } + + // + // Create an instance of the class factory for the caller. + // + + factory = new CClassFactory(); + + if (NULL == factory) + { + hr = E_OUTOFMEMORY; + } + + // + // Query the object we created for the interface the caller wants. After + // that we release the object. This will drive the reference count to + // 1 (if the QI succeeded an referenced the object) or 0 (if the QI failed). + // In the later case the object is automatically deleted. + // + + if (SUCCEEDED(hr)) + { + hr = factory->QueryInterface(InterfaceId, Interface); + factory->Release(); + } + + return hr; +} diff --git a/usb/umdf_fx2/driver/exports.def b/usb/umdf_fx2/driver/exports.def new file mode 100644 index 00000000..15f923d3 --- /dev/null +++ b/usb/umdf_fx2/driver/exports.def @@ -0,0 +1,4 @@ +; WudfOsrUsbDriver.def : Declares the module parameters. + +EXPORTS + DllGetClassObject PRIVATE diff --git a/usb/umdf_fx2/driver/internal.h b/usb/umdf_fx2/driver/internal.h new file mode 100644 index 00000000..2d57793d --- /dev/null +++ b/usb/umdf_fx2/driver/internal.h @@ -0,0 +1,170 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved + +Module Name: + + Internal.h + +Abstract: + + This module contains the local type definitions for the UMDF OSR Fx2 + driver sample. + +Environment: + + Windows User-Mode Driver Framework (WUDF) + +--*/ + +#pragma once + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) +#endif + +// +// Include the WUDF Headers +// + +#include "wudfddi.h" + +// +// Include SetupDi functions. +// + +#include "setupapi.h" + +// +// Use specstrings for in/out annotation of function parameters. +// + +#include "specstrings.h" + +// +// Include the safestring functions. +// + +#include "strsafe.h" + +// +// Get limits on common data types (ULONG_MAX for example) +// + +#include "limits.h" + +// +// We need usb I/O targets to talk to the OSR device. +// + +#include "wudfusb.h" + +// +// Include the header shared between the drivers and the test applications. +// + +#include "public.h" + +// +// Include the header shared between the drivers and the test applications. +// + +#include "WUDFOsrUsbPublic.h" + +// +// Forward definitions of classes in the other header files. +// + +typedef class CMyDriver *PCMyDriver; +typedef class CMyDevice *PCMyDevice; +typedef class CMyQueue *PCMyQueue; + +typedef class CMyControlQueue *PCMyControlQueue; +typedef class CMyReadWriteQueue *PCMyReadWriteQueue; + +typedef class CCancelCallback *PCCancelCallback; + +// +// Define the tracing flags. +// +// TODO: Choose a different trace control GUID +// + +#define WPP_CONTROL_GUIDS \ + WPP_DEFINE_CONTROL_GUID( \ + WudfOsrUsbFx2TraceGuid, (da5fbdfd,1eae,4ecf,b426,a3818f325ddb), \ + \ + WPP_DEFINE_BIT(MYDRIVER_ALL_INFO) \ + WPP_DEFINE_BIT(TEST_TRACE_DRIVER) \ + WPP_DEFINE_BIT(TEST_TRACE_DEVICE) \ + WPP_DEFINE_BIT(TEST_TRACE_QUEUE) \ + ) + +#define WPP_FLAG_LEVEL_LOGGER(flag, level) \ + WPP_LEVEL_LOGGER(flag) + +#define WPP_FLAG_LEVEL_ENABLED(flag, level) \ + (WPP_LEVEL_ENABLED(flag) && \ + WPP_CONTROL(WPP_BIT_ ## flag).Level >= level) + +#define WPP_LEVEL_FLAGS_LOGGER(lvl,flags) \ + WPP_LEVEL_LOGGER(flags) + +#define WPP_LEVEL_FLAGS_ENABLED(lvl, flags) \ + (WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level >= lvl) + +// +// This comment block is scanned by the trace preprocessor to define our +// Trace function. +// +// begin_wpp config +// FUNC Trace{FLAG=MYDRIVER_ALL_INFO}(LEVEL, MSG, ...); +// FUNC TraceEvents(LEVEL, FLAGS, MSG, ...); +// end_wpp +// + +// +// Driver specific #defines +// +// TODO: Change these values to be appropriate for your driver. +// + +#define MYDRIVER_TRACING_ID L"Microsoft\\UMDF\\OsrUsb" +#define MYDRIVER_CLASS_ID {0x0865b2b0, 0x6b73, 0x428f, {0xa3, 0xea, 0x21, 0x72, 0x83, 0x2d, 0x6b, 0xfc}} + +// +// Include the type specific headers. +// + +#include "comsup.h" +#include "driver.h" +#include "device.h" +#include "queue.h" +#include "ControlQueue.h" +#include "ReadWriteQueue.h" +#include "list.h" + +__forceinline +#ifdef _PREFAST_ +__declspec(noreturn) +#endif +VOID +WdfTestNoReturn( + VOID + ) +{ + // do nothing. +} + +#define WUDF_TEST_DRIVER_ASSERT(p) \ +{ \ + if ( !(p) ) \ + { \ + DebugBreak(); \ + WdfTestNoReturn(); \ + } \ +} + +#define SAFE_RELEASE(p) {if ((p)) { (p)->Release(); (p) = NULL; }} + +#define IDLE_TIMEOUT_IN_MSEC 10*1000 diff --git a/usb/umdf_fx2/driver/queue.cpp b/usb/umdf_fx2/driver/queue.cpp new file mode 100644 index 00000000..c56b38bb --- /dev/null +++ b/usb/umdf_fx2/driver/queue.cpp @@ -0,0 +1,147 @@ +/*++ + +Copyright (c) Microsoft Corporation, All Rights Reserved + +Module Name: + + queue.cpp + +Abstract: + + This file implements the I/O queue interface and performs + the read/write/ioctl operations. + +Environment: + + Windows User-Mode Driver Framework (WUDF) + +--*/ + +#include "internal.h" +#include "queue.tmh" + +CMyQueue::CMyQueue( + _In_ PCMyDevice Device + ) : + m_FxQueue(NULL), + m_Device(Device) +{ +} + +// +// Queue destructor. +// Free up the buffer, wait for thread to terminate and +// + +CMyQueue::~CMyQueue( + VOID + ) +/*++ + +Routine Description: + + + IUnknown implementation of Release + +Aruments: + + +Return Value: + + ULONG (reference count after Release) + +--*/ +{ + TraceEvents(TRACE_LEVEL_INFORMATION, + TEST_TRACE_QUEUE, + "%!FUNC! Entry" + ); + +} + + +HRESULT +STDMETHODCALLTYPE +CMyQueue::QueryInterface( + _In_ REFIID InterfaceId, + _Outptr_ PVOID *Object + ) +/*++ + +Routine Description: + + + Query Interface + +Aruments: + + Follows COM specifications + +Return Value: + + HRESULT indicatin success or failure + +--*/ +{ + HRESULT hr; + + hr = CUnknown::QueryInterface(InterfaceId, Object); + + return hr; +} + +// +// Initialize +// + +HRESULT +CMyQueue::Initialize( + _In_ WDF_IO_QUEUE_DISPATCH_TYPE DispatchType, + _In_ bool Default, + _In_ bool PowerManaged + ) +{ + IWDFIoQueue *fxQueue; + HRESULT hr; + + // + // Create the I/O Queue object. + // + + { + IUnknown *callback = QueryIUnknown(); + + hr = m_Device->GetFxDevice()->CreateIoQueue( + callback, + Default, + DispatchType, + PowerManaged, + FALSE, + &fxQueue + ); + callback->Release(); + } + + if (SUCCEEDED(hr)) + { + m_FxQueue = fxQueue; + + // + // Release the creation reference on the queue. This object will be + // destroyed before the queue so we don't need to have a reference out + // on it. + // + + fxQueue->Release(); + } + + return hr; +} + +HRESULT +CMyQueue::Configure( + VOID + ) +{ + return S_OK; +} diff --git a/usb/umdf_fx2/driver/queue.h b/usb/umdf_fx2/driver/queue.h new file mode 100644 index 00000000..5659224b --- /dev/null +++ b/usb/umdf_fx2/driver/queue.h @@ -0,0 +1,93 @@ +/*++ + +Copyright (c) Microsoft Corporation, All Rights Reserved + +Module Name: + + queue.h + +Abstract: + + This file defines the queue callback interface. + +Environment: + + Windows User-Mode Driver Framework (WUDF) + +--*/ + +#pragma once + +// +// Queue Callback Object. +// + +class CMyQueue : + public CUnknown +{ +protected: + // + // Unreferenced pointer to the partner Fx device. + // + + IWDFIoQueue *m_FxQueue; + + // + // Unreferenced pointer to the parent device. + // + + PCMyDevice m_Device; + + HRESULT + Initialize( + _In_ WDF_IO_QUEUE_DISPATCH_TYPE DispatchType, + _In_ bool Default, + _In_ bool PowerManaged + ); + +protected: + + CMyQueue( + _In_ PCMyDevice Device + ); + + virtual ~CMyQueue(); + + HRESULT + Configure( + VOID + ); + +public: + + IWDFIoQueue * + GetFxQueue( + VOID + ) + { + return m_FxQueue; + } + + + PCMyDevice + GetDevice( + VOID + ) + { + return m_Device; + } + + // + // IUnknown + // + + STDMETHOD_(ULONG,AddRef) (VOID) {return CUnknown::AddRef();} + + _At_(this, __drv_freesMem(object)) + STDMETHOD_(ULONG,Release) (VOID) {return CUnknown::Release();} + + STDMETHOD_(HRESULT, QueryInterface)( + _In_ REFIID InterfaceId, + _Outptr_ PVOID *Object + ); +}; diff --git a/usb/umdf_fx2/exe/WudfOsrUsbFx2Test.vcxproj b/usb/umdf_fx2/exe/WudfOsrUsbFx2Test.vcxproj new file mode 100644 index 00000000..0b2f09fd --- /dev/null +++ b/usb/umdf_fx2/exe/WudfOsrUsbFx2Test.vcxproj @@ -0,0 +1,212 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {D567DDDD-4EC8-40B4-AE8F-58B2D41F837F} + $(MSBuildProjectName) + Debug + Win32 + {A76B918B-D92F-4EA3-8BA4-6D560CCAB575} + + + + Windows10 + False + Desktop + + WindowsApplicationForDrivers10.0 + Application + + + Windows10 + True + Desktop + + WindowsApplicationForDrivers10.0 + Application + + + Windows10 + False + Desktop + + WindowsApplicationForDrivers10.0 + Application + + + Windows10 + True + Desktop + + WindowsApplicationForDrivers10.0 + Application + + + + $(IntDir) + + + + + + + + + + + + + + + + WudfOsrUsbFx2Test + + + WudfOsrUsbFx2Test + + + WudfOsrUsbFx2Test + + + WudfOsrUsbFx2Test + + + + %(PreprocessorDefinitions);BUILT_IN_DDK=1;UNICODE=1;_UNICODE=1 + true + Level4 + %(AdditionalIncludeDirectories);..\inc;..\..\inc;$(DDK_INC_PATH) + + + %(PreprocessorDefinitions);BUILT_IN_DDK=1;UNICODE=1;_UNICODE=1 + %(AdditionalIncludeDirectories);..\inc;..\..\inc;$(DDK_INC_PATH) + + + %(PreprocessorDefinitions);BUILT_IN_DDK=1;UNICODE=1;_UNICODE=1 + %(AdditionalIncludeDirectories);..\inc;..\..\inc;$(DDK_INC_PATH) + + + %(AdditionalDependencies);setupapi.lib + + + + + %(PreprocessorDefinitions);BUILT_IN_DDK=1;UNICODE=1;_UNICODE=1 + true + Level4 + %(AdditionalIncludeDirectories);..\inc;..\..\inc;$(DDK_INC_PATH) + + + %(PreprocessorDefinitions);BUILT_IN_DDK=1;UNICODE=1;_UNICODE=1 + %(AdditionalIncludeDirectories);..\inc;..\..\inc;$(DDK_INC_PATH) + + + %(PreprocessorDefinitions);BUILT_IN_DDK=1;UNICODE=1;_UNICODE=1 + %(AdditionalIncludeDirectories);..\inc;..\..\inc;$(DDK_INC_PATH) + + + %(AdditionalDependencies);setupapi.lib + + + + + %(PreprocessorDefinitions);BUILT_IN_DDK=1;UNICODE=1;_UNICODE=1 + true + Level4 + %(AdditionalIncludeDirectories);..\inc;..\..\inc;$(DDK_INC_PATH) + + + %(PreprocessorDefinitions);BUILT_IN_DDK=1;UNICODE=1;_UNICODE=1 + %(AdditionalIncludeDirectories);..\inc;..\..\inc;$(DDK_INC_PATH) + + + %(PreprocessorDefinitions);BUILT_IN_DDK=1;UNICODE=1;_UNICODE=1 + %(AdditionalIncludeDirectories);..\inc;..\..\inc;$(DDK_INC_PATH) + + + %(AdditionalDependencies);setupapi.lib + + + + + %(PreprocessorDefinitions);BUILT_IN_DDK=1;UNICODE=1;_UNICODE=1 + true + Level4 + %(AdditionalIncludeDirectories);..\inc;..\..\inc;$(DDK_INC_PATH) + + + %(PreprocessorDefinitions);BUILT_IN_DDK=1;UNICODE=1;_UNICODE=1 + %(AdditionalIncludeDirectories);..\inc;..\..\inc;$(DDK_INC_PATH) + + + %(PreprocessorDefinitions);BUILT_IN_DDK=1;UNICODE=1;_UNICODE=1 + %(AdditionalIncludeDirectories);..\inc;..\..\inc;$(DDK_INC_PATH) + + + %(AdditionalDependencies);setupapi.lib + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/usb/umdf_fx2/exe/WudfOsrUsbFx2Test.vcxproj.Filters b/usb/umdf_fx2/exe/WudfOsrUsbFx2Test.vcxproj.Filters new file mode 100644 index 00000000..b101faa4 --- /dev/null +++ b/usb/umdf_fx2/exe/WudfOsrUsbFx2Test.vcxproj.Filters @@ -0,0 +1,30 @@ + + + + + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* + {70899A87-F630-4585-8B67-E7450F161ADD} + + + h;hpp;hxx;hm;inl;inc;xsd + {01515B55-99D7-41ED-9B4E-F4E8971BB851} + + + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml + {DC48D49A-F703-4F8E-95F8-ED4DE2603606} + + + + + Source Files + + + Source Files + + + + + Resource Files + + + \ No newline at end of file diff --git a/usb/umdf_fx2/exe/dump.c b/usb/umdf_fx2/exe/dump.c new file mode 100644 index 00000000..aef55116 --- /dev/null +++ b/usb/umdf_fx2/exe/dump.c @@ -0,0 +1,444 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + DUMP.C + +Abstract: + + Routines to dump the descriptors information in a human readable form. + +Environment: + + user mode only + +--*/ + +#include +#include +#include +#include "devioctl.h" + +#pragma warning(disable:4200) // +#pragma warning(disable:4201) // nameless struct/union +#pragma warning(disable:4214) // bit field types other than int + +#include +#include "usbdi.h" +#include "public.h" + +#pragma warning(default:4200) +#pragma warning(default:4201) +#pragma warning(default:4214) + +HANDLE +OpenDevice( + _In_ BOOL Synchronous + ); + + +char* +usbDescriptorTypeString(UCHAR bDescriptorType ) +/*++ +Routine Description: + + Called to get ascii string of USB descriptor + +Arguments: + + PUSB_ENDPOINT_DESCRIPTOR->bDescriptorType or + PUSB_DEVICE_DESCRIPTOR->bDescriptorType or + PUSB_INTERFACE_DESCRIPTOR->bDescriptorType or + PUSB_STRING_DESCRIPTOR->bDescriptorType or + PUSB_POWER_DESCRIPTOR->bDescriptorType or + PUSB_CONFIGURATION_DESCRIPTOR->bDescriptorType + +Return Value: + + ptr to string + +--*/ +{ + + switch(bDescriptorType) { + + case USB_DEVICE_DESCRIPTOR_TYPE: + return "USB_DEVICE_DESCRIPTOR_TYPE"; + + case USB_CONFIGURATION_DESCRIPTOR_TYPE: + return "USB_CONFIGURATION_DESCRIPTOR_TYPE"; + + + case USB_STRING_DESCRIPTOR_TYPE: + return "USB_STRING_DESCRIPTOR_TYPE"; + + + case USB_INTERFACE_DESCRIPTOR_TYPE: + return "USB_INTERFACE_DESCRIPTOR_TYPE"; + + + case USB_ENDPOINT_DESCRIPTOR_TYPE: + return "USB_ENDPOINT_DESCRIPTOR_TYPE"; + + +#ifdef USB_POWER_DESCRIPTOR_TYPE // this is the older definintion which is actually obsolete + // workaround for temporary bug in 98ddk, older USB100.h file + case USB_POWER_DESCRIPTOR_TYPE: + return "USB_POWER_DESCRIPTOR_TYPE"; +#endif + +#ifdef USB_RESERVED_DESCRIPTOR_TYPE // this is the current version of USB100.h as in NT5DDK + + case USB_RESERVED_DESCRIPTOR_TYPE: + return "USB_RESERVED_DESCRIPTOR_TYPE"; + + case USB_CONFIG_POWER_DESCRIPTOR_TYPE: + return "USB_CONFIG_POWER_DESCRIPTOR_TYPE"; + + case USB_INTERFACE_POWER_DESCRIPTOR_TYPE: + return "USB_INTERFACE_POWER_DESCRIPTOR_TYPE"; +#endif // for current nt5ddk version of USB100.h + + default: + return "??? UNKNOWN!!"; + } +} + + +char * +usbEndPointTypeString(UCHAR bmAttributes) +/*++ +Routine Description: + + Called to get ascii string of endpt descriptor type + +Arguments: + + PUSB_ENDPOINT_DESCRIPTOR->bmAttributes + +Return Value: + + ptr to string + +--*/ +{ + UINT typ = bmAttributes & USB_ENDPOINT_TYPE_MASK; + + + switch( typ) { + case USB_ENDPOINT_TYPE_INTERRUPT: + return "USB_ENDPOINT_TYPE_INTERRUPT"; + + case USB_ENDPOINT_TYPE_BULK: + return "USB_ENDPOINT_TYPE_BULK"; + + case USB_ENDPOINT_TYPE_ISOCHRONOUS: + return "USB_ENDPOINT_TYPE_ISOCHRONOUS"; + + case USB_ENDPOINT_TYPE_CONTROL: + return "USB_ENDPOINT_TYPE_CONTROL"; + + default: + return "??? UNKNOWN!!"; + } +} + + +char * +usbConfigAttributesString(UCHAR bmAttributes) +/*++ +Routine Description: + + Called to get ascii string of USB_CONFIGURATION_DESCRIPTOR attributes + +Arguments: + + PUSB_CONFIGURATION_DESCRIPTOR->bmAttributes + +Return Value: + + ptr to string + +--*/ +{ + UINT typ = bmAttributes & USB_CONFIG_POWERED_MASK; + + + switch( typ) { + + case USB_CONFIG_BUS_POWERED: + return "USB_CONFIG_BUS_POWERED"; + + case USB_CONFIG_SELF_POWERED: + return "USB_CONFIG_SELF_POWERED"; + + case USB_CONFIG_REMOTE_WAKEUP: + return "USB_CONFIG_REMOTE_WAKEUP"; + + + default: + return "??? UNKNOWN!!"; + } +} + + +void +print_USB_CONFIGURATION_DESCRIPTOR(PUSB_CONFIGURATION_DESCRIPTOR cd) +/*++ +Routine Description: + + Called to do formatted ascii dump to console of a USB config descriptor + +Arguments: + + ptr to USB configuration descriptor + +Return Value: + + none + +--*/ +{ + printf("\n===================\nUSB_CONFIGURATION_DESCRIPTOR\n"); + + printf( + "bLength = 0x%x, decimal %u\n", cd->bLength, cd->bLength + ); + + printf( + "bDescriptorType = 0x%x ( %s )\n", cd->bDescriptorType, + usbDescriptorTypeString( cd->bDescriptorType ) + ); + + printf( + "wTotalLength = 0x%x, decimal %u\n", cd->wTotalLength, cd->wTotalLength + ); + + printf( + "bNumInterfaces = 0x%x, decimal %u\n", cd->bNumInterfaces, cd->bNumInterfaces + ); + + printf( + "bConfigurationValue = 0x%x, decimal %u\n", + cd->bConfigurationValue, cd->bConfigurationValue + ); + + printf( + "iConfiguration = 0x%x, decimal %u\n", cd->iConfiguration, cd->iConfiguration + ); + + printf( + "bmAttributes = 0x%x ( %s )\n", cd->bmAttributes, + usbConfigAttributesString( cd->bmAttributes ) + ); + + printf( + "MaxPower = 0x%x, decimal %u\n", cd->MaxPower, cd->MaxPower + ); +} + + +void +print_USB_INTERFACE_DESCRIPTOR(PUSB_INTERFACE_DESCRIPTOR id, UINT ix) +/*++ +Routine Description: + + Called to do formatted ascii dump to console of a USB interface descriptor + +Arguments: + + ptr to USB interface descriptor + +Return Value: + + none + +--*/ +{ + printf("\n-----------------------------\nUSB_INTERFACE_DESCRIPTOR #%u\n", ix); + + + printf( + "bLength = 0x%x\n", id->bLength + ); + + + printf( + "bDescriptorType = 0x%x ( %s )\n", id->bDescriptorType, + usbDescriptorTypeString( id->bDescriptorType ) + ); + + + printf( + "bInterfaceNumber = 0x%x\n", id->bInterfaceNumber + ); + printf( + "bAlternateSetting = 0x%x\n", id->bAlternateSetting + ); + printf( + "bNumEndpoints = 0x%x\n", id->bNumEndpoints + ); + printf( + "bInterfaceClass = 0x%x\n", id->bInterfaceClass + ); + printf( + "bInterfaceSubClass = 0x%x\n", id->bInterfaceSubClass + ); + printf( + "bInterfaceProtocol = 0x%x\n", id->bInterfaceProtocol + ); + printf( + "bInterface = 0x%x\n", id->iInterface + ); +} + + +void +print_USB_ENDPOINT_DESCRIPTOR(PUSB_ENDPOINT_DESCRIPTOR ed, int i) +/*++ +Routine Description: + + Called to do formatted ascii dump to console of a USB endpoint descriptor + +Arguments: + + ptr to USB endpoint descriptor, + index of this endpt in interface desc + +Return Value: + + none + +--*/ +{ + printf( + "------------------------------\nUSB_ENDPOINT_DESCRIPTOR for Pipe%02d\n", i + ); + + printf( + "bLength = 0x%x\n", ed->bLength + ); + + printf( + "bDescriptorType = 0x%x ( %s )\n", ed->bDescriptorType, + usbDescriptorTypeString( ed->bDescriptorType ) + ); + + if ( USB_ENDPOINT_DIRECTION_IN( ed->bEndpointAddress ) ) { + printf( + "bEndpointAddress= 0x%x ( INPUT )\n", ed->bEndpointAddress + ); + } else { + printf( + "bEndpointAddress= 0x%x ( OUTPUT )\n", ed->bEndpointAddress + ); + } + + printf( + "bmAttributes= 0x%x ( %s )\n", ed->bmAttributes, + usbEndPointTypeString ( ed->bmAttributes ) + ); + + printf( + "wMaxPacketSize= 0x%x, decimal %u\n", ed->wMaxPacketSize, + ed->wMaxPacketSize + ); + + printf( + "bInterval = 0x%x, decimal %u\n", ed->bInterval, ed->bInterval + ); +} + + +BOOL +DumpUsbConfig() +/*++ +Routine Description: + + Called to do formatted ascii dump to console of USB + configuration, interface, and endpoint descriptors. + +Arguments: + + none + +Return Value: + + TRUE or FALSE + +--*/ +{ + HANDLE hDev; + UINT success; + int siz, nBytes; + char buf[256] = {0}; + + hDev = OpenDevice(TRUE); + if(hDev == INVALID_HANDLE_VALUE) + { + return FALSE; + } + + siz = sizeof(buf); + + success = DeviceIoControl(hDev, + IOCTL_OSRUSBFX2_GET_CONFIG_DESCRIPTOR, + NULL, + 0, + buf, + siz, + (PULONG) &nBytes, + NULL); + + if(success == FALSE) { + printf("Ioct - GetConfigDesc failed %u\n", GetLastError()); + } else { + + ULONG i; + UINT j, n; + char *pch; + PUSB_CONFIGURATION_DESCRIPTOR cd; + PUSB_INTERFACE_DESCRIPTOR id; + PUSB_ENDPOINT_DESCRIPTOR ed; + + pch = buf; + n = 0; + + cd = (PUSB_CONFIGURATION_DESCRIPTOR) pch; + + print_USB_CONFIGURATION_DESCRIPTOR( cd ); + + pch += cd->bLength; + + do { + id = (PUSB_INTERFACE_DESCRIPTOR) pch; + + print_USB_INTERFACE_DESCRIPTOR(id, n++); + + pch += id->bLength; + for (j=0; jbNumEndpoints; j++) { + + ed = (PUSB_ENDPOINT_DESCRIPTOR) pch; + + print_USB_ENDPOINT_DESCRIPTOR(ed,j); + + pch += ed->bLength; + } + i = (ULONG)(pch - buf); + + } while (iwTotalLength); + } + + CloseHandle(hDev); + + return success; + +} + diff --git a/usb/umdf_fx2/exe/testapp.c b/usb/umdf_fx2/exe/testapp.c new file mode 100644 index 00000000..992b20c5 --- /dev/null +++ b/usb/umdf_fx2/exe/testapp.c @@ -0,0 +1,1360 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + TESTAPP.C + +Abstract: + + Console test app for osrusbfx2 driver. + +Environment: + + user mode only + +--*/ + +#include +_Analysis_mode_(_Analysis_code_type_user_code_); + +#include +#include +#include +#include + +#include "devioctl.h" +#include "strsafe.h" + +#pragma warning(push) +#pragma warning(disable:4200) // +#pragma warning(disable:4201) // nameless struct/union +#pragma warning(disable:4214) // bit field types other than int + +#include +#include +#include "usbdi.h" +#include "public.h" + +#pragma warning(pop) + +#define WHILE(a) \ +while(__pragma(warning(disable:4127)) a __pragma(warning(disable:4127))) + +#define countof(x) (sizeof(x) / sizeof(x[0])) + +#define MAX_DEVPATH_LENGTH 256 +#define NUM_ASYNCH_IO 100 +#define BUFFER_SIZE 1024 +#define READER_TYPE 1 +#define WRITER_TYPE 2 + +BOOL G_fDumpUsbConfig = FALSE; // flags set in response to console command line switches +BOOL G_fDumpReadData = FALSE; +BOOL G_fRead = FALSE; +BOOL G_fWrite = FALSE; +BOOL G_fPlayWithDevice = FALSE; +BOOL G_fPerformAsyncIo = FALSE; +ULONG G_IterationCount = 1; //count of iterations of the test we are to perform +int G_WriteLen = 512; // #bytes to write +int G_ReadLen = 512; // #bytes to read +PCWSTR G_SendFileName = NULL; +ULONG G_SendFileInterval = 1; + +BOOL +DumpUsbConfig( // defined in dump.c + ); + +typedef enum _INPUT_FUNCTION { + LIGHT_ONE_BAR = 1, + CLEAR_ONE_BAR, + LIGHT_ALL_BARS, + CLEAR_ALL_BARS, + GET_BAR_GRAPH_LIGHT_STATE, + GET_SWITCH_STATE, + GET_SWITCH_STATE_AS_INTERRUPT_MESSAGE, + GET_7_SEGEMENT_STATE, + SET_7_SEGEMENT_STATE, + RESET_DEVICE, + REENUMERATE_DEVICE, +} INPUT_FUNCTION; + +_Success_ (return != FALSE) +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) { + wprintf(L"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: %s", (LPSTR)lpMsgBuf); + LocalFree(lpMsgBuf); + } + + 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); + wprintf(L"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; + + 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("Error in SetupDiGetDeviceInterfaceDetail: %s\n", (LPSTR)lpMsgBuf); + LocalFree(lpMsgBuf); + } + + SetupDiDestroyDeviceInfoList(HardwareDeviceInfo); + LocalFree(DeviceInterfaceDetailData); + return FALSE; + } + + hr = StringCchCopy(DevicePath, + BufLen, + DeviceInterfaceDetailData->DevicePath); + if (FAILED(hr)) { + SetupDiDestroyDeviceInfoList(HardwareDeviceInfo); + LocalFree(DeviceInterfaceDetailData); + return FALSE; + } + + SetupDiDestroyDeviceInfoList(HardwareDeviceInfo); + LocalFree(DeviceInterfaceDetailData); + + return TRUE; + +} + + +HANDLE +OpenDevice( + _In_ BOOL Synchronous + ) + +/*++ +Routine Description: + + Called by main() to open an instance of our device after obtaining its name + +Arguments: + + Synchronous - TRUE, if Device is to be opened for synchronous access. + FALSE, otherwise. + +Return Value: + + Device handle on success else INVALID_HANDLE_VALUE + +--*/ + +{ + HANDLE hDev; + WCHAR completeDeviceName[MAX_DEVPATH_LENGTH]; + + if ( !GetDevicePath( + (LPGUID) &GUID_DEVINTERFACE_OSRUSBFX2, + completeDeviceName, + countof(completeDeviceName)) ) + { + return INVALID_HANDLE_VALUE; + } + + wprintf(L"DeviceName = (%s)\n", completeDeviceName); + + hDev = CreateFile(completeDeviceName, + GENERIC_WRITE | GENERIC_READ, + FILE_SHARE_WRITE | FILE_SHARE_READ, + NULL, // default security + OPEN_EXISTING, + ((Synchronous ? FILE_ATTRIBUTE_NORMAL : FILE_FLAG_OVERLAPPED) | SECURITY_IMPERSONATION), + NULL); + + if (hDev == INVALID_HANDLE_VALUE) { + wprintf(L"Failed to open the device, error - %d", GetLastError()); + } else { + wprintf(L"Opened the device successfully.\n"); + } + + return hDev; +} + + + +VOID +Usage() + +/*++ +Routine Description: + + Called by main() to dump usage info to the console when + the app is called with no parms or with an invalid parm + +Arguments: + + None + +Return Value: + + None + +--*/ + +{ + wprintf(L"Usage for osrusbfx2 testapp:\n"); + wprintf(L"-r where n is number of bytes to read\n"); + wprintf(L"-w where n is number of bytes to write\n"); + wprintf(L"-c where n is number of iterations (default = 1)\n"); + wprintf(L"-v -- dumps read data\n"); + wprintf(L"-p to control bar LEDs, seven segment, and dip switch\n"); + wprintf(L"-a to perform asynchronous I/O\n"); + wprintf(L"-u to dump USB configuration and pipe info \n"); + wprintf(L"-f [interval-seconds] to send a text file to the seven-segment display (UMDF only)\n"); + + return; +} + + +void +Parse( + _In_ int argc, + _In_reads_(argc) LPWSTR *argv + ) + +/*++ +Routine Description: + + Called by main() to parse command line parms + +Arguments: + + argc and argv that was passed to main() + +Return Value: + + Sets global flags as per user function request + +--*/ + +{ + int i; + PWSTR endchar; + + if ( argc < 2 ) // give usage if invoked with no parms + Usage(); + + for (i=0; i= argc) { + Usage(); + exit(1); + } + else { + G_ReadLen = wcstoul(&argv[i+1][0], &endchar, 10); + G_fRead = TRUE; + } + i++; + break; + case L'w': + case L'W': + if (i+1 >= argc) { + Usage(); + exit(1); + } + else { + G_WriteLen = wcstoul(&argv[i+1][0], &endchar, 10); + G_fWrite = TRUE; + } + i++; + break; + case L'c': + case L'C': + if (i+1 >= argc) { + Usage(); + exit(1); + } + else { + G_IterationCount = wcstoul(&argv[i+1][0], &endchar, 10); + } + i++; + break; + case L'f': + case L'F': + if (i+1 >= argc) { + Usage(); + exit(1); + } + else { + G_SendFileName = argv[i+1]; + } + + i++; + + if (i+1 < argc) { + G_SendFileInterval = wcstoul(&argv[i+1][0], &endchar, 10); + } + i++; + + break; + case L'u': + case L'U': + G_fDumpUsbConfig = TRUE; + break; + case L'p': + case L'P': + G_fPlayWithDevice = TRUE; + break; + case L'a': + case L'A': + G_fPerformAsyncIo = TRUE; + break; + case L'v': + case L'V': + G_fDumpReadData = TRUE; + break; + default: + Usage(); + } + } + } +} + +BOOL +Compare_Buffs( + _In_reads_bytes_(length) PVOID *buff1, + _In_reads_bytes_(length) PVOID *buff2, + _In_ int length + ) +/*++ +Routine Description: + + Called to verify read and write buffers match for loopback test + +Arguments: + + buffers to compare and length + +Return Value: + + TRUE if buffers match, else FALSE + +--*/ +{ + int ok = 1; + + if (memcmp(buff1, buff2, length )) { + // Edi, and Esi point to the mismatching char and ecx indicates the + // remaining length. + ok = 0; + } + + return ok; +} + +#define NPERLN 8 + +VOID +Dump( + UCHAR *b, + int len +) + +/*++ +Routine Description: + + Called to do formatted ascii dump to console of the io buffer + +Arguments: + + buffer and length + +Return Value: + + none + +--*/ + +{ + ULONG i; + ULONG longLen = (ULONG)len / sizeof( ULONG ); + PULONG pBuf = (PULONG) b; + + // dump an ordinal ULONG for each sizeof(ULONG)'th byte + wprintf(L"\n****** BEGIN DUMP LEN decimal %d, 0x%x\n", len,len); + for (i=0; i 8){ + wprintf(L"Invalid bar number!\n"); + goto Error; + } + + bar--; // normalize to 0 to 7 + + barGraphState.BarsAsUChar = 1 << (UCHAR)bar; + + if (!DeviceIoControl(deviceHandle, + IOCTL_OSRUSBFX2_SET_BAR_GRAPH_DISPLAY, + &barGraphState, // Ptr to InBuffer + sizeof(BAR_GRAPH_STATE), // Length of InBuffer + NULL, // Ptr to OutBuffer + 0, // Length of OutBuffer + &index, // BytesReturned + 0)) { // Ptr to Overlapped structure + + code = GetLastError(); + + wprintf(L"DeviceIoControl failed with error 0x%x\n", code); + + goto Error; + } + + break; + + case CLEAR_ONE_BAR: + + + wprintf(L"Which Bar (input number 1 thru 8)?\n"); + if (scanf_s ("%d", &bar) <= 0) { + + wprintf(L"Error reading input!\n"); + goto Error; + + } + + if(bar == 0 || bar > 8){ + wprintf(L"Invalid bar number!\n"); + goto Error; + } + + bar--; + + // + // Read the current state + // + if (!DeviceIoControl(deviceHandle, + IOCTL_OSRUSBFX2_GET_BAR_GRAPH_DISPLAY, + NULL, // Ptr to InBuffer + 0, // Length of InBuffer + &barGraphState, // Ptr to OutBuffer + sizeof(BAR_GRAPH_STATE), // Length of OutBuffer + &index, // BytesReturned + 0)) { // Ptr to Overlapped structure + + code = GetLastError(); + + wprintf(L"DeviceIoControl failed with error 0x%x\n", code); + + goto Error; + } + + if (barGraphState.BarsAsUChar & (1 << bar)) { + + wprintf(L"Bar is set...Clearing it\n"); + barGraphState.BarsAsUChar &= ~(1 << bar); + + if (!DeviceIoControl(deviceHandle, + IOCTL_OSRUSBFX2_SET_BAR_GRAPH_DISPLAY, + &barGraphState, // Ptr to InBuffer + sizeof(BAR_GRAPH_STATE), // Length of InBuffer + NULL, // Ptr to OutBuffer + 0, // Length of OutBuffer + &index, // BytesReturned + 0)) { // Ptr to Overlapped structure + + code = GetLastError(); + + wprintf(L"DeviceIoControl failed with error 0x%x\n", code); + + goto Error; + + } + + } else { + + wprintf(L"Bar not set.\n"); + + } + + break; + + case LIGHT_ALL_BARS: + + barGraphState.BarsAsUChar = 0xFF; + + if (!DeviceIoControl(deviceHandle, + IOCTL_OSRUSBFX2_SET_BAR_GRAPH_DISPLAY, + &barGraphState, // Ptr to InBuffer + sizeof(BAR_GRAPH_STATE), // Length of InBuffer + NULL, // Ptr to OutBuffer + 0, // Length of OutBuffer + &index, // BytesReturned + 0)) { // Ptr to Overlapped structure + + code = GetLastError(); + + wprintf(L"DeviceIoControl failed with error 0x%x\n", code); + + goto Error; + } + + break; + + case CLEAR_ALL_BARS: + + barGraphState.BarsAsUChar = 0; + + if (!DeviceIoControl(deviceHandle, + IOCTL_OSRUSBFX2_SET_BAR_GRAPH_DISPLAY, + &barGraphState, // Ptr to InBuffer + sizeof(BAR_GRAPH_STATE), // Length of InBuffer + NULL, // Ptr to OutBuffer + 0, // Length of OutBuffer + &index, // BytesReturned + 0)) { // Ptr to Overlapped structure + + code = GetLastError(); + + wprintf(L"DeviceIoControl failed with error 0x%x\n", code); + + goto Error; + } + + break; + + + case GET_BAR_GRAPH_LIGHT_STATE: + + barGraphState.BarsAsUChar = 0; + + if (!DeviceIoControl(deviceHandle, + IOCTL_OSRUSBFX2_GET_BAR_GRAPH_DISPLAY, + NULL, // Ptr to InBuffer + 0, // Length of InBuffer + &barGraphState, // Ptr to OutBuffer + sizeof(BAR_GRAPH_STATE), // Length of OutBuffer + &index, // BytesReturned + 0)) { // Ptr to Overlapped structure + + code = GetLastError(); + + wprintf(L"DeviceIoControl failed with error 0x%x\n", code); + + goto Error; + } + + wprintf(L"Bar Graph: \n"); + wprintf(L" Bar8 is %s\n", barGraphState.Bar8 ? L"ON" : L"OFF"); + wprintf(L" Bar7 is %s\n", barGraphState.Bar7 ? L"ON" : L"OFF"); + wprintf(L" Bar6 is %s\n", barGraphState.Bar6 ? L"ON" : L"OFF"); + wprintf(L" Bar5 is %s\n", barGraphState.Bar5 ? L"ON" : L"OFF"); + wprintf(L" Bar4 is %s\n", barGraphState.Bar4 ? L"ON" : L"OFF"); + wprintf(L" Bar3 is %s\n", barGraphState.Bar3 ? L"ON" : L"OFF"); + wprintf(L" Bar2 is %s\n", barGraphState.Bar2 ? L"ON" : L"OFF"); + wprintf(L" Bar1 is %s\n", barGraphState.Bar1 ? L"ON" : L"OFF"); + + break; + + case GET_SWITCH_STATE: + + switchState.SwitchesAsUChar = 0; + + if (!DeviceIoControl(deviceHandle, + IOCTL_OSRUSBFX2_READ_SWITCHES, + NULL, // Ptr to InBuffer + 0, // Length of InBuffer + &switchState, // Ptr to OutBuffer + sizeof(SWITCH_STATE), // Length of OutBuffer + &index, // BytesReturned + 0)) { // Ptr to Overlapped structure + + code = GetLastError(); + + wprintf(L"DeviceIoControl failed with error 0x%x\n", code); + + goto Error; + } + + wprintf(L"Switches: \n"); + wprintf(L" Switch8 is %s\n", switchState.Switch8 ? L"ON" : L"OFF"); + wprintf(L" Switch7 is %s\n", switchState.Switch7 ? L"ON" : L"OFF"); + wprintf(L" Switch6 is %s\n", switchState.Switch6 ? L"ON" : L"OFF"); + wprintf(L" Switch5 is %s\n", switchState.Switch5 ? L"ON" : L"OFF"); + wprintf(L" Switch4 is %s\n", switchState.Switch4 ? L"ON" : L"OFF"); + wprintf(L" Switch3 is %s\n", switchState.Switch3 ? L"ON" : L"OFF"); + wprintf(L" Switch2 is %s\n", switchState.Switch2 ? L"ON" : L"OFF"); + wprintf(L" Switch1 is %s\n", switchState.Switch1 ? L"ON" : L"OFF"); + + break; + + case GET_SWITCH_STATE_AS_INTERRUPT_MESSAGE: + + switchState.SwitchesAsUChar = 0; + + if (!DeviceIoControl(deviceHandle, + IOCTL_OSRUSBFX2_GET_INTERRUPT_MESSAGE, + NULL, // Ptr to InBuffer + 0, // Length of InBuffer + &switchState, // Ptr to OutBuffer + sizeof(switchState), // Length of OutBuffer + &index, // BytesReturned + 0)) { // Ptr to Overlapped structure + + code = GetLastError(); + + wprintf(L"DeviceIoControl failed with error 0x%x\n", code); + + goto Error; + } + + wprintf(L"Switches: %d\n",index); + wprintf(L" Switch8 is %s\n", switchState.Switch8 ? L"ON" : L"OFF"); + wprintf(L" Switch7 is %s\n", switchState.Switch7 ? L"ON" : L"OFF"); + wprintf(L" Switch6 is %s\n", switchState.Switch6 ? L"ON" : L"OFF"); + wprintf(L" Switch5 is %s\n", switchState.Switch5 ? L"ON" : L"OFF"); + wprintf(L" Switch4 is %s\n", switchState.Switch4 ? L"ON" : L"OFF"); + wprintf(L" Switch3 is %s\n", switchState.Switch3 ? L"ON" : L"OFF"); + wprintf(L" Switch2 is %s\n", switchState.Switch2 ? L"ON" : L"OFF"); + wprintf(L" Switch1 is %s\n", switchState.Switch1 ? L"ON" : L"OFF"); + + break; + + case GET_7_SEGEMENT_STATE: + + sevenSegment = 0; + + if (!DeviceIoControl(deviceHandle, + IOCTL_OSRUSBFX2_GET_7_SEGMENT_DISPLAY, + NULL, // Ptr to InBuffer + 0, // Length of InBuffer + &sevenSegment, // Ptr to OutBuffer + sizeof(UCHAR), // Length of OutBuffer + &index, // BytesReturned + 0)) { // Ptr to Overlapped structure + + code = GetLastError(); + + wprintf(L"DeviceIoControl failed with error 0x%x\n", code); + + goto Error; + } + + wprintf(L"7 Segment mask: 0x%x\n", sevenSegment); + break; + + case SET_7_SEGEMENT_STATE: + + for (i = 0; i < 8; i++) { + + sevenSegment = 1 << i; + + if (!DeviceIoControl(deviceHandle, + IOCTL_OSRUSBFX2_SET_7_SEGMENT_DISPLAY, + &sevenSegment, // Ptr to InBuffer + sizeof(UCHAR), // Length of InBuffer + NULL, // Ptr to OutBuffer + 0, // Length of OutBuffer + &index, // BytesReturned + 0)) { // Ptr to Overlapped structure + + code = GetLastError(); + + wprintf(L"DeviceIoControl failed with error 0x%x\n", code); + + goto Error; + } + + wprintf(L"This is %d\n", i); + Sleep(500); + + } + + wprintf(L"7 Segment mask: 0x%x\n", sevenSegment); + break; + + case RESET_DEVICE: + + wprintf(L"Reset the device\n"); + + if (!DeviceIoControl(deviceHandle, + IOCTL_OSRUSBFX2_RESET_DEVICE, + NULL, // Ptr to InBuffer + 0, // Length of InBuffer + NULL, // Ptr to OutBuffer + 0, // Length of OutBuffer + &index, // BytesReturned + NULL)) { // Ptr to Overlapped structure + + code = GetLastError(); + + wprintf(L"DeviceIoControl failed with error 0x%x\n", code); + + goto Error; + } + + break; + + case REENUMERATE_DEVICE: + + wprintf(L"Re-enumerate the device\n"); + + if (!DeviceIoControl(deviceHandle, + IOCTL_OSRUSBFX2_REENUMERATE_DEVICE, + NULL, // Ptr to InBuffer + 0, // Length of InBuffer + NULL, // Ptr to OutBuffer + 0, // Length of OutBuffer + &index, // BytesReturned + NULL)) { // Ptr to Overlapped structure + + code = GetLastError(); + + wprintf(L"DeviceIoControl failed with error 0x%x\n", code); + + goto Error; + } + + // + // Close the handle to the device and exit out so that + // the driver can unload when the device is surprise-removed + // and reenumerated. + // + default: + + result = TRUE; + goto Error; + + } + + } // end of while loop + +Error: + + CloseHandle(deviceHandle); + return result; + +} + +BOOL +SendFileToDevice( + _In_ PCWSTR FileName + ) +{ + HANDLE deviceHandle; + + struct + { + USHORT delay; + WCHAR buffer[MAX_PATH + 1]; + } playback; + + ULONG bufferCch; + + DWORD code; + BOOL result = FALSE; + + // + // Open a handle to the device. + // + + deviceHandle = OpenDevice(FALSE); + + if (deviceHandle == INVALID_HANDLE_VALUE) { + + wprintf(L"Unable to find any OSR FX2 devices!\n"); + + return FALSE; + + } + + // + // Convert the file name from relative to absolute. + // + + bufferCch = GetFullPathName(FileName, + countof(playback.buffer), + playback.buffer, + NULL); + + if (bufferCch == 0) + { + wprintf(L"Error getting full path name for %s - %d\n", + FileName, + GetLastError()); + goto Error; + } + + if ((G_SendFileInterval * 1000) >= ((USHORT) 0xffff)) + { + wprintf(L"Error - delay is too large. Remember that it's in terms of seconds.\n"); + goto Error; + } + + playback.delay = (USHORT) (G_SendFileInterval * 1000); + + if (!DeviceIoControl(deviceHandle, + IOCTL_OSRUSBFX2_PLAY_FILE, + &playback, + sizeof(playback), + NULL, + 0, + &bufferCch, + 0)) { + + code = GetLastError(); + + wprintf(L"DeviceIoControl failed with error 0x%x\n", code); + + goto Error; + } + + result = TRUE; + +Error: + + CloseHandle(deviceHandle); + return result; +} + +ULONG +AsyncIo( + PVOID ThreadParameter + ) +{ + HANDLE hDevice = INVALID_HANDLE_VALUE; + HANDLE hCompletionPort = NULL; + OVERLAPPED *pOvList = NULL; + PUCHAR buf = NULL; + ULONG_PTR i; + ULONG ioType = (ULONG)(ULONG_PTR)ThreadParameter; + ULONG error; + + hDevice = OpenDevice(FALSE); + + if (hDevice == INVALID_HANDLE_VALUE) { + wprintf(L"Cannot open device %d\n", GetLastError()); + goto Error; + } + + hCompletionPort = CreateIoCompletionPort(hDevice, NULL, 1, 0); + + if (hCompletionPort == NULL) { + wprintf(L"Cannot open completion port %d \n",GetLastError()); + goto Error; + } + + pOvList = (OVERLAPPED *)malloc(NUM_ASYNCH_IO * sizeof(OVERLAPPED)); + + if (pOvList == NULL) { + wprintf(L"Cannot allocate overlapped array \n"); + goto Error; + } + + buf = (PUCHAR)malloc(NUM_ASYNCH_IO * BUFFER_SIZE); + + if (buf == NULL) { + wprintf(L"Cannot allocate buffer \n"); + goto Error; + } + + ZeroMemory(pOvList, NUM_ASYNCH_IO * sizeof(OVERLAPPED)); + ZeroMemory(buf, NUM_ASYNCH_IO * BUFFER_SIZE); + + // + // Issue asynch I/O + // + + for (i = 0; i < NUM_ASYNCH_IO; i++) { + if (ioType == READER_TYPE) { + if ( ReadFile( hDevice, + buf + (i* BUFFER_SIZE), + BUFFER_SIZE, + NULL, + &pOvList[i]) == 0) { + + error = GetLastError(); + if (error != ERROR_IO_PENDING) { + wprintf(L" %d th read failed %d \n",i, GetLastError()); + goto Error; + } + } + + } else { + if ( WriteFile( hDevice, + buf + (i* BUFFER_SIZE), + BUFFER_SIZE, + NULL, + &pOvList[i]) == 0) { + error = GetLastError(); + if (error != ERROR_IO_PENDING) { + wprintf(L" %d th write failed %d \n",i, GetLastError()); + goto Error; + } + } + } + } + + // + // Wait for the I/Os to complete. If one completes then reissue the I/O + // + + WHILE (1) { + OVERLAPPED *completedOv; + ULONG_PTR key; + ULONG numberOfBytesTransferred; + + if ( GetQueuedCompletionStatus(hCompletionPort, &numberOfBytesTransferred, + &key, &completedOv, INFINITE) == 0) { + wprintf(L"GetQueuedCompletionStatus failed %d\n", GetLastError()); + goto Error; + } + + // + // Read successfully completed. Issue another one. + // + + if (ioType == READER_TYPE) { + + i = completedOv - pOvList; + + wprintf(L"Number of bytes read by request number %d is %d\n", + i, numberOfBytesTransferred); + + if ( ReadFile( hDevice, + buf + (i * BUFFER_SIZE), + BUFFER_SIZE, + NULL, + completedOv) == 0) { + error = GetLastError(); + if (error != ERROR_IO_PENDING) { + wprintf(L"%d th Read failed %d \n", i, GetLastError()); + goto Error; + } + } + } else { + + i = completedOv - pOvList; + + wprintf(L"Number of bytes written by request number %d is %d\n", + i, numberOfBytesTransferred); + + if ( WriteFile( hDevice, + buf + (i * BUFFER_SIZE), + BUFFER_SIZE, + NULL, + completedOv) == 0) { + error = GetLastError(); + if (error != ERROR_IO_PENDING) { + wprintf(L"%d th write failed %d \n", i, GetLastError()); + goto Error; + } + } + } + } + +Error: + if (hDevice != INVALID_HANDLE_VALUE) { + CloseHandle(hDevice); + } + + if (hCompletionPort) { + CloseHandle(hCompletionPort); + } + + if (pOvList) { + free(pOvList); + } + if (buf) { + free(buf); + } + + return 1; + +} + + +int +_cdecl +wmain( + _In_ int argc, + _In_reads_(argc) LPWSTR *argv + ) +/*++ +Routine Description: + + Entry point to rwbulk.exe + Parses cmdline, performs user-requested tests + +Arguments: + + argc, argv standard console 'c' app arguments + +Return Value: + + Zero + +--*/ + +{ + PWSTR * pinBuf = NULL; + PWSTR * poutBuf = NULL; + int nBytesRead; + int nBytesWrite; + int ok; + int retValue = 0; + UINT success; + HANDLE hRead = INVALID_HANDLE_VALUE; + HANDLE hWrite = INVALID_HANDLE_VALUE; + ULONG fail = 0L; + ULONG i; + + + Parse(argc, argv ); + + // + // dump USB configuation and pipe info + // + if (G_fDumpUsbConfig) { + DumpUsbConfig(); + } + + if (G_fPlayWithDevice) { + PlayWithDevice(); + goto exit; + } + + if (G_SendFileName != NULL) + { + SendFileToDevice(G_SendFileName); + goto exit; + } + + if (G_fPerformAsyncIo) { + HANDLE th1; + + // + // Create a reader thread + // + th1 = CreateThread( NULL, // Default Security Attrib. + 0, // Initial Stack Size, + AsyncIo, // Thread Func + (LPVOID)READER_TYPE, + 0, // Creation Flags + NULL ); // Don't need the Thread Id. + + if (th1 == NULL) { + wprintf(L"Couldn't create reader thread - error %d\n", GetLastError()); + retValue = 1; + goto exit; + } + + // + // Use this thread for peforming write. + // + AsyncIo((PVOID)WRITER_TYPE); + + goto exit; + } + + // + // doing a read, write, or both test + // + if ((G_fRead) || (G_fWrite)) { + + if (G_fRead) { + if ( G_fDumpReadData ) { // round size to sizeof ULONG for readable dumping + while( G_ReadLen % sizeof( ULONG ) ) { + G_ReadLen++; + } + } + + // + // open the output file + // + hRead = OpenDevice(TRUE); + if(hRead == INVALID_HANDLE_VALUE) { + retValue = 1; + goto exit; + } + + pinBuf = malloc(G_ReadLen); + } + + if (G_fWrite) { + if ( G_fDumpReadData ) { // round size to sizeof ULONG for readable dumping + while( G_WriteLen % sizeof( ULONG ) ) { + G_WriteLen++; + } + } + + // + // open the output file + // + hWrite = OpenDevice(TRUE); + if(hWrite == INVALID_HANDLE_VALUE) { + retValue = 1; + goto exit; + } + + poutBuf = malloc(G_WriteLen); + } + + for (i = 0; i < G_IterationCount; i++) { + ULONG j; + + if (G_fWrite && poutBuf && hWrite != INVALID_HANDLE_VALUE) { + + PULONG pOut = (PULONG) poutBuf; + ULONG numLongs = G_WriteLen / sizeof( ULONG ); + + // + // put some data in the output buffer + // + for (j=0; j + +#include + +#define VER_FILETYPE VFT_DLL +#define VER_FILESUBTYPE VFT2_UNKNOWN +#define VER_FILEDESCRIPTION_STR "OSRUSBFX2 Bulk & Isoch Read and Write test App for UMDF" +#define VER_INTERNALNAME_STR "WudfOsrUsbFx2Test.exe" +#define VER_ORIGINALFILENAME_STR "WudfOsrUsbFx2Test.exe" + +#include + + diff --git a/usb/umdf_fx2/inc/WUDFOsrUsbPublic.h b/usb/umdf_fx2/inc/WUDFOsrUsbPublic.h new file mode 100644 index 00000000..6681fa14 --- /dev/null +++ b/usb/umdf_fx2/inc/WUDFOsrUsbPublic.h @@ -0,0 +1,32 @@ +/*++ + +Copyright (c) Microsoft Corporation, All Rights Reserved + +Module Name: + + WUDFOsrUsbPublic.h + +Abstract: + + This module contains the common declarations shared by driver + and user applications for the UMDF OSR device sample. + + Note that this driver does NOT use the same device interface GUID + as the KMDF OSR USB sample. + +Environment: + + user and kernel + +--*/ + +#pragma once + +// +// Define an Interface Guid so that app can find the device and talk to it. +// + +// {573E8C73-0CB4-4471-A1BF-FAB26C31D384} +DEFINE_GUID(GUID_DEVINTERFACE_OSRUSBFX2, + 0x573e8c73, 0xcb4, 0x4471, 0xa1, 0xbf, 0xfa, 0xb2, 0x6c, 0x31, 0xd3, 0x84); + diff --git a/usb/umdf_fx2/inc/list.h b/usb/umdf_fx2/inc/list.h new file mode 100644 index 00000000..38d0b1e9 --- /dev/null +++ b/usb/umdf_fx2/inc/list.h @@ -0,0 +1,77 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved + +Module Name: + + list.h + +Abstract: + + This module contains doubly linked list macros + +Environment: + + Windows User-Mode Driver Framework (WUDF) + +--*/ + +#pragma once + + +FORCEINLINE +VOID +InitializeListHead( + IN PLIST_ENTRY ListHead + ) +{ + ListHead->Flink = ListHead->Blink = ListHead; +} + +FORCEINLINE +BOOLEAN +RemoveEntryList( + IN PLIST_ENTRY Entry + ) +{ + PLIST_ENTRY Blink; + PLIST_ENTRY Flink; + + Flink = Entry->Flink; + Blink = Entry->Blink; + Blink->Flink = Flink; + Flink->Blink = Blink; + return (BOOLEAN)(Flink == Blink); +} + +FORCEINLINE +VOID +InsertHeadList( + IN PLIST_ENTRY ListHead, + IN PLIST_ENTRY Entry + ) +{ + PLIST_ENTRY Flink; + + Flink = ListHead->Flink; + Entry->Flink = Flink; + Entry->Blink = ListHead; + Flink->Blink = Entry; + ListHead->Flink = Entry; +} + +FORCEINLINE +VOID +InsertTailList( + IN PLIST_ENTRY ListHead, + IN PLIST_ENTRY Entry + ) +{ + PLIST_ENTRY Blink; + + Blink = ListHead->Blink; + Entry->Flink = ListHead; + Entry->Blink = Blink; + Blink->Flink = Entry; + ListHead->Blink = Entry; +} diff --git a/usb/umdf_fx2/inc/public.h b/usb/umdf_fx2/inc/public.h new file mode 100644 index 00000000..22f6cb6d --- /dev/null +++ b/usb/umdf_fx2/inc/public.h @@ -0,0 +1,217 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + public.h + +Abstract: + + Public definitions for the OSR_FX2 device operations. + +Environment: + + User & Kernel mode + +--*/ + +#ifndef _PUBLIC_H +#define _PUBLIC_H + +#include + +#include "WudfOsrUsbPublic.h" + + +// +// Define the structures that will be used by the IOCTL +// interface to the driver +// + +// +// BAR_GRAPH_STATE +// +// BAR_GRAPH_STATE is a bit field structure with each +// bit corresponding to one of the bar graph on the +// OSRFX2 Development Board +// +#include + +#pragma warning( push ) +#pragma warning( disable : 4201 ) // nameless struct/union +#pragma warning( disable : 4214 ) // bit-field type other than int + +typedef struct _BAR_GRAPH_STATE { + + union { + + struct { + // + // Individual bars starting from the + // top of the stack of bars + // + // NOTE: There are actually 10 bars, + // but the very top two do not light + // and are not counted here + // + UCHAR Bar1 : 1; + UCHAR Bar2 : 1; + UCHAR Bar3 : 1; + UCHAR Bar4 : 1; + UCHAR Bar5 : 1; + UCHAR Bar6 : 1; + UCHAR Bar7 : 1; + UCHAR Bar8 : 1; + }; + + // + // The state of all the bar graph as a single + // UCHAR + // + UCHAR BarsAsUChar; + + }; + +}BAR_GRAPH_STATE, *PBAR_GRAPH_STATE; + +// +// SWITCH_STATE +// +// SWITCH_STATE is a bit field structure with each +// bit corresponding to one of the switches on the +// OSRFX2 Development Board +// +typedef struct _SWITCH_STATE { + + union { + struct { + // + // Individual switches starting from the + // left of the set of switches + // + UCHAR Switch1 : 1; + UCHAR Switch2 : 1; + UCHAR Switch3 : 1; + UCHAR Switch4 : 1; + UCHAR Switch5 : 1; + UCHAR Switch6 : 1; + UCHAR Switch7 : 1; + UCHAR Switch8 : 1; + }; + + // + // The state of all the switches as a single + // UCHAR + // + UCHAR SwitchesAsUChar; + + }; + + +}SWITCH_STATE, *PSWITCH_STATE; + +// +// Seven segment display bit values. +// + +// +// Undefine conflicting MFC constant +// +#undef SS_CENTER +#undef SS_LEFT +#undef SS_RIGHT + +#define SS_TOP 0x01 +#define SS_TOP_LEFT 0x40 +#define SS_TOP_RIGHT 0x02 +#define SS_CENTER 0x20 +#define SS_BOTTOM_LEFT 0x10 +#define SS_BOTTOM_RIGHT 0x04 +#define SS_BOTTOM 0x80 +#define SS_DOT 0x08 + +// +// FILE_PLAYBACK +// +// FILE_PLAYBACK structure contains the parameters for the PLAY_FILE I/O Control. +// + +typedef struct _FILE_PLAYBACK +{ + // + // The delay between changes in the display, in milliseconds. + // + + USHORT Delay; + + // + // The data file path. + // + + WCHAR Path[1]; +} FILE_PLAYBACK, *PFILE_PLAYBACK; + +#include + +#define IOCTL_INDEX 0x800 +#define FILE_DEVICE_OSRUSBFX2 0x65500 + +#define IOCTL_OSRUSBFX2_GET_CONFIG_DESCRIPTOR CTL_CODE(FILE_DEVICE_OSRUSBFX2, \ + IOCTL_INDEX, \ + METHOD_BUFFERED, \ + FILE_READ_ACCESS) + +#define IOCTL_OSRUSBFX2_RESET_DEVICE CTL_CODE(FILE_DEVICE_OSRUSBFX2, \ + IOCTL_INDEX + 1, \ + METHOD_BUFFERED, \ + FILE_WRITE_ACCESS) + +#define IOCTL_OSRUSBFX2_REENUMERATE_DEVICE CTL_CODE(FILE_DEVICE_OSRUSBFX2, \ + IOCTL_INDEX + 3, \ + METHOD_BUFFERED, \ + FILE_WRITE_ACCESS) + +#define IOCTL_OSRUSBFX2_GET_BAR_GRAPH_DISPLAY CTL_CODE(FILE_DEVICE_OSRUSBFX2,\ + IOCTL_INDEX + 4, \ + METHOD_BUFFERED, \ + FILE_READ_ACCESS) + + +#define IOCTL_OSRUSBFX2_SET_BAR_GRAPH_DISPLAY CTL_CODE(FILE_DEVICE_OSRUSBFX2,\ + IOCTL_INDEX + 5, \ + METHOD_BUFFERED, \ + FILE_WRITE_ACCESS) + + +#define IOCTL_OSRUSBFX2_READ_SWITCHES CTL_CODE(FILE_DEVICE_OSRUSBFX2, \ + IOCTL_INDEX + 6, \ + METHOD_BUFFERED, \ + FILE_READ_ACCESS) + + +#define IOCTL_OSRUSBFX2_GET_7_SEGMENT_DISPLAY CTL_CODE(FILE_DEVICE_OSRUSBFX2, \ + IOCTL_INDEX + 7, \ + METHOD_BUFFERED, \ + FILE_READ_ACCESS) + + +#define IOCTL_OSRUSBFX2_SET_7_SEGMENT_DISPLAY CTL_CODE(FILE_DEVICE_OSRUSBFX2, \ + IOCTL_INDEX + 8, \ + METHOD_BUFFERED, \ + FILE_WRITE_ACCESS) + +#define IOCTL_OSRUSBFX2_GET_INTERRUPT_MESSAGE CTL_CODE(FILE_DEVICE_OSRUSBFX2,\ + IOCTL_INDEX + 9, \ + METHOD_OUT_DIRECT, \ + FILE_READ_ACCESS) + +#define IOCTL_OSRUSBFX2_PLAY_FILE CTL_CODE(FILE_DEVICE_OSRUSBFX2, \ + IOCTL_INDEX + 10, \ + METHOD_BUFFERED, \ + FILE_WRITE_ACCESS) + +#pragma warning(pop) + +#endif + diff --git a/usb/umdf_fx2/inc/usb_hw.h b/usb/umdf_fx2/inc/usb_hw.h new file mode 100644 index 00000000..d6e983f1 --- /dev/null +++ b/usb/umdf_fx2/inc/usb_hw.h @@ -0,0 +1,233 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + Usb.h + +Abstract: + + Contains prototypes for interfacing with a USB connected device. These + are copied from the KMDF WDFUSB.H header file (but with the WDF specific + portions removed) + +Environment: + + kernel mode only + +--*/ + +#pragma once + +typedef enum _WINUSB_BMREQUEST_DIRECTION { + BmRequestHostToDevice = BMREQUEST_HOST_TO_DEVICE, + BmRequestDeviceToHost = BMREQUEST_DEVICE_TO_HOST, +} WINUSB_BMREQUEST_DIRECTION; + +typedef enum _WINUSB_BMREQUEST_TYPE { + BmRequestStandard = BMREQUEST_STANDARD, + BmRequestClass = BMREQUEST_CLASS, + BmRequestVendor = BMREQUEST_VENDOR, +} WINUSB_BMREQUEST_TYPE; + +typedef enum _WINUSB_BMREQUEST_RECIPIENT { + BmRequestToDevice = BMREQUEST_TO_DEVICE, + BmRequestToInterface = BMREQUEST_TO_INTERFACE, + BmRequestToEndpoint = BMREQUEST_TO_ENDPOINT, + BmRequestToOther = BMREQUEST_TO_OTHER, +} WINUSB_BMREQUEST_RECIPIENT; + +typedef enum _WINUSB_DEVICE_TRAITS { + WINUSB_DEVICE_TRAIT_SELF_POWERED = 0x00000001, + WINUSB_DEVICE_TRAIT_REMOTE_WAKE_CAPABLE = 0x00000002, + WINUSB_DEVICE_TRAIT_AT_HIGH_SPEED = 0x00000004, +} WINUSB_DEVICE_TRAITS; + +typedef enum _WdfUsbTargetDeviceSelectInterfaceType { + WdfUsbTargetDeviceSelectInterfaceTypeInterface = 0x10, + WdfUsbTargetDeviceSelectInterfaceTypeUrb = 0x11, +} WdfUsbTargetDeviceSelectInterfaceType; + + + +typedef union _WINUSB_CONTROL_SETUP_PACKET { + struct { + union { + #pragma warning(disable:4214) // bit field types other than int + struct { + // + // Valid values are BMREQUEST_TO_DEVICE, BMREQUEST_TO_INTERFACE, + // BMREQUEST_TO_ENDPOINT, BMREQUEST_TO_OTHER + // + BYTE Recipient:2; + + BYTE Reserved:3; + + // + // Valid values are BMREQUEST_STANDARD, BMREQUEST_CLASS, + // BMREQUEST_VENDOR + // + BYTE Type:2; + + // + // Valid values are BMREQUEST_HOST_TO_DEVICE, + // BMREQUEST_DEVICE_TO_HOST + // + BYTE Dir:1; + } Request; + #pragma warning(default:4214) // bit field types other than int + BYTE Byte; + } bm; + + BYTE bRequest; + + union { + struct { + BYTE LowByte; + BYTE HiByte; + } Bytes; + USHORT Value; + } wValue; + + union { + struct { + BYTE LowByte; + BYTE HiByte; + } Bytes; + USHORT Value; + } wIndex; + + USHORT wLength; + } Packet; + + struct { + BYTE Bytes[8]; + } Generic; + + WINUSB_SETUP_PACKET WinUsb; + +} WINUSB_CONTROL_SETUP_PACKET, *PWINUSB_CONTROL_SETUP_PACKET; + +VOID +FORCEINLINE +WINUSB_CONTROL_SETUP_PACKET_INIT( + PWINUSB_CONTROL_SETUP_PACKET Packet, + WINUSB_BMREQUEST_DIRECTION Direction, + WINUSB_BMREQUEST_RECIPIENT Recipient, + BYTE Request, + USHORT Value, + USHORT Index + ) +{ + RtlZeroMemory(Packet, sizeof(WINUSB_CONTROL_SETUP_PACKET)); + + Packet->Packet.bm.Request.Dir = (BYTE) Direction; + Packet->Packet.bm.Request.Type = (BYTE) BmRequestStandard; + Packet->Packet.bm.Request.Recipient = (BYTE) Recipient; + + Packet->Packet.bRequest = Request; + Packet->Packet.wValue.Value = Value; + Packet->Packet.wIndex.Value = Index; + + // Packet->Packet.wLength will be set by the formatting function +} + +VOID +FORCEINLINE +WINUSB_CONTROL_SETUP_PACKET_INIT_CLASS( + PWINUSB_CONTROL_SETUP_PACKET Packet, + WINUSB_BMREQUEST_DIRECTION Direction, + WINUSB_BMREQUEST_RECIPIENT Recipient, + BYTE Request, + USHORT Value, + USHORT Index + ) +{ + RtlZeroMemory(Packet, sizeof(WINUSB_CONTROL_SETUP_PACKET)); + + Packet->Packet.bm.Request.Dir = (BYTE) Direction; + Packet->Packet.bm.Request.Type = (BYTE) BmRequestClass; + Packet->Packet.bm.Request.Recipient = (BYTE) Recipient; + + Packet->Packet.bRequest = Request; + Packet->Packet.wValue.Value = Value; + Packet->Packet.wIndex.Value = Index; + + // Packet->Packet.wLength will be set by the formatting function +} + +VOID +FORCEINLINE +WINUSB_CONTROL_SETUP_PACKET_INIT_VENDOR( + PWINUSB_CONTROL_SETUP_PACKET Packet, + WINUSB_BMREQUEST_DIRECTION Direction, + WINUSB_BMREQUEST_RECIPIENT Recipient, + BYTE Request, + USHORT Value, + USHORT Index + ) +{ + RtlZeroMemory(Packet, sizeof(WINUSB_CONTROL_SETUP_PACKET)); + + Packet->Packet.bm.Request.Dir = (BYTE) Direction; + Packet->Packet.bm.Request.Type = (BYTE) BmRequestVendor; + Packet->Packet.bm.Request.Recipient = (BYTE) Recipient; + + Packet->Packet.bRequest = Request; + Packet->Packet.wValue.Value = Value; + Packet->Packet.wIndex.Value = Index; + + // Packet->Packet.wLength will be set by the formatting function +} + +VOID +FORCEINLINE +WINUSB_CONTROL_SETUP_PACKET_INIT_FEATURE( + PWINUSB_CONTROL_SETUP_PACKET Packet, + WINUSB_BMREQUEST_RECIPIENT BmRequestRecipient, + USHORT FeatureSelector, + USHORT Index, + BOOLEAN SetFeature + ) +{ + RtlZeroMemory(Packet, sizeof(WINUSB_CONTROL_SETUP_PACKET)); + + Packet->Packet.bm.Request.Dir = (BYTE) BmRequestHostToDevice; + Packet->Packet.bm.Request.Type = (BYTE) BmRequestStandard; + Packet->Packet.bm.Request.Recipient = (BYTE) BmRequestRecipient; + + if (SetFeature) { + Packet->Packet.bRequest = USB_REQUEST_SET_FEATURE; + } + else { + Packet->Packet.bRequest = USB_REQUEST_CLEAR_FEATURE; + } + + Packet->Packet.wValue.Value = FeatureSelector; + Packet->Packet.wIndex.Value = Index; + + // Packet->Packet.wLength will be set by the formatting function +} + +VOID +FORCEINLINE +WINUSB_CONTROL_SETUP_PACKET_INIT_GET_STATUS( + PWINUSB_CONTROL_SETUP_PACKET Packet, + WINUSB_BMREQUEST_RECIPIENT BmRequestRecipient, + USHORT Index + ) +{ + RtlZeroMemory(Packet, sizeof(WINUSB_CONTROL_SETUP_PACKET)); + + Packet->Packet.bm.Request.Dir = (BYTE) BmRequestDeviceToHost; + Packet->Packet.bm.Request.Type = (BYTE) BmRequestStandard; + Packet->Packet.bm.Request.Recipient = (BYTE) BmRequestRecipient; + + Packet->Packet.bRequest = USB_REQUEST_GET_STATUS; + Packet->Packet.wIndex.Value = Index; + Packet->Packet.wValue.Value = 0; + + // Packet->Packet.wLength will be set by the formatting function +} + diff --git a/usb/umdf_fx2/umdf_fx2.sln b/usb/umdf_fx2/umdf_fx2.sln new file mode 100644 index 00000000..9e363469 --- /dev/null +++ b/usb/umdf_fx2/umdf_fx2.sln @@ -0,0 +1,46 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0 +MinimumVisualStudioVersion = 12.0 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Driver", "Driver", "{B339DBBB-24B4-45D7-9F00-655FFD2AA012}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Exe", "Exe", "{2869A0EF-34B9-45CF-9E14-01A016B8FC6E}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WUDFOsrUsbFx2", "driver\WUDFOsrUsbFx2.vcxproj", "{6C6B5C2D-F192-4C22-B8ED-A90C10FB9A1E}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WudfOsrUsbFx2Test", "exe\WudfOsrUsbFx2Test.vcxproj", "{D567DDDD-4EC8-40B4-AE8F-58B2D41F837F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {6C6B5C2D-F192-4C22-B8ED-A90C10FB9A1E}.Debug|Win32.ActiveCfg = Debug|Win32 + {6C6B5C2D-F192-4C22-B8ED-A90C10FB9A1E}.Debug|Win32.Build.0 = Debug|Win32 + {6C6B5C2D-F192-4C22-B8ED-A90C10FB9A1E}.Release|Win32.ActiveCfg = Release|Win32 + {6C6B5C2D-F192-4C22-B8ED-A90C10FB9A1E}.Release|Win32.Build.0 = Release|Win32 + {6C6B5C2D-F192-4C22-B8ED-A90C10FB9A1E}.Debug|x64.ActiveCfg = Debug|x64 + {6C6B5C2D-F192-4C22-B8ED-A90C10FB9A1E}.Debug|x64.Build.0 = Debug|x64 + {6C6B5C2D-F192-4C22-B8ED-A90C10FB9A1E}.Release|x64.ActiveCfg = Release|x64 + {6C6B5C2D-F192-4C22-B8ED-A90C10FB9A1E}.Release|x64.Build.0 = Release|x64 + {D567DDDD-4EC8-40B4-AE8F-58B2D41F837F}.Debug|Win32.ActiveCfg = Debug|Win32 + {D567DDDD-4EC8-40B4-AE8F-58B2D41F837F}.Debug|Win32.Build.0 = Debug|Win32 + {D567DDDD-4EC8-40B4-AE8F-58B2D41F837F}.Release|Win32.ActiveCfg = Release|Win32 + {D567DDDD-4EC8-40B4-AE8F-58B2D41F837F}.Release|Win32.Build.0 = Release|Win32 + {D567DDDD-4EC8-40B4-AE8F-58B2D41F837F}.Debug|x64.ActiveCfg = Debug|x64 + {D567DDDD-4EC8-40B4-AE8F-58B2D41F837F}.Debug|x64.Build.0 = Debug|x64 + {D567DDDD-4EC8-40B4-AE8F-58B2D41F837F}.Release|x64.ActiveCfg = Release|x64 + {D567DDDD-4EC8-40B4-AE8F-58B2D41F837F}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {6C6B5C2D-F192-4C22-B8ED-A90C10FB9A1E} = {B339DBBB-24B4-45D7-9F00-655FFD2AA012} + {D567DDDD-4EC8-40B4-AE8F-58B2D41F837F} = {2869A0EF-34B9-45CF-9E14-01A016B8FC6E} + EndGlobalSection +EndGlobal diff --git a/usb/usbview/usbview.htm b/usb/usbview/usbview.htm new file mode 100644 index 00000000..442cdff2 --- /dev/null +++ b/usb/usbview/usbview.htm @@ -0,0 +1,400 @@ + + + + + + + + +USBVIEW + + + + + + + +
+ +

USBVIEW

+ +

SUMMARY

+ +

Usbview.exe is a Windows +GUI application that allows you to browse all USB controllers and connected USB +devices on your system. The left pane in the main application window displays a +connection-oriented tree view, and the right pane displays the USB data +structures pertaining to the selected USB device, such as the Device, +Configuration, Interface, and Endpoint Descriptors, as well as the current +device configuration.

+ +

This functional +application sample demonstrates how a user-mode application can enumerate USB +host controllers, USB hubs, and attached USB devices, and query information +about the devices from the registry and through USB requests to the devices.

+ +

The IOCTL calls (see the +system include file USBIOCTL.H) demonstrated by this sample include:

+ +
    +
  • IOCTL_GET_HCD_DRIVERKEY_NAME
  • +
  • IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION
  • +
  • IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME
  • +
  • IOCTL_USB_GET_NODE_CONNECTION_INFORMATION
  • +
  • IOCTL_USB_GET_NODE_CONNECTION_NAME
  • +
  • IOCTL_USB_GET_NODE_INFORMATION
  • +
  • IOCTL_USB_GET_ROOT_HUB_NAME
  • +
+ +

BUILDING THE SAMPLE

+ +

The Usbview +sample compiles and links in the standard DDK build environment with Microsoft® +Visual C® 6.0 on both X86 and Alpha systems, producing a single executable +binary Usbview.exe. Both free and checked versions can be built, with assertion +error messages enabled in the checked build to indicate unexpected error +conditions.

+ +

CODE TOUR

+ +

File Manifest

+ +
Files         Description
Usbview.htm    Documentation for this sample (this file)
Sources        Generic build-compatible sources file for this sample
Resource.h     ID definitions for GUI controls
Usbdesc.h      USB descriptor type definitions
Usbview.h      Main header file for this sample
Vndrlist.h     List of USB Vendor IDs and vendor names
Debug.c        Assertion routines for the checked build
Devnode.c      Routines for accessing DevNode information
Dispaud.c      Routines for displaying USB audio class device information
Display.c      Routines for displaying USB device information
Enum.c         Routines for enumerating host controllers, hubs, and devices
Usbview.c      Entry point and GUI handling routines
Usbview.rc     Menu and dialog definitions
Split.cur      Cursor file
Usb.ico        Application icon file
bang.ico               Application icon file
hub.ico        Application icon file
monitor.ico            Application icon file
port.ico               Application icon file
makefile               DDK build environment makefile
 
 
+ +

Programming Tour

+ +

The major topics covered +in this tour are:

+ +
    +
  • GUI handling routines
  • +
  • Device enumeration routines
  • +
  • Device information display routines
  • +
+ +

The file Usbview.c contains the sample application entry point and +GUI handling routines. On entry, the main application window is created, which +is actually a dialog box as defined in Usbview.rc. +The dialog box consists of a split window with a tree view control on the left +side and an edit control on the right side.

+ +

The routine RefreshTree() +is called to enumerate USB host controller, hubs, and attached devices and to +populate the device tree view control. RefreshTree() calls the routine EnumerateHostControllers() +in Enum.c to enumerate USB host controller, hubs, and +attached devices. After the device tree view control has been populated, USBView_OnNotify() +is called when an item is selected in the device tree view control. This calls UpdateEditControl() in Display.c to display +information about the selected item in the edit control.

+ +

The file Enum.c contains the routines that enumerate the USB bus and +populate the tree view control. The USB device enumeration and information +collection process is the main point of this sample application. The +enumeration process starts at EnumerateHostControllers() and goes like this:

+ +

(1) Enumerate Host +Controllers and Root Hubs. Host controllers have symbolic link names of the +form HCDx, where x starts at 0. Use CreateFile() +to open each host controller symbolic link. Create a node in the tree view to +represent each host controller. After a host controller has been opened, send +the host controller an IOCTL_USB_GET_ROOT_HUB_NAME request to get the symbolic +link name of the root hub that is part of the host controller.

+ +

(2) Enumerate Hubs (Root +Hubs and External Hubs). Given the name of a hub, use CreateFile() to open the +hub. Send the hub an IOCTL_USB_GET_NODE_INFORMATION request to get info about +the hub, such as the number of downstream ports. Create a node in the tree view +to represent each hub.

+ +

(3) Enumerate Downstream +Ports. Given a handle to an open hub and the number of downstream ports on the +hub, send the hub an IOCTL_USB_GET_NODE_CONNECTION_INFORMATION request for each +downstream port of the hub to get info about the device (if any) attached to +each port. If there is a device attached to a port, send the hub an +IOCTL_USB_GET_NODE_CONNECTION_NAME request to get the symbolic link name of the +hub attached to the downstream port. If there is a hub attached to the +downstream port, recurse to step (2). Create a node +in the tree view to represent each hub port and attached device. USB +configuration and string descriptors are retrieved from attached devices in GetConfigDescriptor() and GetStringDescriptor() by +sending an IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION() to the hub to which +the device is attached.

+ +

The file Display.c contains routines that display information about +selected devices in the application edit control. Information about the device +was collected during the enumeration of the device tree. This information +includes USB device, configuration, and string descriptors and connection and configuration +information that is maintained by the USB stack. The routines in this file +simply parse and print the data structures for the device that were collected +when it was enumerated. The file Dispaud.c parses and +prints data structures that are specific to USB audio class devices.

+ +

Top of page

+ + + + + +
+

 

+
+ +

© 2004 Microsoft +Corporation

+ +
+ + + + diff --git a/usb/usbview/usbview.sln b/usb/usbview/usbview.sln index 114e5229..d06846d8 100644 --- a/usb/usbview/usbview.sln +++ b/usb/usbview/usbview.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "usbview", "usbview.vcxproj", "{F4C245DD-C596-4498-8905-79FA40CCF7D5}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "usbview", "usbview.vcxproj", "{53F7289B-2210-4DCD-9A41-D83DE76A7372}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +13,14 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {F4C245DD-C596-4498-8905-79FA40CCF7D5}.Debug|Win32.ActiveCfg = Debug|Win32 - {F4C245DD-C596-4498-8905-79FA40CCF7D5}.Debug|Win32.Build.0 = Debug|Win32 - {F4C245DD-C596-4498-8905-79FA40CCF7D5}.Release|Win32.ActiveCfg = Release|Win32 - {F4C245DD-C596-4498-8905-79FA40CCF7D5}.Release|Win32.Build.0 = Release|Win32 - {F4C245DD-C596-4498-8905-79FA40CCF7D5}.Debug|x64.ActiveCfg = Debug|x64 - {F4C245DD-C596-4498-8905-79FA40CCF7D5}.Debug|x64.Build.0 = Debug|x64 - {F4C245DD-C596-4498-8905-79FA40CCF7D5}.Release|x64.ActiveCfg = Release|x64 - {F4C245DD-C596-4498-8905-79FA40CCF7D5}.Release|x64.Build.0 = Release|x64 + {53F7289B-2210-4DCD-9A41-D83DE76A7372}.Debug|Win32.ActiveCfg = Debug|Win32 + {53F7289B-2210-4DCD-9A41-D83DE76A7372}.Debug|Win32.Build.0 = Debug|Win32 + {53F7289B-2210-4DCD-9A41-D83DE76A7372}.Release|Win32.ActiveCfg = Release|Win32 + {53F7289B-2210-4DCD-9A41-D83DE76A7372}.Release|Win32.Build.0 = Release|Win32 + {53F7289B-2210-4DCD-9A41-D83DE76A7372}.Debug|x64.ActiveCfg = Debug|x64 + {53F7289B-2210-4DCD-9A41-D83DE76A7372}.Debug|x64.Build.0 = Debug|x64 + {53F7289B-2210-4DCD-9A41-D83DE76A7372}.Release|x64.ActiveCfg = Release|x64 + {53F7289B-2210-4DCD-9A41-D83DE76A7372}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/usb/usbview/usbview.vcxproj b/usb/usbview/usbview.vcxproj index 1c8a9c0e..2b1fe15d 100644 --- a/usb/usbview/usbview.vcxproj +++ b/usb/usbview/usbview.vcxproj @@ -19,11 +19,11 @@
- {F4C245DD-C596-4498-8905-79FA40CCF7D5} + {53F7289B-2210-4DCD-9A41-D83DE76A7372} $(MSBuildProjectName) Debug Win32 - {26027F55-159C-4FAA-99FB-7CC0A0B74E75} + {5310F3E1-F715-4C85-8EEE-BD30F52FD176} diff --git a/usb/usbview/usbview.vcxproj.Filters b/usb/usbview/usbview.vcxproj.Filters index b3275fc2..0688fd3e 100644 --- a/usb/usbview/usbview.vcxproj.Filters +++ b/usb/usbview/usbview.vcxproj.Filters @@ -3,15 +3,15 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {EEF5A053-6396-47A4-9251-77779C282049} + {902F6120-4AA1-4898-A1FD-6A44ADCFA148} h;hpp;hxx;hm;inl;inc;xsd - {0F82DB55-DA55-4FE8-ABE6-374C2635F9FC} + {B764DF51-5FA0-4F05-B3AE-E7ABC15ABE89} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {A6755BEE-12BC-4A51-B26F-A0BD3DADC2FD} + {1B5253D4-F3D5-4321-9E40-0E3E74955606} diff --git a/video/KMDOD/KMDOD.sln b/video/KMDOD/KMDOD.sln deleted file mode 100644 index 3bc7a354..00000000 --- a/video/KMDOD/KMDOD.sln +++ /dev/null @@ -1,28 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2013 -VisualStudioVersion = 12.0 -MinimumVisualStudioVersion = 12.0 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SampleDisplay", "Sample\SampleDisplay.vcxproj", "{1D4BAEF2-0892-4354-A6EB-546CF37110C9}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Release|Win32 = Release|Win32 - Debug|x64 = Debug|x64 - Release|x64 = Release|x64 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {1D4BAEF2-0892-4354-A6EB-546CF37110C9}.Debug|Win32.ActiveCfg = Debug|Win32 - {1D4BAEF2-0892-4354-A6EB-546CF37110C9}.Debug|Win32.Build.0 = Debug|Win32 - {1D4BAEF2-0892-4354-A6EB-546CF37110C9}.Release|Win32.ActiveCfg = Release|Win32 - {1D4BAEF2-0892-4354-A6EB-546CF37110C9}.Release|Win32.Build.0 = Release|Win32 - {1D4BAEF2-0892-4354-A6EB-546CF37110C9}.Debug|x64.ActiveCfg = Debug|x64 - {1D4BAEF2-0892-4354-A6EB-546CF37110C9}.Debug|x64.Build.0 = Debug|x64 - {1D4BAEF2-0892-4354-A6EB-546CF37110C9}.Release|x64.ActiveCfg = Release|x64 - {1D4BAEF2-0892-4354-A6EB-546CF37110C9}.Release|x64.Build.0 = Release|x64 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/video/KMDOD/ReadMe.md b/video/KMDOD/ReadMe.md deleted file mode 100644 index 338abe7d..00000000 --- a/video/KMDOD/ReadMe.md +++ /dev/null @@ -1,71 +0,0 @@ -Kernel mode display-only miniport driver (KMDOD) sample -======================================================= - -The kernel mode display-only miniport driver (KMDOD) sample implements most of the device driver interfaces (DDIs) that a display-only miniport driver should provide to the Windows Display Driver Model (WDDM). The code is useful to understand how to write a miniport driver for a display-only device, or how to develop a full WDDM driver. - -## Universal Compliant -This sample builds a Windows Universal driver. It uses only APIs and DDIs that are included in Windows Core. - -For more info on how a KMDOD works, see [Kernel Mode Display-Only Driver (KMDOD) Interface](http://msdn.microsoft.com/en-us/library/windows/hardware/jj673962). For more info on WDDM drivers, see [Windows Vista Display Driver Model (WDDM) Design Guide](http://msdn.microsoft.com/en-us/library/windows/hardware/ff570593). - -This code can also help you to understand the use and implementation of display-related DDIs. The INF file shows how to make a display miniport driver visible to other WDDM components. - -The sample can be installed on top of a VESA-capable graphics adapter, or on top of a graphics device that supports access to frame buffer memory through the Unified Extensible Firmware Interface (UEFI). - -The sample driver does not support the *sleep* power state. If it is placed in the sleep state, the driver will cause a system bugcheck to occur. There is no workaround available, by design. - -If the current display driver is not a WDDM 1.2 compliant driver, the sample driver might fail to install, with error code 43 displayed. The KMDOD driver is actually installed, but it cannot be started. The workaround for this issue is to switch to the Microsoft Basic Display Adapter Driver before installing the KMDOD sample driver, or simply to reboot your system after installing the KMDOD sample. - -Installation ------------- - -In Microsoft Visual Studio, press **F5** to build the sample and then deploy it to a target machine. For more info, see [Deploying a Driver to a Test Computer](http://msdn.microsoft.com/en-us/library/windows/hardware/hh454834). - -In some cases you might need to install the driver manually, as follows. - -1. Add the following files to the directory given by …\\[x64]\\C++\\Package: - - SampleDriver.cat - - SampleDriver.inf - - SampleDriver.sys - - SampleDriver.cer - -2. Unless you’ve provided a production certificate, you should manually install the SampleDriver.cer digital certificate with the following command: - - `Certutil.exe -addstore root SampleDriver.cer` - -3. Then enable test signing by running the following BCDEdit command: - - `Bcdedit.exe -set TESTSIGNING ON` - - **Note**  After you change the TESTSIGNING boot configuration option, restart the computer for the change to take effect. - - For more info, see [The TESTSIGNING Boot Configuration Option](http://msdn.microsoft.com/en-us/library/windows/hardware/ff553484). - -4. Manually install the driver using Device Manager, which is available from Control Panel. - -### ACPI-based GPUs - -To install the KMDOD sample driver on a GPU that is an Advanced Configuration and Power Interface (ACPI) device, add these lines to the `[MS]`, `[MS.NTamd64]`, and `[MS.NTarm]` sections of the Sampledisplay.inf file: - - --- - - - - - - - - - - -
Text
" Kernel mode display only sample driver " = KDODSamp_Inst, ACPI\CLS_0003&SUBCLS_0000
-" Kernel mode display only sample driver " = KDODSamp_Inst, ACPI\CLS_0003&SUBCLS_0001
-" Kernel mode display only sample driver " = KDODSamp_Inst, ACPI\CLS_0003&SUBCLS_0003
- -This new code provides generic identifiers for ACPI hardware. - -You can optionally delete the original lines of code within these sections of the INF file. - diff --git a/video/KMDOD/Sample/SampleDisplay.vcxproj b/video/KMDOD/Sample/SampleDisplay.vcxproj deleted file mode 100644 index e90f3a1c..00000000 --- a/video/KMDOD/Sample/SampleDisplay.vcxproj +++ /dev/null @@ -1,198 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - {1D4BAEF2-0892-4354-A6EB-546CF37110C9} - $(MSBuildProjectName) - Debug - Win32 - {747D8F94-A59D-430F-9355-8BCC82821140} - - - - Windows10 - False - Universal - WDM - WindowsKernelModeDriver10.0 - Driver - - - Windows10 - True - Universal - WDM - WindowsKernelModeDriver10.0 - Driver - - - Windows10 - False - Universal - WDM - WindowsKernelModeDriver10.0 - Driver - - - Windows10 - True - Universal - WDM - WindowsKernelModeDriver10.0 - Driver - - - - $(IntDir) - - - - - - - - - - - - - - - - - %(AdditionalDependencies);$(DDK_LIB_PATH)\displib.lib;$(DDK_LIB_PATH)\ntoskrnl.lib - - - %(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH) - - - %(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH) - - - %(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH) - - - - - %(AdditionalDependencies);$(DDK_LIB_PATH)\displib.lib;$(DDK_LIB_PATH)\ntoskrnl.lib - - - %(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH) - - - %(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH) - - - %(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH) - - - - - %(AdditionalDependencies);$(DDK_LIB_PATH)\displib.lib;$(DDK_LIB_PATH)\ntoskrnl.lib - - - %(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH) - - - %(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH) - - - %(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH) - - - - - %(AdditionalDependencies);$(DDK_LIB_PATH)\displib.lib;$(DDK_LIB_PATH)\ntoskrnl.lib - - - %(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH) - - - %(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH) - - - %(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH) - - - - SampleDisplay - - - SampleDisplay - - - SampleDisplay - - - SampleDisplay - - - - Level4 - - - - - - - Level4 - - - - - - - Level4 - - - - - - - Level4 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/video/KMDOD/Sample/SampleDisplay.vcxproj.Filters b/video/KMDOD/Sample/SampleDisplay.vcxproj.Filters deleted file mode 100644 index fcad028c..00000000 --- a/video/KMDOD/Sample/SampleDisplay.vcxproj.Filters +++ /dev/null @@ -1,49 +0,0 @@ - - - - - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {A6BB0B4D-C919-4D91-A64B-EEE3D2786FC8} - - - h;hpp;hxx;hm;inl;inc;xsd - {859C600A-1FD2-4C7B-8AFF-0AC7726F84EC} - - - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {7182D165-92F6-44B0-9AD8-B5DCF77CA59F} - - - inf;inv;inx;mof;mc; - {B6773450-64CD-4172-84AD-A2062E20181D} - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Resource Files - - - \ No newline at end of file diff --git a/video/KMDOD/Sample/sampledisplay.inf b/video/KMDOD/Sample/sampledisplay.inf deleted file mode 100644 index 2efaa97a..00000000 Binary files a/video/KMDOD/Sample/sampledisplay.inf and /dev/null differ diff --git a/video/KMDOD/bdd.cxx b/video/KMDOD/bdd.cxx deleted file mode 100644 index ce38f269..00000000 --- a/video/KMDOD/bdd.cxx +++ /dev/null @@ -1,856 +0,0 @@ -/******************************Module*Header*******************************\ -* Module Name: bdd.cxx -* -* Basic Display Driver functions implementation -* -* -* Copyright (c) 2010 Microsoft Corporation -\**************************************************************************/ - - -#include "BDD.hxx" - -#pragma code_seg("PAGE") - - -BASIC_DISPLAY_DRIVER::BASIC_DISPLAY_DRIVER(_In_ DEVICE_OBJECT* pPhysicalDeviceObject) : m_pPhysicalDevice(pPhysicalDeviceObject), - m_MonitorPowerState(PowerDeviceD0), - m_AdapterPowerState(PowerDeviceD0) -{ - PAGED_CODE(); - *((UINT*)&m_Flags) = 0; - m_Flags._LastFlag = TRUE; - RtlZeroMemory(&m_DxgkInterface, sizeof(m_DxgkInterface)); - RtlZeroMemory(&m_StartInfo, sizeof(m_StartInfo)); - RtlZeroMemory(m_CurrentModes, sizeof(m_CurrentModes)); - RtlZeroMemory(&m_DeviceInfo, sizeof(m_DeviceInfo)); - - - for (UINT i=0;iChildUid < MAX_CHILDREN); - - switch (pChildStatus->Type) - { - case StatusConnection: - { - // HpdAwarenessInterruptible was reported since HpdAwarenessNone is deprecated. - // However, BDD has no knowledge of HotPlug events, so just always return connected. - pChildStatus->HotPlug.Connected = IsDriverActive(); - return STATUS_SUCCESS; - } - - case StatusRotation: - { - // D3DKMDT_MOA_NONE was reported, so this should never be called - BDD_LOG_ERROR0("Child status being queried for StatusRotation even though D3DKMDT_MOA_NONE was reported"); - return STATUS_INVALID_PARAMETER; - } - - default: - { - BDD_LOG_WARNING1("Unknown pChildStatus->Type (0x%I64x) requested.", pChildStatus->Type); - return STATUS_NOT_SUPPORTED; - } - } -} - -// EDID retrieval -NTSTATUS BASIC_DISPLAY_DRIVER::QueryDeviceDescriptor(_In_ ULONG ChildUid, - _Inout_ DXGK_DEVICE_DESCRIPTOR* pDeviceDescriptor) -{ - PAGED_CODE(); - - BDD_ASSERT(pDeviceDescriptor != NULL); - BDD_ASSERT(ChildUid < MAX_CHILDREN); - - // If we haven't successfully retrieved an EDID yet (invalid ones are ok, so long as it was retrieved) - if (!m_Flags.EDID_Attempted) - { - GetEdid(ChildUid); - - } - - if (!m_Flags.EDID_Retrieved || !m_Flags.EDID_ValidHeader || !m_Flags.EDID_ValidChecksum) - { - // Report no EDID if a valid one wasn't retrieved - return STATUS_GRAPHICS_CHILD_DESCRIPTOR_NOT_SUPPORTED; - } - else if (pDeviceDescriptor->DescriptorOffset == 0) - { - // Only the base block is supported - RtlCopyMemory(pDeviceDescriptor->DescriptorBuffer, - m_EDIDs[ChildUid], - min(pDeviceDescriptor->DescriptorLength, EDID_V1_BLOCK_SIZE)); - - return STATUS_SUCCESS; - } - else - { - return STATUS_MONITOR_NO_MORE_DESCRIPTOR_DATA; - } -} - -NTSTATUS BASIC_DISPLAY_DRIVER::QueryAdapterInfo(_In_ CONST DXGKARG_QUERYADAPTERINFO* pQueryAdapterInfo) -{ - PAGED_CODE(); - - BDD_ASSERT(pQueryAdapterInfo != NULL); - - switch (pQueryAdapterInfo->Type) - { - case DXGKQAITYPE_DRIVERCAPS: - { - if (pQueryAdapterInfo->OutputDataSize < sizeof(DXGK_DRIVERCAPS)) - { - BDD_LOG_ERROR2("pQueryAdapterInfo->OutputDataSize (0x%I64x) is smaller than sizeof(DXGK_DRIVERCAPS) (0x%I64x)", pQueryAdapterInfo->OutputDataSize, sizeof(DXGK_DRIVERCAPS)); - return STATUS_BUFFER_TOO_SMALL; - } - - DXGK_DRIVERCAPS* pDriverCaps = (DXGK_DRIVERCAPS*)pQueryAdapterInfo->pOutputData; - - // Nearly all fields must be initialized to zero, so zero out to start and then change those that are non-zero. - // Fields are zero since BDD is Display-Only and therefore does not support any of the render related fields. - // It also doesn't support hardware interrupts, gamma ramps, etc. - RtlZeroMemory(pDriverCaps, sizeof(DXGK_DRIVERCAPS)); - - pDriverCaps->WDDMVersion = DXGKDDI_WDDMv1_2; - pDriverCaps->HighestAcceptableAddress.QuadPart = -1; - - pDriverCaps->SupportNonVGA = TRUE; - pDriverCaps->SupportSmoothRotation = TRUE; - - return STATUS_SUCCESS; - } - - case DXGKQAITYPE_DISPLAY_DRIVERCAPS_EXTENSION: - { - DXGK_DISPLAY_DRIVERCAPS_EXTENSION* pDriverDisplayCaps; - - if (pQueryAdapterInfo->OutputDataSize < sizeof(*pDriverDisplayCaps)) - { - BDD_LOG_ERROR2("pQueryAdapterInfo->OutputDataSize (0x%I64x) is smaller than sizeof(DXGK_DISPLAY_DRIVERCAPS_EXTENSION) (0x%I64x)", - pQueryAdapterInfo->OutputDataSize, - sizeof(DXGK_DISPLAY_DRIVERCAPS_EXTENSION)); - - return STATUS_INVALID_PARAMETER; - } - - pDriverDisplayCaps = (DXGK_DISPLAY_DRIVERCAPS_EXTENSION*)pQueryAdapterInfo->pOutputData; - - // Reset all caps values - RtlZeroMemory(pDriverDisplayCaps, pQueryAdapterInfo->OutputDataSize); - - // We claim to support virtual display mode. - pDriverDisplayCaps->VirtualModeSupport = 1; - - return STATUS_SUCCESS; - } - - default: - { - // BDD does not need to support any other adapter information types - BDD_LOG_WARNING1("Unknown QueryAdapterInfo Type (0x%I64x) requested", pQueryAdapterInfo->Type); - return STATUS_NOT_SUPPORTED; - } - } -} - - -NTSTATUS BASIC_DISPLAY_DRIVER::CheckHardware() -{ - PAGED_CODE(); - - NTSTATUS Status; - ULONG VendorID; - ULONG DeviceID; - -// TODO: If developing a driver for PCI based hardware, then use the second method to retrieve Vendor/Device IDs. -// If developing for non-PCI based hardware (i.e. ACPI based hardware), use the first method to retrieve the IDs. -#if 1 // ACPI-based device - - // Get the Vendor & Device IDs on non-PCI system - ACPI_EVAL_INPUT_BUFFER_COMPLEX AcpiInputBuffer = {0}; - AcpiInputBuffer.Signature = ACPI_EVAL_INPUT_BUFFER_COMPLEX_SIGNATURE; - AcpiInputBuffer.MethodNameAsUlong = ACPI_METHOD_HARDWARE_ID; - AcpiInputBuffer.Size = 0; - AcpiInputBuffer.ArgumentCount = 0; - - BYTE OutputBuffer[sizeof(ACPI_EVAL_OUTPUT_BUFFER) + 0x10]; - RtlZeroMemory(OutputBuffer, sizeof(OutputBuffer)); - ACPI_EVAL_OUTPUT_BUFFER* pAcpiOutputBuffer = reinterpret_cast(&OutputBuffer); - - Status = m_DxgkInterface.DxgkCbEvalAcpiMethod(m_DxgkInterface.DeviceHandle, - DISPLAY_ADAPTER_HW_ID, - &AcpiInputBuffer, - sizeof(AcpiInputBuffer), - pAcpiOutputBuffer, - sizeof(OutputBuffer)); - if (!NT_SUCCESS(Status)) - { - BDD_LOG_ERROR1("DxgkCbReadDeviceSpace failed to get hardware IDs with status 0x%I64x", Status); - return Status; - } - - VendorID = ((ULONG*)(pAcpiOutputBuffer->Argument[0].Data))[0]; - DeviceID = ((ULONG*)(pAcpiOutputBuffer->Argument[0].Data))[1]; - -#else // PCI-based device - - // Get the Vendor & Device IDs on PCI system - PCI_COMMON_HEADER Header = {0}; - ULONG BytesRead; - - Status = m_DxgkInterface.DxgkCbReadDeviceSpace(m_DxgkInterface.DeviceHandle, - DXGK_WHICHSPACE_CONFIG, - &Header, - 0, - sizeof(Header), - &BytesRead); - - if (!NT_SUCCESS(Status)) - { - BDD_LOG_ERROR1("DxgkCbReadDeviceSpace failed with status 0x%I64x", Status); - return Status; - } - - VendorID = Header.VendorID; - DeviceID = Header.DeviceID; - -#endif - - // TODO: Replace 0x1414 with your Vendor ID - if (VendorID == 0x1414) - { - switch (DeviceID) - { - // TODO: Replace the case statements below with the Device IDs supported by this driver - case 0x0000: - case 0xFFFF: return STATUS_SUCCESS; - } - } - - return STATUS_GRAPHICS_DRIVER_MISMATCH; -} - -// Even though Sample Basic Display Driver does not support hardware cursors, and reports such -// in QueryAdapterInfo. This function can still be called to set the pointer to not visible -NTSTATUS BASIC_DISPLAY_DRIVER::SetPointerPosition(_In_ CONST DXGKARG_SETPOINTERPOSITION* pSetPointerPosition) -{ - PAGED_CODE(); - - BDD_ASSERT(pSetPointerPosition != NULL); - BDD_ASSERT(pSetPointerPosition->VidPnSourceId < MAX_VIEWS); - - if (!(pSetPointerPosition->Flags.Visible)) - { - return STATUS_SUCCESS; - } - else - { - BDD_LOG_ASSERTION0("SetPointerPosition should never be called to set the pointer to visible since BDD doesn't support hardware cursors."); - return STATUS_UNSUCCESSFUL; - } -} - -// Basic Sample Display Driver does not support hardware cursors, and reports such -// in QueryAdapterInfo. Therefore this function should never be called. -NTSTATUS BASIC_DISPLAY_DRIVER::SetPointerShape(_In_ CONST DXGKARG_SETPOINTERSHAPE* pSetPointerShape) -{ - PAGED_CODE(); - - BDD_ASSERT(pSetPointerShape != NULL); - BDD_LOG_ASSERTION0("SetPointerShape should never be called since BDD doesn't support hardware cursors."); - - return STATUS_NOT_IMPLEMENTED; -} - - -NTSTATUS BASIC_DISPLAY_DRIVER::PresentDisplayOnly(_In_ CONST DXGKARG_PRESENT_DISPLAYONLY* pPresentDisplayOnly) -{ - PAGED_CODE(); - - BDD_ASSERT(pPresentDisplayOnly != NULL); - BDD_ASSERT(pPresentDisplayOnly->VidPnSourceId < MAX_VIEWS); - - if (pPresentDisplayOnly->BytesPerPixel < MIN_BYTES_PER_PIXEL_REPORTED) - { - // Only >=32bpp modes are reported, therefore this Present should never pass anything less than 4 bytes per pixel - BDD_LOG_ERROR1("pPresentDisplayOnly->BytesPerPixel is 0x%I64x, which is lower than the allowed.", pPresentDisplayOnly->BytesPerPixel); - return STATUS_INVALID_PARAMETER; - } - - // If it is in monitor off state or source is not supposed to be visible, don't present anything to the screen - if ((m_MonitorPowerState > PowerDeviceD0) || - (m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].Flags.SourceNotVisible)) - { - return STATUS_SUCCESS; - } - - // Present is only valid if the target is actively connected to this source - if (m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].Flags.FrameBufferIsActive) - { - - // If actual pixels are coming through, will need to completely zero out physical address next time in BlackOutScreen - m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].ZeroedOutStart.QuadPart = 0; - m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].ZeroedOutEnd.QuadPart = 0; - - - D3DKMDT_VIDPN_PRESENT_PATH_ROTATION RotationNeededByFb = pPresentDisplayOnly->Flags.Rotate ? - m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].Rotation : - D3DKMDT_VPPR_IDENTITY; - BYTE* pDst = (BYTE*)m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].FrameBuffer.Ptr; - UINT DstBitPerPixel = BPPFromPixelFormat(m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].DispInfo.ColorFormat); - if (m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].Scaling == D3DKMDT_VPPS_CENTERED) - { - UINT CenterShift = (m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].DispInfo.Height - - m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].SrcModeHeight)*m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].DispInfo.Pitch; - CenterShift += (m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].DispInfo.Width - - m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].SrcModeWidth)*DstBitPerPixel/8; - pDst += (int)CenterShift/2; - } - return m_HardwareBlt[pPresentDisplayOnly->VidPnSourceId].ExecutePresentDisplayOnly(pDst, - DstBitPerPixel, - (BYTE*)pPresentDisplayOnly->pSource, - pPresentDisplayOnly->BytesPerPixel, - pPresentDisplayOnly->Pitch, - pPresentDisplayOnly->NumMoves, - pPresentDisplayOnly->pMoves, - pPresentDisplayOnly->NumDirtyRects, - pPresentDisplayOnly->pDirtyRect, - RotationNeededByFb); - } - - return STATUS_SUCCESS; -} - -NTSTATUS BASIC_DISPLAY_DRIVER::StopDeviceAndReleasePostDisplayOwnership(_In_ D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId, - _Out_ DXGK_DISPLAY_INFORMATION* pDisplayInfo) -{ - PAGED_CODE(); - - BDD_ASSERT(TargetId < MAX_CHILDREN); - - - D3DDDI_VIDEO_PRESENT_SOURCE_ID SourceId = FindSourceForTarget(TargetId, TRUE); - - // In case BDD is the next driver to run, the monitor should not be off, since - // this could cause the BIOS to hang when the EDID is retrieved on Start. - if (m_MonitorPowerState > PowerDeviceD0) - { - SetPowerState(TargetId, PowerDeviceD0, PowerActionNone); - } - - // The driver has to black out the display and ensure it is visible when releasing ownership - BlackOutScreen(SourceId); - - *pDisplayInfo = m_CurrentModes[SourceId].DispInfo; - - return StopDevice(); -} - -NTSTATUS BASIC_DISPLAY_DRIVER::QueryVidPnHWCapability(_Inout_ DXGKARG_QUERYVIDPNHWCAPABILITY* pVidPnHWCaps) -{ - PAGED_CODE(); - - BDD_ASSERT(pVidPnHWCaps != NULL); - BDD_ASSERT(pVidPnHWCaps->SourceId < MAX_VIEWS); - BDD_ASSERT(pVidPnHWCaps->TargetId < MAX_CHILDREN); - - pVidPnHWCaps->VidPnHWCaps.DriverRotation = 1; // BDD does rotation in software - pVidPnHWCaps->VidPnHWCaps.DriverScaling = 0; // BDD does not support scaling - pVidPnHWCaps->VidPnHWCaps.DriverCloning = 0; // BDD does not support clone - pVidPnHWCaps->VidPnHWCaps.DriverColorConvert = 1; // BDD does color conversions in software - pVidPnHWCaps->VidPnHWCaps.DriverLinkedAdapaterOutput = 0; // BDD does not support linked adapters - pVidPnHWCaps->VidPnHWCaps.DriverRemoteDisplay = 0; // BDD does not support remote displays - - return STATUS_SUCCESS; -} - -NTSTATUS BASIC_DISPLAY_DRIVER::GetEdid(D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId) -{ - PAGED_CODE(); - - BDD_ASSERT_CHK(!m_Flags.EDID_Attempted); - - NTSTATUS Status = STATUS_SUCCESS; - RtlZeroMemory(m_EDIDs[TargetId], sizeof(m_EDIDs[TargetId])); - - - m_Flags.EDID_Attempted = TRUE; - - return Status; -} - - -VOID BASIC_DISPLAY_DRIVER::BlackOutScreen(D3DDDI_VIDEO_PRESENT_SOURCE_ID SourceId) -{ - PAGED_CODE(); - - - UINT ScreenHeight = m_CurrentModes[SourceId].DispInfo.Height; - UINT ScreenPitch = m_CurrentModes[SourceId].DispInfo.Pitch; - - PHYSICAL_ADDRESS NewPhysAddrStart = m_CurrentModes[SourceId].DispInfo.PhysicAddress; - PHYSICAL_ADDRESS NewPhysAddrEnd; - NewPhysAddrEnd.QuadPart = NewPhysAddrStart.QuadPart + (ScreenHeight * ScreenPitch); - - if (m_CurrentModes[SourceId].Flags.FrameBufferIsActive) - { - BYTE* MappedAddr = reinterpret_cast(m_CurrentModes[SourceId].FrameBuffer.Ptr); - - // Zero any memory at the start that hasn't been zeroed recently - if (NewPhysAddrStart.QuadPart < m_CurrentModes[SourceId].ZeroedOutStart.QuadPart) - { - if (NewPhysAddrEnd.QuadPart < m_CurrentModes[SourceId].ZeroedOutStart.QuadPart) - { - // No overlap - RtlZeroMemory(MappedAddr, ScreenHeight * ScreenPitch); - } - else - { - RtlZeroMemory(MappedAddr, (UINT)(m_CurrentModes[SourceId].ZeroedOutStart.QuadPart - NewPhysAddrStart.QuadPart)); - } - } - - // Zero any memory at the end that hasn't been zeroed recently - if (NewPhysAddrEnd.QuadPart > m_CurrentModes[SourceId].ZeroedOutEnd.QuadPart) - { - if (NewPhysAddrStart.QuadPart > m_CurrentModes[SourceId].ZeroedOutEnd.QuadPart) - { - // No overlap - // NOTE: When actual pixels were the most recent thing drawn, ZeroedOutStart & ZeroedOutEnd will both be 0 - // and this is the path that will be used to black out the current screen. - RtlZeroMemory(MappedAddr, ScreenHeight * ScreenPitch); - } - else - { - RtlZeroMemory(MappedAddr, (UINT)(NewPhysAddrEnd.QuadPart - m_CurrentModes[SourceId].ZeroedOutEnd.QuadPart)); - } - } - } - - m_CurrentModes[SourceId].ZeroedOutStart.QuadPart = NewPhysAddrStart.QuadPart; - m_CurrentModes[SourceId].ZeroedOutEnd.QuadPart = NewPhysAddrEnd.QuadPart; - -} - -NTSTATUS BASIC_DISPLAY_DRIVER::WriteHWInfoStr(_In_ HANDLE DevInstRegKeyHandle, _In_ PCWSTR pszwValueName, _In_ PCSTR pszValue) -{ - PAGED_CODE(); - - NTSTATUS Status; - ANSI_STRING AnsiStrValue; - UNICODE_STRING UnicodeStrValue; - UNICODE_STRING UnicodeStrValueName; - - // ZwSetValueKey wants the ValueName as a UNICODE_STRING - RtlInitUnicodeString(&UnicodeStrValueName, pszwValueName); - - // REG_SZ is for WCHARs, there is no equivalent for CHARs - // Use the ansi/unicode conversion functions to get from PSTR to PWSTR - RtlInitAnsiString(&AnsiStrValue, pszValue); - Status = RtlAnsiStringToUnicodeString(&UnicodeStrValue, &AnsiStrValue, TRUE); - if (!NT_SUCCESS(Status)) - { - BDD_LOG_ERROR1("RtlAnsiStringToUnicodeString failed with Status: 0x%I64x", Status); - return Status; - } - - // Write the value to the registry - Status = ZwSetValueKey(DevInstRegKeyHandle, - &UnicodeStrValueName, - 0, - REG_SZ, - UnicodeStrValue.Buffer, - UnicodeStrValue.MaximumLength); - - // Free the earlier allocated unicode string - RtlFreeUnicodeString(&UnicodeStrValue); - - if (!NT_SUCCESS(Status)) - { - BDD_LOG_ERROR1("ZwSetValueKey failed with Status: 0x%I64x", Status); - } - - return Status; -} - -NTSTATUS BASIC_DISPLAY_DRIVER::RegisterHWInfo() -{ - PAGED_CODE(); - - NTSTATUS Status; - - // TODO: Replace these strings with proper information - PCSTR StrHWInfoChipType = "Replace with the chip name"; - PCSTR StrHWInfoDacType = "Replace with the DAC name or identifier (ID)"; - PCSTR StrHWInfoAdapterString = "Replace with the name of the adapter"; - PCSTR StrHWInfoBiosString = "Replace with information about the BIOS"; - - HANDLE DevInstRegKeyHandle; - Status = IoOpenDeviceRegistryKey(m_pPhysicalDevice, PLUGPLAY_REGKEY_DRIVER, KEY_SET_VALUE, &DevInstRegKeyHandle); - if (!NT_SUCCESS(Status)) - { - BDD_LOG_ERROR2("IoOpenDeviceRegistryKey failed for PDO: 0x%I64x, Status: 0x%I64x", m_pPhysicalDevice, Status); - return Status; - } - - Status = WriteHWInfoStr(DevInstRegKeyHandle, L"HardwareInformation.ChipType", StrHWInfoChipType); - if (!NT_SUCCESS(Status)) - { - return Status; - } - - Status = WriteHWInfoStr(DevInstRegKeyHandle, L"HardwareInformation.DacType", StrHWInfoDacType); - if (!NT_SUCCESS(Status)) - { - return Status; - } - - Status = WriteHWInfoStr(DevInstRegKeyHandle, L"HardwareInformation.AdapterString", StrHWInfoAdapterString); - if (!NT_SUCCESS(Status)) - { - return Status; - } - - Status = WriteHWInfoStr(DevInstRegKeyHandle, L"HardwareInformation.BiosString", StrHWInfoBiosString); - if (!NT_SUCCESS(Status)) - { - return Status; - } - - // MemorySize is a ULONG, unlike the others which are all strings - UNICODE_STRING ValueNameMemorySize; - RtlInitUnicodeString(&ValueNameMemorySize, L"HardwareInformation.MemorySize"); - DWORD MemorySize = 0; // BDD has no access to video memory - Status = ZwSetValueKey(DevInstRegKeyHandle, - &ValueNameMemorySize, - 0, - REG_DWORD, - &MemorySize, - sizeof(MemorySize)); - if (!NT_SUCCESS(Status)) - { - BDD_LOG_ERROR1("ZwSetValueKey for MemorySize failed with Status: 0x%I64x", Status); - return Status; - } - - return Status; -} - -// -// Non-Paged Code -// -#pragma code_seg(push) -#pragma code_seg() -D3DDDI_VIDEO_PRESENT_SOURCE_ID BASIC_DISPLAY_DRIVER::FindSourceForTarget(D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId, BOOLEAN DefaultToZero) -{ - UNREFERENCED_PARAMETER(TargetId); - BDD_ASSERT_CHK(TargetId < MAX_CHILDREN); - - for (UINT SourceId = 0; SourceId < MAX_VIEWS; ++SourceId) - { - if (m_CurrentModes[SourceId].FrameBuffer.Ptr != NULL) - { - return SourceId; - } - } - - return DefaultToZero ? 0 : D3DDDI_ID_UNINITIALIZED; -} - -VOID BASIC_DISPLAY_DRIVER::DpcRoutine(VOID) -{ - m_DxgkInterface.DxgkCbNotifyDpc((HANDLE)m_DxgkInterface.DeviceHandle); -} - -BOOLEAN BASIC_DISPLAY_DRIVER::InterruptRoutine(_In_ ULONG MessageNumber) -{ - UNREFERENCED_PARAMETER(MessageNumber); - - // BDD cannot handle interrupts - return FALSE; -} - -VOID BASIC_DISPLAY_DRIVER::ResetDevice(VOID) -{ -} - -// Must be Non-Paged, as it sets up the display for a bugcheck -NTSTATUS BASIC_DISPLAY_DRIVER::SystemDisplayEnable(_In_ D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId, - _In_ PDXGKARG_SYSTEM_DISPLAY_ENABLE_FLAGS Flags, - _Out_ UINT* pWidth, - _Out_ UINT* pHeight, - _Out_ D3DDDIFORMAT* pColorFormat) -{ - UNREFERENCED_PARAMETER(Flags); - - m_SystemDisplaySourceId = D3DDDI_ID_UNINITIALIZED; - - BDD_ASSERT((TargetId < MAX_CHILDREN) || (TargetId == D3DDDI_ID_UNINITIALIZED)); - - // Find the frame buffer for displaying the bugcheck, if it was successfully mapped - if (TargetId == D3DDDI_ID_UNINITIALIZED) - { - for (UINT SourceIdx = 0; SourceIdx < MAX_VIEWS; ++SourceIdx) - { - if (m_CurrentModes[SourceIdx].FrameBuffer.Ptr != NULL) - { - m_SystemDisplaySourceId = SourceIdx; - break; - } - } - } - else - { - m_SystemDisplaySourceId = FindSourceForTarget(TargetId, FALSE); - } - - if (m_SystemDisplaySourceId == D3DDDI_ID_UNINITIALIZED) - { - { - return STATUS_UNSUCCESSFUL; - } - } - - if ((m_CurrentModes[m_SystemDisplaySourceId].Rotation == D3DKMDT_VPPR_ROTATE90) || - (m_CurrentModes[m_SystemDisplaySourceId].Rotation == D3DKMDT_VPPR_ROTATE270)) - { - *pHeight = m_CurrentModes[m_SystemDisplaySourceId].DispInfo.Width; - *pWidth = m_CurrentModes[m_SystemDisplaySourceId].DispInfo.Height; - } - else - { - *pWidth = m_CurrentModes[m_SystemDisplaySourceId].DispInfo.Width; - *pHeight = m_CurrentModes[m_SystemDisplaySourceId].DispInfo.Height; - } - - *pColorFormat = m_CurrentModes[m_SystemDisplaySourceId].DispInfo.ColorFormat; - - - return STATUS_SUCCESS; -} - -// Must be Non-Paged, as it is called to display the bugcheck screen -VOID BASIC_DISPLAY_DRIVER::SystemDisplayWrite(_In_reads_bytes_(SourceHeight * SourceStride) VOID* pSource, - _In_ UINT SourceWidth, - _In_ UINT SourceHeight, - _In_ UINT SourceStride, - _In_ INT PositionX, - _In_ INT PositionY) -{ - - // Rect will be Offset by PositionX/Y in the src to reset it back to 0 - RECT Rect; - Rect.left = PositionX; - Rect.top = PositionY; - Rect.right = Rect.left + SourceWidth; - Rect.bottom = Rect.top + SourceHeight; - - // Set up destination blt info - BLT_INFO DstBltInfo; - DstBltInfo.pBits = m_CurrentModes[m_SystemDisplaySourceId].FrameBuffer.Ptr; - DstBltInfo.Pitch = m_CurrentModes[m_SystemDisplaySourceId].DispInfo.Pitch; - DstBltInfo.BitsPerPel = BPPFromPixelFormat(m_CurrentModes[m_SystemDisplaySourceId].DispInfo.ColorFormat); - DstBltInfo.Offset.x = 0; - DstBltInfo.Offset.y = 0; - DstBltInfo.Rotation = m_CurrentModes[m_SystemDisplaySourceId].Rotation; - DstBltInfo.Width = m_CurrentModes[m_SystemDisplaySourceId].DispInfo.Width; - DstBltInfo.Height = m_CurrentModes[m_SystemDisplaySourceId].DispInfo.Height; - - // Set up source blt info - BLT_INFO SrcBltInfo; - SrcBltInfo.pBits = pSource; - SrcBltInfo.Pitch = SourceStride; - SrcBltInfo.BitsPerPel = 32; - - SrcBltInfo.Offset.x = -PositionX; - SrcBltInfo.Offset.y = -PositionY; - SrcBltInfo.Rotation = D3DKMDT_VPPR_IDENTITY; - SrcBltInfo.Width = SourceWidth; - SrcBltInfo.Height = SourceHeight; - - BltBits(&DstBltInfo, - &SrcBltInfo, - 1, // NumRects - &Rect); -} - -#pragma code_seg(pop) // End Non-Paged Code - diff --git a/video/KMDOD/bdd.hxx b/video/KMDOD/bdd.hxx deleted file mode 100644 index 68d435ba..00000000 --- a/video/KMDOD/bdd.hxx +++ /dev/null @@ -1,649 +0,0 @@ -/******************************Module*Header*******************************\ -* Module Name: BDD.hxx -* -* Basic Display Driver header file -* -* -* Copyright (c) 2010 Microsoft Corporation -\**************************************************************************/ - -#ifndef _BDD_HXX_ -#define _BDD_HXX_ - -extern "C" -{ - #define __CPLUSPLUS - - // Standard C-runtime headers - #include - #include - #include - #include - #include - - #include - - // NTOS headers - #include - - #ifndef FAR - #define FAR - #endif - - // Windows headers - #include - #include - - // Windows GDI headers - #include - - // Windows DDI headers - #include - #include - - #include - #include - - #include - #include - - #include -}; - -#define EDID_V1_BLOCK_SIZE 128 - -#include "BDD_ErrorLog.hxx" - -#define MIN_WIDTH 640 -#define MIN_HEIGHT 480 -#define MIN_BITS_PER_PIXEL_ALLOWED 8 -#define MIN_BYTES_PER_PIXEL_REPORTED 4 - -#define DEFAULT_WIDTH 1024 -#define DEFAULT_HEIGHT 768 - -#define MAX_INVALID_INHERITED_WIDTH 1024 -#define MAX_INVALID_INHERITED_HEIGHT 768 - -#define BITS_PER_BYTE 8 - -typedef struct _BLT_INFO -{ - PVOID pBits; - UINT Pitch; - UINT BitsPerPel; - POINT Offset; // To unrotated top-left of dirty rects - D3DKMDT_VIDPN_PRESENT_PATH_ROTATION Rotation; - UINT Width; // For the unrotated image - UINT Height; // For the unrotated image -} BLT_INFO; - -#define MAX_CHILDREN 1 -#define MAX_VIEWS 1 - -typedef struct _BDD_FLAGS -{ - UINT DriverStarted : 1; // ( 1) 1 after StartDevice and 0 after StopDevice - UINT EDID_Retrieved : 1; // ( 2) EDID was successfully retrieved - UINT EDID_ValidChecksum : 1; // ( 3) Retrieved EDID has a valid checksum - UINT EDID_ValidHeader : 1; // ( 4) Retrieved EDID has a valid header - UINT EDID_Attempted : 1; // ( 5) 1 if an attempt was made to retrieve the EDID, successful or not - - // IMPORTANT: All new flags must be added to just before _LastFlag (i.e. right above this comment), this allows different versions of diagnostics to still be useful. - UINT _LastFlag : 1; // ( 6) Always set to 1, is used to ensure that diagnostic version matches binary version - UINT Unused : 26; -} BDD_FLAGS; - -// Represents the current mode, may not always be set (i.e. frame buffer mapped) if representing the mode passed in on single mode setups. -typedef struct _CURRENT_BDD_MODE -{ - // The source mode currently set for HW Framebuffer - // For sample driver this info filled in StartDevice by the OS and never changed. - DXGK_DISPLAY_INFORMATION DispInfo; - - // The rotation of the current mode. Rotation is performed in software during Present call - D3DKMDT_VIDPN_PRESENT_PATH_ROTATION Rotation; - - D3DKMDT_VIDPN_PRESENT_PATH_SCALING Scaling; - // This mode might be different from one which are supported for HW frame buffer - // Scaling/displasment might be needed (if supported) - UINT SrcModeWidth; - UINT SrcModeHeight; - - // Various boolean flags the struct uses - struct _CURRENT_BDD_MODE_FLAGS - { - UINT SourceNotVisible : 1; // 0 if source is visible - UINT FullscreenPresent : 1; // 0 if should use dirty rects for present - UINT FrameBufferIsActive : 1; // 0 if not currently active (i.e. target not connected to source) - UINT DoNotMapOrUnmap : 1; // 1 if the FrameBuffer should not be (un)mapped during normal execution - UINT IsInternal : 1; // 1 if it was determined (i.e. through ACPI) that an internal panel is being driven - UINT Unused : 27; - } Flags; - - // The start and end of physical memory known to be all zeroes. Used to optimize the BlackOutScreen function to not write - // zeroes to memory already known to be zero. (Physical address is located in DispInfo) - PHYSICAL_ADDRESS ZeroedOutStart; - PHYSICAL_ADDRESS ZeroedOutEnd; - - // Linear frame buffer pointer - // A union with a ULONG64 is used here to ensure this struct looks the same on 32bit and 64bit builds - // since the size of a VOID* changes depending on the build. - union - { - VOID* Ptr; - ULONG64 Force8Bytes; - } FrameBuffer; -} CURRENT_BDD_MODE; - -class BASIC_DISPLAY_DRIVER; - -class BDD_HWBLT -{ -public: - D3DDDI_VIDEO_PRESENT_SOURCE_ID m_SourceId; - BASIC_DISPLAY_DRIVER* m_DevExt; - BOOLEAN m_SynchExecution; - HANDLE m_hPresentWorkerThread; - PVOID m_pPresentWorkerThread; - - // Events to contol thread execution - KEVENT m_hThreadStartupEvent; - KEVENT m_hThreadSuspendEvent; - - BDD_HWBLT(); - - ~BDD_HWBLT(); - - void Initialize(_In_ BASIC_DISPLAY_DRIVER* DevExt, _In_ UINT IdSrc) { m_DevExt = DevExt; m_SourceId = IdSrc; } - void SetPresentWorkerThreadInfo(HANDLE hWorkerThread); - NTSTATUS ExecutePresentDisplayOnly(_In_ BYTE* DstAddr, - _In_ UINT DstBitPerPixel, - _In_ BYTE* SrcAddr, - _In_ UINT SrcBytesPerPixel, - _In_ LONG SrcPitch, - _In_ ULONG NumMoves, - _In_ D3DKMT_MOVE_RECT* pMoves, - _In_ ULONG NumDirtyRects, - _In_ RECT* pDirtyRect, - _In_ D3DKMDT_VIDPN_PRESENT_PATH_ROTATION Rotation); - -}; - -class BASIC_DISPLAY_DRIVER -{ -private: - DEVICE_OBJECT* m_pPhysicalDevice; - DXGKRNL_INTERFACE m_DxgkInterface; - - // Information passed in by StartDevice DDI - DXGK_START_INFO m_StartInfo; - - - // Array of EDIDs, currently only supporting base block, hence EDID_V1_BLOCK_SIZE for size of each EDID - BYTE m_EDIDs[MAX_CHILDREN][EDID_V1_BLOCK_SIZE]; - - CURRENT_BDD_MODE m_CurrentModes[MAX_VIEWS]; - - - BDD_HWBLT m_HardwareBlt[MAX_VIEWS]; - - // Current monitorpower state (this needs to be changed if MAX_CHILDREN != 1) - DEVICE_POWER_STATE m_MonitorPowerState; - - // Current adapter power state - DEVICE_POWER_STATE m_AdapterPowerState; - - // Source ID to be used by SystemDisplay functions - D3DDDI_VIDEO_PRESENT_SOURCE_ID m_SystemDisplaySourceId; - - // Various boolean flags the class uses - BDD_FLAGS m_Flags; - - // Device information - DXGK_DEVICE_INFO m_DeviceInfo; - -public: - BASIC_DISPLAY_DRIVER(_In_ DEVICE_OBJECT* pPhysicalDeviceObject); - ~BASIC_DISPLAY_DRIVER(); - -#pragma code_seg(push) -#pragma code_seg() - BOOLEAN IsDriverActive() const - { - return m_Flags.DriverStarted; - } -#pragma code_seg(pop) - - NTSTATUS StartDevice(_In_ DXGK_START_INFO* pDxgkStartInfo, - _In_ DXGKRNL_INTERFACE* pDxgkInterface, - _Out_ ULONG* pNumberOfViews, - _Out_ ULONG* pNumberOfChildren); - - NTSTATUS StopDevice(VOID); - - // Must be Non-Paged - VOID ResetDevice(VOID); - - - const CURRENT_BDD_MODE* GetCurrentMode(UINT SourceId) const - { - return (SourceId < MAX_VIEWS)?&m_CurrentModes[SourceId]:NULL; - } - const DXGKRNL_INTERFACE* GetDxgkInterface() const { return &m_DxgkInterface;} - - // Not implemented since no IOCTLs currently handled. - NTSTATUS DispatchIoRequest(_In_ ULONG VidPnSourceId, - _In_ VIDEO_REQUEST_PACKET* pVideoRequestPacket); - - // Used to either turn off/on monitor (if possible), or mark that system is going into hibernate - NTSTATUS SetPowerState(_In_ ULONG HardwareUid, - _In_ DEVICE_POWER_STATE DevicePowerState, - _In_ POWER_ACTION ActionType); - - // Report back child capabilities - NTSTATUS QueryChildRelations(_Out_writes_bytes_(ChildRelationsSize) DXGK_CHILD_DESCRIPTOR* pChildRelations, - _In_ ULONG ChildRelationsSize); - - NTSTATUS QueryChildStatus(_Inout_ DXGK_CHILD_STATUS* pChildStatus, - _In_ BOOLEAN NonDestructiveOnly); - - // Return EDID if previously retrieved - NTSTATUS QueryDeviceDescriptor(_In_ ULONG ChildUid, - _Inout_ DXGK_DEVICE_DESCRIPTOR* pDeviceDescriptor); - - // Must be Non-Paged - // BDD doesn't have interrupts, so just returns false - BOOLEAN InterruptRoutine(_In_ ULONG MessageNumber); - - VOID DpcRoutine(VOID); - - // Return DriverCaps, doesn't support other queries though - NTSTATUS QueryAdapterInfo(_In_ CONST DXGKARG_QUERYADAPTERINFO* pQueryAdapterInfo); - - NTSTATUS SetPointerPosition(_In_ CONST DXGKARG_SETPOINTERPOSITION* pSetPointerPosition); - - NTSTATUS SetPointerShape(_In_ CONST DXGKARG_SETPOINTERSHAPE* pSetPointerShape); - - NTSTATUS PresentDisplayOnly(_In_ CONST DXGKARG_PRESENT_DISPLAYONLY* pPresentDisplayOnly); - - NTSTATUS IsSupportedVidPn(_Inout_ DXGKARG_ISSUPPORTEDVIDPN* pIsSupportedVidPn); - - NTSTATUS RecommendFunctionalVidPn(_In_ CONST DXGKARG_RECOMMENDFUNCTIONALVIDPN* CONST pRecommendFunctionalVidPn); - - NTSTATUS RecommendVidPnTopology(_In_ CONST DXGKARG_RECOMMENDVIDPNTOPOLOGY* CONST pRecommendVidPnTopology); - - NTSTATUS RecommendMonitorModes(_In_ CONST DXGKARG_RECOMMENDMONITORMODES* CONST pRecommendMonitorModes); - - NTSTATUS EnumVidPnCofuncModality(_In_ CONST DXGKARG_ENUMVIDPNCOFUNCMODALITY* CONST pEnumCofuncModality); - - NTSTATUS SetVidPnSourceVisibility(_In_ CONST DXGKARG_SETVIDPNSOURCEVISIBILITY* pSetVidPnSourceVisibility); - - NTSTATUS CommitVidPn(_In_ CONST DXGKARG_COMMITVIDPN* CONST pCommitVidPn); - - NTSTATUS UpdateActiveVidPnPresentPath(_In_ CONST DXGKARG_UPDATEACTIVEVIDPNPRESENTPATH* CONST pUpdateActiveVidPnPresentPath); - - NTSTATUS QueryVidPnHWCapability(_Inout_ DXGKARG_QUERYVIDPNHWCAPABILITY* pVidPnHWCaps); - - // Part of PnPStop (PnP instance only), returns current mode information (which will be passed to fallback instance by dxgkrnl) - NTSTATUS StopDeviceAndReleasePostDisplayOwnership(_In_ D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId, - _Out_ DXGK_DISPLAY_INFORMATION* pDisplayInfo); - - // Must be Non-Paged - // Call to initialize as part of bugcheck - NTSTATUS SystemDisplayEnable(_In_ D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId, - _In_ PDXGKARG_SYSTEM_DISPLAY_ENABLE_FLAGS Flags, - _Out_ UINT* pWidth, - _Out_ UINT* pHeight, - _Out_ D3DDDIFORMAT* pColorFormat); - - // Must be Non-Paged - // Write out pixels as part of bugcheck - VOID SystemDisplayWrite(_In_reads_bytes_(SourceHeight * SourceStride) VOID* pSource, - _In_ UINT SourceWidth, - _In_ UINT SourceHeight, - _In_ UINT SourceStride, - _In_ INT PositionX, - _In_ INT PositionY); - - -private: - VOID CleanUp(); - - NTSTATUS CommonStart(); - - NTSTATUS GetEdid(D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId); - - - // Given pixel format, give back the bits per pixel. Only supports pixel formats expected by BDD - // (i.e. the ones found below in PixelFormatFromBPP or that may come in from FallbackStart) - // This is because these two functions combine to allow BDD to store the bpp of a VBE mode in the - // ColorFormat field of a DispInfo - UINT BPPFromPixelFormat(D3DDDIFORMAT Format) const - { - switch (Format) - { - case D3DDDIFMT_UNKNOWN: return 0; - case D3DDDIFMT_P8: return 8; - case D3DDDIFMT_R5G6B5: return 16; - case D3DDDIFMT_R8G8B8: return 24; - case D3DDDIFMT_X8R8G8B8: // fall through - case D3DDDIFMT_A8R8G8B8: return 32; - default: BDD_LOG_ASSERTION1("Unknown D3DDDIFORMAT 0x%I64x", Format); return 0; - } - } - - // Given bits per pixel, return the pixel format at the same bpp - D3DDDIFORMAT PixelFormatFromBPP(UINT BPP) const - { - switch (BPP) - { - case 8: return D3DDDIFMT_P8; - case 16: return D3DDDIFMT_R5G6B5; - case 24: return D3DDDIFMT_R8G8B8; - case 32: return D3DDDIFMT_X8R8G8B8; - default: BDD_LOG_ASSERTION1("A bit per pixel of 0x%I64x is not supported.", BPP); return D3DDDIFMT_UNKNOWN; - } - } - - // These two functions make checks on the values of some of the fields of their respective structures to ensure - // that the specified fields are supported by BDD, i.e. gamma ramp must be D3DDDI_GAMMARAMP_DEFAULT - NTSTATUS IsVidPnPathFieldsValid(CONST D3DKMDT_VIDPN_PRESENT_PATH* pPath) const; - NTSTATUS IsVidPnSourceModeFieldsValid(CONST D3DKMDT_VIDPN_SOURCE_MODE* pSourceMode) const; - - VOID BlackOutScreen(D3DDDI_VIDEO_PRESENT_SOURCE_ID SourceId); - - // Returns the index into gBddBiosData.BddModes of the VBE mode that matches the given VidPnSourceMode. - // If such a mode cannot be found, returns a number outside of [0, gBddBiosData.CountBddModes) - UINT FindMatchingVBEMode(CONST D3DKMDT_VIDPN_SOURCE_MODE* pSourceMode) const; - - // Must be Non-Paged - // Returns the SourceId that has TargetId as a valid frame buffer or D3DDDI_ID_UNINITIALIZED if no such SourceId exists - D3DDDI_VIDEO_PRESENT_SOURCE_ID FindSourceForTarget(D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId, BOOLEAN DefaultToZero); - - // Set the given source mode on the given path - NTSTATUS SetSourceModeAndPath(CONST D3DKMDT_VIDPN_SOURCE_MODE* pSourceMode, - CONST D3DKMDT_VIDPN_PRESENT_PATH* pPath); - - - // Add the current mode to the given monitor source mode set - NTSTATUS AddSingleMonitorMode(_In_ CONST DXGKARG_RECOMMENDMONITORMODES* CONST pRecommendMonitorModes); - - - // Add the current mode to the given VidPn source mode set - NTSTATUS AddSingleSourceMode(_In_ CONST DXGK_VIDPNSOURCEMODESET_INTERFACE* pVidPnSourceModeSetInterface, - D3DKMDT_HVIDPNSOURCEMODESET hVidPnSourceModeSet, - D3DDDI_VIDEO_PRESENT_SOURCE_ID SourceId); - - // Add the current mode (or the matching to pinned source mode) to the give VidPn target mode set - NTSTATUS AddSingleTargetMode(_In_ CONST DXGK_VIDPNTARGETMODESET_INTERFACE* pVidPnTargetModeSetInterface, - D3DKMDT_HVIDPNTARGETMODESET hVidPnTargetModeSet, - _In_opt_ CONST D3DKMDT_VIDPN_SOURCE_MODE* pVidPnPinnedSourceModeInfo, - D3DDDI_VIDEO_PRESENT_SOURCE_ID SourceId); - - // Check that the hardware the driver is running on is hardware it is capable of driving. - NTSTATUS CheckHardware(); - - // Helper function for RegisterHWInfo - NTSTATUS WriteHWInfoStr(_In_ HANDLE DevInstRegKeyHandle, _In_ PCWSTR pszwValueName, _In_ PCSTR pszValue); - - // Set the information in the registry as described here: http://msdn.microsoft.com/en-us/library/windows/hardware/ff569240(v=vs.85).aspx - NTSTATUS RegisterHWInfo(); -}; - -// -// Blt functions -// - -// Must be Non-Paged -VOID BltBits( - BLT_INFO* pDst, - CONST BLT_INFO* pSrc, - UINT NumRects, - _In_reads_(NumRects) CONST RECT *pRects); - -// -// Driver Entry point -// - -extern "C" -DRIVER_INITIALIZE DriverEntry; - -// -// PnP DDIs -// - -VOID -BddDdiUnload(VOID); - -// If uncommenting ENABLE_DXGK_SAL in the sources file, all the below function prototypes should be updated to use -// the function typedef's from the header files. Additionally, annotations on the function definitions can be removed -// as they are inherited from the prototype definition here. As an example the entire 4-line prototype for BddDdiAddDevice -// is replaced by the single commented line below: -// DXGKDDI_ADD_DEVICE BddDdiAddDevice; -NTSTATUS -BddDdiAddDevice( - _In_ DEVICE_OBJECT* pPhysicalDeviceObject, - _Outptr_ PVOID* ppDeviceContext); - -NTSTATUS -BddDdiRemoveDevice( - _In_ VOID* pDeviceContext); - -NTSTATUS -BddDdiStartDevice( - _In_ VOID* pDeviceContext, - _In_ DXGK_START_INFO* pDxgkStartInfo, - _In_ DXGKRNL_INTERFACE* pDxgkInterface, - _Out_ ULONG* pNumberOfViews, - _Out_ ULONG* pNumberOfChildren); - -NTSTATUS -BddDdiStopDevice( - _In_ VOID* pDeviceContext); - -VOID -BddDdiResetDevice( - _In_ VOID* pDeviceContext); - - -NTSTATUS -BddDdiDispatchIoRequest( - _In_ VOID* pDeviceContext, - _In_ ULONG VidPnSourceId, - _In_ VIDEO_REQUEST_PACKET* pVideoRequestPacket); - -NTSTATUS -BddDdiSetPowerState( - _In_ VOID* pDeviceContext, - _In_ ULONG HardwareUid, - _In_ DEVICE_POWER_STATE DevicePowerState, - _In_ POWER_ACTION ActionType); - -NTSTATUS -BddDdiQueryChildRelations( - _In_ VOID* pDeviceContext, - _Out_writes_bytes_(ChildRelationsSize) DXGK_CHILD_DESCRIPTOR* pChildRelations, - _In_ ULONG ChildRelationsSize); - -NTSTATUS -BddDdiQueryChildStatus( - _In_ VOID* pDeviceContext, - _Inout_ DXGK_CHILD_STATUS* pChildStatus, - _In_ BOOLEAN NonDestructiveOnly); - -NTSTATUS -BddDdiQueryDeviceDescriptor( - _In_ VOID* pDeviceContext, - _In_ ULONG ChildUid, - _Inout_ DXGK_DEVICE_DESCRIPTOR* pDeviceDescriptor); - -// Must be Non-Paged -BOOLEAN -BddDdiInterruptRoutine( - _In_ VOID* pDeviceContext, - _In_ ULONG MessageNumber); - -VOID -BddDdiDpcRoutine( - _In_ VOID* pDeviceContext); - -// -// WDDM Display Only Driver DDIs -// - -NTSTATUS -APIENTRY -BddDdiQueryAdapterInfo( - _In_ CONST HANDLE hAdapter, - _In_ CONST DXGKARG_QUERYADAPTERINFO* pQueryAdapterInfo); - -NTSTATUS -APIENTRY -BddDdiSetPointerPosition( - _In_ CONST HANDLE hAdapter, - _In_ CONST DXGKARG_SETPOINTERPOSITION* pSetPointerPosition); - -NTSTATUS -APIENTRY -BddDdiSetPointerShape( - _In_ CONST HANDLE hAdapter, - _In_ CONST DXGKARG_SETPOINTERSHAPE* pSetPointerShape); - -NTSTATUS -APIENTRY -BddDdiPresentDisplayOnly( - _In_ CONST HANDLE hAdapter, - _In_ CONST DXGKARG_PRESENT_DISPLAYONLY* pPresentDisplayOnly); - -NTSTATUS -APIENTRY -BddDdiIsSupportedVidPn( - _In_ CONST HANDLE hAdapter, - _Inout_ DXGKARG_ISSUPPORTEDVIDPN* pIsSupportedVidPn); - -NTSTATUS -APIENTRY -BddDdiRecommendFunctionalVidPn( - _In_ CONST HANDLE hAdapter, - _In_ CONST DXGKARG_RECOMMENDFUNCTIONALVIDPN* CONST pRecommendFunctionalVidPn); - -NTSTATUS -APIENTRY -BddDdiRecommendVidPnTopology( - _In_ CONST HANDLE hAdapter, - _In_ CONST DXGKARG_RECOMMENDVIDPNTOPOLOGY* CONST pRecommendVidPnTopology); - -NTSTATUS -APIENTRY -BddDdiRecommendMonitorModes( - _In_ CONST HANDLE hAdapter, - _In_ CONST DXGKARG_RECOMMENDMONITORMODES* CONST pRecommendMonitorModes); - -NTSTATUS -APIENTRY -BddDdiEnumVidPnCofuncModality( - _In_ CONST HANDLE hAdapter, - _In_ CONST DXGKARG_ENUMVIDPNCOFUNCMODALITY* CONST pEnumCofuncModality); - -NTSTATUS -APIENTRY -BddDdiSetVidPnSourceVisibility( - _In_ CONST HANDLE hAdapter, - _In_ CONST DXGKARG_SETVIDPNSOURCEVISIBILITY* pSetVidPnSourceVisibility); - -NTSTATUS -APIENTRY -BddDdiCommitVidPn( - _In_ CONST HANDLE hAdapter, - _In_ CONST DXGKARG_COMMITVIDPN* CONST pCommitVidPn); - -NTSTATUS -APIENTRY -BddDdiUpdateActiveVidPnPresentPath( - _In_ CONST HANDLE hAdapter, - _In_ CONST DXGKARG_UPDATEACTIVEVIDPNPRESENTPATH* CONST pUpdateActiveVidPnPresentPath); - -NTSTATUS -APIENTRY -BddDdiQueryVidPnHWCapability( - _In_ CONST HANDLE hAdapter, - _Inout_ DXGKARG_QUERYVIDPNHWCAPABILITY* pVidPnHWCaps); - -NTSTATUS -APIENTRY -BddDdiStopDeviceAndReleasePostDisplayOwnership( - _In_ VOID* pDeviceContext, - _In_ D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId, - _Out_ DXGK_DISPLAY_INFORMATION* DisplayInfo); - -// Must be Non-Paged -NTSTATUS -APIENTRY -BddDdiSystemDisplayEnable( - _In_ VOID* pDeviceContext, - _In_ D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId, - _In_ PDXGKARG_SYSTEM_DISPLAY_ENABLE_FLAGS Flags, - _Out_ UINT* Width, - _Out_ UINT* Height, - _Out_ D3DDDIFORMAT* ColorFormat); - -// Must be Non-Paged -VOID -APIENTRY -BddDdiSystemDisplayWrite( - _In_ VOID* pDeviceContext, - _In_ VOID* Source, - _In_ UINT SourceWidth, - _In_ UINT SourceHeight, - _In_ UINT SourceStride, - _In_ UINT PositionX, - _In_ UINT PositionY); - -// -// Frame buffer map/unmap -// - -NTSTATUS -MapFrameBuffer( - _In_ PHYSICAL_ADDRESS PhysicalAddress, - _In_ ULONG Length, - _Outptr_result_bytebuffer_(Length) VOID** VirtualAddress); - -NTSTATUS -UnmapFrameBuffer( - _In_reads_bytes_(Length) VOID* VirtualAddress, - _In_ ULONG Length); - - -BOOLEAN -IsEdidHeaderValid(_In_reads_bytes_(EDID_V1_BLOCK_SIZE) const BYTE* pEdid); - -BOOLEAN -IsEdidChecksumValid(_In_reads_bytes_(EDID_V1_BLOCK_SIZE) const BYTE* pEdid); - -// -// Memory handling -// - -// Defaulting the value of PoolType means that any call to new Foo() -// will raise a compiler error for being ambiguous. This is to help keep -// any calls to allocate memory from accidentally NOT going through -// these functions. -_When_((PoolType & NonPagedPoolMustSucceed) != 0, - __drv_reportError("Must succeed pool allocations are forbidden. " - "Allocation failures cause a system crash")) -void* __cdecl operator new(size_t Size, POOL_TYPE PoolType = PagedPool); -_When_((PoolType & NonPagedPoolMustSucceed) != 0, - __drv_reportError("Must succeed pool allocations are forbidden. " - "Allocation failures cause a system crash")) -void* __cdecl operator new[](size_t Size, POOL_TYPE PoolType = PagedPool); -void __cdecl operator delete(void* pObject); -void __cdecl operator delete[](void* pObject); - -// Pool allocation tag for the Sample Display Driver. All allocations use this tag. -#define BDDTAG 'DDBS' - -#endif // _BDD_HXX_ - - diff --git a/video/KMDOD/bdd_ddi.cxx b/video/KMDOD/bdd_ddi.cxx deleted file mode 100644 index 5a53a3be..00000000 --- a/video/KMDOD/bdd_ddi.cxx +++ /dev/null @@ -1,579 +0,0 @@ -/******************************Module*Header*******************************\ -* Module Name: BDD_DDI.cxx -* -* Basic Display Driver DDI entry points redirects -* -* -* Copyright (c) 2010 Microsoft Corporation -\**************************************************************************/ - -#include "BDD.hxx" - - -#pragma code_seg(push) -#pragma code_seg("INIT") -// BEGIN: Init Code - -// -// Driver Entry point -// - -extern "C" -NTSTATUS -DriverEntry( - _In_ DRIVER_OBJECT* pDriverObject, - _In_ UNICODE_STRING* pRegistryPath) -{ - PAGED_CODE(); - - - // Initialize DDI function pointers and dxgkrnl - KMDDOD_INITIALIZATION_DATA InitialData = {0}; - - InitialData.Version = DXGKDDI_INTERFACE_VERSION; - - InitialData.DxgkDdiAddDevice = BddDdiAddDevice; - InitialData.DxgkDdiStartDevice = BddDdiStartDevice; - InitialData.DxgkDdiStopDevice = BddDdiStopDevice; - InitialData.DxgkDdiResetDevice = BddDdiResetDevice; - InitialData.DxgkDdiRemoveDevice = BddDdiRemoveDevice; - InitialData.DxgkDdiDispatchIoRequest = BddDdiDispatchIoRequest; - InitialData.DxgkDdiInterruptRoutine = BddDdiInterruptRoutine; - InitialData.DxgkDdiDpcRoutine = BddDdiDpcRoutine; - InitialData.DxgkDdiQueryChildRelations = BddDdiQueryChildRelations; - InitialData.DxgkDdiQueryChildStatus = BddDdiQueryChildStatus; - InitialData.DxgkDdiQueryDeviceDescriptor = BddDdiQueryDeviceDescriptor; - InitialData.DxgkDdiSetPowerState = BddDdiSetPowerState; - InitialData.DxgkDdiUnload = BddDdiUnload; - InitialData.DxgkDdiQueryAdapterInfo = BddDdiQueryAdapterInfo; - InitialData.DxgkDdiSetPointerPosition = BddDdiSetPointerPosition; - InitialData.DxgkDdiSetPointerShape = BddDdiSetPointerShape; - InitialData.DxgkDdiIsSupportedVidPn = BddDdiIsSupportedVidPn; - InitialData.DxgkDdiRecommendFunctionalVidPn = BddDdiRecommendFunctionalVidPn; - InitialData.DxgkDdiEnumVidPnCofuncModality = BddDdiEnumVidPnCofuncModality; - InitialData.DxgkDdiSetVidPnSourceVisibility = BddDdiSetVidPnSourceVisibility; - InitialData.DxgkDdiCommitVidPn = BddDdiCommitVidPn; - InitialData.DxgkDdiUpdateActiveVidPnPresentPath = BddDdiUpdateActiveVidPnPresentPath; - InitialData.DxgkDdiRecommendMonitorModes = BddDdiRecommendMonitorModes; - InitialData.DxgkDdiQueryVidPnHWCapability = BddDdiQueryVidPnHWCapability; - InitialData.DxgkDdiPresentDisplayOnly = BddDdiPresentDisplayOnly; - InitialData.DxgkDdiStopDeviceAndReleasePostDisplayOwnership = BddDdiStopDeviceAndReleasePostDisplayOwnership; - InitialData.DxgkDdiSystemDisplayEnable = BddDdiSystemDisplayEnable; - InitialData.DxgkDdiSystemDisplayWrite = BddDdiSystemDisplayWrite; - - NTSTATUS Status = DxgkInitializeDisplayOnlyDriver(pDriverObject, pRegistryPath, &InitialData); - if (!NT_SUCCESS(Status)) - { - BDD_LOG_ERROR1("DxgkInitializeDisplayOnlyDriver failed with Status: 0x%I64x", Status); - return Status; - } - - - return Status; -} -// END: Init Code -#pragma code_seg(pop) - -#pragma code_seg(push) -#pragma code_seg("PAGE") - -// -// PnP DDIs -// - -VOID -BddDdiUnload(VOID) -{ - PAGED_CODE(); -} - -NTSTATUS -BddDdiAddDevice( - _In_ DEVICE_OBJECT* pPhysicalDeviceObject, - _Outptr_ PVOID* ppDeviceContext) -{ - PAGED_CODE(); - - if ((pPhysicalDeviceObject == NULL) || - (ppDeviceContext == NULL)) - { - BDD_LOG_ERROR2("One of pPhysicalDeviceObject (0x%I64x), ppDeviceContext (0x%I64x) is NULL", - pPhysicalDeviceObject, ppDeviceContext); - return STATUS_INVALID_PARAMETER; - } - *ppDeviceContext = NULL; - - BASIC_DISPLAY_DRIVER* pBDD = new(NonPagedPoolNx) BASIC_DISPLAY_DRIVER(pPhysicalDeviceObject); - if (pBDD == NULL) - { - BDD_LOG_LOW_RESOURCE0("pBDD failed to be allocated"); - return STATUS_NO_MEMORY; - } - - *ppDeviceContext = pBDD; - - return STATUS_SUCCESS; -} - -NTSTATUS -BddDdiRemoveDevice( - _In_ VOID* pDeviceContext) -{ - PAGED_CODE(); - - BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast(pDeviceContext); - - if (pBDD) - { - delete pBDD; - pBDD = NULL; - } - - return STATUS_SUCCESS; -} - -NTSTATUS -BddDdiStartDevice( - _In_ VOID* pDeviceContext, - _In_ DXGK_START_INFO* pDxgkStartInfo, - _In_ DXGKRNL_INTERFACE* pDxgkInterface, - _Out_ ULONG* pNumberOfViews, - _Out_ ULONG* pNumberOfChildren) -{ - PAGED_CODE(); - BDD_ASSERT_CHK(pDeviceContext != NULL); - - BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast(pDeviceContext); - return pBDD->StartDevice(pDxgkStartInfo, pDxgkInterface, pNumberOfViews, pNumberOfChildren); -} - -NTSTATUS -BddDdiStopDevice( - _In_ VOID* pDeviceContext) -{ - PAGED_CODE(); - BDD_ASSERT_CHK(pDeviceContext != NULL); - - BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast(pDeviceContext); - return pBDD->StopDevice(); -} - - -NTSTATUS -BddDdiDispatchIoRequest( - _In_ VOID* pDeviceContext, - _In_ ULONG VidPnSourceId, - _In_ VIDEO_REQUEST_PACKET* pVideoRequestPacket) -{ - PAGED_CODE(); - BDD_ASSERT_CHK(pDeviceContext != NULL); - - BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast(pDeviceContext); - if (!pBDD->IsDriverActive()) - { - BDD_LOG_ASSERTION1("BDD (0x%I64x) is being called when not active!", pBDD); - return STATUS_UNSUCCESSFUL; - } - return pBDD->DispatchIoRequest(VidPnSourceId, pVideoRequestPacket); -} - -NTSTATUS -BddDdiSetPowerState( - _In_ VOID* pDeviceContext, - _In_ ULONG HardwareUid, - _In_ DEVICE_POWER_STATE DevicePowerState, - _In_ POWER_ACTION ActionType) -{ - PAGED_CODE(); - BDD_ASSERT_CHK(pDeviceContext != NULL); - - BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast(pDeviceContext); - if (!pBDD->IsDriverActive()) - { - // If the driver isn't active, SetPowerState can still be called, however in BDD's case - // this shouldn't do anything, as it could for instance be called on BDD Fallback after - // Fallback has been stopped and BDD PnP is being started. Fallback doesn't have control - // of the hardware in this case. - return STATUS_SUCCESS; - } - return pBDD->SetPowerState(HardwareUid, DevicePowerState, ActionType); -} - -NTSTATUS -BddDdiQueryChildRelations( - _In_ VOID* pDeviceContext, - _Out_writes_bytes_(ChildRelationsSize) DXGK_CHILD_DESCRIPTOR* pChildRelations, - _In_ ULONG ChildRelationsSize) -{ - PAGED_CODE(); - BDD_ASSERT_CHK(pDeviceContext != NULL); - - BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast(pDeviceContext); - return pBDD->QueryChildRelations(pChildRelations, ChildRelationsSize); -} - -NTSTATUS -BddDdiQueryChildStatus( - _In_ VOID* pDeviceContext, - _Inout_ DXGK_CHILD_STATUS* pChildStatus, - _In_ BOOLEAN NonDestructiveOnly) -{ - PAGED_CODE(); - BDD_ASSERT_CHK(pDeviceContext != NULL); - - BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast(pDeviceContext); - return pBDD->QueryChildStatus(pChildStatus, NonDestructiveOnly); -} - -NTSTATUS -BddDdiQueryDeviceDescriptor( - _In_ VOID* pDeviceContext, - _In_ ULONG ChildUid, - _Inout_ DXGK_DEVICE_DESCRIPTOR* pDeviceDescriptor) -{ - PAGED_CODE(); - BDD_ASSERT_CHK(pDeviceContext != NULL); - - BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast(pDeviceContext); - if (!pBDD->IsDriverActive()) - { - // During stress testing of PnPStop, it is possible for BDD Fallback to get called to start then stop in quick succession. - // The first call queues a worker thread item indicating that it now has a child device, the second queues a worker thread - // item that it no longer has any child device. This function gets called based on the first worker thread item, but after - // the driver has been stopped. Therefore instead of asserting like other functions, we only warn. - BDD_LOG_WARNING1("BDD (0x%I64x) is being called when not active!", pBDD); - return STATUS_UNSUCCESSFUL; - } - return pBDD->QueryDeviceDescriptor(ChildUid, pDeviceDescriptor); -} - - -// -// WDDM Display Only Driver DDIs -// - -NTSTATUS -APIENTRY -BddDdiQueryAdapterInfo( - _In_ CONST HANDLE hAdapter, - _In_ CONST DXGKARG_QUERYADAPTERINFO* pQueryAdapterInfo) -{ - PAGED_CODE(); - BDD_ASSERT_CHK(hAdapter != NULL); - - BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast(hAdapter); - return pBDD->QueryAdapterInfo(pQueryAdapterInfo); -} - -NTSTATUS -APIENTRY -BddDdiSetPointerPosition( - _In_ CONST HANDLE hAdapter, - _In_ CONST DXGKARG_SETPOINTERPOSITION* pSetPointerPosition) -{ - PAGED_CODE(); - BDD_ASSERT_CHK(hAdapter != NULL); - - BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast(hAdapter); - if (!pBDD->IsDriverActive()) - { - BDD_LOG_ASSERTION1("BDD (0x%I64x) is being called when not active!", pBDD); - return STATUS_UNSUCCESSFUL; - } - return pBDD->SetPointerPosition(pSetPointerPosition); -} - -NTSTATUS -APIENTRY -BddDdiSetPointerShape( - _In_ CONST HANDLE hAdapter, - _In_ CONST DXGKARG_SETPOINTERSHAPE* pSetPointerShape) -{ - PAGED_CODE(); - BDD_ASSERT_CHK(hAdapter != NULL); - - BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast(hAdapter); - if (!pBDD->IsDriverActive()) - { - BDD_LOG_ASSERTION1("BDD (0x%I64x) is being called when not active!", pBDD); - return STATUS_UNSUCCESSFUL; - } - return pBDD->SetPointerShape(pSetPointerShape); -} - - -NTSTATUS -APIENTRY -BddDdiPresentDisplayOnly( - _In_ CONST HANDLE hAdapter, - _In_ CONST DXGKARG_PRESENT_DISPLAYONLY* pPresentDisplayOnly) -{ - PAGED_CODE(); - BDD_ASSERT_CHK(hAdapter != NULL); - - BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast(hAdapter); - if (!pBDD->IsDriverActive()) - { - BDD_LOG_ASSERTION1("BDD (0x%I64x) is being called when not active!", pBDD); - return STATUS_UNSUCCESSFUL; - } - return pBDD->PresentDisplayOnly(pPresentDisplayOnly); -} - -NTSTATUS -APIENTRY -BddDdiStopDeviceAndReleasePostDisplayOwnership( - _In_ VOID* pDeviceContext, - _In_ D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId, - _Out_ DXGK_DISPLAY_INFORMATION* DisplayInfo) -{ - PAGED_CODE(); - BDD_ASSERT_CHK(pDeviceContext != NULL); - - BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast(pDeviceContext); - return pBDD->StopDeviceAndReleasePostDisplayOwnership(TargetId, DisplayInfo); -} - -NTSTATUS -APIENTRY -BddDdiIsSupportedVidPn( - _In_ CONST HANDLE hAdapter, - _Inout_ DXGKARG_ISSUPPORTEDVIDPN* pIsSupportedVidPn) -{ - PAGED_CODE(); - BDD_ASSERT_CHK(hAdapter != NULL); - - BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast(hAdapter); - if (!pBDD->IsDriverActive()) - { - // This path might hit because win32k/dxgport doesn't check that an adapter is active when taking the adapter lock. - // The adapter lock is the main thing BDD Fallback relies on to not be called while it's inactive. It is still a rare - // timing issue around PnpStart/Stop and isn't expected to have any effect on the stability of the system. - BDD_LOG_WARNING1("BDD (0x%I64x) is being called when not active!", pBDD); - return STATUS_UNSUCCESSFUL; - } - return pBDD->IsSupportedVidPn(pIsSupportedVidPn); -} - -NTSTATUS -APIENTRY -BddDdiRecommendFunctionalVidPn( - _In_ CONST HANDLE hAdapter, - _In_ CONST DXGKARG_RECOMMENDFUNCTIONALVIDPN* CONST pRecommendFunctionalVidPn) -{ - PAGED_CODE(); - BDD_ASSERT_CHK(hAdapter != NULL); - - BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast(hAdapter); - if (!pBDD->IsDriverActive()) - { - BDD_LOG_ASSERTION1("BDD (0x%I64x) is being called when not active!", pBDD); - return STATUS_UNSUCCESSFUL; - } - return pBDD->RecommendFunctionalVidPn(pRecommendFunctionalVidPn); -} - -NTSTATUS -APIENTRY -BddDdiRecommendVidPnTopology( - _In_ CONST HANDLE hAdapter, - _In_ CONST DXGKARG_RECOMMENDVIDPNTOPOLOGY* CONST pRecommendVidPnTopology) -{ - PAGED_CODE(); - BDD_ASSERT_CHK(hAdapter != NULL); - - BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast(hAdapter); - if (!pBDD->IsDriverActive()) - { - BDD_LOG_ASSERTION1("BDD (0x%I64x) is being called when not active!", pBDD); - return STATUS_UNSUCCESSFUL; - } - return pBDD->RecommendVidPnTopology(pRecommendVidPnTopology); -} - -NTSTATUS -APIENTRY -BddDdiRecommendMonitorModes( - _In_ CONST HANDLE hAdapter, - _In_ CONST DXGKARG_RECOMMENDMONITORMODES* CONST pRecommendMonitorModes) -{ - PAGED_CODE(); - BDD_ASSERT_CHK(hAdapter != NULL); - - BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast(hAdapter); - if (!pBDD->IsDriverActive()) - { - BDD_LOG_ASSERTION1("BDD (0x%I64x) is being called when not active!", pBDD); - return STATUS_UNSUCCESSFUL; - } - return pBDD->RecommendMonitorModes(pRecommendMonitorModes); -} - -NTSTATUS -APIENTRY -BddDdiEnumVidPnCofuncModality( - _In_ CONST HANDLE hAdapter, - _In_ CONST DXGKARG_ENUMVIDPNCOFUNCMODALITY* CONST pEnumCofuncModality) -{ - PAGED_CODE(); - BDD_ASSERT_CHK(hAdapter != NULL); - - BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast(hAdapter); - if (!pBDD->IsDriverActive()) - { - BDD_LOG_ASSERTION1("BDD (0x%I64x) is being called when not active!", pBDD); - return STATUS_UNSUCCESSFUL; - } - return pBDD->EnumVidPnCofuncModality(pEnumCofuncModality); -} - -NTSTATUS -APIENTRY -BddDdiSetVidPnSourceVisibility( - _In_ CONST HANDLE hAdapter, - _In_ CONST DXGKARG_SETVIDPNSOURCEVISIBILITY* pSetVidPnSourceVisibility) -{ - PAGED_CODE(); - BDD_ASSERT_CHK(hAdapter != NULL); - - BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast(hAdapter); - if (!pBDD->IsDriverActive()) - { - BDD_LOG_ASSERTION1("BDD (0x%I64x) is being called when not active!", pBDD); - return STATUS_UNSUCCESSFUL; - } - return pBDD->SetVidPnSourceVisibility(pSetVidPnSourceVisibility); -} - -NTSTATUS -APIENTRY -BddDdiCommitVidPn( - _In_ CONST HANDLE hAdapter, - _In_ CONST DXGKARG_COMMITVIDPN* CONST pCommitVidPn) -{ - PAGED_CODE(); - BDD_ASSERT_CHK(hAdapter != NULL); - - BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast(hAdapter); - if (!pBDD->IsDriverActive()) - { - BDD_LOG_ASSERTION1("BDD (0x%I64x) is being called when not active!", pBDD); - return STATUS_UNSUCCESSFUL; - } - return pBDD->CommitVidPn(pCommitVidPn); -} - -NTSTATUS -APIENTRY -BddDdiUpdateActiveVidPnPresentPath( - _In_ CONST HANDLE hAdapter, - _In_ CONST DXGKARG_UPDATEACTIVEVIDPNPRESENTPATH* CONST pUpdateActiveVidPnPresentPath) -{ - PAGED_CODE(); - BDD_ASSERT_CHK(hAdapter != NULL); - - BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast(hAdapter); - if (!pBDD->IsDriverActive()) - { - BDD_LOG_ASSERTION1("BDD (0x%I64x) is being called when not active!", pBDD); - return STATUS_UNSUCCESSFUL; - } - return pBDD->UpdateActiveVidPnPresentPath(pUpdateActiveVidPnPresentPath); -} - -NTSTATUS -APIENTRY -BddDdiQueryVidPnHWCapability( - _In_ CONST HANDLE hAdapter, - _Inout_ DXGKARG_QUERYVIDPNHWCAPABILITY* pVidPnHWCaps) -{ - PAGED_CODE(); - BDD_ASSERT_CHK(hAdapter != NULL); - - BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast(hAdapter); - if (!pBDD->IsDriverActive()) - { - BDD_LOG_ASSERTION1("BDD (0x%I64x) is being called when not active!", pBDD); - return STATUS_UNSUCCESSFUL; - } - return pBDD->QueryVidPnHWCapability(pVidPnHWCaps); -} -//END: Paged Code -#pragma code_seg(pop) - -#pragma code_seg(push) -#pragma code_seg() -// BEGIN: Non-Paged Code - -VOID -BddDdiDpcRoutine( - _In_ VOID* pDeviceContext) -{ - BDD_ASSERT_CHK(pDeviceContext != NULL); - - BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast(pDeviceContext); - if (!pBDD->IsDriverActive()) - { - BDD_LOG_ASSERTION1("BDD (0x%I64x) is being called when not active!", pBDD); - return; - } - pBDD->DpcRoutine(); -} - -BOOLEAN -BddDdiInterruptRoutine( - _In_ VOID* pDeviceContext, - _In_ ULONG MessageNumber) -{ - BDD_ASSERT_CHK(pDeviceContext != NULL); - - BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast(pDeviceContext); - return pBDD->InterruptRoutine(MessageNumber); -} - -VOID -BddDdiResetDevice( - _In_ VOID* pDeviceContext) -{ - BDD_ASSERT_CHK(pDeviceContext != NULL); - - BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast(pDeviceContext); - pBDD->ResetDevice(); -} - -NTSTATUS -APIENTRY -BddDdiSystemDisplayEnable( - _In_ VOID* pDeviceContext, - _In_ D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId, - _In_ PDXGKARG_SYSTEM_DISPLAY_ENABLE_FLAGS Flags, - _Out_ UINT* Width, - _Out_ UINT* Height, - _Out_ D3DDDIFORMAT* ColorFormat) -{ - BDD_ASSERT_CHK(pDeviceContext != NULL); - - BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast(pDeviceContext); - return pBDD->SystemDisplayEnable(TargetId, Flags, Width, Height, ColorFormat); -} - -VOID -APIENTRY -BddDdiSystemDisplayWrite( - _In_ VOID* pDeviceContext, - _In_ VOID* Source, - _In_ UINT SourceWidth, - _In_ UINT SourceHeight, - _In_ UINT SourceStride, - _In_ UINT PositionX, - _In_ UINT PositionY) -{ - BDD_ASSERT_CHK(pDeviceContext != NULL); - - BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast(pDeviceContext); - pBDD->SystemDisplayWrite(Source, SourceWidth, SourceHeight, SourceStride, PositionX, PositionY); -} - -// END: Non-Paged Code -#pragma code_seg(pop) - diff --git a/video/KMDOD/bdd_dmm.cxx b/video/KMDOD/bdd_dmm.cxx deleted file mode 100644 index 95c59538..00000000 --- a/video/KMDOD/bdd_dmm.cxx +++ /dev/null @@ -1,1083 +0,0 @@ -/******************************Module*Header*******************************\ -* Module Name: bdd_dmm.hxx -* -* Basic Display Driver display-mode management (DMM) function implementations -* -* -* Copyright (c) 2010 Microsoft Corporation -\**************************************************************************/ - -#include "BDD.hxx" - -#pragma code_seg("PAGE") - -// Display-Only Devices can only return display modes of D3DDDIFMT_A8R8G8B8. -// Color conversion takes place if the app's fullscreen backbuffer has different format. -// Full display drivers can add more if the hardware supports them. -D3DDDIFORMAT gBddPixelFormats[] = { - D3DDDIFMT_A8R8G8B8 -}; - -// TODO: Need to also check pinned modes and the path parameters, not just topology -NTSTATUS BASIC_DISPLAY_DRIVER::IsSupportedVidPn(_Inout_ DXGKARG_ISSUPPORTEDVIDPN* pIsSupportedVidPn) -{ - PAGED_CODE(); - - BDD_ASSERT(pIsSupportedVidPn != NULL); - - if (pIsSupportedVidPn->hDesiredVidPn == 0) - { - // A null desired VidPn is supported - pIsSupportedVidPn->IsVidPnSupported = TRUE; - return STATUS_SUCCESS; - } - - // Default to not supported, until shown it is supported - pIsSupportedVidPn->IsVidPnSupported = FALSE; - - CONST DXGK_VIDPN_INTERFACE* pVidPnInterface; - NTSTATUS Status = m_DxgkInterface.DxgkCbQueryVidPnInterface(pIsSupportedVidPn->hDesiredVidPn, DXGK_VIDPN_INTERFACE_VERSION_V1, &pVidPnInterface); - if (!NT_SUCCESS(Status)) - { - BDD_LOG_ERROR2("DxgkCbQueryVidPnInterface failed with Status = 0x%I64x, hDesiredVidPn = 0x%I64x", Status, pIsSupportedVidPn->hDesiredVidPn); - return Status; - } - - D3DKMDT_HVIDPNTOPOLOGY hVidPnTopology; - CONST DXGK_VIDPNTOPOLOGY_INTERFACE* pVidPnTopologyInterface; - Status = pVidPnInterface->pfnGetTopology(pIsSupportedVidPn->hDesiredVidPn, &hVidPnTopology, &pVidPnTopologyInterface); - if (!NT_SUCCESS(Status)) - { - BDD_LOG_ERROR2("pfnGetTopology failed with Status = 0x%I64x, hDesiredVidPn = 0x%I64x", Status, pIsSupportedVidPn->hDesiredVidPn); - return Status; - } - - // For every source in this topology, make sure they don't have more paths than there are targets - for (D3DDDI_VIDEO_PRESENT_SOURCE_ID SourceId = 0; SourceId < MAX_VIEWS; ++SourceId) - { - SIZE_T NumPathsFromSource = 0; - Status = pVidPnTopologyInterface->pfnGetNumPathsFromSource(hVidPnTopology, SourceId, &NumPathsFromSource); - if (Status == STATUS_GRAPHICS_SOURCE_NOT_IN_TOPOLOGY) - { - continue; - } - else if (!NT_SUCCESS(Status)) - { - BDD_LOG_ERROR3("pfnGetNumPathsFromSource failed with Status = 0x%I64x. hVidPnTopology = 0x%I64x, SourceId = 0x%I64x", - Status, hVidPnTopology, SourceId); - return Status; - } - else if (NumPathsFromSource > MAX_CHILDREN) - { - // This VidPn is not supported, which has already been set as the default - return STATUS_SUCCESS; - } - } - - // All sources succeeded so this VidPn is supported - pIsSupportedVidPn->IsVidPnSupported = TRUE; - return STATUS_SUCCESS; -} - -NTSTATUS BASIC_DISPLAY_DRIVER::RecommendFunctionalVidPn(_In_ CONST DXGKARG_RECOMMENDFUNCTIONALVIDPN* CONST pRecommendFunctionalVidPn) -{ - PAGED_CODE(); - - BDD_ASSERT(pRecommendFunctionalVidPn == NULL); - - return STATUS_GRAPHICS_NO_RECOMMENDED_FUNCTIONAL_VIDPN; -} - -NTSTATUS BASIC_DISPLAY_DRIVER::RecommendVidPnTopology(_In_ CONST DXGKARG_RECOMMENDVIDPNTOPOLOGY* CONST pRecommendVidPnTopology) -{ - PAGED_CODE(); - - BDD_ASSERT(pRecommendVidPnTopology == NULL); - - return STATUS_GRAPHICS_NO_RECOMMENDED_FUNCTIONAL_VIDPN; -} - -NTSTATUS BASIC_DISPLAY_DRIVER::RecommendMonitorModes(_In_ CONST DXGKARG_RECOMMENDMONITORMODES* CONST pRecommendMonitorModes) -{ - PAGED_CODE(); - - // This is always called to recommend modes for the monitor. The sample driver doesn't provide EDID for a monitor, so - // the OS prefills the list with default monitor modes. Since the required mode might not be in the list, it should - // be provided as a recommended mode. - return AddSingleMonitorMode(pRecommendMonitorModes); -} - -// Tell DMM about all the modes, etc. that are supported -NTSTATUS BASIC_DISPLAY_DRIVER::EnumVidPnCofuncModality(_In_ CONST DXGKARG_ENUMVIDPNCOFUNCMODALITY* CONST pEnumCofuncModality) -{ - PAGED_CODE(); - - BDD_ASSERT(pEnumCofuncModality != NULL); - - D3DKMDT_HVIDPNTOPOLOGY hVidPnTopology = 0; - D3DKMDT_HVIDPNSOURCEMODESET hVidPnSourceModeSet = 0; - D3DKMDT_HVIDPNTARGETMODESET hVidPnTargetModeSet = 0; - CONST DXGK_VIDPN_INTERFACE* pVidPnInterface = NULL; - CONST DXGK_VIDPNTOPOLOGY_INTERFACE* pVidPnTopologyInterface = NULL; - CONST DXGK_VIDPNSOURCEMODESET_INTERFACE* pVidPnSourceModeSetInterface = NULL; - CONST DXGK_VIDPNTARGETMODESET_INTERFACE* pVidPnTargetModeSetInterface = NULL; - CONST D3DKMDT_VIDPN_PRESENT_PATH* pVidPnPresentPath = NULL; - CONST D3DKMDT_VIDPN_PRESENT_PATH* pVidPnPresentPathTemp = NULL; // Used for AcquireNextPathInfo - CONST D3DKMDT_VIDPN_SOURCE_MODE* pVidPnPinnedSourceModeInfo = NULL; - CONST D3DKMDT_VIDPN_TARGET_MODE* pVidPnPinnedTargetModeInfo = NULL; - - // Get the VidPn Interface so we can get the 'Source Mode Set', 'Target Mode Set' and 'VidPn Topology' interfaces - NTSTATUS Status = m_DxgkInterface.DxgkCbQueryVidPnInterface(pEnumCofuncModality->hConstrainingVidPn, DXGK_VIDPN_INTERFACE_VERSION_V1, &pVidPnInterface); - if (!NT_SUCCESS(Status)) - { - BDD_LOG_ERROR2("DxgkCbQueryVidPnInterface failed with Status = 0x%I64x, hFunctionalVidPn = 0x%I64x", Status, pEnumCofuncModality->hConstrainingVidPn); - return Status; - } - - // Get the VidPn Topology interface so we can enumerate all paths - Status = pVidPnInterface->pfnGetTopology(pEnumCofuncModality->hConstrainingVidPn, &hVidPnTopology, &pVidPnTopologyInterface); - if (!NT_SUCCESS(Status)) - { - BDD_LOG_ERROR2("pfnGetTopology failed with Status = 0x%I64x, hFunctionalVidPn = 0x%I64x", Status, pEnumCofuncModality->hConstrainingVidPn); - return Status; - } - - // Get the first path before we start looping through them - Status = pVidPnTopologyInterface->pfnAcquireFirstPathInfo(hVidPnTopology, &pVidPnPresentPath); - if (!NT_SUCCESS(Status)) - { - BDD_LOG_ERROR2("pfnAcquireFirstPathInfo failed with Status = 0x%I64x, hVidPnTopology = 0x%I64x", Status, hVidPnTopology); - return Status; - } - - // Loop through all available paths. - while (Status != STATUS_GRAPHICS_NO_MORE_ELEMENTS_IN_DATASET) - { - // Get the Source Mode Set interface so the pinned mode can be retrieved - Status = pVidPnInterface->pfnAcquireSourceModeSet(pEnumCofuncModality->hConstrainingVidPn, - pVidPnPresentPath->VidPnSourceId, - &hVidPnSourceModeSet, - &pVidPnSourceModeSetInterface); - if (!NT_SUCCESS(Status)) - { - BDD_LOG_ERROR3("pfnAcquireSourceModeSet failed with Status = 0x%I64x, hConstrainingVidPn = 0x%I64x, SourceId = 0x%I64x", - Status, pEnumCofuncModality->hConstrainingVidPn, pVidPnPresentPath->VidPnSourceId); - break; - } - - // Get the pinned mode, needed when VidPnSource isn't pivot, and when VidPnTarget isn't pivot - Status = pVidPnSourceModeSetInterface->pfnAcquirePinnedModeInfo(hVidPnSourceModeSet, &pVidPnPinnedSourceModeInfo); - if (!NT_SUCCESS(Status)) - { - BDD_LOG_ERROR2("pfnAcquirePinnedModeInfo failed with Status = 0x%I64x, hVidPnSourceModeSet = 0x%I64x", Status, hVidPnSourceModeSet); - break; - } - - // SOURCE MODES: If this source mode isn't the pivot point, do work on the source mode set - if (!((pEnumCofuncModality->EnumPivotType == D3DKMDT_EPT_VIDPNSOURCE) && - (pEnumCofuncModality->EnumPivot.VidPnSourceId == pVidPnPresentPath->VidPnSourceId))) - { - // If there's no pinned source add possible modes (otherwise they've already been added) - if (pVidPnPinnedSourceModeInfo == NULL) - { - // Release the acquired source mode set, since going to create a new one to put all modes in - Status = pVidPnInterface->pfnReleaseSourceModeSet(pEnumCofuncModality->hConstrainingVidPn, hVidPnSourceModeSet); - if (!NT_SUCCESS(Status)) - { - BDD_LOG_ERROR3("pfnReleaseSourceModeSet failed with Status = 0x%I64x, hConstrainingVidPn = 0x%I64x, hVidPnSourceModeSet = 0x%I64x", - Status, pEnumCofuncModality->hConstrainingVidPn, hVidPnSourceModeSet); - break; - } - hVidPnSourceModeSet = 0; // Successfully released it - - // Create a new source mode set which will be added to the constraining VidPn with all the possible modes - Status = pVidPnInterface->pfnCreateNewSourceModeSet(pEnumCofuncModality->hConstrainingVidPn, - pVidPnPresentPath->VidPnSourceId, - &hVidPnSourceModeSet, - &pVidPnSourceModeSetInterface); - if (!NT_SUCCESS(Status)) - { - BDD_LOG_ERROR3("pfnCreateNewSourceModeSet failed with Status = 0x%I64x, hConstrainingVidPn = 0x%I64x, SourceId = 0x%I64x", - Status, pEnumCofuncModality->hConstrainingVidPn, pVidPnPresentPath->VidPnSourceId); - break; - } - - // Add the appropriate modes to the source mode set - { - Status = AddSingleSourceMode(pVidPnSourceModeSetInterface, hVidPnSourceModeSet, pVidPnPresentPath->VidPnSourceId); - } - - if (!NT_SUCCESS(Status)) - { - break; - } - - // Give DMM back the source modes just populated - Status = pVidPnInterface->pfnAssignSourceModeSet(pEnumCofuncModality->hConstrainingVidPn, pVidPnPresentPath->VidPnSourceId, hVidPnSourceModeSet); - if (!NT_SUCCESS(Status)) - { - BDD_LOG_ERROR4("pfnAssignSourceModeSet failed with Status = 0x%I64x, hConstrainingVidPn = 0x%I64x, SourceId = 0x%I64x, hVidPnSourceModeSet = 0x%I64x", - Status, pEnumCofuncModality->hConstrainingVidPn, pVidPnPresentPath->VidPnSourceId, hVidPnSourceModeSet); - break; - } - hVidPnSourceModeSet = 0; // Successfully assigned it (equivalent to releasing it) - } - }// End: SOURCE MODES - - // TARGET MODES: If this target mode isn't the pivot point, do work on the target mode set - if (!((pEnumCofuncModality->EnumPivotType == D3DKMDT_EPT_VIDPNTARGET) && - (pEnumCofuncModality->EnumPivot.VidPnTargetId == pVidPnPresentPath->VidPnTargetId))) - { - // Get the Target Mode Set interface so modes can be added if necessary - Status = pVidPnInterface->pfnAcquireTargetModeSet(pEnumCofuncModality->hConstrainingVidPn, - pVidPnPresentPath->VidPnTargetId, - &hVidPnTargetModeSet, - &pVidPnTargetModeSetInterface); - if (!NT_SUCCESS(Status)) - { - BDD_LOG_ERROR3("pfnAcquireTargetModeSet failed with Status = 0x%I64x, hConstrainingVidPn = 0x%I64x, TargetId = 0x%I64x", - Status, pEnumCofuncModality->hConstrainingVidPn, pVidPnPresentPath->VidPnTargetId); - break; - } - - Status = pVidPnTargetModeSetInterface->pfnAcquirePinnedModeInfo(hVidPnTargetModeSet, &pVidPnPinnedTargetModeInfo); - if (!NT_SUCCESS(Status)) - { - BDD_LOG_ERROR2("pfnAcquirePinnedModeInfo failed with Status = 0x%I64x, hVidPnTargetModeSet = 0x%I64x", Status, hVidPnTargetModeSet); - break; - } - - // If there's no pinned target add possible modes (otherwise they've already been added) - if (pVidPnPinnedTargetModeInfo == NULL) - { - // Release the acquired target mode set, since going to create a new one to put all modes in - Status = pVidPnInterface->pfnReleaseTargetModeSet(pEnumCofuncModality->hConstrainingVidPn, hVidPnTargetModeSet); - if (!NT_SUCCESS(Status)) - { - BDD_LOG_ASSERTION3("pfnReleaseTargetModeSet failed with Status = 0x%I64x, hConstrainingVidPn = 0x%I64x, hVidPnTargetModeSet = 0x%I64x", - Status, pEnumCofuncModality->hConstrainingVidPn, hVidPnTargetModeSet); - break; - } - hVidPnTargetModeSet = 0; // Successfully released it - - // Create a new target mode set which will be added to the constraining VidPn with all the possible modes - Status = pVidPnInterface->pfnCreateNewTargetModeSet(pEnumCofuncModality->hConstrainingVidPn, - pVidPnPresentPath->VidPnTargetId, - &hVidPnTargetModeSet, - &pVidPnTargetModeSetInterface); - if (!NT_SUCCESS(Status)) - { - BDD_LOG_ERROR3("pfnCreateNewTargetModeSet failed with Status = 0x%I64x, hConstrainingVidPn = 0x%I64x, TargetId = 0x%I64x", - Status, pEnumCofuncModality->hConstrainingVidPn, pVidPnPresentPath->VidPnTargetId); - break; - } - - Status = AddSingleTargetMode(pVidPnTargetModeSetInterface, hVidPnTargetModeSet, pVidPnPinnedSourceModeInfo, pVidPnPresentPath->VidPnSourceId); - - if (!NT_SUCCESS(Status)) - { - break; - } - - // Give DMM back the source modes just populated - Status = pVidPnInterface->pfnAssignTargetModeSet(pEnumCofuncModality->hConstrainingVidPn, pVidPnPresentPath->VidPnTargetId, hVidPnTargetModeSet); - if (!NT_SUCCESS(Status)) - { - BDD_LOG_ERROR4("pfnAssignTargetModeSet failed with Status = 0x%I64x, hConstrainingVidPn = 0x%I64x, TargetId = 0x%I64x, hVidPnTargetModeSet = 0x%I64x", - Status, pEnumCofuncModality->hConstrainingVidPn, pVidPnPresentPath->VidPnTargetId, hVidPnTargetModeSet); - break; - } - hVidPnTargetModeSet = 0; // Successfully assigned it (equivalent to releasing it) - } - else - { - // Release the pinned target as there's no other work to do - Status = pVidPnTargetModeSetInterface->pfnReleaseModeInfo(hVidPnTargetModeSet, pVidPnPinnedTargetModeInfo); - if (!NT_SUCCESS(Status)) - { - BDD_LOG_ASSERTION3("pfnReleaseModeInfo failed with Status = 0x%I64x, hVidPnTargetModeSet = 0x%I64x, pVidPnPinnedTargetModeInfo = 0x%I64x", - Status, hVidPnTargetModeSet, pVidPnPinnedTargetModeInfo); - break; - } - pVidPnPinnedTargetModeInfo = NULL; // Successfully released it - - // Release the acquired target mode set, since it is no longer needed - Status = pVidPnInterface->pfnReleaseTargetModeSet(pEnumCofuncModality->hConstrainingVidPn, hVidPnTargetModeSet); - if (!NT_SUCCESS(Status)) - { - BDD_LOG_ASSERTION3("pfnReleaseTargetModeSet failed with Status = 0x%I64x, hConstrainingVidPn = 0x%I64x, hVidPnTargetModeSet = 0x%I64x", - Status, pEnumCofuncModality->hConstrainingVidPn, hVidPnTargetModeSet); - break; - } - hVidPnTargetModeSet = 0; // Successfully released it - } - }// End: TARGET MODES - - // Nothing else needs the pinned source mode so release it - if (pVidPnPinnedSourceModeInfo != NULL) - { - Status = pVidPnSourceModeSetInterface->pfnReleaseModeInfo(hVidPnSourceModeSet, pVidPnPinnedSourceModeInfo); - if (!NT_SUCCESS(Status)) - { - BDD_LOG_ASSERTION3("pfnReleaseModeInfo failed with Status = 0x%I64x, hVidPnSourceModeSet = 0x%I64x, pVidPnPinnedSourceModeInfo = 0x%I64x", - Status, hVidPnSourceModeSet, pVidPnPinnedSourceModeInfo); - break; - } - pVidPnPinnedSourceModeInfo = NULL; // Successfully released it - } - - // With the pinned source mode now released, if the source mode set hasn't been released, release that as well - if (hVidPnSourceModeSet != 0) - { - Status = pVidPnInterface->pfnReleaseSourceModeSet(pEnumCofuncModality->hConstrainingVidPn, hVidPnSourceModeSet); - if (!NT_SUCCESS(Status)) - { - BDD_LOG_ERROR3("pfnReleaseSourceModeSet failed with Status = 0x%I64x, hConstrainingVidPn = 0x%I64x, hVidPnSourceModeSet = 0x%I64x", - Status, pEnumCofuncModality->hConstrainingVidPn, hVidPnSourceModeSet); - break; - } - hVidPnSourceModeSet = 0; // Successfully released it - } - - // If modifying support fields, need to modify a local version of a path structure since the retrieved one is const - D3DKMDT_VIDPN_PRESENT_PATH LocalVidPnPresentPath = *pVidPnPresentPath; - BOOLEAN SupportFieldsModified = FALSE; - - // SCALING: If this path's scaling isn't the pivot point, do work on the scaling support - if (!((pEnumCofuncModality->EnumPivotType == D3DKMDT_EPT_SCALING) && - (pEnumCofuncModality->EnumPivot.VidPnSourceId == pVidPnPresentPath->VidPnSourceId) && - (pEnumCofuncModality->EnumPivot.VidPnTargetId == pVidPnPresentPath->VidPnTargetId))) - { - // If the scaling is unpinned, then modify the scaling support field - if (pVidPnPresentPath->ContentTransformation.Scaling == D3DKMDT_VPPS_UNPINNED) - { - // Identity and centered scaling are supported, but not any stretch modes - RtlZeroMemory(&(LocalVidPnPresentPath.ContentTransformation.ScalingSupport), sizeof(D3DKMDT_VIDPN_PRESENT_PATH_SCALING_SUPPORT)); - LocalVidPnPresentPath.ContentTransformation.ScalingSupport.Identity = 1; - LocalVidPnPresentPath.ContentTransformation.ScalingSupport.Centered = 1; - SupportFieldsModified = TRUE; - } - } // End: SCALING - - // ROTATION: If this path's rotation isn't the pivot point, do work on the rotation support - if (!((pEnumCofuncModality->EnumPivotType != D3DKMDT_EPT_ROTATION) && - (pEnumCofuncModality->EnumPivot.VidPnSourceId == pVidPnPresentPath->VidPnSourceId) && - (pEnumCofuncModality->EnumPivot.VidPnTargetId == pVidPnPresentPath->VidPnTargetId))) - { - // If the rotation is unpinned, then modify the rotation support field - if (pVidPnPresentPath->ContentTransformation.Rotation == D3DKMDT_VPPR_UNPINNED) - { - LocalVidPnPresentPath.ContentTransformation.RotationSupport.Identity = 1; - // Sample supports only Rotate90 - LocalVidPnPresentPath.ContentTransformation.RotationSupport.Rotate90 = 1; - LocalVidPnPresentPath.ContentTransformation.RotationSupport.Rotate180 = 0; - LocalVidPnPresentPath.ContentTransformation.RotationSupport.Rotate270 = 0; - - // Since clone is not supported, should not support path-independent rotations - LocalVidPnPresentPath.ContentTransformation.RotationSupport.Offset0 = 1; - - SupportFieldsModified = TRUE; - } - } // End: ROTATION - - if (SupportFieldsModified) - { - // The correct path will be found by this function and the appropriate fields updated - Status = pVidPnTopologyInterface->pfnUpdatePathSupportInfo(hVidPnTopology, &LocalVidPnPresentPath); - if (!NT_SUCCESS(Status)) - { - BDD_LOG_ERROR2("pfnUpdatePathSupportInfo failed with Status = 0x%I64x, hVidPnTopology = 0x%I64x", Status, hVidPnTopology); - break; - } - } - - // Get the next path... - // (NOTE: This is the value of Status that will return STATUS_GRAPHICS_NO_MORE_ELEMENTS_IN_DATASET when it's time to quit the loop) - pVidPnPresentPathTemp = pVidPnPresentPath; - Status = pVidPnTopologyInterface->pfnAcquireNextPathInfo(hVidPnTopology, pVidPnPresentPathTemp, &pVidPnPresentPath); - if (!NT_SUCCESS(Status)) - { - BDD_LOG_ERROR3("pfnAcquireNextPathInfo failed with Status = 0x%I64x, hVidPnTopology = 0x%I64x, pVidPnPresentPathTemp = 0x%I64x", Status, hVidPnTopology, pVidPnPresentPathTemp); - break; - } - - // ...and release the last path - NTSTATUS TempStatus = pVidPnTopologyInterface->pfnReleasePathInfo(hVidPnTopology, pVidPnPresentPathTemp); - if (!NT_SUCCESS(TempStatus)) - { - BDD_LOG_ERROR3("pfnReleasePathInfo failed with Status = 0x%I64x, hVidPnTopology = 0x%I64x, pVidPnPresentPathTemp = 0x%I64x", TempStatus, hVidPnTopology, pVidPnPresentPathTemp); - Status = TempStatus; - break; - } - pVidPnPresentPathTemp = NULL; // Successfully released it - }// End: while loop for paths in topology - - // If quit the while loop normally, set the return value to success - if (Status == STATUS_GRAPHICS_NO_MORE_ELEMENTS_IN_DATASET) - { - Status = STATUS_SUCCESS; - } - - // Release any resources hanging around because the loop was quit early. - // Since in normal execution everything should be released by this point, TempStatus is initialized to a bogus error to be used as an - // assertion that if anything had to be released now (TempStatus changing) Status isn't successful. - NTSTATUS TempStatus = STATUS_NOT_FOUND; - - if ((pVidPnSourceModeSetInterface != NULL) && - (pVidPnPinnedSourceModeInfo != NULL)) - { - TempStatus = pVidPnSourceModeSetInterface->pfnReleaseModeInfo(hVidPnSourceModeSet, pVidPnPinnedSourceModeInfo); - BDD_ASSERT_CHK(NT_SUCCESS(TempStatus)); - } - - if ((pVidPnTargetModeSetInterface != NULL) && - (pVidPnPinnedTargetModeInfo != NULL)) - { - TempStatus = pVidPnTargetModeSetInterface->pfnReleaseModeInfo(hVidPnTargetModeSet, pVidPnPinnedTargetModeInfo); - BDD_ASSERT_CHK(NT_SUCCESS(TempStatus)); - } - - if (pVidPnPresentPath != NULL) - { - TempStatus = pVidPnTopologyInterface->pfnReleasePathInfo(hVidPnTopology, pVidPnPresentPath); - BDD_ASSERT_CHK(NT_SUCCESS(TempStatus)); - } - - if (pVidPnPresentPathTemp != NULL) - { - TempStatus = pVidPnTopologyInterface->pfnReleasePathInfo(hVidPnTopology, pVidPnPresentPathTemp); - BDD_ASSERT_CHK(NT_SUCCESS(TempStatus)); - } - - if (hVidPnSourceModeSet != 0) - { - TempStatus = pVidPnInterface->pfnReleaseSourceModeSet(pEnumCofuncModality->hConstrainingVidPn, hVidPnSourceModeSet); - BDD_ASSERT_CHK(NT_SUCCESS(TempStatus)); - } - - if (hVidPnTargetModeSet != 0) - { - TempStatus = pVidPnInterface->pfnReleaseTargetModeSet(pEnumCofuncModality->hConstrainingVidPn, hVidPnTargetModeSet); - BDD_ASSERT_CHK(NT_SUCCESS(TempStatus)); - } - - BDD_ASSERT_CHK(TempStatus == STATUS_NOT_FOUND || Status != STATUS_SUCCESS); - - return Status; -} - -NTSTATUS BASIC_DISPLAY_DRIVER::SetVidPnSourceVisibility(_In_ CONST DXGKARG_SETVIDPNSOURCEVISIBILITY* pSetVidPnSourceVisibility) -{ - PAGED_CODE(); - - BDD_ASSERT(pSetVidPnSourceVisibility != NULL); - BDD_ASSERT((pSetVidPnSourceVisibility->VidPnSourceId < MAX_VIEWS) || - (pSetVidPnSourceVisibility->VidPnSourceId == D3DDDI_ID_ALL)); - - UINT StartVidPnSourceId = (pSetVidPnSourceVisibility->VidPnSourceId == D3DDDI_ID_ALL) ? 0 : pSetVidPnSourceVisibility->VidPnSourceId; - UINT MaxVidPnSourceId = (pSetVidPnSourceVisibility->VidPnSourceId == D3DDDI_ID_ALL) ? MAX_VIEWS : pSetVidPnSourceVisibility->VidPnSourceId + 1; - - for (UINT SourceId = StartVidPnSourceId; SourceId < MaxVidPnSourceId; ++SourceId) - { - if (pSetVidPnSourceVisibility->Visible) - { - m_CurrentModes[SourceId].Flags.FullscreenPresent = TRUE; - } - else - { - BlackOutScreen(SourceId); - } - - // Store current visibility so it can be dealt with during Present call - m_CurrentModes[SourceId].Flags.SourceNotVisible = !(pSetVidPnSourceVisibility->Visible); - } - - return STATUS_SUCCESS; -} - -// NOTE: The value of pCommitVidPn->MonitorConnectivityChecks is ignored, since BDD is unable to recognize whether a monitor is connected or not -// The value of pCommitVidPn->hPrimaryAllocation is also ignored, since BDD is a display only driver and does not deal with allocations -NTSTATUS BASIC_DISPLAY_DRIVER::CommitVidPn(_In_ CONST DXGKARG_COMMITVIDPN* CONST pCommitVidPn) -{ - PAGED_CODE(); - - BDD_ASSERT(pCommitVidPn != NULL); - BDD_ASSERT(pCommitVidPn->AffectedVidPnSourceId < MAX_VIEWS); - - NTSTATUS Status; - SIZE_T NumPaths = 0; - D3DKMDT_HVIDPNTOPOLOGY hVidPnTopology = 0; - D3DKMDT_HVIDPNSOURCEMODESET hVidPnSourceModeSet = 0; - CONST DXGK_VIDPN_INTERFACE* pVidPnInterface = NULL; - CONST DXGK_VIDPNTOPOLOGY_INTERFACE* pVidPnTopologyInterface = NULL; - CONST DXGK_VIDPNSOURCEMODESET_INTERFACE* pVidPnSourceModeSetInterface = NULL; - CONST D3DKMDT_VIDPN_PRESENT_PATH* pVidPnPresentPath = NULL; - CONST D3DKMDT_VIDPN_SOURCE_MODE* pPinnedVidPnSourceModeInfo = NULL; - - // Check this CommitVidPn is for the mode change notification when monitor is in power off state. - if (pCommitVidPn->Flags.PathPoweredOff) - { - // Ignore the commitVidPn call for the mode change notification when monitor is in power off state. - Status = STATUS_SUCCESS; - goto CommitVidPnExit; - } - - // Get the VidPn Interface so we can get the 'Source Mode Set' and 'VidPn Topology' interfaces - Status = m_DxgkInterface.DxgkCbQueryVidPnInterface(pCommitVidPn->hFunctionalVidPn, DXGK_VIDPN_INTERFACE_VERSION_V1, &pVidPnInterface); - if (!NT_SUCCESS(Status)) - { - BDD_LOG_ERROR2("DxgkCbQueryVidPnInterface failed with Status = 0x%I64x, hFunctionalVidPn = 0x%I64x", Status, pCommitVidPn->hFunctionalVidPn); - goto CommitVidPnExit; - } - - // Get the VidPn Topology interface so can enumerate paths from source - Status = pVidPnInterface->pfnGetTopology(pCommitVidPn->hFunctionalVidPn, &hVidPnTopology, &pVidPnTopologyInterface); - if (!NT_SUCCESS(Status)) - { - BDD_LOG_ERROR2("pfnGetTopology failed with Status = 0x%I64x, hFunctionalVidPn = 0x%I64x", Status, pCommitVidPn->hFunctionalVidPn); - goto CommitVidPnExit; - } - - // Find out the number of paths now, if it's 0 don't bother with source mode set and pinned mode, just clear current and then quit - Status = pVidPnTopologyInterface->pfnGetNumPaths(hVidPnTopology, &NumPaths); - if (!NT_SUCCESS(Status)) - { - BDD_LOG_ERROR2("pfnGetNumPaths failed with Status = 0x%I64x, hVidPnTopology = 0x%I64x", Status, hVidPnTopology); - goto CommitVidPnExit; - } - - if (NumPaths != 0) - { - // Get the Source Mode Set interface so we can get the pinned mode - Status = pVidPnInterface->pfnAcquireSourceModeSet(pCommitVidPn->hFunctionalVidPn, - pCommitVidPn->AffectedVidPnSourceId, - &hVidPnSourceModeSet, - &pVidPnSourceModeSetInterface); - if (!NT_SUCCESS(Status)) - { - BDD_LOG_ERROR3("pfnAcquireSourceModeSet failed with Status = 0x%I64x, hFunctionalVidPn = 0x%I64x, SourceId = 0x%I64x", Status, pCommitVidPn->hFunctionalVidPn, pCommitVidPn->AffectedVidPnSourceId); - goto CommitVidPnExit; - } - - // Get the mode that is being pinned - Status = pVidPnSourceModeSetInterface->pfnAcquirePinnedModeInfo(hVidPnSourceModeSet, &pPinnedVidPnSourceModeInfo); - if (!NT_SUCCESS(Status)) - { - BDD_LOG_ERROR2("pfnAcquirePinnedModeInfo failed with Status = 0x%I64x, hFunctionalVidPn = 0x%I64x", Status, pCommitVidPn->hFunctionalVidPn); - goto CommitVidPnExit; - } - } - else - { - // This will cause the successful quit below - pPinnedVidPnSourceModeInfo = NULL; - } - - if (m_CurrentModes[pCommitVidPn->AffectedVidPnSourceId].FrameBuffer.Ptr && - !m_CurrentModes[pCommitVidPn->AffectedVidPnSourceId].Flags.DoNotMapOrUnmap) - { - Status = UnmapFrameBuffer(m_CurrentModes[pCommitVidPn->AffectedVidPnSourceId].FrameBuffer.Ptr, - m_CurrentModes[pCommitVidPn->AffectedVidPnSourceId].DispInfo.Pitch * m_CurrentModes[pCommitVidPn->AffectedVidPnSourceId].DispInfo.Height); - m_CurrentModes[pCommitVidPn->AffectedVidPnSourceId].FrameBuffer.Ptr = NULL; - m_CurrentModes[pCommitVidPn->AffectedVidPnSourceId].Flags.FrameBufferIsActive = FALSE; - - if (!NT_SUCCESS(Status)) - { - goto CommitVidPnExit; - } - } - - if (pPinnedVidPnSourceModeInfo == NULL) - { - // There is no mode to pin on this source, any old paths here have already been cleared - Status = STATUS_SUCCESS; - goto CommitVidPnExit; - } - - Status = IsVidPnSourceModeFieldsValid(pPinnedVidPnSourceModeInfo); - if (!NT_SUCCESS(Status)) - { - goto CommitVidPnExit; - } - - // Get the number of paths from this source so we can loop through all paths - SIZE_T NumPathsFromSource = 0; - Status = pVidPnTopologyInterface->pfnGetNumPathsFromSource(hVidPnTopology, pCommitVidPn->AffectedVidPnSourceId, &NumPathsFromSource); - if (!NT_SUCCESS(Status)) - { - BDD_LOG_ERROR2("pfnGetNumPathsFromSource failed with Status = 0x%I64x, hVidPnTopology = 0x%I64x", Status, hVidPnTopology); - goto CommitVidPnExit; - } - - // Loop through all paths to set this mode - for (SIZE_T PathIndex = 0; PathIndex < NumPathsFromSource; ++PathIndex) - { - // Get the target id for this path - D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId = D3DDDI_ID_UNINITIALIZED; - Status = pVidPnTopologyInterface->pfnEnumPathTargetsFromSource(hVidPnTopology, pCommitVidPn->AffectedVidPnSourceId, PathIndex, &TargetId); - if (!NT_SUCCESS(Status)) - { - BDD_LOG_ERROR4("pfnEnumPathTargetsFromSource failed with Status = 0x%I64x, hVidPnTopology = 0x%I64x, SourceId = 0x%I64x, PathIndex = 0x%I64x", - Status, hVidPnTopology, pCommitVidPn->AffectedVidPnSourceId, PathIndex); - goto CommitVidPnExit; - } - - // Get the actual path info - Status = pVidPnTopologyInterface->pfnAcquirePathInfo(hVidPnTopology, pCommitVidPn->AffectedVidPnSourceId, TargetId, &pVidPnPresentPath); - if (!NT_SUCCESS(Status)) - { - BDD_LOG_ERROR4("pfnAcquirePathInfo failed with Status = 0x%I64x, hVidPnTopology = 0x%I64x, SourceId = 0x%I64x, TargetId = 0x%I64x", - Status, hVidPnTopology, pCommitVidPn->AffectedVidPnSourceId, TargetId); - goto CommitVidPnExit; - } - - Status = IsVidPnPathFieldsValid(pVidPnPresentPath); - if (!NT_SUCCESS(Status)) - { - goto CommitVidPnExit; - } - - Status = SetSourceModeAndPath(pPinnedVidPnSourceModeInfo, pVidPnPresentPath); - if (!NT_SUCCESS(Status)) - { - goto CommitVidPnExit; - } - - Status = pVidPnTopologyInterface->pfnReleasePathInfo(hVidPnTopology, pVidPnPresentPath); - if (!NT_SUCCESS(Status)) - { - BDD_LOG_ERROR3("pfnReleasePathInfo failed with Status = 0x%I64x, hVidPnTopoogy = 0x%I64x, pVidPnPresentPath = 0x%I64x", - Status, hVidPnTopology, pVidPnPresentPath); - goto CommitVidPnExit; - } - pVidPnPresentPath = NULL; // Successfully released it - } - -CommitVidPnExit: - - NTSTATUS TempStatus; - - if ((pVidPnSourceModeSetInterface != NULL) && - (hVidPnSourceModeSet != 0) && - (pPinnedVidPnSourceModeInfo != NULL)) - { - TempStatus = pVidPnSourceModeSetInterface->pfnReleaseModeInfo(hVidPnSourceModeSet, pPinnedVidPnSourceModeInfo); - NT_ASSERT(NT_SUCCESS(TempStatus)); - } - - if ((pVidPnInterface != NULL) && - (pCommitVidPn->hFunctionalVidPn != 0) && - (hVidPnSourceModeSet != 0)) - { - TempStatus = pVidPnInterface->pfnReleaseSourceModeSet(pCommitVidPn->hFunctionalVidPn, hVidPnSourceModeSet); - NT_ASSERT(NT_SUCCESS(TempStatus)); - } - - if ((pVidPnTopologyInterface != NULL) && - (hVidPnTopology != 0) && - (pVidPnPresentPath != NULL)) - { - TempStatus = pVidPnTopologyInterface->pfnReleasePathInfo(hVidPnTopology, pVidPnPresentPath); - NT_ASSERT(NT_SUCCESS(TempStatus)); - } - - return Status; -} - -NTSTATUS BASIC_DISPLAY_DRIVER::UpdateActiveVidPnPresentPath(_In_ CONST DXGKARG_UPDATEACTIVEVIDPNPRESENTPATH* CONST pUpdateActiveVidPnPresentPath) -{ - PAGED_CODE(); - - BDD_ASSERT(pUpdateActiveVidPnPresentPath != NULL); - - NTSTATUS Status = IsVidPnPathFieldsValid(&(pUpdateActiveVidPnPresentPath->VidPnPresentPathInfo)); - if (!NT_SUCCESS(Status)) - { - return Status; - } - - // Mark the next present as fullscreen to make sure the full rotation comes through - m_CurrentModes[pUpdateActiveVidPnPresentPath->VidPnPresentPathInfo.VidPnSourceId].Flags.FullscreenPresent = TRUE; - - m_CurrentModes[pUpdateActiveVidPnPresentPath->VidPnPresentPathInfo.VidPnSourceId].Rotation = pUpdateActiveVidPnPresentPath->VidPnPresentPathInfo.ContentTransformation.Rotation; - - return STATUS_SUCCESS; -} - -// -// Private BDD DMM functions -// - -NTSTATUS BASIC_DISPLAY_DRIVER::SetSourceModeAndPath(CONST D3DKMDT_VIDPN_SOURCE_MODE* pSourceMode, - CONST D3DKMDT_VIDPN_PRESENT_PATH* pPath) -{ - PAGED_CODE(); - - CURRENT_BDD_MODE* pCurrentBddMode = &m_CurrentModes[pPath->VidPnSourceId]; - - NTSTATUS Status = STATUS_SUCCESS; - pCurrentBddMode->Scaling = pPath->ContentTransformation.Scaling; - pCurrentBddMode->SrcModeWidth = pSourceMode->Format.Graphics.PrimSurfSize.cx; - pCurrentBddMode->SrcModeHeight = pSourceMode->Format.Graphics.PrimSurfSize.cy; - pCurrentBddMode->Rotation = pPath->ContentTransformation.Rotation; - - - if (!pCurrentBddMode->Flags.DoNotMapOrUnmap) - { - // Map the new frame buffer - BDD_ASSERT(pCurrentBddMode->FrameBuffer.Ptr == NULL); - Status = MapFrameBuffer(pCurrentBddMode->DispInfo.PhysicAddress, - pCurrentBddMode->DispInfo.Pitch * pCurrentBddMode->DispInfo.Height, - &(pCurrentBddMode->FrameBuffer.Ptr)); - } - - if (NT_SUCCESS(Status)) - { - - pCurrentBddMode->Flags.FrameBufferIsActive = TRUE; - BlackOutScreen(pPath->VidPnSourceId); - - // Mark that the next present should be fullscreen so the screen doesn't go from black to actual pixels one dirty rect at a time. - pCurrentBddMode->Flags.FullscreenPresent = TRUE; - } - - return Status; -} - - -NTSTATUS BASIC_DISPLAY_DRIVER::IsVidPnPathFieldsValid(CONST D3DKMDT_VIDPN_PRESENT_PATH* pPath) const -{ - PAGED_CODE(); - - if (pPath->VidPnSourceId >= MAX_VIEWS) - { - BDD_LOG_ERROR2("VidPnSourceId is 0x%I64x is too high (MAX_VIEWS is 0x%I64x)", - pPath->VidPnSourceId, MAX_VIEWS); - return STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE; - } - else if (pPath->VidPnTargetId >= MAX_CHILDREN) - { - BDD_LOG_ERROR2("VidPnTargetId is 0x%I64x is too high (MAX_CHILDREN is 0x%I64x)", - pPath->VidPnTargetId, MAX_CHILDREN); - return STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_TARGET; - } - else if (pPath->GammaRamp.Type != D3DDDI_GAMMARAMP_DEFAULT) - { - BDD_LOG_ERROR1("pPath contains a gamma ramp (0x%I64x)", pPath->GammaRamp.Type); - return STATUS_GRAPHICS_GAMMA_RAMP_NOT_SUPPORTED; - } - else if ((pPath->ContentTransformation.Scaling != D3DKMDT_VPPS_IDENTITY) && - (pPath->ContentTransformation.Scaling != D3DKMDT_VPPS_CENTERED) && - (pPath->ContentTransformation.Scaling != D3DKMDT_VPPS_NOTSPECIFIED) && - (pPath->ContentTransformation.Scaling != D3DKMDT_VPPS_UNINITIALIZED)) - { - BDD_LOG_ERROR1("pPath contains a non-identity scaling (0x%I64x)", pPath->ContentTransformation.Scaling); - return STATUS_GRAPHICS_VIDPN_MODALITY_NOT_SUPPORTED; - } - else if ((pPath->ContentTransformation.Rotation != D3DKMDT_VPPR_IDENTITY) && - (pPath->ContentTransformation.Rotation != D3DKMDT_VPPR_ROTATE90) && - (pPath->ContentTransformation.Rotation != D3DKMDT_VPPR_NOTSPECIFIED) && - (pPath->ContentTransformation.Rotation != D3DKMDT_VPPR_UNINITIALIZED)) - { - BDD_LOG_ERROR1("pPath contains a not-supported rotation (0x%I64x)", pPath->ContentTransformation.Rotation); - return STATUS_GRAPHICS_VIDPN_MODALITY_NOT_SUPPORTED; - } - else if ((pPath->VidPnTargetColorBasis != D3DKMDT_CB_SCRGB) && - (pPath->VidPnTargetColorBasis != D3DKMDT_CB_UNINITIALIZED)) - { - BDD_LOG_ERROR1("pPath has a non-linear RGB color basis (0x%I64x)", pPath->VidPnTargetColorBasis); - return STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE_MODE; - } - else - { - return STATUS_SUCCESS; - } -} - -NTSTATUS BASIC_DISPLAY_DRIVER::IsVidPnSourceModeFieldsValid(CONST D3DKMDT_VIDPN_SOURCE_MODE* pSourceMode) const -{ - PAGED_CODE(); - - if (pSourceMode->Type != D3DKMDT_RMT_GRAPHICS) - { - BDD_LOG_ERROR1("pSourceMode is a non-graphics mode (0x%I64x)", pSourceMode->Type); - return STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE_MODE; - } - else if ((pSourceMode->Format.Graphics.ColorBasis != D3DKMDT_CB_SCRGB) && - (pSourceMode->Format.Graphics.ColorBasis != D3DKMDT_CB_UNINITIALIZED)) - { - BDD_LOG_ERROR1("pSourceMode has a non-linear RGB color basis (0x%I64x)", pSourceMode->Format.Graphics.ColorBasis); - return STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE_MODE; - } - else if (pSourceMode->Format.Graphics.PixelValueAccessMode != D3DKMDT_PVAM_DIRECT) - { - BDD_LOG_ERROR1("pSourceMode has a palettized access mode (0x%I64x)", pSourceMode->Format.Graphics.PixelValueAccessMode); - return STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE_MODE; - } - else - { - for (UINT PelFmtIdx = 0; PelFmtIdx < ARRAYSIZE(gBddPixelFormats); ++PelFmtIdx) - { - if (pSourceMode->Format.Graphics.PixelFormat == gBddPixelFormats[PelFmtIdx]) - { - return STATUS_SUCCESS; - } - } - - BDD_LOG_ERROR1("pSourceMode has an unknown pixel format (0x%I64x)", pSourceMode->Format.Graphics.PixelFormat); - return STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE_MODE; - } -} - - - -// Add more mode from the table. -struct SampleSourceMode -{ - UINT ModeWidth; - UINT ModeHeight; -}; - -// The driver will advertise all modes that fit within the actual required mode (see AddSingleSourceMode below) -const static SampleSourceMode C_SampleSourceMode[] = {{800,600},{1024,768},{1152,864},{1280,800},{1280,1024},{1400,1050},{1600,1200},{1680,1050},{1920,1200}}; -const static UINT C_SampleSourceModeMax = sizeof(C_SampleSourceMode)/sizeof(C_SampleSourceMode[0]); - -NTSTATUS BASIC_DISPLAY_DRIVER::AddSingleSourceMode(_In_ CONST DXGK_VIDPNSOURCEMODESET_INTERFACE* pVidPnSourceModeSetInterface, - D3DKMDT_HVIDPNSOURCEMODESET hVidPnSourceModeSet, - D3DDDI_VIDEO_PRESENT_SOURCE_ID SourceId) -{ - PAGED_CODE(); - - // There is only one source format supported by display-only drivers, but more can be added in a - // full WDDM driver if the hardware supports them - for (UINT PelFmtIdx = 0; PelFmtIdx < ARRAYSIZE(gBddPixelFormats); ++PelFmtIdx) - { - // Create new mode info that will be populated - D3DKMDT_VIDPN_SOURCE_MODE* pVidPnSourceModeInfo = NULL; - NTSTATUS Status = pVidPnSourceModeSetInterface->pfnCreateNewModeInfo(hVidPnSourceModeSet, &pVidPnSourceModeInfo); - if (!NT_SUCCESS(Status)) - { - // If failed to create a new mode info, mode doesn't need to be released since it was never created - BDD_LOG_ERROR2("pfnCreateNewModeInfo failed with Status = 0x%I64x, hVidPnSourceModeSet = 0x%I64x", Status, hVidPnSourceModeSet); - return Status; - } - - // Populate mode info with values from current mode and hard-coded values - // Always report 32 bpp format, this will be color converted during the present if the mode is < 32bpp - pVidPnSourceModeInfo->Type = D3DKMDT_RMT_GRAPHICS; - pVidPnSourceModeInfo->Format.Graphics.PrimSurfSize.cx = m_CurrentModes[SourceId].DispInfo.Width; - pVidPnSourceModeInfo->Format.Graphics.PrimSurfSize.cy = m_CurrentModes[SourceId].DispInfo.Height; - pVidPnSourceModeInfo->Format.Graphics.VisibleRegionSize = pVidPnSourceModeInfo->Format.Graphics.PrimSurfSize; - pVidPnSourceModeInfo->Format.Graphics.Stride = m_CurrentModes[SourceId].DispInfo.Pitch; - pVidPnSourceModeInfo->Format.Graphics.PixelFormat = gBddPixelFormats[PelFmtIdx]; - pVidPnSourceModeInfo->Format.Graphics.ColorBasis = D3DKMDT_CB_SCRGB; - pVidPnSourceModeInfo->Format.Graphics.PixelValueAccessMode = D3DKMDT_PVAM_DIRECT; - - // Add the mode to the source mode set - Status = pVidPnSourceModeSetInterface->pfnAddMode(hVidPnSourceModeSet, pVidPnSourceModeInfo); - if (!NT_SUCCESS(Status)) - { - // If adding the mode failed, release the mode, if this doesn't work there is nothing that can be done, some memory will get leaked - NTSTATUS TempStatus = pVidPnSourceModeSetInterface->pfnReleaseModeInfo(hVidPnSourceModeSet, pVidPnSourceModeInfo); - UNREFERENCED_PARAMETER(TempStatus); - NT_ASSERT(NT_SUCCESS(TempStatus)); - - if (Status != STATUS_GRAPHICS_MODE_ALREADY_IN_MODESET) - { - BDD_LOG_ERROR3("pfnAddMode failed with Status = 0x%I64x, hVidPnSourceModeSet = 0x%I64x, pVidPnSourceModeInfo = 0x%I64x", Status, hVidPnSourceModeSet, pVidPnSourceModeInfo); - return Status; - } - } - } - - UINT WidthMax = m_CurrentModes[SourceId].DispInfo.Width; - UINT HeightMax = m_CurrentModes[SourceId].DispInfo.Height; - - // Add all predefined modes that fit within the bounds of the required (POST) mode - for (UINT ModeIndex = 0; ModeIndex < C_SampleSourceModeMax; ++ModeIndex) - { - if (C_SampleSourceMode[ModeIndex].ModeWidth > WidthMax) - { - break; - } - else if (C_SampleSourceMode[ModeIndex].ModeWidth == WidthMax) - { - if(C_SampleSourceMode[ModeIndex].ModeHeight >= HeightMax) - { - break; - } - } - else - { - if(C_SampleSourceMode[ModeIndex].ModeHeight > HeightMax) - { - continue; - } - } - - // There is only one source format supported by display-only drivers, but more can be added in a - // full WDDM driver if the hardware supports them - for (UINT PelFmtIdx = 0; PelFmtIdx < ARRAYSIZE(gBddPixelFormats); ++PelFmtIdx) - { - // Create new mode info that will be populated - D3DKMDT_VIDPN_SOURCE_MODE* pVidPnSourceModeInfo = NULL; - NTSTATUS Status = pVidPnSourceModeSetInterface->pfnCreateNewModeInfo(hVidPnSourceModeSet, &pVidPnSourceModeInfo); - if (!NT_SUCCESS(Status)) - { - // If failed to create a new mode info, continuing to the next mode and trying again isn't going to be at all helpful, so return - // Also, mode doesn't need to be released since it was never created - BDD_LOG_ERROR2("pfnCreateNewModeInfo failed with Status = 0x%I64x, hVidPnSourceModeSet = 0x%I64x", Status, hVidPnSourceModeSet); - return Status; - } - - // Populate mode info with values from mode at ModeIndex and hard-coded values - // Always report 32 bpp format, this will be color converted during the present if the mode at ModeIndex was < 32bpp - pVidPnSourceModeInfo->Type = D3DKMDT_RMT_GRAPHICS; - pVidPnSourceModeInfo->Format.Graphics.PrimSurfSize.cx = C_SampleSourceMode[ModeIndex].ModeWidth; - pVidPnSourceModeInfo->Format.Graphics.PrimSurfSize.cy = C_SampleSourceMode[ModeIndex].ModeHeight; - pVidPnSourceModeInfo->Format.Graphics.VisibleRegionSize = pVidPnSourceModeInfo->Format.Graphics.PrimSurfSize; - pVidPnSourceModeInfo->Format.Graphics.Stride = 4*C_SampleSourceMode[ModeIndex].ModeWidth; - pVidPnSourceModeInfo->Format.Graphics.PixelFormat = gBddPixelFormats[PelFmtIdx]; - pVidPnSourceModeInfo->Format.Graphics.ColorBasis = D3DKMDT_CB_SCRGB; - pVidPnSourceModeInfo->Format.Graphics.PixelValueAccessMode = D3DKMDT_PVAM_DIRECT; - - // Add the mode to the source mode set - Status = pVidPnSourceModeSetInterface->pfnAddMode(hVidPnSourceModeSet, pVidPnSourceModeInfo); - if (!NT_SUCCESS(Status)) - { - if (Status != STATUS_GRAPHICS_MODE_ALREADY_IN_MODESET) - { - BDD_LOG_ERROR3("pfnAddMode failed with Status = 0x%I64x, hVidPnSourceModeSet = 0x%I64x, pVidPnSourceModeInfo = 0x%I64x", Status, hVidPnSourceModeSet, pVidPnSourceModeInfo); - } - - // If adding the mode failed, release the mode, if this doesn't work there is nothing that can be done, some memory will get leaked, continue to next mode anyway - Status = pVidPnSourceModeSetInterface->pfnReleaseModeInfo(hVidPnSourceModeSet, pVidPnSourceModeInfo); - BDD_ASSERT_CHK(NT_SUCCESS(Status)); - } - } - } - - - return STATUS_SUCCESS; -} - - -// Add the current mode information (acquired from the POST frame buffer) as the target mode. -NTSTATUS BASIC_DISPLAY_DRIVER::AddSingleTargetMode(_In_ CONST DXGK_VIDPNTARGETMODESET_INTERFACE* pVidPnTargetModeSetInterface, - D3DKMDT_HVIDPNTARGETMODESET hVidPnTargetModeSet, - _In_opt_ CONST D3DKMDT_VIDPN_SOURCE_MODE* pVidPnPinnedSourceModeInfo, - D3DDDI_VIDEO_PRESENT_SOURCE_ID SourceId) -{ - PAGED_CODE(); - - D3DKMDT_VIDPN_TARGET_MODE* pVidPnTargetModeInfo = NULL; - NTSTATUS Status = pVidPnTargetModeSetInterface->pfnCreateNewModeInfo(hVidPnTargetModeSet, &pVidPnTargetModeInfo); - if (!NT_SUCCESS(Status)) - { - // If failed to create a new mode info, mode doesn't need to be released since it was never created - BDD_LOG_ERROR2("pfnCreateNewModeInfo failed with Status = 0x%I64x, hVidPnTargetModeSet = 0x%I64x", Status, hVidPnTargetModeSet); - return Status; - } - - pVidPnTargetModeInfo->VideoSignalInfo.VideoStandard = D3DKMDT_VSS_OTHER; - UNREFERENCED_PARAMETER(pVidPnPinnedSourceModeInfo); - pVidPnTargetModeInfo->VideoSignalInfo.TotalSize.cx = m_CurrentModes[SourceId].DispInfo.Width; - pVidPnTargetModeInfo->VideoSignalInfo.TotalSize.cy = m_CurrentModes[SourceId].DispInfo.Height; - pVidPnTargetModeInfo->VideoSignalInfo.ActiveSize = pVidPnTargetModeInfo->VideoSignalInfo.TotalSize; - pVidPnTargetModeInfo->VideoSignalInfo.VSyncFreq.Numerator = D3DKMDT_FREQUENCY_NOTSPECIFIED; - pVidPnTargetModeInfo->VideoSignalInfo.VSyncFreq.Denominator = D3DKMDT_FREQUENCY_NOTSPECIFIED; - pVidPnTargetModeInfo->VideoSignalInfo.HSyncFreq.Numerator = D3DKMDT_FREQUENCY_NOTSPECIFIED; - pVidPnTargetModeInfo->VideoSignalInfo.HSyncFreq.Denominator = D3DKMDT_FREQUENCY_NOTSPECIFIED; - pVidPnTargetModeInfo->VideoSignalInfo.PixelRate = D3DKMDT_FREQUENCY_NOTSPECIFIED; - pVidPnTargetModeInfo->VideoSignalInfo.ScanLineOrdering = D3DDDI_VSSLO_PROGRESSIVE; - // We add this as PREFERRED since it is the only supported target - pVidPnTargetModeInfo->Preference = D3DKMDT_MP_PREFERRED; - - Status = pVidPnTargetModeSetInterface->pfnAddMode(hVidPnTargetModeSet, pVidPnTargetModeInfo); - if (!NT_SUCCESS(Status)) - { - if (Status != STATUS_GRAPHICS_MODE_ALREADY_IN_MODESET) - { - BDD_LOG_ERROR3("pfnAddMode failed with Status = 0x%I64x, hVidPnTargetModeSet = 0x%I64x, pVidPnTargetModeInfo = 0x%I64x", Status, hVidPnTargetModeSet, pVidPnTargetModeInfo); - } - else - { - Status = STATUS_SUCCESS; - } - - // If adding the mode failed, release the mode, if this doesn't work there is nothing that can be done, some memory will get leaked - NTSTATUS TempStatus = pVidPnTargetModeSetInterface->pfnReleaseModeInfo(hVidPnTargetModeSet, pVidPnTargetModeInfo); - UNREFERENCED_PARAMETER(TempStatus); - NT_ASSERT(NT_SUCCESS(TempStatus)); - return Status; - } - else - { - // If AddMode succeeded with something other than STATUS_SUCCESS treat it as such anyway when propagating up - return STATUS_SUCCESS; - } -} - - -NTSTATUS BASIC_DISPLAY_DRIVER::AddSingleMonitorMode(_In_ CONST DXGKARG_RECOMMENDMONITORMODES* CONST pRecommendMonitorModes) -{ - PAGED_CODE(); - - D3DKMDT_MONITOR_SOURCE_MODE* pMonitorSourceMode = NULL; - NTSTATUS Status = pRecommendMonitorModes->pMonitorSourceModeSetInterface->pfnCreateNewModeInfo(pRecommendMonitorModes->hMonitorSourceModeSet, &pMonitorSourceMode); - if (!NT_SUCCESS(Status)) - { - // If failed to create a new mode info, mode doesn't need to be released since it was never created - BDD_LOG_ERROR2("pfnCreateNewModeInfo failed with Status = 0x%I64x, hMonitorSourceModeSet = 0x%I64x", Status, pRecommendMonitorModes->hMonitorSourceModeSet); - return Status; - } - - D3DDDI_VIDEO_PRESENT_SOURCE_ID CorrespondingSourceId = FindSourceForTarget(pRecommendMonitorModes->VideoPresentTargetId, TRUE); - - // Since we don't know the real monitor timing information, just use the current display mode (from the POST device) with unknown frequencies - pMonitorSourceMode->VideoSignalInfo.VideoStandard = D3DKMDT_VSS_OTHER; - pMonitorSourceMode->VideoSignalInfo.TotalSize.cx = m_CurrentModes[CorrespondingSourceId].DispInfo.Width; - pMonitorSourceMode->VideoSignalInfo.TotalSize.cy = m_CurrentModes[CorrespondingSourceId].DispInfo.Height; - pMonitorSourceMode->VideoSignalInfo.ActiveSize = pMonitorSourceMode->VideoSignalInfo.TotalSize; - pMonitorSourceMode->VideoSignalInfo.VSyncFreq.Numerator = D3DKMDT_FREQUENCY_NOTSPECIFIED; - pMonitorSourceMode->VideoSignalInfo.VSyncFreq.Denominator = D3DKMDT_FREQUENCY_NOTSPECIFIED; - pMonitorSourceMode->VideoSignalInfo.HSyncFreq.Numerator = D3DKMDT_FREQUENCY_NOTSPECIFIED; - pMonitorSourceMode->VideoSignalInfo.HSyncFreq.Denominator = D3DKMDT_FREQUENCY_NOTSPECIFIED; - pMonitorSourceMode->VideoSignalInfo.PixelRate = D3DKMDT_FREQUENCY_NOTSPECIFIED; - pMonitorSourceMode->VideoSignalInfo.ScanLineOrdering = D3DDDI_VSSLO_PROGRESSIVE; - - // We set the preference to PREFERRED since this is the only supported mode - pMonitorSourceMode->Origin = D3DKMDT_MCO_DRIVER; - pMonitorSourceMode->Preference = D3DKMDT_MP_PREFERRED; - pMonitorSourceMode->ColorBasis = D3DKMDT_CB_SRGB; - pMonitorSourceMode->ColorCoeffDynamicRanges.FirstChannel = 8; - pMonitorSourceMode->ColorCoeffDynamicRanges.SecondChannel = 8; - pMonitorSourceMode->ColorCoeffDynamicRanges.ThirdChannel = 8; - pMonitorSourceMode->ColorCoeffDynamicRanges.FourthChannel = 8; - - Status = pRecommendMonitorModes->pMonitorSourceModeSetInterface->pfnAddMode(pRecommendMonitorModes->hMonitorSourceModeSet, pMonitorSourceMode); - if (!NT_SUCCESS(Status)) - { - if (Status != STATUS_GRAPHICS_MODE_ALREADY_IN_MODESET) - { - BDD_LOG_ERROR3("pfnAddMode failed with Status = 0x%I64x, hMonitorSourceModeSet = 0x%I64x, pMonitorSourceMode = 0x%I64x", - Status, pRecommendMonitorModes->hMonitorSourceModeSet, pMonitorSourceMode); - } - else - { - Status = STATUS_SUCCESS; - } - - // If adding the mode failed, release the mode, if this doesn't work there is nothing that can be done, some memory will get leaked - NTSTATUS TempStatus = pRecommendMonitorModes->pMonitorSourceModeSetInterface->pfnReleaseModeInfo(pRecommendMonitorModes->hMonitorSourceModeSet, pMonitorSourceMode); - UNREFERENCED_PARAMETER(TempStatus); - NT_ASSERT(NT_SUCCESS(TempStatus)); - return Status; - } - else - { - // If AddMode succeeded with something other than STATUS_SUCCESS treat it as such anyway when propagating up - return STATUS_SUCCESS; - } -} - diff --git a/video/KMDOD/bdd_errorlog.hxx b/video/KMDOD/bdd_errorlog.hxx deleted file mode 100644 index f9c394f8..00000000 --- a/video/KMDOD/bdd_errorlog.hxx +++ /dev/null @@ -1,84 +0,0 @@ -/******************************Module*Header*******************************\ -* Module Name: BDD_ErrorLog.hxx -* -* Basic Display Driver Logging Macros -* -* -* Copyright (c) 2010 Microsoft Corporation -* -\**************************************************************************/ -#ifndef _BDD_ERRORLOG_HXX_ -#define _BDD_ERRORLOG_HXX_ - -#define BDD_LOG_ERROR0(Msg) -#define BDD_LOG_ERROR1(Msg,Param1) -#define BDD_LOG_ERROR2(Msg,Param1,Param2) -#define BDD_LOG_ERROR3(Msg,Param1,Param2,Param3) -#define BDD_LOG_ERROR4(Msg,Param1,Param2,Param3,Param4) -#define BDD_LOG_ERROR5(Msg,Param1,Param2,Param3,Param4,Param5) - -// -// Warnings -// - -#define BDD_LOG_WARNING0(Msg) -#define BDD_LOG_WARNING1(Msg,Param1) -#define BDD_LOG_WARNING2(Msg,Param1,Param2) -#define BDD_LOG_WARNING3(Msg,Param1,Param2,Param3) -#define BDD_LOG_WARNING4(Msg,Param1,Param2,Param3,Param4) -#define BDD_LOG_WARNING5(Msg,Param1,Param2,Param3,Param4,Param5) - -// -// Events (i.e. low-frequency tracing) -// - -#define BDD_LOG_EVENT0(Msg) -#define BDD_LOG_EVENT1(Msg,Param1) -#define BDD_LOG_EVENT2(Msg,Param1,Param2) -#define BDD_LOG_EVENT3(Msg,Param1,Param2,Param3) -#define BDD_LOG_EVENT4(Msg,Param1,Param2,Param3,Param4) -#define BDD_LOG_EVENT5(Msg,Param1,Param2,Param3,Param4,Param5) - -// -// Information (i.e. high-frequency tracing) -// - -#define BDD_LOG_INFORMATION0(Msg) -#define BDD_LOG_INFORMATION1(Msg,Param1) -#define BDD_LOG_INFORMATION2(Msg,Param1,Param2) -#define BDD_LOG_INFORMATION3(Msg,Param1,Param2,Param3) -#define BDD_LOG_INFORMATION4(Msg,Param1,Param2,Param3,Param4) -#define BDD_LOG_INFORMATION5(Msg,Param1,Param2,Param3,Param4,Param5) - -// -// Low resource logging macros. -// - -#define BDD_LOG_LOW_RESOURCE0(Msg) -#define BDD_LOG_LOW_RESOURCE1(Msg,Param1) -#define BDD_LOG_LOW_RESOURCE2(Msg,Param1,Param2) -#define BDD_LOG_LOW_RESOURCE3(Msg,Param1,Param2,Param3) -#define BDD_LOG_LOW_RESOURCE4(Msg,Param1,Param2,Param3,Param4) -#define BDD_LOG_LOW_RESOURCE5(Msg,Param1,Param2,Param3,Param4,Param5) - -// -// Assertion logging macros. -// - -#define BDD_LOG_ASSERTION0(Msg) NT_ASSERT(FALSE) -#define BDD_LOG_ASSERTION1(Msg,Param1) NT_ASSERT(FALSE) -#define BDD_LOG_ASSERTION2(Msg,Param1,Param2) NT_ASSERT(FALSE) -#define BDD_LOG_ASSERTION3(Msg,Param1,Param2,Param3) NT_ASSERT(FALSE) -#define BDD_LOG_ASSERTION4(Msg,Param1,Param2,Param3,Param4) NT_ASSERT(FALSE) -#define BDD_LOG_ASSERTION5(Msg,Param1,Param2,Param3,Param4,Param5) NT_ASSERT(FALSE) -#define BDD_ASSERT(exp) {if (!(exp)) {BDD_LOG_ASSERTION0(#exp);}} - -#if DBG -#define BDD_ASSERT_CHK(exp) BDD_ASSERT(exp) -#else -#define BDD_ASSERT_CHK(exp) {} -#endif - - -#endif //_BDD_ERRORLOG_HXX_ - diff --git a/video/KMDOD/bdd_util.cxx b/video/KMDOD/bdd_util.cxx deleted file mode 100644 index a80dc4d1..00000000 --- a/video/KMDOD/bdd_util.cxx +++ /dev/null @@ -1,115 +0,0 @@ -/******************************Module*Header*******************************\ -* Module Name: bdd_util.cxx -* -* Basic Display Driver utility functions -* -* Created: 29-Mar-2011 -* Author: Amos Eshel [amosesh] -* -* Copyright (c) 2011 Microsoft Corporation -\**************************************************************************/ - -#include "BDD.hxx" - - -#pragma code_seg("PAGE") - -// -// EDID validation -// - -BOOLEAN IsEdidHeaderValid(_In_reads_bytes_(EDID_V1_BLOCK_SIZE) const BYTE* pEdid) -{ - PAGED_CODE(); - - static const UCHAR EDID1Header[8] = {0,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0}; - return memcmp(pEdid, EDID1Header, sizeof(EDID1Header)) == 0; -} - -BOOLEAN IsEdidChecksumValid(_In_reads_bytes_(EDID_V1_BLOCK_SIZE) const BYTE* pEdid) -{ - PAGED_CODE(); - - BYTE CheckSum = 0; - for (const BYTE* pEdidStart = pEdid; pEdidStart < (pEdid + EDID_V1_BLOCK_SIZE); ++pEdidStart) - { - CheckSum += *pEdidStart; - } - - return CheckSum == 0; -} - -// -// Frame buffer map/unmap -// - -NTSTATUS -MapFrameBuffer( - _In_ PHYSICAL_ADDRESS PhysicalAddress, - _In_ ULONG Length, - _Outptr_result_bytebuffer_(Length) VOID** VirtualAddress) -{ - PAGED_CODE(); - - // - // Check for parameters - // - if ((PhysicalAddress.QuadPart == (ULONGLONG)0) || - (Length == 0) || - (VirtualAddress == NULL)) - { - BDD_LOG_ERROR3("One of PhysicalAddress.QuadPart (0x%I64x), Length (0x%I64x), VirtualAddress (0x%I64x) is NULL or 0", - PhysicalAddress.QuadPart, Length, VirtualAddress); - return STATUS_INVALID_PARAMETER; - } - - *VirtualAddress = MmMapIoSpace(PhysicalAddress, - Length, - MmWriteCombined); - if (*VirtualAddress == NULL) - { - // The underlying call to MmMapIoSpace failed. This may be because, MmWriteCombined - // isn't supported, so try again with MmNonCached - - *VirtualAddress = MmMapIoSpace(PhysicalAddress, - Length, - MmNonCached); - if (*VirtualAddress == NULL) - { - BDD_LOG_LOW_RESOURCE1("MmMapIoSpace returned a NULL buffer when trying to allocate 0x%I64x bytes", Length); - return STATUS_NO_MEMORY; - } - } - - return STATUS_SUCCESS; -} - -NTSTATUS -UnmapFrameBuffer( - _In_reads_bytes_(Length) VOID* VirtualAddress, - _In_ ULONG Length) -{ - PAGED_CODE(); - - - // - // Check for parameters - // - if ((VirtualAddress == NULL) && (Length == 0)) - { - // Allow this function to be called when there's no work to do, and treat as successful - return STATUS_SUCCESS; - } - else if ((VirtualAddress == NULL) || (Length == 0)) - { - BDD_LOG_ERROR2("Only one of Length (0x%I64x), VirtualAddress (0x%I64x) is NULL or 0", - Length, VirtualAddress); - return STATUS_INVALID_PARAMETER; - } - - MmUnmapIoSpace(VirtualAddress, - Length); - - return STATUS_SUCCESS; -} - diff --git a/video/KMDOD/bltfuncs.cxx b/video/KMDOD/bltfuncs.cxx deleted file mode 100644 index 9df7ee6b..00000000 --- a/video/KMDOD/bltfuncs.cxx +++ /dev/null @@ -1,346 +0,0 @@ -/******************************Module*Header*******************************\ - * Module Name: BltFuncs.cxx - * - * Basic Display Driver copying functionality - * - * - * Copyright (c) 2010 Microsoft Corporation -\**************************************************************************/ - -#include "BDD.hxx" - -// For the following macros, c must be a UCHAR. -#define UPPER_6_BITS(c) (((c) & rMaskTable[6 - 1]) >> 2) -#define UPPER_5_BITS(c) (((c) & rMaskTable[5 - 1]) >> 3) -#define LOWER_6_BITS(c) (((BYTE)(c)) & lMaskTable[BITS_PER_BYTE - 6]) -#define LOWER_5_BITS(c) (((BYTE)(c)) & lMaskTable[BITS_PER_BYTE - 5]) - - -#define SHIFT_FOR_UPPER_5_IN_565 (6 + 5) -#define SHIFT_FOR_MIDDLE_6_IN_565 (5) -#define SHIFT_UPPER_5_IN_565_BACK ((BITS_PER_BYTE * 2) + (BITS_PER_BYTE - 5)) -#define SHIFT_MIDDLE_6_IN_565_BACK ((BITS_PER_BYTE * 1) + (BITS_PER_BYTE - 6)) -#define SHIFT_LOWER_5_IN_565_BACK ((BITS_PER_BYTE * 0) + (BITS_PER_BYTE - 5)) - -// For the following macros, pPixel must be a BYTE* pointing to the start of a 32 bit pixel -#define CONVERT_32BPP_TO_16BPP(pPixel) ((UPPER_5_BITS(pPixel[2]) << SHIFT_FOR_UPPER_5_IN_565) | \ - (UPPER_6_BITS(pPixel[1]) << SHIFT_FOR_MIDDLE_6_IN_565) | \ - (UPPER_5_BITS(pPixel[0]))) - -// 8bpp is done with 6 levels per color channel since this gives true grays, even if it leaves 40 empty palette entries -// The 6 levels per color is the reason for dividing below by 43 (43 * 6 == 258, closest multiple of 6 to 256) -// It is also the reason for multiplying the red channel by 36 (== 6*6) and the green channel by 6, as this is the -// equivalent to bit shifting in a 3:3:2 model. Changes to this must be reflected in vesasup.cxx with the Blues/Greens/Reds arrays -#define CONVERT_32BPP_TO_8BPP(pPixel) (((pPixel[2] / 43) * 36) + \ - ((pPixel[1] / 43) * 6) + \ - ((pPixel[0] / 43))) - -// 4bpp is done with strict grayscale since this has been found to be usable -// 30% of the red value, 59% of the green value, and 11% of the blue value is the standard way to convert true color to grayscale -#define CONVERT_32BPP_TO_4BPP(pPixel) ((BYTE)(((pPixel[2] * 30) + \ - (pPixel[1] * 59) + \ - (pPixel[0] * 11)) / (100 * 16))) - - -// For the following macro, Pixel must be a WORD representing a 16 bit pixel -#define CONVERT_16BPP_TO_32BPP(Pixel) (((ULONG)LOWER_5_BITS((Pixel) >> SHIFT_FOR_UPPER_5_IN_565) << SHIFT_UPPER_5_IN_565_BACK) | \ - ((ULONG)LOWER_6_BITS((Pixel) >> SHIFT_FOR_MIDDLE_6_IN_565) << SHIFT_MIDDLE_6_IN_565_BACK) | \ - ((ULONG)LOWER_5_BITS((Pixel)) << SHIFT_LOWER_5_IN_565_BACK)) - -#pragma code_seg(push) -#pragma code_seg() -// BEGIN: Non-Paged Code - -// Bit is 1 from Idx to end of byte, with bit count starting at high order -BYTE lMaskTable[BITS_PER_BYTE] = {0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01}; - -// Bit is 1 from Idx to start of byte, with bit count starting at high order -BYTE rMaskTable[BITS_PER_BYTE] = {0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff}; - -// Bit of Idx is 1, with bit count starting at high order -BYTE PixelMask[BITS_PER_BYTE] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01}; - -/****************************Internal*Routine******************************\ - * CopyBits32_32 - * - * - * Copies rectangles from one surface to another. Both surfaces must have - * the same resolution. - * - * OffsetX, OffsetY - to add to the rectangle coordinates. - * - * Copied from %SDXROOT%\windows\Core\dxkernel\cdd\enable.cxx (CopySurfBits) - * -\**************************************************************************/ - -VOID CopyBits32_32( - BLT_INFO* pDst, - CONST BLT_INFO* pSrc, - UINT NumRects, - _In_reads_(NumRects) CONST RECT *pRects) -{ - NT_ASSERT((pDst->BitsPerPel == 32) && - (pSrc->BitsPerPel == 32)); - NT_ASSERT((pDst->Rotation == D3DKMDT_VPPR_IDENTITY) && - (pSrc->Rotation == D3DKMDT_VPPR_IDENTITY)); - - for (UINT iRect = 0; iRect < NumRects; iRect++) - { - CONST RECT* pRect = &pRects[iRect]; - - NT_ASSERT(pRect->right >= pRect->left); - NT_ASSERT(pRect->bottom >= pRect->top); - - UINT NumPixels = pRect->right - pRect->left; - UINT NumRows = pRect->bottom - pRect->top; - UINT BytesToCopy = NumPixels * 4; - BYTE* pStartDst = ((BYTE*)pDst->pBits + - (pRect->top + pDst->Offset.y) * pDst->Pitch + - (pRect->left + pDst->Offset.x) * 4); - CONST BYTE* pStartSrc = ((BYTE*)pSrc->pBits + - (pRect->top + pSrc->Offset.y) * pSrc->Pitch + - (pRect->left + pSrc->Offset.x) * 4); - - for (UINT i = 0; i < NumRows; ++i) - { - RtlCopyMemory(pStartDst, pStartSrc, BytesToCopy); - pStartDst += pDst->Pitch; - pStartSrc += pSrc->Pitch; - } - } -} - - -VOID GetPitches(_In_ CONST BLT_INFO* pBltInfo, _Out_ LONG* pPixelPitch, _Out_ LONG* pRowPitch) -{ - switch (pBltInfo->Rotation) - { - case D3DKMDT_VPPR_IDENTITY: - { - *pPixelPitch = (pBltInfo->BitsPerPel / BITS_PER_BYTE); - *pRowPitch = pBltInfo->Pitch; - return; - } - case D3DKMDT_VPPR_ROTATE90: - { - *pPixelPitch = -((LONG)pBltInfo->Pitch); - *pRowPitch = (pBltInfo->BitsPerPel / BITS_PER_BYTE); - return; - } - case D3DKMDT_VPPR_ROTATE180: - { - *pPixelPitch = -((LONG)pBltInfo->BitsPerPel / BITS_PER_BYTE); - *pRowPitch = -((LONG)pBltInfo->Pitch); - return; - } - case D3DKMDT_VPPR_ROTATE270: - { - *pPixelPitch = pBltInfo->Pitch; - *pRowPitch = -((LONG)pBltInfo->BitsPerPel / BITS_PER_BYTE); - return; - } - default: - { - BDD_LOG_ASSERTION1("Invalid rotation (0x%I64x) specified", pBltInfo->Rotation); - *pPixelPitch = 0; - *pRowPitch = 0; - return; - } - } -} - -BYTE* GetRowStart(_In_ CONST BLT_INFO* pBltInfo, CONST RECT* pRect) -{ - BYTE* pRet = NULL; - LONG OffLeft = pRect->left + pBltInfo->Offset.x; - LONG OffTop = pRect->top + pBltInfo->Offset.y; - LONG BytesPerPixel = (pBltInfo->BitsPerPel / BITS_PER_BYTE); - switch (pBltInfo->Rotation) - { - case D3DKMDT_VPPR_IDENTITY: - { - pRet = ((BYTE*)pBltInfo->pBits + - OffTop * pBltInfo->Pitch + - OffLeft * BytesPerPixel); - break; - } - case D3DKMDT_VPPR_ROTATE90: - { - pRet = ((BYTE*)pBltInfo->pBits + - (pBltInfo->Height - 1 - OffLeft) * pBltInfo->Pitch + - OffTop * BytesPerPixel); - break; - } - case D3DKMDT_VPPR_ROTATE180: - { - pRet = ((BYTE*)pBltInfo->pBits + - (pBltInfo->Height - 1 - OffTop) * pBltInfo->Pitch + - (pBltInfo->Width - 1 - OffLeft) * BytesPerPixel); - break; - } - case D3DKMDT_VPPR_ROTATE270: - { - pRet = ((BYTE*)pBltInfo->pBits + - OffLeft * pBltInfo->Pitch + - (pBltInfo->Width - 1 - OffTop) * BytesPerPixel); - break; - } - default: - { - BDD_LOG_ASSERTION1("Invalid rotation (0x%I64x) specified", pBltInfo->Rotation); - break; - } - } - - return pRet; -} - -/****************************Internal*Routine******************************\ - * CopyBitsGeneric - * - * - * Blt function which can handle a rotated dst/src, offset rects in dst/src - * and bpp combinations of: - * dst | src - * 32 | 32 // For identity rotation this is much faster in CopyBits32_32 - * 32 | 24 - * 32 | 16 - * 24 | 32 - * 16 | 32 - * 8 | 32 - * 24 | 24 // untested - * -\**************************************************************************/ - -VOID CopyBitsGeneric( - BLT_INFO* pDst, - CONST BLT_INFO* pSrc, - UINT NumRects, - _In_reads_(NumRects) CONST RECT *pRects) -{ - LONG DstPixelPitch = 0; - LONG DstRowPitch = 0; - LONG SrcPixelPitch = 0; - LONG SrcRowPitch = 0; - - GetPitches(pDst, &DstPixelPitch, &DstRowPitch); - GetPitches(pSrc, &SrcPixelPitch, &SrcRowPitch); - - for (UINT iRect = 0; iRect < NumRects; iRect++) - { - CONST RECT* pRect = &pRects[iRect]; - - NT_ASSERT(pRect->right >= pRect->left); - NT_ASSERT(pRect->bottom >= pRect->top); - - UINT NumPixels = pRect->right - pRect->left; - UINT NumRows = pRect->bottom - pRect->top; - - BYTE* pDstRow = GetRowStart(pDst, pRect); - CONST BYTE* pSrcRow = GetRowStart(pSrc, pRect); - - for (UINT y=0; y < NumRows; y++) - { - BYTE* pDstPixel = pDstRow; - CONST BYTE* pSrcPixel = pSrcRow; - - for (UINT x=0; x < NumPixels; x++) - { - if ((pDst->BitsPerPel == 24) || - (pSrc->BitsPerPel == 24)) - { - pDstPixel[0] = pSrcPixel[0]; - pDstPixel[1] = pSrcPixel[1]; - pDstPixel[2] = pSrcPixel[2]; - // pPixel[3] is the alpha channel and is ignored for whichever of Src/Dst is 32bpp - } - else if (pDst->BitsPerPel == 32) - { - if (pSrc->BitsPerPel == 32) - { - UINT32* pDstPixelAs32 = (UINT32*)pDstPixel; - UINT32* pSrcPixelAs32 = (UINT32*)pSrcPixel; - *pDstPixelAs32 = *pSrcPixelAs32; - } - else if (pSrc->BitsPerPel == 16) - { - UINT32* pDstPixelAs32 = (UINT32*)pDstPixel; - UINT16* pSrcPixelAs16 = (UINT16*)pSrcPixel; - - *pDstPixelAs32 = CONVERT_16BPP_TO_32BPP(*pSrcPixelAs16); - } - else - { - // Invalid pSrc->BitsPerPel on a pDst->BitsPerPel of 32 - NT_ASSERT(FALSE); - } - } - else if (pDst->BitsPerPel == 16) - { - NT_ASSERT(pSrc->BitsPerPel == 32); - - UINT16* pDstPixelAs16 = (UINT16*)pDstPixel; - *pDstPixelAs16 = CONVERT_32BPP_TO_16BPP(pSrcPixel); - } - else if (pDst->BitsPerPel == 8) - { - NT_ASSERT(pSrc->BitsPerPel == 32); - - *pDstPixel = CONVERT_32BPP_TO_8BPP(pSrcPixel); - } - else - { - // Invalid pDst->BitsPerPel - NT_ASSERT(FALSE); - } - pDstPixel += DstPixelPitch; - pSrcPixel += SrcPixelPitch; - } - - pDstRow += DstRowPitch; - pSrcRow += SrcRowPitch; - } - } -} - -/****************************Internal*Routine******************************\ - * BltBits - * - * - * Logic to decide which of the above functions to call based on Rotation/BPP - * -\**************************************************************************/ -VOID BltBits( - BLT_INFO* pDst, - CONST BLT_INFO* pSrc, - UINT NumRects, - _In_reads_(NumRects) CONST RECT *pRects) -{ - // pSrc->pBits might be coming from user-mode. User-mode addresses when accessed by kernel need to be protected by a __try/__except. - // This usage is redundant in the sample driver since it is already being used for MmProbeAndLockPages. However, it is very important - // to have this in place and to make sure developers don't miss it, it is in these two locations. - __try - { - if (pDst->BitsPerPel == 32 && - pSrc->BitsPerPel == 32 && - pDst->Rotation == D3DKMDT_VPPR_IDENTITY && - pSrc->Rotation == D3DKMDT_VPPR_IDENTITY) - { - // This is by far the most common copy function being called - CopyBits32_32(pDst, pSrc, NumRects, pRects); - } - else - { - CopyBitsGeneric(pDst, pSrc, NumRects, pRects); - } - } - #pragma prefast(suppress: __WARNING_EXCEPTIONEXECUTEHANDLER, "try/except is only able to protect against user-mode errors and these are the only errors we try to catch here"); - __except(EXCEPTION_EXECUTE_HANDLER) - { - BDD_LOG_ERROR2("Either dst (0x%I64x) or src (0x%I64x) bits encountered exception during access.", pDst->pBits, pSrc->pBits); - } -} - -// END: Non-Paged Code -#pragma code_seg(pop) - diff --git a/video/KMDOD/blthw.cxx b/video/KMDOD/blthw.cxx deleted file mode 100644 index 2e6d2e5d..00000000 --- a/video/KMDOD/blthw.cxx +++ /dev/null @@ -1,556 +0,0 @@ -/******************************Module*Header*******************************\ -* Module Name: blthw.cxx -* -* Sample display driver functions for a HW blt simulation. This file is -* only provided to simulate how a real hardware-accelerated display-only -* driver functions, and should not be used in a real driver. -* -* Copyright (c) 2011 Microsoft Corporation -\**************************************************************************/ - -#include "BDD.hxx" - -typedef struct -{ - CONST DXGKRNL_INTERFACE* DxgkInterface; - DXGKARGCB_NOTIFY_INTERRUPT_DATA NotifyInterrupt; -} SYNC_NOTIFY_INTERRUPT; - -KSYNCHRONIZE_ROUTINE SynchronizeVidSchNotifyInterrupt; - -BOOLEAN SynchronizeVidSchNotifyInterrupt(_In_opt_ PVOID params) -{ - // This routine is non-paged code called at the device interrupt level (DIRQL) - // to notify VidSch and schedule a DPC. It is meant as a demonstration of handling - // a real hardware interrupt, even though it is actually called from asynchronous - // present worker threads in this sample. - SYNC_NOTIFY_INTERRUPT* pParam = reinterpret_cast(params); - - // The context is known to be non-NULL - __analysis_assume(pParam != NULL); - - // Update driver information related to fences - switch(pParam->NotifyInterrupt.InterruptType) - { - case DXGK_INTERRUPT_DISPLAYONLY_VSYNC: - case DXGK_INTERRUPT_DISPLAYONLY_PRESENT_PROGRESS: - break; - default: - NT_ASSERT(FALSE); - return FALSE; - } - - // Callback OS to report about the interrupt - pParam->DxgkInterface->DxgkCbNotifyInterrupt(pParam->DxgkInterface->DeviceHandle,&pParam->NotifyInterrupt); - - // Now queue a DPC for this interrupt (to callback schedule at DCP level and let it do more work there) - // DxgkCbQueueDpc can return FALSE if there is already a DPC queued - // this is an acceptable condition - pParam->DxgkInterface->DxgkCbQueueDpc(pParam->DxgkInterface->DeviceHandle); - - return TRUE; -} - -#pragma code_seg("PAGE") - -KSTART_ROUTINE HwContextWorkerThread; - -struct DoPresentMemory -{ - PVOID DstAddr; - UINT DstStride; - ULONG DstBitPerPixel; - UINT SrcWidth; - UINT SrcHeight; - BYTE* SrcAddr; - LONG SrcPitch; - ULONG NumMoves; // in: Number of screen to screen moves - D3DKMT_MOVE_RECT* Moves; // in: Point to the list of moves - ULONG NumDirtyRects; // in: Number of direct rects - RECT* DirtyRect; // in: Point to the list of dirty rects - D3DKMDT_VIDPN_PRESENT_PATH_ROTATION Rotation; - BOOLEAN SynchExecution; - D3DDDI_VIDEO_PRESENT_SOURCE_ID SourceID; - HANDLE hAdapter; - PMDL Mdl; - BDD_HWBLT* DisplaySource; -}; - -void -HwExecutePresentDisplayOnly( - HANDLE Context); - -NTSTATUS -StartHwBltPresentWorkerThread( - _In_ PKSTART_ROUTINE StartRoutine, - _In_ _When_(return==0, __drv_aliasesMem) PVOID StartContext) -/*++ - - Routine Description: - - This routine creates the worker thread to execute a single present - command. Creating a new thread on every asynchronous present is not - efficient, but this file is only meant as a simulation, not an example - of implementation. - - Arguments: - - StartRoutine - start routine - StartContext - start context - - Return Value: - - Status - ---*/ -{ - PAGED_CODE(); - - OBJECT_ATTRIBUTES ObjectAttributes; - InitializeObjectAttributes(&ObjectAttributes, NULL, OBJ_KERNEL_HANDLE, NULL, NULL); - HANDLE hWorkerThread = NULL; - - // copy data from the context which is need here, as it will be deleted in separate thread - DoPresentMemory* ctx = reinterpret_cast(StartContext); - BDD_HWBLT* displaySource = ctx->DisplaySource; - - NTSTATUS Status = PsCreateSystemThread( - &hWorkerThread, - THREAD_ALL_ACCESS, - &ObjectAttributes, - NULL, - NULL, - StartRoutine, - StartContext); - - if (!NT_SUCCESS(Status)) - { - return Status; - } - - - // wait for thread to start - infinite wait - - // need to make sure the tread is running before OS stars submitting the work items to it - KeWaitForSingleObject(&displaySource->m_hThreadStartupEvent, Executive, KernelMode, FALSE, NULL); - - // Handle is passed to the parent object which must close it - displaySource->SetPresentWorkerThreadInfo(hWorkerThread); - - // Resume context thread, this is done by setting the event the thread is waiting on - KeSetEvent(&displaySource->m_hThreadSuspendEvent, 0, FALSE); - - return STATUS_PENDING; -} - -BDD_HWBLT::BDD_HWBLT():m_DevExt (NULL), - m_SynchExecution(TRUE), - m_hPresentWorkerThread(NULL), - m_pPresentWorkerThread(NULL) -{ - PAGED_CODE(); - - KeInitializeEvent(&m_hThreadStartupEvent, NotificationEvent, FALSE); - KeInitializeEvent(&m_hThreadSuspendEvent, SynchronizationEvent, FALSE); - -} - - -BDD_HWBLT::~BDD_HWBLT() -/*++ - - Routine Description: - - This routine waits on present worker thread to exit before - destroying the object - - Arguments: - - None - - Return Value: - - None - ---*/ -{ - PAGED_CODE(); - - // make sure the worker thread has exited - SetPresentWorkerThreadInfo(NULL); -} - -#pragma warning(push) -#pragma warning(disable:26135) // The function doesn't lock anything - -void -BDD_HWBLT::SetPresentWorkerThreadInfo( - HANDLE hWorkerThread) -/*++ - - Routine Description: - - The method is updating present worker information - It is called in following cases: - - In ExecutePresent to update worker thread information - - In Dtor to wait on worker thread to exit - - Arguments: - - hWorkerThread - handle of the present worker thread - - Return Value: - - None - ---*/ -{ - - PAGED_CODE(); - - if (m_pPresentWorkerThread) - { - // Wait for thread to exit - KeWaitForSingleObject(m_pPresentWorkerThread, Executive, KernelMode, - FALSE, NULL); - // Dereference thread object - ObDereferenceObject(m_pPresentWorkerThread); - m_pPresentWorkerThread = NULL; - - NT_ASSERT(m_hPresentWorkerThread); - ZwClose(m_hPresentWorkerThread); - m_hPresentWorkerThread = NULL; - } - - if (hWorkerThread) - { - // Make sure that thread's handle would be valid even if the thread exited - ObReferenceObjectByHandle(hWorkerThread, THREAD_ALL_ACCESS, NULL, - KernelMode, &m_pPresentWorkerThread, NULL); - NT_ASSERT(m_pPresentWorkerThread); - m_hPresentWorkerThread = hWorkerThread; - } - -} -#pragma warning(pop) - -NTSTATUS -BDD_HWBLT::ExecutePresentDisplayOnly( - _In_ BYTE* DstAddr, - _In_ UINT DstBitPerPixel, - _In_ BYTE* SrcAddr, - _In_ UINT SrcBytesPerPixel, - _In_ LONG SrcPitch, - _In_ ULONG NumMoves, - _In_ D3DKMT_MOVE_RECT* Moves, - _In_ ULONG NumDirtyRects, - _In_ RECT* DirtyRect, - _In_ D3DKMDT_VIDPN_PRESENT_PATH_ROTATION Rotation) -/*++ - - Routine Description: - - The method creates present worker thread and provides context - for it filled with present commands - - Arguments: - - DstAddr - address of destination surface - DstBitPerPixel - color depth of destination surface - SrcAddr - address of source surface - SrcBytesPerPixel - bytes per pixel of source surface - SrcPitch - source surface pitch (bytes in a row) - NumMoves - number of moves to be copied - Moves - moves' data - NumDirtyRects - number of rectangles to be copied - DirtyRect - rectangles' data - Rotation - roatation to be performed when executing copy - CallBack - callback for present worker thread to report execution status - - Return Value: - - Status - ---*/ -{ - - PAGED_CODE(); - - NTSTATUS Status = STATUS_SUCCESS; - - SIZE_T sizeMoves = NumMoves*sizeof(D3DKMT_MOVE_RECT); - SIZE_T sizeRects = NumDirtyRects*sizeof(RECT); - SIZE_T size = sizeof(DoPresentMemory) + sizeMoves + sizeRects; - - DoPresentMemory* ctx = reinterpret_cast - (new (PagedPool) BYTE[size]); - - if (!ctx) - { - return STATUS_NO_MEMORY; - } - - RtlZeroMemory(ctx,size); - - const CURRENT_BDD_MODE* pModeCur = m_DevExt->GetCurrentMode(m_SourceId); - - ctx->DstAddr = DstAddr; - ctx->DstBitPerPixel = DstBitPerPixel; - ctx->DstStride = pModeCur->DispInfo.Pitch; - ctx->SrcWidth = pModeCur->SrcModeWidth; - ctx->SrcHeight = pModeCur->SrcModeHeight; - ctx->SrcAddr = NULL; - ctx->SrcPitch = SrcPitch; - ctx->Rotation = Rotation; - ctx->NumMoves = NumMoves; - ctx->Moves = Moves; - ctx->NumDirtyRects = NumDirtyRects; - ctx->DirtyRect = DirtyRect; - ctx->SourceID = m_SourceId; - ctx->hAdapter = m_DevExt; - ctx->Mdl = NULL; - ctx->DisplaySource = this; - - // Alternate between synch and asynch execution, for demonstrating - // that a real hardware implementation can do either - m_SynchExecution = !m_SynchExecution; - - ctx->SynchExecution = m_SynchExecution; - - { - // Map Source into kernel space, as Blt will be executed by system worker thread - UINT sizeToMap = SrcBytesPerPixel*pModeCur->SrcModeWidth*pModeCur->SrcModeHeight; - - PMDL mdl = IoAllocateMdl((PVOID)SrcAddr, sizeToMap, FALSE, FALSE, NULL); - if(!mdl) - { - return STATUS_INSUFFICIENT_RESOURCES; - } - - KPROCESSOR_MODE AccessMode = static_cast(( SrcAddr <= - (BYTE* const) MM_USER_PROBE_ADDRESS)?UserMode:KernelMode); - __try - { - // Probe and lock the pages of this buffer in physical memory. - // We need only IoReadAccess. - MmProbeAndLockPages(mdl, AccessMode, IoReadAccess); - } - #pragma prefast(suppress: __WARNING_EXCEPTIONEXECUTEHANDLER, "try/except is only able to protect against user-mode errors and these are the only errors we try to catch here"); - __except(EXCEPTION_EXECUTE_HANDLER) - { - Status = GetExceptionCode(); - IoFreeMdl(mdl); - return Status; - } - - // Map the physical pages described by the MDL into system space. - // Note: double mapping the buffer this way causes lot of system - // overhead for large size buffers. - ctx->SrcAddr = reinterpret_cast - (MmGetSystemAddressForMdlSafe(mdl, NormalPagePriority )); - - if(!ctx->SrcAddr) { - Status = STATUS_INSUFFICIENT_RESOURCES; - MmUnlockPages(mdl); - IoFreeMdl(mdl); - return Status; - } - - // Save Mdl to unmap and unlock the pages in worker thread - ctx->Mdl = mdl; - } - - BYTE* rects = reinterpret_cast(ctx+1); - - // copy moves and update pointer - if (Moves) - { - memcpy(rects,Moves,sizeMoves); - ctx->Moves = reinterpret_cast(rects); - rects += sizeMoves; - } - - // copy dirty rects and update pointer - if (DirtyRect) - { - memcpy(rects,DirtyRect,sizeRects); - ctx->DirtyRect = reinterpret_cast(rects); - } - - - if (m_SynchExecution) - { - HwExecutePresentDisplayOnly((PVOID)ctx); - return STATUS_SUCCESS; - } - else - { - // Create a worker thread to perform the present asynchronously - // Ctx will be deleted in worker thread (on exit) - return StartHwBltPresentWorkerThread(HwContextWorkerThread,(PVOID)ctx); - } -} - - -void -ReportPresentProgress( - _In_ HANDLE Adapter, - _In_ D3DDDI_VIDEO_PRESENT_SOURCE_ID VidPnSourceId, - _In_ BOOLEAN CompletedOrFailed) -/*++ - - Routine Description: - - This routine runs a fake interrupt routine in order to tell the OS about the present progress. - - Arguments: - - Adapter - Handle to the adapter (Device Extension) - VidPnSourceId - Video present source id for the callback - CompletedOrFailed - Present progress status for the source - - Return Value: - - None - ---*/ -{ - PAGED_CODE(); - - BASIC_DISPLAY_DRIVER* pDevExt = - reinterpret_cast(Adapter); - - SYNC_NOTIFY_INTERRUPT SyncNotifyInterrupt = {}; - SyncNotifyInterrupt.DxgkInterface = pDevExt->GetDxgkInterface(); - SyncNotifyInterrupt.NotifyInterrupt.InterruptType = DXGK_INTERRUPT_DISPLAYONLY_PRESENT_PROGRESS; - SyncNotifyInterrupt.NotifyInterrupt.DisplayOnlyPresentProgress.VidPnSourceId = VidPnSourceId; - - SyncNotifyInterrupt.NotifyInterrupt.DisplayOnlyPresentProgress.ProgressId = - (CompletedOrFailed)?DXGK_PRESENT_DISPLAYONLY_PROGRESS_ID_COMPLETE: - DXGK_PRESENT_DISPLAYONLY_PROGRESS_ID_FAILED; - - // Execute the SynchronizeVidSchNotifyInterrupt function at the interrupt - // IRQL in order to fake a real present progress interrupt - BOOLEAN bRet = FALSE; - NT_VERIFY(NT_SUCCESS(pDevExt->GetDxgkInterface()->DxgkCbSynchronizeExecution( - pDevExt->GetDxgkInterface()->DeviceHandle, - (PKSYNCHRONIZE_ROUTINE)SynchronizeVidSchNotifyInterrupt, - (PVOID)&SyncNotifyInterrupt,0,&bRet))); - NT_ASSERT(bRet); -} - - -void -HwContextWorkerThread( - HANDLE Context) -{ - PAGED_CODE(); - - DoPresentMemory* ctx = reinterpret_cast(Context); - BDD_HWBLT* displaySource = ctx->DisplaySource; - - // Signal event to indicate that the tread has started - KeSetEvent(&displaySource->m_hThreadStartupEvent, 0, FALSE); - - // Suspend context thread, do this by waiting on the suspend event - KeWaitForSingleObject(&displaySource->m_hThreadSuspendEvent, Executive, KernelMode, FALSE, NULL); - - HwExecutePresentDisplayOnly(Context); -} - - -void -HwExecutePresentDisplayOnly( - HANDLE Context) -/*++ - - Routine Description: - - The routine executes present's commands and report progress to the OS - - Arguments: - - Context - Context with present's command - - Return Value: - - None - ---*/ -{ - PAGED_CODE(); - - DoPresentMemory* ctx = reinterpret_cast(Context); - - // Set up destination blt info - BLT_INFO DstBltInfo; - DstBltInfo.pBits = ctx->DstAddr; - DstBltInfo.Pitch = ctx->DstStride; - DstBltInfo.BitsPerPel = ctx->DstBitPerPixel; - DstBltInfo.Offset.x = 0; - DstBltInfo.Offset.y = 0; - DstBltInfo.Rotation = ctx->Rotation; - DstBltInfo.Width = ctx->SrcWidth; - DstBltInfo.Height = ctx->SrcHeight; - - // Set up source blt info - BLT_INFO SrcBltInfo; - SrcBltInfo.pBits = ctx->SrcAddr; - SrcBltInfo.Pitch = ctx->SrcPitch; - SrcBltInfo.BitsPerPel = 32; - SrcBltInfo.Offset.x = 0; - SrcBltInfo.Offset.y = 0; - SrcBltInfo.Rotation = D3DKMDT_VPPR_IDENTITY; - if (ctx->Rotation == D3DKMDT_VPPR_ROTATE90 || - ctx->Rotation == D3DKMDT_VPPR_ROTATE270) - { - SrcBltInfo.Width = DstBltInfo.Height; - SrcBltInfo.Height = DstBltInfo.Width; - } - else - { - SrcBltInfo.Width = DstBltInfo.Width; - SrcBltInfo.Height = DstBltInfo.Height; - } - - - // Copy all the scroll rects from source image to video frame buffer. - for (UINT i = 0; i < ctx->NumMoves; i++) - { - BltBits(&DstBltInfo, - &SrcBltInfo, - 1, // NumRects - &ctx->Moves[i].DestRect); - } - - // Copy all the dirty rects from source image to video frame buffer. - for (UINT i = 0; i < ctx->NumDirtyRects; i++) - { - - BltBits(&DstBltInfo, - &SrcBltInfo, - 1, // NumRects - &ctx->DirtyRect[i]); - } - - // Unmap unmap and unlock the pages. - if (ctx->Mdl) - { - MmUnlockPages(ctx->Mdl); - IoFreeMdl(ctx->Mdl); - } - - if(ctx->SynchExecution) - { - // This code simulates Blt executed synchronously - // nothing should be done here, just exit - ; - } - else - { - // TRUE == completed - // This code is emulates interrupt which HW should generate - ReportPresentProgress(ctx->hAdapter,ctx->SourceID,TRUE); - } - - delete [] reinterpret_cast(ctx); -} diff --git a/video/KMDOD/memory.cxx b/video/KMDOD/memory.cxx deleted file mode 100644 index e3b5b4a9..00000000 --- a/video/KMDOD/memory.cxx +++ /dev/null @@ -1,78 +0,0 @@ -/******************************Module*Header*******************************\ -* Module Name: bdd.h -* -* Basic Display Driver memory allocation, deletion, and tracking -* -* -* Copyright (c) 2010 Microsoft Corporation -\**************************************************************************/ - -#include "BDD.hxx" - -#pragma code_seg("PAGE") - -// -// New and delete operators -// -_When_((PoolType & NonPagedPoolMustSucceed) != 0, - __drv_reportError("Must succeed pool allocations are forbidden. " - "Allocation failures cause a system crash")) -void* __cdecl operator new(size_t Size, POOL_TYPE PoolType) -{ - PAGED_CODE(); - - Size = (Size != 0) ? Size : 1; - - void* pObject = ExAllocatePoolWithTag(PoolType, Size, BDDTAG); - -#if DBG - if (pObject != NULL) - { - RtlFillMemory(pObject, Size, 0xCD); - } -#endif // DBG - - return pObject; -} - -_When_((PoolType & NonPagedPoolMustSucceed) != 0, - __drv_reportError("Must succeed pool allocations are forbidden. " - "Allocation failures cause a system crash")) -void* __cdecl operator new[](size_t Size, POOL_TYPE PoolType) -{ - PAGED_CODE(); - - Size = (Size != 0) ? Size : 1; - - void* pObject = ExAllocatePoolWithTag(PoolType, Size, BDDTAG); - -#if DBG - if (pObject != NULL) - { - RtlFillMemory(pObject, Size, 0xCD); - } -#endif // DBG - - return pObject; -} - -void __cdecl operator delete(void* pObject) -{ - PAGED_CODE(); - - if (pObject != NULL) - { - ExFreePool(pObject); - } -} - -void __cdecl operator delete[](void* pObject) -{ - PAGED_CODE(); - - if (pObject != NULL) - { - ExFreePool(pObject); - } -} - diff --git a/video/KMDOD/sampledisplay.rc b/video/KMDOD/sampledisplay.rc deleted file mode 100644 index f495476d..00000000 --- a/video/KMDOD/sampledisplay.rc +++ /dev/null @@ -1,30 +0,0 @@ -/*++ - -Copyright (c) 2011 Microsoft Corporation - -Module Name: - - SampleDisplay.rc - -Abstract: - - This modules contains the version information for the Sample Display Driver - -Environment: - - Kernel mode only - ---*/ - -#include - -#include - -#define VER_FILETYPE VFT_DRV -#define VER_FILESUBTYPE VFT2_DRV_DISPLAY -#define VER_FILEDESCRIPTION_STR "Microsoft Sample Display Driver" -#define VER_INTERNALNAME_STR "SampleDisplay.sys" -#define VER_ORIGINALFILENAME_STR "SampleDisplay.sys" - -#define VER_LANGNEUTRAL -#include "common.ver" diff --git a/video/pixlib/PixLib.vcxproj b/video/pixlib/PixLib.vcxproj index 422787ba..78e2b236 100644 --- a/video/pixlib/PixLib.vcxproj +++ b/video/pixlib/PixLib.vcxproj @@ -19,11 +19,11 @@
- {4E06B3AB-DFAD-4F48-8936-FFF04466B8EA} + {F7850F91-2B8B-4646-9214-9FEC52E95365} $(MSBuildProjectName) Debug Win32 - {81B1500C-93FF-426B-9F4E-AE70C8AC0E32} + {14F26315-FCC7-4B70-B304-B9BB589DE042} diff --git a/video/pixlib/PixLib.vcxproj.Filters b/video/pixlib/PixLib.vcxproj.Filters index 48f6096a..10c134f7 100644 --- a/video/pixlib/PixLib.vcxproj.Filters +++ b/video/pixlib/PixLib.vcxproj.Filters @@ -3,15 +3,15 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {A8B745DE-6F64-4D24-9987-A54ECE81A482} + {AE3F0C15-3824-4BF5-9012-CB71D541730A} h;hpp;hxx;hm;inl;inc;xsd - {826CC0FB-F174-4CEB-B426-B314EF20FC3D} + {83784D0E-55CF-4946-AD66-C1DEB6BDC0B4} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {AABC8FBD-8833-4320-AD01-F66555EFE527} + {C99ABA84-B090-45ED-BD98-DA59A71CD4B3} diff --git a/video/pixlib/pixlib.sln b/video/pixlib/pixlib.sln index 4be1ce6b..9f698ee8 100644 --- a/video/pixlib/pixlib.sln +++ b/video/pixlib/pixlib.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PixLib", "PixLib.vcxproj", "{4E06B3AB-DFAD-4F48-8936-FFF04466B8EA}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PixLib", "PixLib.vcxproj", "{F7850F91-2B8B-4646-9214-9FEC52E95365}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +13,14 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {4E06B3AB-DFAD-4F48-8936-FFF04466B8EA}.Debug|Win32.ActiveCfg = Debug|Win32 - {4E06B3AB-DFAD-4F48-8936-FFF04466B8EA}.Debug|Win32.Build.0 = Debug|Win32 - {4E06B3AB-DFAD-4F48-8936-FFF04466B8EA}.Release|Win32.ActiveCfg = Release|Win32 - {4E06B3AB-DFAD-4F48-8936-FFF04466B8EA}.Release|Win32.Build.0 = Release|Win32 - {4E06B3AB-DFAD-4F48-8936-FFF04466B8EA}.Debug|x64.ActiveCfg = Debug|x64 - {4E06B3AB-DFAD-4F48-8936-FFF04466B8EA}.Debug|x64.Build.0 = Debug|x64 - {4E06B3AB-DFAD-4F48-8936-FFF04466B8EA}.Release|x64.ActiveCfg = Release|x64 - {4E06B3AB-DFAD-4F48-8936-FFF04466B8EA}.Release|x64.Build.0 = Release|x64 + {F7850F91-2B8B-4646-9214-9FEC52E95365}.Debug|Win32.ActiveCfg = Debug|Win32 + {F7850F91-2B8B-4646-9214-9FEC52E95365}.Debug|Win32.Build.0 = Debug|Win32 + {F7850F91-2B8B-4646-9214-9FEC52E95365}.Release|Win32.ActiveCfg = Release|Win32 + {F7850F91-2B8B-4646-9214-9FEC52E95365}.Release|Win32.Build.0 = Release|Win32 + {F7850F91-2B8B-4646-9214-9FEC52E95365}.Debug|x64.ActiveCfg = Debug|x64 + {F7850F91-2B8B-4646-9214-9FEC52E95365}.Debug|x64.Build.0 = Debug|x64 + {F7850F91-2B8B-4646-9214-9FEC52E95365}.Release|x64.ActiveCfg = Release|x64 + {F7850F91-2B8B-4646-9214-9FEC52E95365}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/wmi/wmiacpi/ReadMe.md b/wmi/wmiacpi/ReadMe.md deleted file mode 100644 index b2057e16..00000000 --- a/wmi/wmiacpi/ReadMe.md +++ /dev/null @@ -1,54 +0,0 @@ -WMI ACPI Sample -=============== - -The WMIACPI sample contains ACPI BIOS and Microsoft Windows Management Instrumentation (WMI) sample code that enables instrumentation of the ACPI BIOS from within ACPI Source Language (ASL) code. ASL code can expose data blocks, methods, and events through WMI by leveraging the ACPI-WMI mapping driver (Wmiacpi.sys). - -Operation ---------- - -The WMIACPI sample contains files which allow an ACPI BIOS developer to add instrumentation from within ASL code. ASL code can expose data blocks, methods, and events through WMI by leveraging the Wmiacpi.sys driver. For more information about the mechanics of writing ASL to expose instrumentation, see the *Windows Instrumentation: WMI and ACPI* white paper included in this sample and available on the Windows Hardware Developer Central (WHDC) Web site. - -The following table lists the files included in the sample and their function: - -File - -Description - -Device.asl - -ASL code that can be included in the ACPI bios that exposes a set of packages, strings, data, methods and events. - -Acpimof.mof - -Managed object format (MOF) file that contains a description of the data blocks, methods, and events that are exposed. This description is required so that WMI can access the data blocks, methods, and events. - -Acpimof.rc - -Acpimof.def - -Files that are required to build Acpimof.dll, which is a resource-only DLL. - -Wmi-Acpi.htm - -The *Windows Instrumentation: WMI and ACPI* whitepaper. - -acpimov.vcxproj - -Visual Studio project file for the sample. - -acpimof.sln - -Visual Studio solution file for the sample. - -Installation ------------- - -To add the sample code to your ACPI bios and access through WMI: - -1. Include the contents of *Device.asl* to your ASL source and rebuild the DSDT. Update the operating system with the new DSDT through reflashing. -2. Build *Acpimof.dll* in the WMIACPI directory. *Acpimof.dll* is a resource-only DLL that contains the compiled MOF in a form that WMI can import into its schema. -3. Copy *Acpimof.dll* to %windir%\\system32 and add a value named "MofImagePath" under the HKEY\_LOCAL\_MACHINE\\CurrentControlSet\\Services\\WmiAcpi key. The contents of the value should be a path to the *Acpimof.dll* file. -4. Restart your computer. When Plug and Play (PnP) recognizes the new device with a pnpid of pnp0c14, it will install *Wmiacpi.sys* automatically and make the MOF resource in Acpimof.dll available to the WMI schema. - -Note that you do not need an INF file because Windows supplies an INF for the ACPI-WMI mapping driver device as part of the operating system. - diff --git a/wmi/wmiacpi/wmiacpi.sln b/wmi/wmiacpi/wmiacpi.sln index 5b64ac06..6c24484a 100644 --- a/wmi/wmiacpi/wmiacpi.sln +++ b/wmi/wmiacpi/wmiacpi.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "acpimof", "wmiacpi\acpimof.vcxproj", "{3970C74C-8528-4B40-9629-B6FDD78D7B60}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "acpimof", "wmiacpi\acpimof.vcxproj", "{698C6C2B-7B91-4243-8004-3CA38732948B}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +13,14 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {3970C74C-8528-4B40-9629-B6FDD78D7B60}.Debug|Win32.ActiveCfg = Debug|Win32 - {3970C74C-8528-4B40-9629-B6FDD78D7B60}.Debug|Win32.Build.0 = Debug|Win32 - {3970C74C-8528-4B40-9629-B6FDD78D7B60}.Release|Win32.ActiveCfg = Release|Win32 - {3970C74C-8528-4B40-9629-B6FDD78D7B60}.Release|Win32.Build.0 = Release|Win32 - {3970C74C-8528-4B40-9629-B6FDD78D7B60}.Debug|x64.ActiveCfg = Debug|x64 - {3970C74C-8528-4B40-9629-B6FDD78D7B60}.Debug|x64.Build.0 = Debug|x64 - {3970C74C-8528-4B40-9629-B6FDD78D7B60}.Release|x64.ActiveCfg = Release|x64 - {3970C74C-8528-4B40-9629-B6FDD78D7B60}.Release|x64.Build.0 = Release|x64 + {698C6C2B-7B91-4243-8004-3CA38732948B}.Debug|Win32.ActiveCfg = Debug|Win32 + {698C6C2B-7B91-4243-8004-3CA38732948B}.Debug|Win32.Build.0 = Debug|Win32 + {698C6C2B-7B91-4243-8004-3CA38732948B}.Release|Win32.ActiveCfg = Release|Win32 + {698C6C2B-7B91-4243-8004-3CA38732948B}.Release|Win32.Build.0 = Release|Win32 + {698C6C2B-7B91-4243-8004-3CA38732948B}.Debug|x64.ActiveCfg = Debug|x64 + {698C6C2B-7B91-4243-8004-3CA38732948B}.Debug|x64.Build.0 = Debug|x64 + {698C6C2B-7B91-4243-8004-3CA38732948B}.Release|x64.ActiveCfg = Release|x64 + {698C6C2B-7B91-4243-8004-3CA38732948B}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/wmi/wmiacpi/wmiacpi/ReadMe.md b/wmi/wmiacpi/wmiacpi/ReadMe.md new file mode 100644 index 00000000..b2057e16 --- /dev/null +++ b/wmi/wmiacpi/wmiacpi/ReadMe.md @@ -0,0 +1,54 @@ +WMI ACPI Sample +=============== + +The WMIACPI sample contains ACPI BIOS and Microsoft Windows Management Instrumentation (WMI) sample code that enables instrumentation of the ACPI BIOS from within ACPI Source Language (ASL) code. ASL code can expose data blocks, methods, and events through WMI by leveraging the ACPI-WMI mapping driver (Wmiacpi.sys). + +Operation +--------- + +The WMIACPI sample contains files which allow an ACPI BIOS developer to add instrumentation from within ASL code. ASL code can expose data blocks, methods, and events through WMI by leveraging the Wmiacpi.sys driver. For more information about the mechanics of writing ASL to expose instrumentation, see the *Windows Instrumentation: WMI and ACPI* white paper included in this sample and available on the Windows Hardware Developer Central (WHDC) Web site. + +The following table lists the files included in the sample and their function: + +File + +Description + +Device.asl + +ASL code that can be included in the ACPI bios that exposes a set of packages, strings, data, methods and events. + +Acpimof.mof + +Managed object format (MOF) file that contains a description of the data blocks, methods, and events that are exposed. This description is required so that WMI can access the data blocks, methods, and events. + +Acpimof.rc + +Acpimof.def + +Files that are required to build Acpimof.dll, which is a resource-only DLL. + +Wmi-Acpi.htm + +The *Windows Instrumentation: WMI and ACPI* whitepaper. + +acpimov.vcxproj + +Visual Studio project file for the sample. + +acpimof.sln + +Visual Studio solution file for the sample. + +Installation +------------ + +To add the sample code to your ACPI bios and access through WMI: + +1. Include the contents of *Device.asl* to your ASL source and rebuild the DSDT. Update the operating system with the new DSDT through reflashing. +2. Build *Acpimof.dll* in the WMIACPI directory. *Acpimof.dll* is a resource-only DLL that contains the compiled MOF in a form that WMI can import into its schema. +3. Copy *Acpimof.dll* to %windir%\\system32 and add a value named "MofImagePath" under the HKEY\_LOCAL\_MACHINE\\CurrentControlSet\\Services\\WmiAcpi key. The contents of the value should be a path to the *Acpimof.dll* file. +4. Restart your computer. When Plug and Play (PnP) recognizes the new device with a pnpid of pnp0c14, it will install *Wmiacpi.sys* automatically and make the MOF resource in Acpimof.dll available to the WMI schema. + +Note that you do not need an INF file because Windows supplies an INF for the ACPI-WMI mapping driver device as part of the operating system. + diff --git a/wmi/wmiacpi/wmiacpi/acpimof.vcxproj b/wmi/wmiacpi/wmiacpi/acpimof.vcxproj index 5d051b9e..3c6bb3d5 100644 --- a/wmi/wmiacpi/wmiacpi/acpimof.vcxproj +++ b/wmi/wmiacpi/wmiacpi/acpimof.vcxproj @@ -19,11 +19,11 @@ - {3970C74C-8528-4B40-9629-B6FDD78D7B60} + {698C6C2B-7B91-4243-8004-3CA38732948B} $(MSBuildProjectName) Debug Win32 - {D8A14171-BF7C-43FD-86DD-37B4684E7D53} + {21CC1425-4EAD-40AF-AEAE-684618F326F2} diff --git a/wmi/wmiacpi/wmiacpi/acpimof.vcxproj.Filters b/wmi/wmiacpi/wmiacpi/acpimof.vcxproj.Filters index 70d607e3..3d36b235 100644 --- a/wmi/wmiacpi/wmiacpi/acpimof.vcxproj.Filters +++ b/wmi/wmiacpi/wmiacpi/acpimof.vcxproj.Filters @@ -3,15 +3,15 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {6D71DCDF-542C-410B-9C39-3BCABA55E977} + {0B8A6C1E-2E0C-4D5F-A4C8-222D806C3C3D} h;hpp;hxx;hm;inl;inc;xsd - {1341EBF1-D4D9-4C93-AADF-166A1363BD8E} + {34F549CF-EF79-4160-AD59-87BF005E5EA4} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {7743945B-C300-4BC4-BB37-3D69924FC46D} + {A674355E-0640-4EF1-A30A-55D72CFEF4CF} diff --git a/wmi/wmiacpi/wmiacpi/readme.htm b/wmi/wmiacpi/wmiacpi/readme.htm new file mode 100644 index 00000000..15df59fc --- /dev/null +++ b/wmi/wmiacpi/wmiacpi/readme.htm @@ -0,0 +1,228 @@ + + + + + + + + +WMI ACPI Mapper + + + + + + +
+ +

This +directory contains files that allow an ACPI bios developer to add

+ +

instrumentation +from within ASL code. ASL code can expose data blocks, methods

+ +

and +events via WMI by leveraging the WMIACPI.SYS driver. More information

+ +

about the +mechanics of writing ASL to expose instrumentation information is

+ +

available +in wmi-acpi.doc or on

+ +

http://www.microsoft.com/HWDev/MANAGEABILITY/wmi-acpi.htm.

+ +

 

+ +

 

+ +

Device.ASL +- ASL code that can be included in the acpi bios that exposes

+ +

             a set of packages, strings, data, +methods and events.

+ +

 

+ +

acpimof.mof +- Managed Object Format file that contains a description  of the

+ +

              data blocks, methods and events +exposed. This description is

+ +

              required so that WMI is able to +access the data blocks, methods

+ +

              and events.

+ +

 

+ +

acpimof.rc, +acpimof.def - FIles required to build acpimof.dll, a resource only

+ +

              dll.

+ +

 

+ +

makefile, +sources, makefile.inc - build glue

+ +

 

+ +

wmi-acpi.doc +- White paper describing how to add instrumentation to ASL code.

+ +

 

+ +

acpimof.vbs +- Built at the same time as acpimof.dll, this file contains a

+ +

              VBScript applet that will query +all classes specified in the

+ +

              acpimof.mof file.

+ +

 

+ +

 

+ +

To add +the sample code to your acpi bios and access via WMI:

+ +

 

+ +

1. +Include the contents of device.asl to your asl source and rebuild the

+ +

   DSDT. Update the OS with the new dsdt via +the registry or reflashing.

+ +

 

+ +

2. +Build acpimof.dll in this directory. acpimof.dll is a resource only dll

+ +

   that contains the compiled mof in a form +that WMI can import into its

+ +

   schema.

+ +

 

+ +

3. Copy +acpimof.dll to %windir%\system32 and add a value named "MofImagePath"

+ +

   under the +HKEY_LOCAL_MACHINE\CurrentControlSet\Services\WmiAcpi key. The

+ +

   contents of the value should be a path to +the acpimof.dll file.

+ +

 

+ +

4. +Reboot. When PNP recognizes the new device with a pnpid of pnp0c14

+ +

   it will install wmiacpi.sys automatically +and make the mof resource

+ +

   in acpimof.dll available to the WMI schema.

+ +

 

+ +

5. +Execute the acpimof.vbs test by entering acpimof.vbs at the command line

+ +

   and reviewing the acpitest.log to insure +that all data returned is correct.

+ +

 

+ +

 

+ +

Note +that no INF file is needed since Windows supplies an INF for the ACPI mapper +device as part of Windows

+ +
+ + + + diff --git a/wmi/wmiacpi/wmiacpi/wmi-acpi.htm b/wmi/wmiacpi/wmiacpi/wmi-acpi.htm new file mode 100644 index 00000000..6bf9de16 --- /dev/null +++ b/wmi/wmiacpi/wmiacpi/wmi-acpi.htm @@ -0,0 +1,1804 @@ + + + + + + +New Page 1 + + + + + +
+

+ WinHEC 99 White + Paper +

+ + + + + +
+

Windows® Hardware + Engineering Conference:
+ Advancing the Platform

+

 

+

Windows 2000 Instrumentation: WMI and ACPI

+

Abstract

+
+

 

+

This paper describes the process that system manufacturers +(OEMs) can use to provide instrumentation information by including ACPI objects +in the systems they build that will be recognized by Microsoft® Windows® +Management Instrumentation (WMI). This information applies for Windows 2000 and +Windows 98 OSR 1. By including ACPI objects in the systems they build, OEMs can +take advantage of a generic mapping driver that allows WMI to make the +information available to the instrumentation consumers.

+

 

+

The ACPI subsystem contains a wealth of instrumentation +information; OEMs are encouraged to use ACPI to add additional platform specific +instrumentation information. However, ACPI objects are not readily accessible by +instrumentation data consumers such as Web-Based Enterprise Management (WBEM). +

+

 

+

This paper assumes the reader is familiar with driver +mapping under Windows operating systems and the Data Block GUID Mapping control +method for WMI. References for background and details are cited at +http://www.microsoft.com/hwdev/manageability/; ACPI implementation information +is available at http://www.teleport.com/~acpi/.

+

 

+

March 12, 1999

+

 

+

 

+

Disclaimer and Copyright

+
+

 

+

+Microsoft Disclaimer: This document is +for informational purposes only. MICROSOFT MAKES NO WARRANTIES, EXPRESS OR +IMPLIED, IN THIS DOCUMENT.

+

+Microsoft Corporation may have patents or pending patent applications, +trademarks, copyrights, or other intellectual property rights covering subject +matter in this document. The furnishing of this document does not give you any +license to the patents, trademarks, copyrights, or other intellectual property +rights except as expressly provided in any written license agreement from +Microsoft Corporation.

+

+Microsoft does not make any representation or warranty regarding specifications +in this document or any product or item developed based on these specifications. +Microsoft disclaims all express and implied warranties, including but not +limited to the implied warranties or merchantability, fitness for a particular +purpose and freedom from infringement. Without limiting the generality of the +foregoing, Microsoft does not make any warranty of any kind that any item +developed based on these specifications, or any portion of a specification, will +not infringe any copyright, patent, trade secret or other intellectual property +right of any person or entity in any country. It is your responsibility to seek +licenses for such intellectual property rights where appropriate. Microsoft +shall not be liable for any damages arising out of or in connection with the use +of these specifications, including liability for lost profit, business +interruption, or any other damages whatsoever. Some states do not allow the +exclusion or limitation of liability or consequential or incidental damages; the +above limitation may not apply to you.

+

+Microsoft, DirectX, MS‑DOS, Win32, Windows, and Windows NT are registered +trademarks of Microsoft Corporation. Other product and company names mentioned +herein may be the trademarks of their respective owners.

+

© 1999 +Microsoft Corporation. All rights reserved.

+

 

+

Contents

+
+

 

+

Technology +Overview for Windows 2000 +Instrumentation....................................................................................... +3

+

WMI Overview for Windows 2000 +Instrumentation................................................................................................... +3

+

ACPI-to-WMI Mapper Goals for Windows 2000 +Instrumentation........................................................................... +4

+

ACPI Control Method Naming Conventions and Functionality for +Windows 2000 Instrumentation................ 5

+

Data Block Design for Windows 2000 +Instrumentation............................................................................................. +8

+

FAQ about WMI and ACPI for Windows 2000 +Instrumentation........................................................................... +11

+

ASL Methods and Sample +Code.................................................................................................................................. +11

+

ASL Sample Code for an +Event and Initiating Method...................................................................................... +12

+

Sample ASL Code Embedding MOD Data in ASL.............................................................................................. +14

+

Sample .Mof +File....................................................................................................................................................... +17

+

 

+

+

+
+

Technology Overview for Windows 2000 + Instrumentation

+
+

The ACPI-to-WMI mapping functionality is achieved by means +of two device drivers provided with the Windows 2000 and Windows 98 OSR1 +operating systems:

+

·         +Acpi.sys is the regular ACPI device driver with some +modifications.

+

·         +Wmiacpi.sys registers with Plug and Play ID PNP0c14.

+

 

+

OEMs can differentiate their PC system capabilities by +writing ACPI Source Language (ASL) code and a Managed Object Format (.mof or MOF) +file. The .mof file can be in the BIOS or on disk. For more information about +MOF, see the “MOF Data Types” section later in this paper.

+

 

+

ASL code is never executed directly by the Wmiacpi.sys +driver. ASL code is always executed by the Acpi.sys driver (see the ASL +information at http://www.teleport.com/~acpi/). Wmiacpi.sys will invoke Acpi.sys +to call control methods that access the management data exposed by the mapping +driver.

+

 

+

Microsoft does not ship a .mof file that is associated with +the Wmiacpi.sys driver. The only information surfaced through ACPI is the +temperature zone information, which is surfaced through and associated with the +Acpi.sys device driver.

+

 

+
+

WMI Overview for Windows 2000 Instrumentation

+
+

WMI organizes individual data items (properties) into data +blocks (structures) that contain related information. Data blocks may have one +or more data items. Each data item has a unique index within the data block, and +each data block is named by a globally unique 128-bit number called a globally +unique identifier (GUID). WMI can provide notifications to the data producer as +to when to start and stop collecting the data items that compose a data block. +WMI has no knowledge of the data format for individual data blocks.

+

 

+

WMI functionality allows for querying all instances of a +data block or a single instance of a data block. It also allows for setting all +data items in an instance of a data block or a single data item within a single +instance of a data block.

+

 

+

In addition to queries and sets, WMI allows WMI method +calls, which are functionally equivalent to an I/O control (IOCTL) call to a +device. Each WMI method call is identified by a GUID and a method index for that +GUID. All WMI method calls use one buffer for input and output parameters. WMI +allows notifications of significant events to be delivered to interested +user-mode applications. Each type of event is uniquely named by a GUID. Events +may also carry a data block with additional information about the event. WMI can +provide notifications to the event generator about when to enable and disable an +event type.

+

 

+

WMI is an open architecture that allows OEMs to define +their own data blocks, methods, and events. Along with the data that composes +the custom data block, the OEM must also provide a description that generally +represents how a data block or WMI method is mapped to a 2-character ID. This +2‑character ID is part of the names of the control methods that act upon the +data block.

+

 

+

For example, when a call is made to query about the data +block represented by a WMI GUID, the mapper will evaluate the WQxx +control method (where xx is the 2-character ID mapped to that GUID). +These mappings are defined by the ACPI code and obtained by the mapper +evaluating the _WDG control method. For more information, see “ACPI Control +Method Naming Conventions and Functionality” later in this paper.

+

 

+

The mapping process is similar for events. The _WDG control +method provides a mapping between the WMI event GUID that represents the event +and the notification code specified in the ASL notify instruction. For example, +when ACPI provides a callback to the mapper that a control method executed a +notify(mapper-device, 0x81) function, the mapper will look up +the WMI GUID mapped to 0x81 and use this WMI GUID in building the WMI event. +Before launching the WMI event, the mapper will evaluate _WED to retrieve any +additional data that belongs with the event.

+

 

+

Loading the Mapping Driver. +The Plug and Play ID PNP0c14 is assigned as the WMI-mapping pseudo device; +the operating system device INFs (Plug and Play ID-to-device driver lookup +table) point this Plug and Play ID to the ACPI-to-WMI mapping driver. To cause +the ACPI-to-WMI mapping driver to load, an ACPI system needs to define one or +more devices with that Plug and Play ID in the ACPI device tree. Each device +declared in the ACPI device tree would have its own operating system device +object with its own set of mappings.

+

 

+

In this way, different sets of data blocks can be organized +in the appropriate place within the device tree. This organization allows the +different devices and their corresponding data blocks to come and go from the +ACPI device tree. Note that if there are multiple WMI-mapping pseudo devices in +the ACPI device tree, each device must have a unique value for its _UID.

+

 

+

Mapping Driver Functionality. +Essentially the mapping driver will do the following:

+

·         +Manage all registration and unregistration with WMI and other +interactions with the operating system. This registration of data and data +blocks is done when the mapper gets the IRP_MN_REGINFO IRP.

+

·         +At WMI initialization time, the mapping driver will query an ACPI +method for the list of data block, event, and method GUIDs it supports, as well +as the mapping from the GUID to control method IDs. With this information, the +mapping driver will register those GUIDs with WMI.

+

·         +Translate data block queries, sets, and method call I/O IRPs into +the appropriate ACPI control method call.

+

·         +Receive notifications from the ACPI event handler control methods +and relaunch them as WMI events.

+

·         +Translate strings between ASCIZ and UNICODE for data blocks marked +as wholly composed of a string.

+

 

+
+

ACPI-to-WMI Mapper Goals for Windows 2000 + Instrumentation

+
+

The following list describes the goals for the ACPI-to-WMI +mapper:

+

·         +Expose data maintained by the hardware or firmware and accessible +through ACPI to user-mode instrumentation data consumers, such as WBEM or DMI.

+

·         +Allow specific ACPI control methods to be called from a user-mode +instrumentation data consumer or hardware configuration application—for example, +from a control panel applet.

+

·         +Deliver specific ACPI events to all user-mode callers that request +notification of that particular event.

+

·         +Allow OEMs to include OEM-specific data blocks, user-mode–callable +ACPI control methods, and events without requiring any changes to the +ACPI-to-WMI mapper.

+

·         +Allow general-purpose data consumer applications—those written +without any special knowledge of the data blocks exposed by a particular +machine—to be able to access and understand the data blocks, user-mode–callable +ACPI control methods, and events being mapped—including those that are OEM +specific.

+

·         +Define standard data block formats, user-mode–callable ACPI +control methods, events and their WMI GUID mappings for common data blocks, and +callable control methods and events expected to be provided by all OEMs. This +can include dynamic data and functions identified by the industry in the SMBIOS +specification and other specifications.

+

 

+

These goals are achieved by having supporting code in the +ACPI-to-WMI mapper (Wmiacpi.sys) as well as in the core ACPI code itself (Acpi.sys).

+

 

+

The following are not goals for the ACPI-to-WMI +mapper:

+

+·         +To have specific knowledge about any data block that passes +through the mapper.

+

·         +To provide interfaces specifically for SMBIOS data and functions. +The mapper is an open architecture that is not restricted to SMBIOS data and +functionality.

+

 

+

How SMBIOS-provided information +is handled. Vendors who want to provide OEM and system-specific +instrumentation data may choose to use SMBIOS as the mechanism. To use the +capabilities of the WMI infrastructure to surface this SMBIOS data, they must +conform to any SMBIOS version between 2.0 and 2.2. (Microsoft intends to support +future revisions of SMBIOS as and when they appear. To date, we have only one +SMBIOS 2.2 machine for testing). This allows the Microsoft Win32® +provider—which is shipped with Windows 2000 and future versions of Windows and +is available as an update to Windows 98—to populate almost all of the SMBIOS-provided +information into the CIMv2 namespace. In particular, almost all of the +information is put into Win32 classes. Some of these Win32 classes are derived +from the CIMv2.1 physical MOF.

+

 

+

The one exception where SMBIOS information will not be +automatically populated by the Win32 provider into the CIMv2 namespace is SMBIOS +vendor-specific data. Such SMBIOS vendor-defined data will be placed in a +“VendorBucket” class in a “Root\VendorDefined” namespace, and will not be +available in the CIMv2 namespace by default. Any system vendor who wants to +provide such data must write a provider that will interpret this data.

+

 

+

The SMBIOS data is read only once, either at boot time in +Windows 2000 or post boot on Windows 98. Dynamic updates that are made to the +SMBIOS data after it has been read will not be reflected in the namespaces in +this implementation. Microsoft is working with the industry to define standard +ACPI methods for dynamic updates.

+

 

+

The SMBIOS raw data will be available as a WMI data block +in Windows 2000 and as a flat file in Windows 98. This data will be interpreted +and populated into the namespaces by the Win32 provider.

+

 

+

Note: The Win32 provider capabilities used to read +and populate SMBIOS data as described above will be available in Windows 2000 +Beta 3.

+

 

+
+

ACPI Control Method Naming Conventions and + Functionality for Windows 2000 Instrumentation

+
+

The Data Block GUID Mapping control +method named _WDG evaluates to a buffer that has the GUID mapping +information for data blocks, events, and WMI methods. The result of the +evaluation is a buffer containing an array of the following structure.

+

 

+

typedef struct

+

{

+

     GUID guid;             // +GUID that names data block

+

     union

+

     {

+

         CHAR ObjectId[2];  // +2-character ACPI ID  (Data Blocks and Methods)

+

         struct

+

         {

+

+             UCHAR NotificationValue;  // Byte value passed by event handler +control method

+

             UCHAR Reserved[1];

+

         } NotifyId;

+

    }

+

     USHORT InstanceCount;  // +Number of separate instances of data block

+

     USHORT Flags;          // +Flags

+

};

+

 

+

// Set this flag if the WCxx control method should be run to +whenever the first

+

// data consumer is interested in collecting the data block and +whenever the last data

+

// consumer is no longer interested.

+

 

+

#define WMIACPI_REGFLAG_EXPENSIVE   0x1

+

 

+

// Set this flag if the GUID represents a set of WMI method calls +and not a data block

+

 

+

#define WMIACPI_REGFLAG_METHOD      0x2

+

 

+

// Set this flag if the data block is wholly composed of a string +and should be

+

// translated from ASCIZ to UNICODE in returning queries and from +UNICODE to ASCIZ

+

// when passing sets

+

 

+

#define WMIACPI_REGFLAG_STRING      0x04

+

 

+

// Set this flag if the guid maps to an event rather than a data +block or method

+

 

+

#define WMIACPI_REGFLAG_EVENT       0x08

+

 

+

 

+

Each element in the array describes the mapping of a WMI +data block GUID to a 2-letter ACPI method identifier used to compose the method +names that operate on the data block or on the notification value used in the +ASL Notify operation. Each element of the array also contains the number +of instances of the data block that exist and any flags that are set.

+

 

+

This control method is required.

+

 

+

The following table summarizes the +information for each control method described later in this section.

+

 

+

Control Method Summary

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Control method

+

Object name

+

Parameters

+

Control method required

+

Data Block Query

+

WQxx

+

ULONG

+

Yes.

+

Data Block Set

+

WSxx

+

ULONG, buffer

+

No. Not required for data blocks that are read only.

+

Data Item Set

+

Not supported

+

 

+

 

+

Method Execution

+

WMxx

+

ULONG, method ID,
+ buffer

+

Yes. Required for data blocks specified in the data block GUID + mapping array and that have the WMIACPI_REG_METHOD flag set.

+

 

+ + + + + + + + + + + + + +
+

Event Enable and Disable

+

WExx

+

UCHAR

+

No. Support only when keeping the event enabled incurs + significant overhead.

+

Data Collection
+ Enable and Disable

+

WCxx

+

UCHAR

+

No. Support only when data collecting for the data block + incurs significant overhead.

+

 

+

·         +Data Block Query Control Method. If the Data Block GUID +Mapping control method describes a data block that does not have the +WMIACPI_REG_METHOD flag set, there needs to be a control method that evaluates +to the contents of an instance of the data block.

+

By convention, the name of the object is WQxx, where xx +is the 2-character ID that maps to the GUID being queried. One parameter is +passed to the method—the index of the instance, which is of type ULONG. Data +blocks registered with only a single instance can ignore the parameter. If the +result of the evaluation of the WQxx method is a string, then the mapper +will convert that string to UNICODE so that it can be understood by WMI.

+

This control method is required.

+

+·         +Data Block Set Control Method. If the Data Block +GUID Mapping control method describes a data block that does not have the +WMIACPI_REG_METHOD flag set, there needs to be a control method that evaluates +to the contents of an instance of the data block.

+

By convention, the name of the object is WSxx, where xx +is the 2-character ID that maps to the GUID being set. Two parameters are passed +to the method; one is a ULONG that is the index of the instance, and the other +is a buffer that contains the new values for the data block.

+

If the GUID for the data block is registered with the +WMIACPI_REGFLAG_STRING flag, then the mapper assumes that the data block passed +is wholly composed of a single string and will convert that string from UNICODE +to ASCIZ so that it can be understood by the WSxx control method.

+

This control method is not required for those data blocks that +are read only.

+

Because the mapper is unaware of the format of the data block +passed by the caller of the WMI method, it will pass the buffer as a single +buffer parameter to the WMxx control method. The control method can use +the ASL instructions CreateBitField, CreateDWordField, +CreateField, and CreateWordField to break up the buffer into its +parts

+

+·         +Data Item Set Control Method. Setting of +individual data items within a data block is not supported. Typically, data +items that can be modified should be placed in their own data block or the +entire data block should be modified.

+

+·         +Method Execution Control Method. If the Data +Block GUID Mapping control method describes a data block that does have the +WMIACPI_REG_METHOD flag set, there needs to be a control method that performs +the action required of the method.

+

By convention, the name of the control method is WMxx, +where xx is the 2-character ID that maps to the GUID. This method call +has three parameters; the first is a ULONG that has the instance index being +executed; the second contains the method ID for the method being executed; and +the third is a buffer that contains the input for the method call.

+

If the GUID for the WMI method is registered with the +WMIACPI_REGFLAG_STRING flag, then the mapper assumes that buffer passed in is a +string. The mapper will convert the incoming string from UNICODE to ASCIZ.

+

If the result of the WMxx control method is a string, the +mapper will convert the result string from ASCIZ to UNICODE. The return value of +the WMxx method should be a buffer with the result of the method call. +

+

This control method is required for those data blocks +specified in the Data Block GUID Mapping array that have the WMIACPI_REG_METHOD +flag set.

+

Because the mapper is unaware of the format of the data block +passed by the caller of the WMI method, it will pass the buffer as a single +buffer parameter to the WMxx control method. The control method can use +the ASL instructions CreateBitField, CreateDWordField, +CreateField, and CreateWordField to break the buffer into its parts.

+

+·         +Event Enable and Disable Control Method. For +each event specified in the Event GUID Mapping control method that has the +WMIACPI_REG_EXPENSIVE flag set, there needs to be a control method that is +invoked whenever launching of the event should be enabled and disabled.

+

By convention, the control method is named WExx, where +xx is the hex value of the notification code passed by the event handler +control method. This method has one parameter, a UCHAR that has a value of 0 if +the event is to be disabled or a nonzero value if it is to be enabled.

+

This method is optional and should only be supported if keeping +the event enabled incurs significant overhead.

+

+·         +Data Collection Enable and Disable Control Method. +For each data block described in the Data Block GUID Mapping control method +that has the WMIACPI_REG_EXPENSIVE flag set, there needs to be a control method +that is invoked whenever collection of the data that composes the data block +should be enabled and disabled

+

By convention, the control method is named WCxx, where +xx is the 2-character ID that maps to the GUID. This method has one +parameter, a UCHAR that has a value of 0 if data block collection is to be +disabled or a nonzero value if it is to be enabled.

+

This method is optional and should only be supported if +collecting the data for the data block incurs significant overhead.

+

+·         +Additional Event Data. The _WED control method +is evaluated by the mapper in response to receiving a notification from a +control method. The results of the evaluation are passed as part of the WMI +event information. This mechanism allows additional data to be included with an +event.

+

The control method takes one parameter, which is the notification +code that caused the notification to occur. If the result of the _WED control +method is a string, then the string is converted from ASCIZ to UNICODE before +launching the WMI event.

+

 

+
+

Data Block Design for Windows 2000 + Instrumentation

+
+

Design Considerations. Consider the following in +designing data blocks for instrumentation under Windows 2000:

+

·         +Data items that are read-only and are commonly used together +should be combined into a single data block.

+

·         +Data items that are strings must be segregated into their own data +block and registered with the WMIACPI_REGFLAG_STRING flag set so that the mapper +can convert between ASCIZ and UNICODE.

+

·         +Data items that can be set individually should be segregated into +their own data blocks. For example, a set of data items that must be set all at +the same time can be combined into a single data block.

+

 

+

MOF Data Types. +The Managed Object Format (MOF) for the data blocks implemented can be supplied +as either a resource attached to a file or as the buffer that results from the +evaluation of a control method. To establish the former, either bind the +resource to the Wmiacpi.sys image or establish a REG_EXPAND_SZ registry value +named MofImagePath under the WMIACPI service key. The contents of the +value is a path to the image file that contains the resource. In either case, +the resource must be named MofResourceName.

+

 

+

The buffer resulting from the evaluation of the WQxx +control method assigned to the binary MOF GUID describes all data blocks, WMI +methods, and events for the device in a compressed binary format. This binary +data is created by building a text file using the MOF language and compiling it +with the MOF compiler.

+

 

+

MOF data types are very rich. MOF supports the basic data +types of 8-, 16-, 32-, and 64-bit signed and unsigned integers, Boolean terms, +floating points, strings, and UTC datetimes. Embedded classes—that is, +structures that can contain basic data types and other embedded classes—are also +supported. In addition, fixed and variable length arrays of basic data types and +embedded classes are supported.

+

 

+

The MOF language defines the data types shown in the +following table.

+

 

+

MOF Data Types

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Data types

+

Data format

+

String

+

Null terminated ANSI string

+

sint32

+

Signed 32-bit integer

+

uint32

+

Unsigned 32-bit integer

+

sint16

+

Signed 16-bit integer

+

uint16

+

Unsigned 16-bit integer

+

sint64

+

Signed 64-bit integer

+

uint64

+

Unsigned 64-bit integer

+

sint8

+

Signed 8-bit character

+

uint8

+

Unsigned 8-bit integer

+

Datetime

+

25-character string used to specify absolute dates or time + intervals.

+

Boolean

+

Byte where 0 is FALSE, != 0 is TRUE

+

 

+

Important: Because the MOF data types are much +richer than those for ACPI control methods, the control method must be careful +to pack the data blocks correctly within an ACPI buffer. The control method can +also restrict itself to using only common data types.

+

 

+

Each MOF class represents a data block and may contain one +or more properties that represent data items within the data block. A MOF class +would hold all information needed to parse a data block returned from the mapper. +In addition, the MOF language allows rich meta-data to be included as qualifiers +on properties and classes. Some qualifiers are required, but most are optional.

+

 

+

Class and data item qualifiers are defined in the following +table.

+

 

+

Class and Data Item Qualifiers

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Qualifier

+

Description

+

 

+

Class qualifiers:

+

 

+

 

+

[guid(“guid-string”)]

+

Declares the GUID that represents the class within WMI. This + qualifier is required.

+

 

+

[Dynamic]

+

Required for WBEM.

+

 

+

[WMI]

+

Required for WBEM.

+

 

+

[Provider(“WmiProv”)]

+

Required for WBEM.

+

 

+

[Description(“description-text”)]

+

Specifies description text for the class or property in the + locale specified for the locale qualifier.

+

 

+

[WmiExpense(expense-value)]

+

Specifies the quantity of system resources required in order + to collect data in the data block; expense-value is defined to be the + average number of CPU cycles needed to collect the data block. If this + qualifier is not specified, then the expense-value is assumed to be + 0.

+

 

+

Data item qualifiers:

+

 

+

[read]

+

Specifies that the data item may be read.

+

[write]

+

Specifies that the data item may be written.

+

[WmiDataID(data-item-ID)]

+

Specifies the data item ID for the data item. This qualifier + is required.

+

[WmiScale(scale-factor)] +

+

Specifies the scaling + factor to use when displaying the data. Before displaying the data returned + from a query of the data item, it is multiplied by 10 to the power of + scale-factor. If this qualifier is not specified, then the + scale-factor is assumed to be 0.

+

[WmiComplexity(“complexity-category”)]

+

Specifies the level of detail associated with the counter. + Complexity-category can have the value of “Novice” for the information + that anyone can understand, “Advanced” for information that is useful for + advanced users, “Expert” for information that is useful to only expert + users, and “Wizard” for information that is useful for the data provider + designer. If this qualifier is not specified, then a complexity-category + of “Novice” is assumed.

+

[WmiVolatility(validity-interval)]

+

Specifies how often this data item value is updated + internally. Validity-interval is defined in units of milliseconds, so + a validity-interval of 1000 would mean that the data item is updated + internally every second. Data consumers can use this measure to determine + how frequently it should poll for changes in a data item. If this qualifier + is not specified, then no assumption on the length of validity for a data + item can be made.

+

[WmiSizeIs(“property-name”)]

+

Specifies the property within the current class that has the + count of the number of array elements (not bytes) contained in a variable + length array.

+

 

+

The order that the data items +are laid out in the data block is controlled by the data item ID. Data item IDs +must be allocated contiguously starting with data item ID 1. The data item order +specified in the MOF is not relevant.

+

 

+

MOF supports arrays of the +basic types shown in the “MOF Data Types” table shown earlier. A variable sized +array must have a WmiSizeIs() qualifier that specifies the property that +has the number of elements in the array.

+

 

+

Data Block Format. +The format of the data block buffer returned from the query control method +and passed into the set control method must be consistent with the description +of it specified by the MOF for that data block with respect to the order and +size of the data items within the data block. +The Boolean data type is 1 byte in length and has a value of 0 for FALSE and +non-zero value for TRUE. The string data type is a C-style ANSI null-terminated +string.

+

 

+

Standard Data Blocks, Methods, +and Events. Additional data blocks, events, and methods will be +defined in the future; they should be implemented by all OEMs in order to ensure +a minimum of functionality on all PCs. In the future, an industry standard will +be defined for the globally unique GUIDs to be assigned to the data blocks. The +WMI component within Windows will contain the MOF definition for these standard +data blocks so it does not need to be part of the result from the binary .mof +query.

+

 

+

Custom Data Blocks, Methods and +Events. Custom or OEM-specific data blocks, events, and methods +can be added by including them in the result of the _WDG method. The GUIDs that +are assigned must be globally unique so they can be generated by a tool such as +Guidgen or Uuidgen, which are provided with the WMI information in the Microsoft +Platform SDK.

+

 

+

The MOF definition for these custom data blocks must be +included in the results of the WQxx method, where xx has been +mapped to the MOF Data GUID, which is the GUID that is queried and returns MOF +data—in order for applications to be able to access the data blocks. Or the MOF +could be added as a resource to Wmiacpi.sys with a name of MofResourceName +and a type MOFDATA. It can also be a resource in another image file with same +name and type that is pointed to by the MofImagePath value in the +registry key HKLM\CurrentControlSet\Services\WmiAcpi

+

 

+
+

FAQ about WMI and ACPI for Windows 2000 + Instrumentation

+
+

How does WMI find ACPI/ASL code?

+

In ASL, the developer +creates a device with an _HID of PNP0c14. +The operating system enumerates the device and loads the Wmiacpi.sys driver on +top of it.

+

How does the MOF +associated with ACPI BIOS get registered?

+

It is either a resource +attached to Wmiacpi.sys or another image file such as a resource-only DLL. +

+

How does a management +application discover the classes and properties provided by ASL instrumentation?

+

By looking in the WMI +namespace of the schema.

+

Is the following true? +Because very few ACPI standards exist for instrumentation, most of the ACPI +instrumented features will appear differently on each vendor’s product, and +management applications will have to be “taught” to interpret the varying +classes and methods.

+

Microsoft is looking at +standardizing this. Any suggestions are appreciated.

+

Who provides the .mof +files for standard ACPI features such as thermal monitoring?

+

Windows 2000 has a .mof +file for thermal zone temperature as part of the operating system and +instruments it within Acpi.sys, outside of the mapper.

+

Typically, .mof files are +compiled into .bmf files and attached to a driver as a resource. The .bmf files +can be in the ROM or on disk. WMI determines the location of the .mof +information by looking at the registry for the MofImagePath value under +the WMIACPI service. If this does not exist, then WMI looks at the ImagePath +value. If Wmiacpi.sys does not have a .mof resource, then WMI will query the +binary .mof GUID for the .mof information.

+

A driver may have a static +list of pre-built .mof files; if so, it can “dynamically” report one of them. +The mechanism is to report the file using a predefined GUID that returns a +binary .mof.

+

To dynamically build a .mof +file, a driver would have to build a .mof file and then launch the .mof +compiler, which is difficult. Currently, to do this on the machine running +Wmiacpi.sys, the mofcomp command can be used to load the .mof file +directly into the CIMOM database.

+ +

The following list +represents some of the ASL methods defined by the ACPI specification. These +methods are of particular interest for systems management. None of these methods +have been implemented yet within the WMI/ACPI mapper to date. A BIOS +developer, for example, could use these methods to expose data using the mapper. +These methods represent good opportunities +for OEMs to differentiate their products with minimal effort:

+

+·         +_ACX — Temperature threshold +at which various degrees of active cooling are engaged

+

+·         +_CRT — Critical temperature +at which system will shut down

+

+·         +_PSV — Temperature at which +system will throttle CPU in order to cool system

+

+·         +_LID — Status of the lid +(open or closed)

+

+·         +_PSR— Whether the machine +running on AC

+

 

+

The same applies for +these method for Control Method Battery devices:

+

+·         +_BIF — Battery information +such as model, serial number, design capacity, last full charge capacity, +technology, and battery capacity

+

+·         +_BST — Battery state, battery +present rate, battery remaining capacity, and battery voltage present

+

 

+

ASL Sample Code +for an Event and Initiating Method

+

The following ASL code +implements an event and a method that can be called to initiate that event.

+

Device(AMW0)

+

{

+

   // pnp0c14 is Plug and Play ID assigned to WMI mapper

+

   Name(_HID, "*pnp0c14")

+

   Name(_UID, 0x0)

+

 

+

   //

+

   // Description of data and events supported

+

   Name(_WDG, Buffer() {

+

       0x6a, 0x0f, 0xBC, 0xAB, 0xa1, +0x8e, 0xd1, 0x11, 0x00, 0xa0, 0xc9, 0x06, 0x29, 0x10, 0, 0,

+

        66, 65,        // Object ID (BA)

+

        3,             // Instance Count

+

        0x01,          // Flags (WMIACPI_REGFLAG_EXPENSIVE)

+

 

+

       0x6b, 0x0f, 0xBC, 0xAB, 0xa1, +0x8e, 0xd1, 0x11, 0x00, 0xa0, 0xc9, 0x06, 0x29, 0x10, 0, 0,

+

        66, 66,        // Object ID (BB)

+

        3,             // Instance Count

+

        0x02,          // Flags (WMIACPI_REGFLAG_METHOD)

+

 

+

       0x6c, 0x0f, 0xBC, 0xAB, 0xa1, +0x8e, 0xd1, 0x11, 0x00, 0xa0, 0xc9, 0x06, 0x29, 0x10, 0, 0,

+

        0xb0, 0,       // Notification ID

+

                    1,             // Instance Count

+

        0x08           // Flags (WMIACPI_REGFLAG_EVENT)

+

    })

+

 

+

    //

+

    // Storage for the 3 instances of BA

+

    Name(STB0, Buffer(0x10) {

+

        1,0,0,0, 2,0,0,0, 3,0,0,0, 4,0,0,0

+

         })

+

    Name(STB1, Buffer(0x10) {

+

        0,1,0,0, 0,2,0,0, 0,3,0,0, 0,4,0,0

+

         })

+

    Name(STB2, Buffer(0x10) {

+

        0,0,1,0, 0,0,2,0, 0,0,3,0, 0,0,4,0

+

         })

+

 

+

    //

+

    // Query data block

+

    // Arg0 has the instance being queried

+

    Method(WQBA, 1) {

+

        if (LEqual(Arg0, 0)) {

+

            Return(STB0)

+

        }

+

        if (LEqual(Arg0, 1)) {

+

            Return(STB1)

+

        }

+

        if (LEqual(Arg0, 2)) {

+

            Return(STB2)

+

        }

+

    }

+

 

+

    //

+

    // Set Data Block

+

    // Arg0 has the instance being +queried

+

    // Arg1 has the new value for +the data block instance

+

    Method(WSBA, 2) {

+

        if (LEqual(Arg0, 0)) {

+

            Store(Arg1, STB0)

+

        }

+

        if (LEqual(Arg0, 1)) {

+

            Store(Arg1, STB1)

+

        }

+

        if (LEqual(Arg0, 2)) {

+

            Store(Arg1, STB2)

+

        }

+

    }

+

 

+

    //

+

    // Storage for data block BB

+

    Name(B0ED, Buffer(0x10) {

+

        0,0,0,1, 0,0,0,2, 0,0,0,3, 0,0,0,4

+

         })

+

 

+

    //

+

    // Method Execution

+

    // Arg0 is instance being queried

+

    // Arg1 is the method ID

+

    // Arg2 is the method data passed

+

    Method(WMBB, 3) {

+

        if (LEqual(Arg1, 1))

+

        {

+

            Store(Arg3, B0ED)

+

            Notify(AMW0, 0xB0)

+

            Return(Arg3)

+

        } else {

+

            Return(Arg1)

+

        }

+

    }

+

 

+

    //

+

    // More info about an event

+

    // Arg0 is the event ID that was launched (“fired”)

+

    Method(_WED, 1) {

+

        if (LEqual(Arg0, 0xB0)) {

+

            Return(B0ED)

+

        }

+

    }

+

 

+

}

+

 

+

Sample ASL Code Embedding MOD Data in ASL

+

The following  sample ASL +code shows another example of implementing an event mechanism using ASL code.  +It also provides an example of embedding MOF data into ASL.

+

Device(AMW0)

+

{

+

//

+

// pnp0c14 is the ID assigned by +Microsoft to the WMI to ACPI mapper

+

   Name(_HID, "*pnp0c14")

+

   Name(_UID, 0x0)

+

//

+

// _WDG evaluates to a data +structure that specifies the data blocks supported

+

// by the ACPI device.

+

   +Name(_WDG, Buffer() {

+

       0x5a, 0x0f, 0xBC, 0xAB, 0xa1, +0x8e, 0xd1, 0x11, 0x00, 0xa0, 0xc9, 0x06, 0x29, 0x10, 0, 0,

+

       65, 65,        // Object ID (AA)

+

       2,             // Instance Count

+

       0x01,          // Flags WMIACPI_REGFLAG_EXPENSIVE

+

 

+

       0x5b, 0x0f, 0xBC, 0xAB, 0xa1, +0x8e, 0xd1, 0x11, 0x00, 0xa0, 0xc9, 0x06, 0x29, 0x10, 0, 0,

+

       65, 66,        // Object ID (AB)

+

       2,             // Instance Count

+

       0x02,          // Flags WMIACPI_REGFLAG_METHOD

+

 

+

       0x5c, 0x0f, 0xBC, 0xAB, 0xa1, +0x8e, 0xd1, 0x11, 0x00, 0xa0, 0xc9, 0x06, 0x29, 0x10, 0, 0,

+

       0xa0, 0,       // Notification ID

+

       1,             // Instance Count

+

       0x08,          // Flags (WMIACPI_REGFLAG_EVENT)

+

 

+

//

+

// This GUID for +returning the MOF data

+

 

+

       0x21, 0x12, 0x90, 0x05, 0x66, +0xd5, 0xd1, 0x11, 0xb2, 0xf0, 0x00, 0xa0, 0xc9, 0x06, 0x29, 0x10,

+

       66, 65,        // Object ID (BA)

+

       1,             // Instance Count

+

       0x00,          // Flags

+

 

+

   })

+

 

+

//

+

// Collection control method. If Arg0 is not zero then collection +for the

+

// data block is enabled. If Arg0 is zero then collection is +disabled. If

+

// this method does not exist then it is assumed that collection +control is

+

// not required. Collection control is only useful when collection +of the

+

// data block causes overhead.

+

   Method(WCAA, 1) {

+

       if (LEqual(Arg0, Zero)) {

+

           // Disable collection of data

+

       } else {

+

           // Enable collection of data

+

       }

+

   }

+

 

+

//

+

// Query method for data block AA. +Arg0 has the data block instance index

+

   Method(WQAA, 1) {

+

       if (LEqual(Arg0, Zero)) {

+

           // Query is for first +instance of data block

+

           return(0x10)

+

       } else {

+

           // Query is for second +instance of data block

+

           return(0x20)

+

       }

+

   }

+

 

+

//

+

// Set method for data block AA. If data block is read-only then +this method

+

// does not need to exist. Arg0 has the instance index of the data +block,

+

// Arg1 has the new value for the data block.

+

   Method(WSAA, 2) {

+

       if (LEqual(Arg0, Zero)) {

+

           // Set is for first instance of data block

+

       } else {

+

           // Set is for second instance of data block

+

       }

+

   }

+

 

+

//

+

// Event enable/disable method. If event does not need to be +armed/disarmed

+

// then this method is not needed. Arg0 is Zero if event is being +disarmed or

+

// non zero if event is being armed.

+

   Name(ACEN, 0)

+

   Method(WEA0, 1) {

+

       Store(Arg0, ACEN)

+

   }

+

 

+

//

+

// _WED is called in response to an event launching (“firing”) to +gain additional

+

// information about the event. Arg0 has the NotifyId for the +event launched.

+

   Method(_WED, 1) {

+

       if (LEqual(Arg0, 0xA0)) {

+

           Return(0x100)

+

       }

+

   }

+

//

+

// Evaluation of this method causes the event 0xA0 to be fired. +Since it is

+

// defined by the _WDG method it is callable via WMI. Arg0 has the +instance

+

// index and Arg1 has any input parameters.

+

   Method(WMAB, 3) {

+

       //

+

       // If event was armed then launch it

+

       if (LEqual(ACEN, 1)) {

+

           Notify(AMW0, 0xa0)

+

       }

+

       Return(Arg1)

+

   }

+

 

+

   Name(WQBA, Buffer(926) {

+

    0x46, +0x4f, 0x4d, 0x42, 0x01, 0x00, 0x00, 0x00, 0x8e, 0x03, 0x00, 0x00, 0xf6, 0x0f, +0x00, 0x00,

+

    0x44, +0x53, 0x00, 0x01, 0x1a, 0x7d, 0xda, 0x54, 0x98, 0xdd, 0x87, 0x00, 0x01, 0x06, +0x18, 0x42,

+

    0x10, +0x0b, 0x10, 0x0a, 0x0b, 0x21, 0x02, 0xcb, 0x82, 0x50, 0x3c, 0x18, 0x14, 0xa0, +0x25, 0x41,

+

    0xc8, +0x05, 0x14, 0x55, 0x02, 0x21, 0xc3, 0x02, 0x14, 0x0b, 0x70, 0x2e, 0x40, 0xba, +0x00, 0xe5,

+

    0x28, +0x72, 0x0c, 0x22, 0x82, 0xfd, 0xfb, 0x07, 0xc1, 0x90, 0x02, 0x08, 0x29, 0x84, +0x90, 0x08,

+

    0x58, +0x2a, 0x04, 0x8d, 0x10, 0xf4, 0x2b, 0x00, 0xa1, 0x43, 0x01, 0x32, 0x05, 0x18, +0x14, 0xe0,

+

    0x14, +0x41, 0x04, 0x41, 0x62, 0x17, 0x2e, 0xc0, 0x34, 0x8c, 0x06, 0xd0, 0x36, 0x8a, +0x64, 0x0b,

+

    0xb0, +0x0c, 0x2e, 0x98, 0xa3, 0x08, 0x92, 0xa0, 0xc6, 0x09, 0xa0, 0xc4, 0x4c, 0x00, +0xa5, 0x13,

+

    0x5c, +0x36, 0x05, 0x58, 0xc4, 0x96, 0x50, 0x14, 0x0d, 0x22, 0x4a, 0x82, 0x13, 0xea, +0x1b, 0x41,

+

    0x13, +0x2a, 0x57, 0x80, 0x64, 0x78, 0x69, 0x1e, 0x81, 0xac, 0xcf, 0x41, 0x93, 0xf2, +0x04, 0xb8,

+

    0x9a, +0x05, 0x7a, 0x8c, 0x34, 0xff, 0x30, 0x41, 0x99, 0x14, 0x43, 0x0e, 0x20, 0x24, +0x71, 0x98,

+

    0xa0, +0x9d, 0x59, 0xed, 0x18, 0xd2, 0x3d, 0x07, 0x32, 0x4d, 0x60, 0x21, 0x70, 0x9e, +0xb8, 0x19,

+

    0xa0, +0xf0, 0x5b, 0x1d, 0x80, 0xe0, 0x2b, 0x1d, 0x15, 0xd2, 0xeb, 0x34, 0x64, 0x72, +0x46, 0x48,

+

    0xf8, +0xff, 0x7f, 0x02, 0x26, 0xe3, 0xb7, 0x60, 0x02, 0xa5, 0xd9, 0xb2, 0x82, 0x4b, +0x80, 0xc1,

+

    0x68, +0x00, 0x91, 0xa2, 0x69, 0xa3, 0xe6, 0xea, 0xf9, 0x36, 0x8f, 0xaf, 0x59, 0x7a, +0x9e, 0x47,

+

    0x7a, +0x34, 0x56, 0x36, 0x05, 0xd4, 0xf8, 0x3d, 0x9d, 0x93, 0xf3, 0x4c, 0x02, 0x1e, +0x9c, 0x61,

+

    0x4e, +0x87, 0x83, 0xf1, 0xb1, 0xb1, 0x51, 0x70, 0x74, 0x03, 0xb2, 0x31, 0x38, 0xc6, +0xb0, 0xd1,

+

    0x73, +0x39, 0x81, 0x47, 0x82, 0x43, 0x89, 0x7e, 0x0e, 0x6f, 0x00, 0x47, 0x17, 0xe3, +0x04, 0xce,

+

    0x27, +0xc1, 0x61, 0x06, 0x39, 0xe3, 0x33, 0xf4, 0x44, 0x2c, 0x68, 0xd6, 0x02, 0x0a, +0x62, 0xa4,

+

    0x58, +0xa7, 0xf5, 0x7c, 0x10, 0x8b, 0x41, 0x05, 0x8b, 0x11, 0xdb, 0x50, 0x87, 0x60, +0x18, 0x8b,

+

    0x46, +0x11, 0xc8, 0x49, 0x3c, 0x49, 0x30, 0x94, 0x40, 0x51, 0x0c, 0x12, 0xda, 0xc3, +0x36, 0x92,

+

    0x81, +0xcf, 0xdb, 0x20, 0xc7, 0x84, 0x51, 0x01, 0x21, 0xcf, 0xe3, 0xd0, 0x28, 0x4d, +0xd0, 0xfd,

+

    0x29, +0x40, 0x37, 0x8b, 0x08, 0x67, 0x54, 0xd8, 0x44, 0x64, 0x6d, 0x02, 0xb2, 0x25, +0x40, 0x1c,

+

    0xbe, +0x40, 0x1a, 0x43, 0x11, 0x44, 0x84, 0x98, 0x51, 0x8c, 0x19, 0x30, 0x82, 0x51, +0x0e, 0xa6,

+

    0x39, +0x10, 0x69, 0x13, 0x30, 0xf6, 0x20, 0xd1, 0x62, 0x31, 0x04, 0xdb, 0x9f, 0x83, +0x30, 0x0e,

+

    0x05, +0xa3, 0x03, 0x42, 0xe7, 0x84, 0xc3, 0x3b, 0x30, 0x9f, 0x1e, 0x4c, 0x70, 0xda, +0xcf, 0x07,

+

    0xaf, +0x0b, 0x21, 0x8b, 0x17, 0x20, 0x0d, 0x43, 0xf8, 0x09, 0x6a, 0x7d, 0x51, 0xe8, +0x5a, 0xe0,

+

    0x34, +0xe0, 0xa8, 0xeb, 0x82, 0x6f, 0x01, 0xbe, 0x01, 0x9c, 0xe0, 0xe3, 0x85, 0xf1, +0x83, 0x1c,

+

    0xc1, +0x01, 0x3c, 0x44, 0xbc, 0x1a, 0x78, 0x08, 0x9e, 0xc3, 0xfb, 0x05, 0x3b, 0x0f, +0x60, 0xff,

+

    0xff, +0x04, 0x5d, 0xe3, 0xe9, 0x92, 0x70, 0x02, 0x96, 0x83, 0x86, 0x1a, 0xac, 0x2f, +0x00, 0x27,

+

    0xe9, +0xc1, 0x1a, 0xae, 0xae, 0xd3, 0x06, 0x7a, 0xba, 0xa7, 0x72, 0x5a, 0xa5, 0x0a, +0x30, 0x7b,

+

    0x94, +0x20, 0x04, 0xcf, 0x1e, 0x6c, 0xde, 0x67, 0x73, 0xe6, 0x09, 0x9e, 0x14, 0x3c, +0x05, 0x3e,

+

    0x2d, +0xcf, 0xd2, 0x97, 0x0e, 0x5f, 0x09, 0x7c, 0x9f, 0x30, 0x41, 0xf4, 0x27, 0x17, +0x36, 0x1a,

+

    0xb8, +0xc3, 0xc6, 0x8d, 0x06, 0xce, 0xe5, 0xe0, 0xb1, 0xc3, 0x33, 0xf7, 0x5c, 0x4d, +0x50, 0xf3,

+

    0xe5, +0x42, 0x4e, 0x66, 0x83, 0xd2, 0x03, 0xa2, 0x01, 0x3f, 0x34, 0x60, 0xd0, 0x1f, +0x19, 0xb8,

+

    0xc8, +0x8b, 0x02, 0x95, 0x86, 0xac, 0xbf, 0x86, 0x45, 0x8d, 0x9b, 0x12, 0x58, 0xca, +0xa1, 0x82,

+

    0xdc, 0x33, 0x7c, 0x9e, 0x38, +0x8c, 0x57, 0x00, 0xcf, 0xe6, 0xa0, 0x7c, 0x73, 0x71, 0xba, 0x7b,

+

    0x05, 0x68, 0x66, 0x83, 0xbb, +0x51, 0x80, 0x05, 0xc3, 0xd7, 0x03, 0xdf, 0x30, 0xd8, 0xf1, 0xc3,

+

    0xd7, 0x0c, 0x36, 0x24, 0x83, +0x45, 0x89, 0x14, 0x9b, 0x4d, 0xca, 0x03, 0xc0, 0xe0, 0xbd, 0xd7,

+

    0xf8, 0x70, 0x61, 0x48, 0x9f, +0x31, 0xe0, 0x1e, 0x05, 0xe0, 0xfd, 0xff, 0xcf, 0x09, 0xe0, 0xb8,

+

    0x6d, 0xf8, 0x2a, 0x62, 0x67, +0xf7, 0x0b, 0x5d, 0x6f, 0xb0, 0xf7, 0x1d, 0x78, 0xf8, 0x87, 0x85,

+

    0xbb, 0x0b, 0x30, 0xb0, 0x13, +0xc5, 0x1c, 0x78, 0x80, 0xc7, 0x64, 0x1e, 0x78, 0xc0, 0x75, 0x96,

+

    0x82, 0x3d, 0x04, 0xae, 0xfa, +0xc0, 0x83, 0xca, 0xf1, 0x6a, 0xa0, 0x67, 0x1e, 0xc0, 0xec, 0xff,

+

    0xff, 0xcc, 0x03, 0x8c, 0xe0, +0x9f, 0x79, 0x80, 0x6b, 0xf4, 0x6b, 0x81, 0xde, 0x57, 0x3e, 0xf3,

+

    0x00, 0x7c, 0x50, 0x79, 0x33, +0x01, 0xcd, 0xff, 0xff, 0x66, 0x02, 0xe3, 0xe0, 0xe0, 0x83, 0x88,

+

    0xaf, 0x32, 0x3e, 0x11, 0x02, +0x93, 0xab, 0x09, 0x70, 0x09, 0x79, 0x27, 0xa2, 0x01, 0x07, 0x41,

+

    0xaf, 0x01, 0x5c, 0x0b, 0x88, +0x66, 0xc8, 0xa6, 0x89, 0x25, 0x98, 0xe5, 0x22, 0x40, 0xef, 0x8a,

+

    0x3e, 0x2a, 0xf1, 0x31, 0xfa, +0xa8, 0xc4, 0x70, 0xdf, 0x85, 0x8c, 0x7b, 0x7a, 0x67, 0xf7, 0xac,

+

    0x84, 0xb9, 0x04, 0xbc, 0x8f, +0x80, 0x65, 0xf2, 0xf8, 0xd3, 0x07, 0x47, 0xf4, 0x85, 0xc1, 0x77,

+

    0x23, 0x78, 0x04, 0xd5, 0x5f, +0x65, 0xa8, 0xfe, 0xbd, 0x48, 0x2f, 0x0c, 0xea, 0x2a, 0x03, 0x5c,

+

    0xff, 0xff, 0x57, 0x19, 0x36, +0xc8, 0x63, 0x05, 0xcb, 0xf9, 0x11, 0x33, 0xc7, 0xd3, 0x8c, 0xe2,

+

    0xa9, 0x78, 0xb8, 0xec, 0x62, +0x65, 0xef, 0x53, 0x25, 0xc7, 0x17, 0x5f, 0xab, 0xf0, 0x20, 0x8f,

+

    0x31, 0xbe, 0xc3, 0x80, 0x71, +0x04, 0xef, 0x30, 0xc0, 0x35, 0xf0, 0xcb, 0x41, 0xd7, 0x40, 0xc0,

+

    0xf6, 0xff, 0xff, 0x0e, 0x03, +0x96, 0xe0, 0x10, 0xba, 0x06, 0xe2, 0x64, 0x1c, 0x5b, 0xc8, 0x4d,

+

    0xca, +0x53, 0x36, 0xc1, 0xa0, 0x13, 0xa6, 0x47, 0x40, 0xf0, 0xdc, 0x2b, 0x7c, 0x98, +0x00, 0xc7,

+

    0x48, +0x30, 0xe7, 0x08, 0x9f, 0x1f, 0x7c, 0x7d, 0x78, 0x93, 0x60, 0x37, 0x0e, 0xc3, +0xf8, 0xca,

+

    0x07, +0x0f, 0xf2, 0x15, 0x8b, 0x5d, 0x26, 0xf8, 0x49, 0x0f, 0x6c, 0x17, 0x65, 0x70, +0xdc, 0x7f,

+

    0xe0, +0x5c, 0x94, 0x81, 0x11, 0xee, 0xe3, 0x0f, 0xf8, 0x0f, 0xcb, 0x70, 0xfe, 0xff

+

           })

+

        }

+

 

+

Sample .Mof File

+

This sample .mof file +complements the previous ASL code.

+

[abstract]

+

class AcpiSampleBase

+

{

+

};

+

 

+

[abstract]

+

class AcpiSampleEvent : WMIEvent

+

{

+

};

+

 

+

[Dynamic, Provider("WMIProv"),

+

 WMI,

+

 Description("Counter for number +of times the case has been hit"),

+

 GUID("{ABBC0f5a-8ea1-11d1-A000-c90629100000}"),

+

 locale("MS\\0x409")]

+

class MachineHitSensor : AcpiSampleBase

+

{

+

    [key, read]

+

     string InstanceName;

+

    [read] Boolean Active;

+

 

+

    [WmiDataId(1),

+

     Description("Number of times the case sensor determined that +the machine has been hit"),

+

     read

+

    ] uint32 NumberTimesHit;

+

};

+

 

+

[Dynamic, Provider("WMIProv"),

+

 WMI,

+

 Description("Counter for number of times the case has been hit"),

+

 GUID("{ABBC0f5b-8ea1-11d1-A000-c90629100000}"),

+

 locale("MS\\0x409")]

+

class MachineHitSimulate : AcpiSampleBase

+

{

+

    [key, read]

+

     string InstanceName;

+

    [read] Boolean Active;

+

 

+

    [WmiMethodId(1),

+

     Description("Simulate hitting the machine")

+

    ] void HitMachine();

+

};

+

 

+

[Dynamic, Provider("WMIProv"),

+

 WMI,

+

 Description("Event generated when machine is hit"),

+

 GUID("{ABBC0f5c-8ea1-11d1-A000-c90629100000}"),

+

 locale("MS\\0x409")]

+

class MachineHitEvent : AcpiSampleEvent

+

{

+

    [key, read]

+

     string InstanceName;

+

    [read] Boolean Active;

+

 

+

    [WmiDataId(1),

+

     Description("Force with which the machine was hit")

+

    ] uint32 Force;

+

};

+

 

+

Appendix C—ASL sample code

+

Device(WMI1) {

+

    Name (_HID, EISAID("PNP0Cxx"))        // Plug and Play ID for +mapping driver (TBD)

+

    _UID(1)

+

 

+

    //

+

    // Data block and Wmi method to Object ID mappings

+

    Name(_WDG, Buffer() {

+

          // Object AA - {ABBC0F5A-8EA1-11d1-A53F-00A0C9062910}

+

              0xABBC0F5A, 0x8ea1, 0x11d1, 0x00, 0xa0, 0xc9, 0x06, +0x29, 0x10,

+

              `A','A',       // Object ID

+

               1,            // Instance Count

+

               0x04,         // Flags (WMIACPI_REGFLAG_STRING)

+

   

+

          // Object AB - {ABBC0F5B-8EA1-11d1-A53F-00A0C9062910}

+

              0xABBC0F5B, 0x8ea1, 0x11d1, 0x00, 0xa0, 0xc9, 0x06, +0x29, 0x10,

+

              `A','B',    // Object ID

+

              2,          // Instance Count

+

              0x01,       // Flag (WMIACPI_REGFLAG_EXPENSIVE)

+

 

+

          // Object AC - {ABBC0F5C-8EA1-11d1-A53F-00A0C9062910}

+

              0xABBC0F5C, 0x8ea1, 0x11d1, 0x00, 0xa0, 0xc9, 0x06, +0x29, 0x10,

+

              `A','C',    // Object ID

+

              1,          // Instance Count

+

              0x06,       // Flag (WMIACPI_REGFLAG_METHOD | +_STRING)

+

 

+

          // Event 0x80 - {ABBC0F5D-8EA1-11d1-A53F-00A0C9062910}

+

              0xABBC0F5D, 0x8ea1, 0x11d1, 0x00, 0xa0, 0xc9, 0x06, +0x29, 0x10,

+

              0x80,        // Notification value

+

              0,           // Reserved

+

              0,           // Instance Count (Not meaningful for +events)

+

              0x0D         // Flags (WMIACPI_REGFLAG_EXPENSIVE | +_STRING |_EVENT)

+

    })

+

 

+

 

+

 

+

    //

+

    // IO ports for configuration of Object AB

+

    OperationRegion(CAB0, SystemIo, 0xf8, 1)   // Instance 0

+

    OperationRegion(CAB1, SystemIo, 0xfc, 1)   // Instance 1

+

    OperationRegion(CABC, SystemIo, 0xf4, 1)   // Enable/Disable +Collection

+

 

+

    Method(WQAB, 1) {

+

        //

+

        // Read value from IO space for instance

+

        if (LEqual(Arg0, Zero) {

+

            Store(CAB0, Local0)

+

        } else {

+

            Store(CAB1, Local0)

+

        }

+

 

+

        //

+

        // If any of the lower 3 bits are set then return TRUE, +else FALSE

+

        if (And(Local0, 7))

+

            Return( 0x00000001 )

+

        } else {

+

            Return( 0x00000000 )

+

        }

+

    }

+

 

+

    //

+

    // Set the values for object AB

+

    Method(WSAB, 2) {

+

        if (LEqual(Arg0, Zero) {

+

                // Change contents of first instance of data block +to

+

                // values in buffer in Arg1

+

            } else {

+

               // Change contents of second instance of data block +to

+

               // values in buffer in Arg1

+

            }

+

       }

+

 

+

    //

+

    // Collection notification for object AB

+

    Method(WCAB, 1) {

+

        if (LEqual(Arg0, 1)

+

        {

+

            Store(One, CABC)     // If enable, write all 1's to +port

+

        } else {

+

            Store(Zero, CABC)    // If disable, write all 0's to +port

+

        }

+

    }

+

 

+

 

+

    //

+

    // Storage for maintaining values for the AA method.

+

    Name(STAA, "XYZZY")

+

 

+

    Method(WQAA, 1) {

+

        //

+

        // Only one instance for AA so no need to check arg

+

        return(STAA);

+

    }

+

 

+

    // Data block mapped to Object AA does not support set so it +does not need

+

    // a WSAA method

+

 

+

    //

+

    // Storage for maintaining state of flag that determines +whether to fire (launch)

+

    // the event or not. By default firing is disabled

+

    Name(FIRE, 0)

+

 

+

    //

+

    // This method will reset the +values for AA and send a notification of

+

    // its occurrence

+

    Method(WMAC, 3) {

+

        Store(STAA, Local0)

+

        Store("XYZZY", STAA)

+

        if (LEqual(FIRE, 1))

+

        {

+

            Notify(WMI1, 0x80)

+

        }

+

        Return(Local0)

+

    }

+

 

+

    //

+

    // Additional information about event

+

    Method(_WED) {

+

        return("Fired")

+

    }

+

 

+

    //

+

    // Event 0x80 Enable/Disable control method

+

    Method(WE80, 1) {

+

        Store(FIRE, Arg0)

+

    }

+

)

+

 

+

 

+

 

+ + + + diff --git a/wmi/wmisamp/WmiSamp.vcxproj b/wmi/wmisamp/WmiSamp.vcxproj index fda9553a..0d36a354 100644 --- a/wmi/wmisamp/WmiSamp.vcxproj +++ b/wmi/wmisamp/WmiSamp.vcxproj @@ -19,12 +19,12 @@
- {06CD57B4-A48B-4ECB-A9F2-A7DFAE5DD889} + {09048545-F6CE-4908-9BB5-9186BD12776B} $(MSBuildProjectName) 1 Debug Win32 - {E1E884D9-A9BB-487C-940F-3DFC56D5CF6B} + {F006BD87-731B-4D2A-B741-D0B1F762BABC} diff --git a/wmi/wmisamp/WmiSamp.vcxproj.Filters b/wmi/wmisamp/WmiSamp.vcxproj.Filters index e87c4143..33866ca0 100644 --- a/wmi/wmisamp/WmiSamp.vcxproj.Filters +++ b/wmi/wmisamp/WmiSamp.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {238A725C-DAE4-400C-AE13-B6F0C0F4DA2C} + {5EF5CA7C-7CAE-4919-A630-40021ADBAD7A} h;hpp;hxx;hm;inl;inc;xsd - {59E4EF23-B527-4C8A-B5CC-0A9E02261478} + {36AFBC05-BF36-497F-9479-232E53032646} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {D0529155-7635-407E-B449-600DD00471D4} + {4754802C-E1A1-40AA-A07E-FDD309D1FE65} inf;inv;inx;mof;mc; - {74D250C1-56AE-46BF-A6A8-FB47A4D81F97} + {2873486C-A803-4AC3-99EC-2F2589EFBAD4} diff --git a/wmi/wmisamp/wmisamp.sln b/wmi/wmisamp/wmisamp.sln index ac0fca53..d2935890 100644 --- a/wmi/wmisamp/wmisamp.sln +++ b/wmi/wmisamp/wmisamp.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WmiSamp", "WmiSamp.vcxproj", "{06CD57B4-A48B-4ECB-A9F2-A7DFAE5DD889}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WmiSamp", "WmiSamp.vcxproj", "{09048545-F6CE-4908-9BB5-9186BD12776B}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +13,14 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {06CD57B4-A48B-4ECB-A9F2-A7DFAE5DD889}.Debug|Win32.ActiveCfg = Debug|Win32 - {06CD57B4-A48B-4ECB-A9F2-A7DFAE5DD889}.Debug|Win32.Build.0 = Debug|Win32 - {06CD57B4-A48B-4ECB-A9F2-A7DFAE5DD889}.Release|Win32.ActiveCfg = Release|Win32 - {06CD57B4-A48B-4ECB-A9F2-A7DFAE5DD889}.Release|Win32.Build.0 = Release|Win32 - {06CD57B4-A48B-4ECB-A9F2-A7DFAE5DD889}.Debug|x64.ActiveCfg = Debug|x64 - {06CD57B4-A48B-4ECB-A9F2-A7DFAE5DD889}.Debug|x64.Build.0 = Debug|x64 - {06CD57B4-A48B-4ECB-A9F2-A7DFAE5DD889}.Release|x64.ActiveCfg = Release|x64 - {06CD57B4-A48B-4ECB-A9F2-A7DFAE5DD889}.Release|x64.Build.0 = Release|x64 + {09048545-F6CE-4908-9BB5-9186BD12776B}.Debug|Win32.ActiveCfg = Debug|Win32 + {09048545-F6CE-4908-9BB5-9186BD12776B}.Debug|Win32.Build.0 = Debug|Win32 + {09048545-F6CE-4908-9BB5-9186BD12776B}.Release|Win32.ActiveCfg = Release|Win32 + {09048545-F6CE-4908-9BB5-9186BD12776B}.Release|Win32.Build.0 = Release|Win32 + {09048545-F6CE-4908-9BB5-9186BD12776B}.Debug|x64.ActiveCfg = Debug|x64 + {09048545-F6CE-4908-9BB5-9186BD12776B}.Debug|x64.Build.0 = Debug|x64 + {09048545-F6CE-4908-9BB5-9186BD12776B}.Release|x64.ActiveCfg = Release|x64 + {09048545-F6CE-4908-9BB5-9186BD12776B}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/wpd/WpdBasicHardwareDriver/Device.cpp b/wpd/WpdBasicHardwareDriver/Device.cpp deleted file mode 100644 index 22a7ade8..00000000 --- a/wpd/WpdBasicHardwareDriver/Device.cpp +++ /dev/null @@ -1,415 +0,0 @@ -#include "stdafx.h" -#include "Device.tmh" - -#include "WpdBasicHardwareDriver_i.c" - -STDMETHODIMP_(HRESULT) -CDevice::OnD0Entry(_In_ IWDFDevice* pDevice, - WDF_POWER_DEVICE_STATE previousState) -{ - TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_FLAG_DEVICE, "%!FUNC! Entry"); - - UNREFERENCED_PARAMETER(pDevice); - UNREFERENCED_PARAMETER(previousState); - - HRESULT hr = S_OK; - RS232Target* pTarget = NULL; - - if (m_pWpdBaseDriver != NULL) - { - pTarget = m_pWpdBaseDriver->GetRS232Target(); - if (pTarget != NULL) - { - hr = pTarget->Start(); - } - } - - return hr; -} - -STDMETHODIMP_(HRESULT) -CDevice::OnD0Exit(_In_ IWDFDevice* pDevice, - WDF_POWER_DEVICE_STATE newState) -{ - TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_FLAG_DEVICE, "%!FUNC! Entry"); - - UNREFERENCED_PARAMETER(pDevice); - UNREFERENCED_PARAMETER(newState); - - HRESULT hr = S_OK; - RS232Target* pTarget = NULL; - - if (m_pWpdBaseDriver != NULL) - { - pTarget = m_pWpdBaseDriver->GetRS232Target(); - if (pTarget != NULL) - { - hr = pTarget->Stop(); - } - } - return hr; -} - -STDMETHODIMP_(VOID) -CDevice::OnSurpriseRemoval(_In_ IWDFDevice* pDevice) -{ - UNREFERENCED_PARAMETER(pDevice); - return; -} - -STDMETHODIMP_(HRESULT) -CDevice::OnQueryRemove(_In_ IWDFDevice* /*pDevice*/) -{ - return S_OK; -} - -STDMETHODIMP_(HRESULT) -CDevice::OnQueryStop(_In_ IWDFDevice* /*pDevice*/) -{ - return S_OK; -} - -STDMETHODIMP_(VOID) -CDevice::OnSelfManagedIoCleanup(_In_ IWDFDevice* pDevice) -{ - UNREFERENCED_PARAMETER(pDevice); - return; -} - -STDMETHODIMP_(VOID) -CDevice::OnSelfManagedIoFlush(_In_ IWDFDevice* pDevice) -{ - UNREFERENCED_PARAMETER(pDevice); - return; -} - -STDMETHODIMP_(HRESULT) -CDevice::OnSelfManagedIoInit(_In_ IWDFDevice* pDevice) -{ - UNREFERENCED_PARAMETER(pDevice); - return S_OK; -} - -STDMETHODIMP_(HRESULT) -CDevice::OnSelfManagedIoSuspend(_In_ IWDFDevice* pDevice) -{ - UNREFERENCED_PARAMETER(pDevice); - return S_OK; -} - -STDMETHODIMP_(HRESULT) -CDevice::OnSelfManagedIoRestart(_In_ IWDFDevice* pDevice) -{ - UNREFERENCED_PARAMETER(pDevice); - return S_OK; -} - -STDMETHODIMP_(HRESULT) -CDevice::OnSelfManagedIoStop(_In_ IWDFDevice* pDevice) -{ - UNREFERENCED_PARAMETER(pDevice); - return S_OK; -} - -STDMETHODIMP_(HRESULT) -CDevice::OnPrepareHardware(_In_ IWDFDevice* pDevice) -{ - TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_FLAG_DEVICE, "%!FUNC! Entry"); - - HRESULT hr = S_OK; - - if (m_pWpdBaseDriver != NULL) - { - hr = m_pWpdBaseDriver->Initialize(pDevice); - CHECK_HR(hr, "Failed to Initialize the driver class"); - } - - // Initialize the WPD Class Extension. This will enable the appropriate WPD interface GUID, - // as well as do any additional initialization (e.g. enabling Legacy Compatibility layers for those drivers - // which requested support in their INF). - if (hr == S_OK && m_pPortableDeviceClassExtension == NULL) - { - hr = CoCreateInstance(CLSID_PortableDeviceClassExtension, - NULL, - CLSCTX_INPROC_SERVER, - IID_IPortableDeviceClassExtension, - (VOID**)&m_pPortableDeviceClassExtension); - CHECK_HR(hr, "Failed to CoCreate CLSID_PortableDeviceClassExtension"); - - if (hr == S_OK) - { - CComPtr pOptions; - hr = CoCreateInstance(CLSID_PortableDeviceValues, - NULL, - CLSCTX_INPROC_SERVER, - IID_IPortableDeviceValues, - (VOID**)&pOptions); - CHECK_HR(hr, "Failed to CoCreate CLSID_PortableDeviceValues"); - - if (hr == S_OK) - { - CComPtr pContentTypes; - hr = CoCreateInstance(CLSID_PortableDevicePropVariantCollection, - NULL, - CLSCTX_INPROC_SERVER, - IID_IPortableDevicePropVariantCollection, - (VOID**)&pContentTypes); - CHECK_HR(hr, "Failed to CoCreate CLSID_PortableDevicePropVariantCollection"); - - // Driver has no supported content types, add an empty list of supported content types to the options - if (hr == S_OK) - { - hr = pOptions->SetIPortableDevicePropVariantCollectionValue(WPD_CLASS_EXTENSION_OPTIONS_SUPPORTED_CONTENT_TYPES, pContentTypes); - CHECK_HR(hr, "Failed to set WPD_CLASS_EXTENSION_OPTIONS_SUPPORTED_CONTENT_TYPES"); - } - - if (hr == S_OK) - { - // Initialize the PortableDeviceClassExtension - hr = m_pPortableDeviceClassExtension->Initialize(pDevice, pOptions); - CHECK_HR(hr, "Failed to Initialize portable device class extension object"); - } - } - } - - if (hr == S_OK) - { - // Since users commonly have the abiltity to customize their device even when it is not - // connected to the PC, we need to make sure the PC is current when the driver loads. - // - // Send the latest device friendly name to the PortableDeviceClassExtension component - // so the system is always updated with the current device name. - // - // This call should also be made after a successful property set operation of - // WPD_DEVICE_FRIENDLY_NAME. - LPWSTR wszDeviceFriendlyName = NULL; - - if (hr == S_OK) - { - hr = GetDeviceFriendlyName(&wszDeviceFriendlyName); - CHECK_HR(hr, "Failed to get device's friendly name"); - } - - if (hr == S_OK && wszDeviceFriendlyName != NULL) - { - hr = UpdateDeviceFriendlyName(m_pPortableDeviceClassExtension, wszDeviceFriendlyName); - CHECK_HR(hr, "Failed to update device's friendly name"); - } - - // Free the memory. - CoTaskMemFree(wszDeviceFriendlyName); - wszDeviceFriendlyName = NULL; - } - } - return hr; -} - -STDMETHODIMP_(HRESULT) -CDevice::OnReleaseHardware(_In_ IWDFDevice* pDevice) -{ - TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_FLAG_DEVICE, "%!FUNC! Entry"); - - UNREFERENCED_PARAMETER(pDevice); - if (m_pWpdBaseDriver != NULL) - { - m_pWpdBaseDriver->Uninitialize(); - } - - if (m_pPortableDeviceClassExtension != NULL) - { - m_pPortableDeviceClassExtension = NULL; - } - - return S_OK; -} - -HRESULT CDevice::GetDeviceFriendlyName( - _Outptr_result_maybenull_ LPWSTR* pwszDeviceFriendlyName) -{ - HRESULT hr = S_OK; - - CComPtr pParams; - CComPtr pResults; - CComPtr pKeys; - CComPtr pValues; - - if (pwszDeviceFriendlyName == NULL) - { - hr = E_INVALIDARG; - return hr; - } - - *pwszDeviceFriendlyName = NULL; - - // CoCreate a collection to store the WPD_COMMAND_OBJECT_PROPERTIES_GET command parameters. - if (hr == S_OK) - { - hr = CoCreateInstance(CLSID_PortableDeviceValues, - NULL, - CLSCTX_INPROC_SERVER, - IID_IPortableDeviceValues, - (VOID**)&pParams); - CHECK_HR(hr, "Failed to CoCreate CLSID_PortableDeviceValues"); - } - - // CoCreate a collection to store the WPD_COMMAND_OBJECT_PROPERTIES_GET command results. - if (hr == S_OK) - { - hr = CoCreateInstance(CLSID_PortableDeviceValues, - NULL, - CLSCTX_INPROC_SERVER, - IID_IPortableDeviceValues, - (VOID**)&pResults); - CHECK_HR(hr, "Failed to CoCreate CLSID_PortableDeviceValues"); - } - - // CoCreate a collection to store the requested property keys. In our case, we are requesting just the device friendly name - // (WPD_DEVICE_FRIENDLY_NAME) - if (hr == S_OK) - { - hr = CoCreateInstance(CLSID_PortableDeviceKeyCollection, - NULL, - CLSCTX_INPROC_SERVER, - IID_IPortableDeviceKeyCollection, - (VOID**)&pKeys); - CHECK_HR(hr, "Failed to CoCreate CLSID_PortableDeviceKeyCollection for results"); - } - - // Set the params - if (hr == S_OK) - { - hr = pParams->SetGuidValue(WPD_PROPERTY_COMMON_COMMAND_CATEGORY, WPD_COMMAND_OBJECT_PROPERTIES_GET.fmtid); - CHECK_HR(hr, ("Failed to set WPD_PROPERTY_COMMON_COMMAND_CATEGORY")); - } - - if (hr == S_OK) - { - hr = pParams->SetUnsignedIntegerValue(WPD_PROPERTY_COMMON_COMMAND_ID, WPD_COMMAND_OBJECT_PROPERTIES_GET.pid); - CHECK_HR(hr, ("Failed to set WPD_PROPERTY_COMMON_COMMAND_ID")); - } - - if (hr == S_OK) - { - hr = pParams->SetStringValue(WPD_PROPERTY_OBJECT_PROPERTIES_OBJECT_ID, WPD_DEVICE_OBJECT_ID); - CHECK_HR(hr, ("Failed to set WPD_PROPERTY_OBJECT_PROPERTIES_OBJECT_ID")); - } - - if (hr == S_OK) - { - hr = pKeys->Add(WPD_DEVICE_FRIENDLY_NAME); - CHECK_HR(hr, ("Failed to add WPD_DEVICE_FRIENDLY_NAME to key collection")); - } - - if (hr == S_OK) - { - hr = pParams->SetIPortableDeviceKeyCollectionValue(WPD_PROPERTY_OBJECT_PROPERTIES_PROPERTY_KEYS, pKeys); - CHECK_HR(hr, ("Failed to set WPD_PROPERTY_OBJECT_PROPERTIES_PROPERTY_KEYS")); - } - - // Make the call - if (hr == S_OK) - { - hr = m_pWpdBaseDriver->DispatchWpdMessage(pParams, pResults); - CHECK_HR(hr, ("Failed to dispatch message to get supported content types")); - } - - // Get the results - if (hr == S_OK) - { - hr = pResults->GetIPortableDeviceValuesValue(WPD_PROPERTY_OBJECT_PROPERTIES_PROPERTY_VALUES, &pValues); - CHECK_HR(hr, ("Failed to get WPD_PROPERTY_OBJECT_PROPERTIES_PROPERTY_VALUES")); - } - - if (hr == S_OK) - { - hr = pValues->GetStringValue(WPD_DEVICE_FRIENDLY_NAME, pwszDeviceFriendlyName); - CHECK_HR(hr, ("Failed to get WPD_DEVICE_FRIENDLY_NAME")); - } - - return hr; -} - -HRESULT UpdateDeviceFriendlyName( - _In_ IPortableDeviceClassExtension* pPortableDeviceClassExtension, - _In_ LPCWSTR wszDeviceFriendlyName) -{ - HRESULT hr = S_OK; - - // If we were passed NULL parameters we have nothing to do, return S_OK. - if ((pPortableDeviceClassExtension == NULL) || - (wszDeviceFriendlyName == NULL)) - { - return S_OK; - } - - CComPtr pParams; - CComPtr pResults; - CComPtr pValues; - - // Prepare to make a call to set the device information - if (hr == S_OK) - { - hr = CoCreateInstance(CLSID_PortableDeviceValues, - NULL, - CLSCTX_INPROC_SERVER, - IID_IPortableDeviceValues, - (VOID**)&pParams); - CHECK_HR(hr, "Failed to CoCreate CLSID_PortableDeviceValues"); - } - - if (hr == S_OK) - { - hr = CoCreateInstance(CLSID_PortableDeviceValues, - NULL, - CLSCTX_INPROC_SERVER, - IID_IPortableDeviceValues, - (VOID**)&pResults); - CHECK_HR(hr, "Failed to CoCreate CLSID_PortableDeviceValues for results"); - } - - if (hr == S_OK) - { - hr = CoCreateInstance(CLSID_PortableDeviceValues, - NULL, - CLSCTX_INPROC_SERVER, - IID_IPortableDeviceValues, - (VOID**)&pValues); - CHECK_HR(hr, "Failed to CoCreate CLSID_PortableDeviceValues for results"); - } - - // Get the information values to update and set them in WPD_PROPERTY_CLASS_EXTENSION_DEVICE_INFORMATION_VALUES - if (hr == S_OK) - { - hr = pValues->SetStringValue(WPD_DEVICE_FRIENDLY_NAME, wszDeviceFriendlyName); - CHECK_HR(hr, ("Failed to set WPD_DEVICE_FRIENDLY_NAME")); - } - - // Set the params - if (hr == S_OK) - { - hr = pParams->SetGuidValue(WPD_PROPERTY_COMMON_COMMAND_CATEGORY, WPD_COMMAND_CLASS_EXTENSION_WRITE_DEVICE_INFORMATION.fmtid); - CHECK_HR(hr, ("Failed to set WPD_PROPERTY_COMMON_COMMAND_CATEGORY")); - } - if (hr == S_OK) - { - hr = pParams->SetUnsignedIntegerValue(WPD_PROPERTY_COMMON_COMMAND_ID, WPD_COMMAND_CLASS_EXTENSION_WRITE_DEVICE_INFORMATION.pid); - CHECK_HR(hr, ("Failed to set WPD_PROPERTY_COMMON_COMMAND_ID")); - } - if (hr == S_OK) - { - hr = pParams->SetIPortableDeviceValuesValue(WPD_PROPERTY_CLASS_EXTENSION_DEVICE_INFORMATION_VALUES, pValues); - CHECK_HR(hr, ("Failed to set WPD_PROPERTY_CLASS_EXTENSION_DEVICE_INFORMATION_VALUES")); - } - - // Make the call - if (hr == S_OK) - { - hr = pPortableDeviceClassExtension->ProcessLibraryMessage(pParams, pResults); - CHECK_HR(hr, ("Failed to process update device information message")); - } - - // A Failed ProcessLibraryMessage operation for updating this value is not considered - // fatal and should return S_OK. - - return S_OK; -} diff --git a/wpd/WpdBasicHardwareDriver/Device.h b/wpd/WpdBasicHardwareDriver/Device.h deleted file mode 100644 index 6b7ed2d0..00000000 --- a/wpd/WpdBasicHardwareDriver/Device.h +++ /dev/null @@ -1,89 +0,0 @@ -#pragma once - -#include "resource.h" -#include "WpdBasicHardwareDriver.h" - -class ATL_NO_VTABLE CDevice : - public CComObjectRootEx, - public IPnpCallback, - public IPnpCallbackSelfManagedIo, - public IPnpCallbackHardware -{ -public: - CDevice() : - m_pWpdBaseDriver(NULL) - { - } - - DECLARE_NOT_AGGREGATABLE(CDevice) - - BEGIN_COM_MAP(CDevice) - COM_INTERFACE_ENTRY(IPnpCallback) - COM_INTERFACE_ENTRY(IPnpCallbackSelfManagedIo) - COM_INTERFACE_ENTRY(IPnpCallbackHardware) - END_COM_MAP() - -public: - static HRESULT - CreateInstance( - _In_ IWDFDeviceInitialize* pDeviceInit, - _In_ WpdBaseDriver* pWpdBaseDriver, - _COM_Outptr_ IUnknown** ppUnkwn) - { - *ppUnkwn = NULL; - - // - // Set device properties. - // - pDeviceInit->SetLockingConstraint(None); - - CComObject< CDevice> *pMyDevice = NULL; - HRESULT hr = CComObject::CreateInstance( &pMyDevice ); - if( SUCCEEDED (hr) ) - { - pMyDevice->AddRef(); - hr = pMyDevice->QueryInterface( __uuidof(IUnknown),(void **) ppUnkwn); - if (hr == S_OK) - { - pMyDevice->m_pWpdBaseDriver = pWpdBaseDriver; - } - pMyDevice->Release(); - pMyDevice = NULL; - } - - return hr; - } - - // IPnpCallback - // - STDMETHOD_(HRESULT, OnD0Entry) (_In_ IWDFDevice* pDevice, WDF_POWER_DEVICE_STATE previousState); - STDMETHOD_(HRESULT, OnD0Exit) (_In_ IWDFDevice* pDevice, WDF_POWER_DEVICE_STATE newState); - STDMETHOD_(VOID, OnSurpriseRemoval)(_In_ IWDFDevice* pDevice); - STDMETHOD_(HRESULT, OnQueryRemove) (_In_ IWDFDevice* pDevice); - STDMETHOD_(HRESULT, OnQueryStop) (_In_ IWDFDevice* pDevice); - - // IPnpCallbackSelfManagedIo - // - STDMETHOD_(VOID, OnSelfManagedIoCleanup)(_In_ IWDFDevice* pDevice); - STDMETHOD_(VOID, OnSelfManagedIoFlush) (_In_ IWDFDevice* pDevice); - STDMETHOD_(HRESULT, OnSelfManagedIoInit) (_In_ IWDFDevice* pDevice); - STDMETHOD_(HRESULT, OnSelfManagedIoSuspend)(_In_ IWDFDevice* pDevice); - STDMETHOD_(HRESULT, OnSelfManagedIoRestart)(_In_ IWDFDevice* pDevice); - STDMETHOD_(HRESULT, OnSelfManagedIoStop) (_In_ IWDFDevice* pDevice); - - // IPnpCallbackHardware - // - STDMETHOD_(HRESULT, OnPrepareHardware)(_In_ IWDFDevice* pDevice); - STDMETHOD_(HRESULT, OnReleaseHardware)(_In_ IWDFDevice* pDevice); - -private: - - HRESULT GetDeviceFriendlyName( - _Outptr_result_maybenull_ LPWSTR* pwszDeviceFriendlyName); - -private: - - WpdBaseDriver* m_pWpdBaseDriver; - CComPtr m_pPortableDeviceClassExtension; -}; - diff --git a/wpd/WpdBasicHardwareDriver/Driver.cpp b/wpd/WpdBasicHardwareDriver/Driver.cpp deleted file mode 100644 index ca0697a1..00000000 --- a/wpd/WpdBasicHardwareDriver/Driver.cpp +++ /dev/null @@ -1,197 +0,0 @@ -#include "stdafx.h" - -#include "Driver.tmh" - -CDriver::CDriver() -{ - - -} - -HRESULT -CDriver::OnDeviceAdd( - _In_ IWDFDriver* pDriver, - _In_ IWDFDeviceInitialize* pDeviceInit - ) -/*++ - -Routine Description: - - The framework calls this function when a device is being added to - the driver stack. - -Arguments: - - IWDFDriver - Framework interface. The driver uses this - interface to create device objects. - IWDFDeviceInitialize - Framework interface. The driver uses this - interface to set device parameters before - creating the device obeject. - -Return Value: - - HRESULT S_OK - Device added successfully - ---*/ -{ - TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_FLAG_DRIVER, "%!FUNC! Entry"); - - HRESULT hr = S_OK; - CComPtr pDeviceCallback; - - WpdBaseDriver *pWpdBaseDriver = NULL; - - // - // Create the WPD driver object that handles all WPD messages for this device - // - pWpdBaseDriver = new WpdBaseDriver(); - if(pWpdBaseDriver == NULL) - { - hr = E_OUTOFMEMORY; - } - - if(SUCCEEDED(hr)) - { - // - // Create device callback object - // - hr = CDevice::CreateInstance(pDeviceInit, pWpdBaseDriver, &pDeviceCallback); - } - - // - // This driver has no special power management requirements and so - // we set power policy ownership to UMDF to indicate that UMDF should - // handle powermanagement for us. - // - pDeviceInit->SetPowerPolicyOwnership(FALSE); - - // - // Create WDFDevice. - // - CComPtr pIWDFDevice; - if(SUCCEEDED(hr)) - { - hr = pDriver->CreateDevice( - pDeviceInit, - pDeviceCallback, - &pIWDFDevice); - } - - // - // Assign pWpdBaseDriver to the device object. Each UMDF device requires its own instance of - // a WpdBaseDriver to handle WPD messages. - // - if(SUCCEEDED(hr)) - { - hr = pIWDFDevice->AssignContext(this, (void*)pWpdBaseDriver); - if(SUCCEEDED(hr)) - { - // AddRef the WpdBaseDriver object since it is not stored with the - // device context. - pWpdBaseDriver->AddRef(); - } - } - - // - // Create queue callback object - // - CComPtr pIUnknown; - if(S_OK == hr) - { - hr = CQueue::CreateInstance(&pIUnknown); - } - - // - // Configure the default queue. - // - if(S_OK == hr) - { - CComPtr pDefaultQueue; - hr = pIWDFDevice->CreateIoQueue( - pIUnknown, - TRUE, // bDefaultQueue - WdfIoQueueDispatchSequential, - TRUE, // bPowerManaged - FALSE, // bAllowZeroLengthRequests - &pDefaultQueue); - } - - pDeviceCallback = NULL; - pIWDFDevice = NULL; - - // - // It is fine to release the interface on the callback object. - // The framework has its own refcount on this object and will - // provide an interface when calling into the driver. - // - pIUnknown = NULL; - - // Release the WpdBaseDriver object. If it was successfully added to the device context, - // it was already addref'd above. Releasing it here ensures it will be destroyed if - // an error occured and it could not be added to the device context. - SAFE_RELEASE(pWpdBaseDriver); - - return hr; -} - -void -CDriver::OnDeinitialize( - _In_ IWDFDriver* pDriver - ) -/*++ - -Routine Description: - - The framework calls this function just before de-initializing itself. All - WDF framework resources should be released by driver before returning from this call. - -Arguments: - -Return Value: - ---*/ -{ - UNREFERENCED_PARAMETER(pDriver); - return; -} - -HRESULT -CDriver::OnInitialize( - _In_ IWDFDriver* pDriver - ) -/*++ - -Routine Description: - - The framework calls this function just after loading the driver. The driver can - perform any global, device independent intialization in this routine. - -Arguments: - -Return Value: - ---*/ -{ - UNREFERENCED_PARAMETER(pDriver); - return S_OK; -} - -STDMETHODIMP_ (void) -CDriver::OnCleanup( - _In_ IWDFObject* pWdfObject - ) -{ - TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_FLAG_DRIVER, "%!FUNC! Entry"); - - // Release the base driver object - HRESULT hr = S_OK; - WpdBaseDriver* pWpdBaseDriver = NULL; - - hr = pWdfObject->RetrieveContext((void**)&pWpdBaseDriver); - if((hr == S_OK) && (pWpdBaseDriver != NULL)) - { - pWpdBaseDriver->Release(); - pWpdBaseDriver = NULL; - } -} - diff --git a/wpd/WpdBasicHardwareDriver/Driver.h b/wpd/WpdBasicHardwareDriver/Driver.h deleted file mode 100644 index 9b8cadec..00000000 --- a/wpd/WpdBasicHardwareDriver/Driver.h +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once - -class ATL_NO_VTABLE CDriver : - public CComObjectRootEx, - public CComCoClass, - public IDriverEntry, - public IObjectCleanup -{ -public: - CDriver(); - - DECLARE_REGISTRY_RESOURCEID(IDR_WpdBasicHardwareDriver) - - DECLARE_NOT_AGGREGATABLE(CDriver) - - BEGIN_COM_MAP(CDriver) - COM_INTERFACE_ENTRY(IDriverEntry) - END_COM_MAP() - -public: - // - // IDriverEntry - // - STDMETHOD (OnInitialize)( - _In_ IWDFDriver* pDriver - ); - STDMETHOD (OnDeviceAdd)( - _In_ IWDFDriver* pDriver, - _In_ IWDFDeviceInitialize* pDeviceInit - ); - STDMETHOD_ (void, OnDeinitialize)( - _In_ IWDFDriver* pDriver - ); - - // - // IObjectCleanup - // - STDMETHOD_ (void, OnCleanup)( - _In_ IWDFObject* pWdfObject - ); -}; - -OBJECT_ENTRY_AUTO(__uuidof(WpdBasicHardwareDriver), CDriver) - diff --git a/wpd/WpdBasicHardwareDriver/Queue.cpp b/wpd/WpdBasicHardwareDriver/Queue.cpp deleted file mode 100644 index e4e81c09..00000000 --- a/wpd/WpdBasicHardwareDriver/Queue.cpp +++ /dev/null @@ -1,340 +0,0 @@ -// Queue.cpp : Implementation of CQueue - - -#include "stdafx.h" -#include - -#include "Queue.tmh" - -// Add table used to lookup the Access required for Wpd Commands -BEGIN_WPD_COMMAND_ACCESS_MAP(g_WpdCommandAccessMap) - DECLARE_WPD_STANDARD_COMMAND_ACCESS_ENTRIES - // Add any custom commands here e.g. - // WPD_COMMAND_ACCESS_ENTRY(MyCustomCommand, WPD_COMMAND_ACCESS_READWRITE) -END_WPD_COMMAND_ACCESS_MAP - -// This enables use to use VERIFY_WPD_COMMAND_ACCESS to check command access function for us. -DECLARE_VERIFY_WPD_COMMAND_ACCESS; - -/****************************************************************************** - * This function calls the WpdBaseDriver to handle the WPD message. In order - * to do this it does the following: - * - * - Deserializes pBuffer into an IPortableDeviceValues which holds the command - * input parameters from the WPD application. - * - Creates an IPortableDeviceValues for the results. - * - Calls the WpdBaseDriver to handle the message. (The results of this - * operation are put into the previously created results IPortableDeviceValues.) - * - The results IPortableDeviceValues is then serialized back into pBuffer, making - * sure that it does not overrun ulOutputBufferLength. - * - *****************************************************************************/ -HRESULT CQueue::ProcessWpdMessage( - ULONG ControlCode, - _In_ ContextMap* pClientContextMap, - _In_ IWDFDevice* pDevice, - _In_reads_bytes_(ulInputBufferLength) PVOID pInBuffer, - ULONG ulInputBufferLength, - _Out_writes_bytes_to_(ulOutputBufferLength, *pdwBytesWritten) PVOID pOutBuffer, - ULONG ulOutputBufferLength, - _Out_ DWORD* pdwBytesWritten) -{ - CComCritSecLock Lock(m_CriticalSection); - - HRESULT hr = S_OK; - CComPtr pParams; - CComPtr pResults; - CComPtr pWpdBaseDriver; - - *pdwBytesWritten = 0; - - if (hr == S_OK) - { - hr = m_pWpdSerializer->GetIPortableDeviceValuesFromBuffer((BYTE*)pInBuffer, - ulInputBufferLength, - &pParams); - CHECK_HR(hr, "Failed to deserialize command parameters from input buffer"); - } - - // Verify that that command was sent with the appropriate access - if (hr == S_OK) - { - hr = VERIFY_WPD_COMMAND_ACCESS(ControlCode, pParams, g_WpdCommandAccessMap); - CHECK_HR(hr, "Wpd Command was sent with incorrect access flags"); - } - - // Create the WPD results collection - if (hr == S_OK) - { - hr = CoCreateInstance(CLSID_PortableDeviceValues, - NULL, - CLSCTX_INPROC_SERVER, - IID_IPortableDeviceValues, - (VOID**)&pResults); - CHECK_HR(hr, "Failed to CoCreate CLSID_PortableDeviceValues"); - } - - // Insert the client context map as one of this driver's private properties. This is - // just a convenient place holder which allows other methods down the chain to - // access the context map. - if (hr == S_OK) - { - hr = pParams->SetIUnknownValue(PRIVATE_SAMPLE_DRIVER_CLIENT_CONTEXT_MAP, pClientContextMap); - CHECK_HR(hr, "Failed to set PRIVATE_SAMPLE_DRIVER_CLIENT_CONTEXT_MAP"); - } - - // Insert the IWDFDevice interface as one of this driver's private properties. This is - // just a convenient place holder which allows other methods down the chain to - // access the WUDF Device object. - if (hr == S_OK) - { - hr = pParams->SetIUnknownValue(PRIVATE_SAMPLE_DRIVER_WUDF_DEVICE_OBJECT, pDevice); - CHECK_HR(hr, "Failed to set PRIVATE_SAMPLE_DRIVER_WUDF_DEVICE_OBJECT"); - } - - // Insert the IWpdSerializer interface as one of this driver's private properties. This is - // just a convenient place holder which allows other methods down the chain to - // access the WPD Serializer object. - if (hr == S_OK) - { - hr = pParams->SetIUnknownValue(PRIVATE_SAMPLE_DRIVER_WPD_SERIALIZER_OBJECT, m_pWpdSerializer); - CHECK_HR(hr, "Failed to set PRIVATE_SAMPLE_DRIVER_WPD_SERIALIZER_OBJECT"); - } - - // Get the WpdBaseDriver so we can dispatch the message - if (hr == S_OK) - { - hr = GetWpdBaseDriver(pDevice, &pWpdBaseDriver); - CHECK_HR(hr, "Failed to get WpdBaseDriver"); - } - - if (hr == S_OK) - { - hr = pWpdBaseDriver->DispatchWpdMessage(pParams, pResults); - CHECK_HR(hr, "Failed to handle WPD command"); - } - - if (hr == S_OK) - { - hr = m_pWpdSerializer->WriteIPortableDeviceValuesToBuffer(ulOutputBufferLength, - pResults, - (BYTE*)pOutBuffer, - pdwBytesWritten); - CHECK_HR(hr, "Failed to serialize results to output buffer"); - } - - return hr; -} - -/****************************************************************************** - * This method gets the WpdBaseDriver associated with the UMDF device object. - * The caller should Release *ppWpdBaseDriver when it is done. - * - * When this device was created, we assigned the WpdBaseDriver as the context. - * So, in order to retrieve the correct WpdBaseDriver for this device, we simply - * get the device context. - *****************************************************************************/ -HRESULT CQueue::GetWpdBaseDriver( - _In_ IWDFDevice* pDevice, - _Outptr_result_nullonfailure_ WpdBaseDriver** ppWpdBaseDriver) -{ - HRESULT hr = S_OK; - WpdBaseDriver* pContext = NULL; - - if((pDevice == NULL) || (ppWpdBaseDriver == NULL)) - { - hr = E_POINTER; - CHECK_HR(hr, "Cannot have NULL parameter for pDevice or ppWpdBaseDriver"); - } - - *ppWpdBaseDriver = NULL; - - if(SUCCEEDED(hr)) - { - hr = pDevice->RetrieveContext((void**)&pContext); - if(SUCCEEDED(hr)) - { - if(pContext != NULL) - { - pContext->AddRef(); - *ppWpdBaseDriver = pContext; - } - else - { - hr = E_UNEXPECTED; - CHECK_HR(hr, "Device context is NULL"); - } - } - } - - return hr; -} - -// CQueue - -STDMETHODIMP_ (void) -CQueue::OnCreateFile( - _In_ IWDFIoQueue* pQueue, - _In_ IWDFIoRequest* pRequest, - _In_ IWDFFile* pFileObject - ) -{ - UNREFERENCED_PARAMETER(pQueue); - TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_FLAG_QUEUE, "%!FUNC! Entry"); - - // This critical section protects the section of code where we - // Create the serializer and results interfaces used in handling I/O messages. - // We only need to create them once, then we hang on to them for the lifetime of this - // queue object. - CComCritSecLock Lock(m_CriticalSection); - HRESULT hr = S_OK; - - // Create the WPD serializer - if ((hr == S_OK) && - (m_pWpdSerializer == NULL)) - { - hr = CoCreateInstance(CLSID_WpdSerializer, - NULL, - CLSCTX_INPROC_SERVER, - IID_IWpdSerializer, - (VOID**)&m_pWpdSerializer); - - CHECK_HR(hr, "Failed to CoCreate CLSID_WpdSerializer"); - } - - // Create the client context map and associate it with the File Object - // so we can obtain it on a per-client basis. - if (hr == S_OK) - { - ContextMap* pClientContextMap = new ContextMap(); - - if(pClientContextMap != NULL) - { - hr = pFileObject->AssignContext(this, (void*)pClientContextMap); - CHECK_HR(hr, "Failed to set client context map"); - - // Release the client context map if we cannot set it - // properly - if(FAILED(hr)) - { - pClientContextMap->Release(); - pClientContextMap = NULL; - } - } - else - { - hr = E_OUTOFMEMORY; - CHECK_HR(hr, "Failed to create client context map"); - } - } - - pRequest->Complete(hr); - return; -} - -STDMETHODIMP_ (void) -CQueue::OnDeviceIoControl( - _In_ IWDFIoQueue* pQueue, - _In_ IWDFIoRequest* pRequest, - ULONG ControlCode, - SIZE_T InputBufferSizeInBytes, - SIZE_T OutputBufferSizeInBytes - ) -{ - UNREFERENCED_PARAMETER(InputBufferSizeInBytes); - UNREFERENCED_PARAMETER(OutputBufferSizeInBytes); - - HRESULT hr = S_OK; - DWORD dwBytesWritten = 0; - - if(IS_WPD_IOCTL(ControlCode)) - { - BYTE* pInputBuffer = NULL; - SIZE_T cbInputBuffer = 0; - BYTE* pOutputBuffer = NULL; - SIZE_T cbOutputBuffer = 0; - ContextMap* pClientContextMap = NULL; - CComPtr pMemoryIn; - CComPtr pMemoryOut; - CComPtr pDevice; - CComPtr pFileObject; - - // - // Get input memory buffer, the memory object is always returned even if the - // underlying buffer is NULL - // - pRequest->GetInputMemory(&pMemoryIn); - pInputBuffer = (BYTE*) pMemoryIn->GetDataBuffer(&cbInputBuffer); - - // - // Get output memory buffer, the memory object is always returned even if the - // underlying buffer is NULL - // - pRequest->GetOutputMemory(&pMemoryOut); - pOutputBuffer = (BYTE*) pMemoryOut->GetDataBuffer(&cbOutputBuffer); - - // Get the Context map for this client - pRequest->GetFileObject(&pFileObject); - if (pFileObject != NULL) - { - hr = pFileObject->RetrieveContext((void**)&pClientContextMap); - CHECK_HR(hr, "Failed to get Contextmap from WDF File Object"); - - if (hr == S_OK) - { - // Get the device object - pQueue->GetDevice(&pDevice ); - hr = ProcessWpdMessage(ControlCode, - pClientContextMap, - pDevice, - pInputBuffer, - (DWORD)cbInputBuffer, - pOutputBuffer, - (DWORD)cbOutputBuffer, - &dwBytesWritten); - } - } - else - { - hr = E_UNEXPECTED; - CHECK_HR(hr, "WDF File Object is NULL"); - } - } - else - { - hr = E_UNEXPECTED; - CHECK_HR(hr, "Received invalid/unsupported IOCTL code '0x%lx'",ControlCode); - } - - // Complete the request - if (hr == S_OK) - { - pRequest->CompleteWithInformation(hr, dwBytesWritten); - } - else - { - pRequest->Complete(hr); - } - - return; -} - -STDMETHODIMP_ (void) -CQueue::OnCleanup( - _In_ IWDFObject* pWdfObject - ) -{ - TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_FLAG_QUEUE, "%!FUNC! Entry"); - - // Destroy the client context map - HRESULT hr = S_OK; - ContextMap* pClientContextMap = NULL; - - hr = pWdfObject->RetrieveContext((void**)&pClientContextMap); - if((hr == S_OK) && (pClientContextMap != NULL)) - { - pClientContextMap->Release(); - pClientContextMap = NULL; - } -} - diff --git a/wpd/WpdBasicHardwareDriver/Queue.h b/wpd/WpdBasicHardwareDriver/Queue.h deleted file mode 100644 index e5cea69d..00000000 --- a/wpd/WpdBasicHardwareDriver/Queue.h +++ /dev/null @@ -1,93 +0,0 @@ -// Queue.h : Declaration of the CQueue - -#pragma once -#include "resource.h" // main symbols -#include "WpdBasicHardwareDriver.h" - -class ATL_NO_VTABLE CQueue : - public CComObjectRootEx, - public IQueueCallbackDeviceIoControl, - public IQueueCallbackCreate, - public IObjectCleanup -{ -public: - CQueue() - { - - } - - DECLARE_NOT_AGGREGATABLE(CQueue) - - BEGIN_COM_MAP(CQueue) - COM_INTERFACE_ENTRY(IQueueCallbackDeviceIoControl) - COM_INTERFACE_ENTRY(IQueueCallbackCreate) - END_COM_MAP() - -public: - static - HRESULT CreateInstance( - _COM_Outptr_ IUnknown **ppUkwn) - { - *ppUkwn = NULL; - CComObject< CQueue> *pMyQueue = NULL; - HRESULT hr = CComObject::CreateInstance( &pMyQueue ); - if( SUCCEEDED (hr) ) - { - pMyQueue->AddRef(); - hr = pMyQueue->QueryInterface( __uuidof(IUnknown), (void **) ppUkwn ); - pMyQueue->Release(); - pMyQueue = NULL; - } - - return hr; - } - - // - // Wdf Callbacks - // - - // IQueueCallbackCreateClose - // - STDMETHOD_ (void, OnCreateFile)( - _In_ IWDFIoQueue *pQueue, - _In_ IWDFIoRequest *pRequest, - _In_ IWDFFile *pFileObject - ); - - // - // IQueueCallbackDeviceIoControl - // - STDMETHOD_ (void, OnDeviceIoControl)( - _In_ IWDFIoQueue* pQueue, - _In_ IWDFIoRequest* pRequest, - ULONG ControlCode, - SIZE_T InputBufferSizeInBytes, - SIZE_T OutputBufferSizeInBytes - ); - - // - // IObjectCleanup - // - STDMETHOD_ (void, OnCleanup)( - _In_ IWDFObject* pWdfObject - ); - -private: - HRESULT ProcessWpdMessage( - ULONG ControlCode, - _In_ ContextMap* pClientContextMap, - _In_ IWDFDevice* pDevice, - _In_reads_bytes_(ulInputBufferLength) PVOID pInBuffer, - ULONG ulInputBufferLength, - _Out_writes_bytes_to_(ulOutputBufferLength, *pdwBytesWritten) PVOID pOutBuffer, - ULONG ulOutputBufferLength, - _Out_ DWORD* pdwBytesWritten); - - HRESULT GetWpdBaseDriver( - _In_ IWDFDevice* pDevice, - _Outptr_result_nullonfailure_ WpdBaseDriver** ppWpdBaseDriver); - - CComPtr m_pWpdSerializer; - CComAutoCriticalSection m_CriticalSection; -}; - diff --git a/wpd/WpdBasicHardwareDriver/RS232Connection.cpp b/wpd/WpdBasicHardwareDriver/RS232Connection.cpp deleted file mode 100644 index bd456f54..00000000 --- a/wpd/WpdBasicHardwareDriver/RS232Connection.cpp +++ /dev/null @@ -1,316 +0,0 @@ -#include "stdafx.h" - -#include "RS232Connection.tmh" - -/*----------------------------------------------------------------------------- - -FUNCTION: RS232Connection() - -PURPOSE: Constructor. Initializes TTY structure - -COMMENTS: This structure is a collection of TTY attributes - used by all parts of this program - -HISTORY: Date: Author: Comment: - 10/27/95 AllenD Wrote it - 2/14/96 AllenD Removed npTTYInfo - 12/06/06 DonnMo Changed return value type - 12/06/06 DonnMo Replaced macro calls with member-variable settings - 12/06/06 DonnMo Removed initialization of font-related variables - ------------------------------------------------------------------------------*/ -RS232Connection::RS232Connection() -{ - // - // initialize generial TTY info - // - m_hCommPort = NULL; - m_fConnected = FALSE; - m_fLocalEcho = FALSE; - m_bPort = 1; - m_dwBaudRate = CBR_9600; - m_bByteSize = 8; - m_bParity = NOPARITY; - m_bStopBits = ONESTOPBIT; - m_fAutowrap = TRUE; - m_fNewLine = FALSE; - m_fDisplayErrors = TRUE; - - // - // timeouts - // - - // - // TimeoutsDefault - // We need ReadIntervalTimeout here to cause the read operations - // that we do to actually timeout and become overlapped. - // Specifying 1 here causes ReadFile to return very quickly - // so that our reader thread will continue execution. - // - - COMMTIMEOUTS m_TimeoutsDefault = { 25, 0, 0, 0, 0 }; - m_timeoutsnew = m_TimeoutsDefault; - - // - // read state and status events - // - m_dwReceiveState = RECEIVE_TTY; - m_dwEventFlags = EVENTFLAGS_DEFAULT; - m_chFlag = FLAGCHAR_DEFAULT; - - // - // Flow Control Settings - // - m_fDtrControl = DTR_CONTROL_ENABLE; - m_fRtsControl = RTS_CONTROL_ENABLE; - m_chXON = ASCII_XON; - m_chXOFF = ASCII_XOFF; - m_wXONLimit = 0; - m_wXOFFLimit = 0; - m_fCTSOutFlow = FALSE; - m_fDSROutFlow = FALSE; - m_fDSRInFlow = FALSE; - m_fXonXoffOutFlow = FALSE; - m_fXonXoffInFlow = FALSE; - m_fTXafterXoffSent = FALSE; - m_fNoReading = FALSE; - m_fNoWriting = FALSE; - m_fNoEvents = FALSE; - m_fNoStatus = FALSE; - m_fDisplayTimeouts = FALSE; - -} - - -/*----------------------------------------------------------------------------- - -FUNCTION: SetPortState( void ) - -PURPOSE: Sets port state based on settings from the user - -COMMENTS: Sets up DCB structure and calls SetCommState. - Sets up new timeouts by calling SetCommTimeouts. - -HISTORY: Date: Author: Comment: - 1/9/96 AllenD Wrote it - 12/06/06 DonnMo Replaced calls to ErrorReporter() with CHECK_HR() - ------------------------------------------------------------------------------*/ -HRESULT RS232Connection::SetPortState() -{ - HRESULT hr = S_OK; - DCB dcb = {0}; - DWORD dwLastError = 0; - - dcb.DCBlength = sizeof(dcb); - - // - // get current DCB settings - // - if (!GetCommState(m_hCommPort, &dcb)) - { - dwLastError = GetLastError(); - hr = HRESULT_FROM_WIN32(dwLastError); - CHECK_HR(hr, "GetCommState() failed within SetPortState()."); - return hr; - } - - // - // update DCB rate, byte size, parity, and stop bits size - // - dcb.BaudRate = m_dwBaudRate; - dcb.ByteSize = m_bByteSize; - dcb.Parity = m_bParity; - dcb.StopBits = m_bStopBits; - - // - // update event flags - // - if (m_dwEventFlags & EV_RXFLAG) - { - dcb.EvtChar = m_chFlag; - } - else - { - dcb.EvtChar = '\0'; - } - - dcb.EofChar = '\n'; - - // - // update flow control settings - // - dcb.fDtrControl = m_fDtrControl; - dcb.fRtsControl = m_fRtsControl; - - dcb.fOutxCtsFlow = m_fCTSOutFlow; - dcb.fOutxDsrFlow = m_fDSROutFlow; - dcb.fDsrSensitivity = m_fDSRInFlow; - dcb.fOutX = m_fXonXoffOutFlow; - dcb.fInX = m_fXonXoffInFlow; - dcb.fTXContinueOnXoff = m_fTXafterXoffSent; - dcb.XonChar = m_chXON; - dcb.XoffChar = m_chXOFF; - dcb.XonLim = m_wXONLimit; - dcb.XoffLim = m_wXOFFLimit; - - // - // DCB settings not in the user's control - // - dcb.fParity = TRUE; - - // - // set new state - // - if (!SetCommState(m_hCommPort, &dcb)) - { - dwLastError = GetLastError(); - hr = HRESULT_FROM_WIN32(dwLastError); - CHECK_HR(hr, "SetCommState() failed within SetPortState() when setting the new state."); - return hr; - } - - - // - // set new timeouts - // - if (!SetCommTimeouts(m_hCommPort, &m_timeoutsnew)) - { - dwLastError = GetLastError(); - hr = HRESULT_FROM_WIN32(dwLastError); - CHECK_HR(hr, "SetCommTimeouts() failed within SetPortState() when setting the new timeouts."); - return hr; - } - - return hr; -} - - -/*----------------------------------------------------------------------------- - -FUNCTION: Connect( void ) - -PURPOSE: Setup Communication Port with our settings - -RETURN: - S_OK and handle of com port if successful - ------------------------------------------------------------------------------*/ -HRESULT RS232Connection::Connect(_In_ LPCWSTR wszPortName, _Out_ HANDLE *phCommPort) -{ - HRESULT hr = S_OK; - DWORD dwLastError = 0; - - if (phCommPort == NULL) - { - hr = E_POINTER; - CHECK_HR(hr, "A NULL phCommPort parameter was received"); - return hr; - } - - *phCommPort = NULL; - - // - // retrieve a handle for the com port - // and configure the port for asynchronous - // communications. - // - m_hCommPort = CreateFileW(wszPortName, - GENERIC_READ | GENERIC_WRITE, - 0, - 0, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, - 0); - - if (m_hCommPort == NULL) - { - dwLastError = GetLastError(); - hr = HRESULT_FROM_WIN32(dwLastError); - CHECK_HR(hr, "CreateFileW() failed in RS232Connection::Connect"); - return hr; - } - - // - // Save original comm timeouts and set new ones - // - if (!GetCommTimeouts( m_hCommPort, &(m_timeoutsorig))) - { - dwLastError = GetLastError(); - hr = HRESULT_FROM_WIN32(dwLastError); - CHECK_HR(hr, "GetCommTimeouts() failed within RS232Connection::Connect"); - return hr; - } - - // - // Set port state - // - hr = SetPortState(); - if (FAILED(hr)) - { - CHECK_HR(hr, "SetPortState() failed within RS232Connection::Connect"); - return hr; - } - - // - // set comm buffer sizes - // - if (!SetupComm(m_hCommPort, MAX_READ_BUFFER, MAX_WRITE_BUFFER)) - { - dwLastError = GetLastError(); - hr = HRESULT_FROM_WIN32(dwLastError); - CHECK_HR(hr, "SetupComm(SETDTR) failed within RS232Connection::Connect"); - return hr; - } - - // - // raise DTR - // - if (!EscapeCommFunction(m_hCommPort, SETDTR)) - { - dwLastError = GetLastError(); - hr = HRESULT_FROM_WIN32(dwLastError); - CHECK_HR(hr, "EscapeCommFunction() failed within RS232Connection::Connect"); - return hr; - } - - // - // set overall connect flag - // - m_fConnected = TRUE; - - // - // set the return value - // - *phCommPort = m_hCommPort; - - - if (SUCCEEDED(hr)) - { - TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_FLAG_DEVICE, "%!FUNC! handle: %p", m_hCommPort); - } - - return hr; -} - - -/*----------------------------------------------------------------------------- - -FUNCTION: Disconnect( void ) - -PURPOSE: Tears down the Communication Port - -RETURN: nothing - ------------------------------------------------------------------------------*/ -void RS232Connection::Disconnect() -{ - if (m_hCommPort != NULL) - { - TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_FLAG_DEVICE, "%!FUNC! handle: %p", m_hCommPort); - - CloseHandle(m_hCommPort); - m_hCommPort = NULL; - - } -} \ No newline at end of file diff --git a/wpd/WpdBasicHardwareDriver/RS232Connection.h b/wpd/WpdBasicHardwareDriver/RS232Connection.h deleted file mode 100644 index cd7f10b7..00000000 --- a/wpd/WpdBasicHardwareDriver/RS232Connection.h +++ /dev/null @@ -1,153 +0,0 @@ -#pragma once - -// -// Sensor device structures and definitions -// - -// -// Format of the 9-byte receive packet (device to PC): -// -// ORIGINAL TEMP_SENSOR PACKET FORMAT: [ VALUE (4 bytes) | INTERVAL (5 bytes) ] -// -// Format of the multi-byte receive packet (device to PC): -// -// NEW PACKET FORMAT: [ SENSOR_ID (1 byte) | ELEMENT_COUNT (1 byte) | ELEMENT_SIZE (1 byte) | ELEMENTS (size bytes) | INTERVAL (5 bytes) ] -// COMPASS PACKET FORMAT: [ SENSOR_ID = 1 | ELEMENT_COUNT = 1 | ELEMENT_SIZE = 3 | HEADING 3-bytes | INTERVAL (5 bytes) ] -// SENSIRON PACKET FORMAT: [ SENSOR_ID = 2 | ELEMENT_COUNT = 1 | ELEMENT_SIZE = 7 | TEMP 4-bytes | HUMIDITY 3-bytes | INTERVAL (5 bytes) ] -// FLEX PACKET FORMAT: [ SENSOR_ID = 3 | ELEMENT_COUNT = 1 | ELEMENT_SIZE = 5 | PRESSURE 5-bytes | INTERVAL (5 bytes) ] -// PING PACKET FORMAT: [ SENSOR_ID = 4 | ELEMENT_COUNT = 1 | ELEMENT_SIZE = 5 | PRESSURE 5-bytes | INTERVAL (5 bytes) ] -// PIR PACKET FORMAT: [ SENSOR_ID = 5 | ELEMENT_COUNT = 1 | ELEMENT_SIZE = 1 | STATE 1-byte | INTERVAL (5 bytes) ] -// MEMSIC PACKET FORMAT: [ SENSOR_ID = 6 | ELEMENT_COUNT = 1 | ELEMENT_SIZE = 6 | X-Axis Gs 3-bytes | Y-Axis Gs 3-bytes | INTERVAL (5 bytes) ] -// QTI PACKET FORMAT: [ SENSOR_ID = 7 | ELEMENT_COUNT = 1 | ELEMENT_SIZE = 4 | PRESSURE 4-bytes | INTERVAL (5 bytes) ] -// PIEZO PACKET FORMAT: [ SENSOR_ID = 8 | ELEMENT_COUNT = 1 | ELEMENT_SIZE = 1 | STATE 1-byte | INTERVAL (5 bytes) -// HITACHI PACKET FORMAT: [ SENSOR_ID = 9 | ELEMENT_COUNT = 3 | ELEMENT_SIZE = 4 | X-Axis Gs 4-bytes | Y-Axis Gs 4-bytes | Z-Axis Gs 4-bytes | INTERVAL (5 bytes) ] -// -// -// Format of the 6-byte send packet (PC to device): -// The final NULL byte signals the SERIN DEC formatter to stop reading -// -// [ INTERVAL (5 bytes) | 0 (1 byte) ] -// -#define INTERVAL_DATA_LENGTH 6 // count of bytes for interval -#define MIN_DATA_LENGTH 4 // minimum count of bytes for any sensor -#define MAX_DATA_LENGTH 21 // maximum count of bytes for any sensor -#define MAX_AMOUNT_TO_READ (MAX_DATA_LENGTH+INTERVAL_DATA_LENGTH) // maximum total bytes to read - -#define MEMSIC_DATA_LENGTH 9 // count of data bytes for Memsic dual-axis accelerometer -#define HITACHI_DATA_LENGTH 15 // count of data bytes for Hitachi tri-axis accelerometer -#define COMPASS_DATA_LENGTH 6 // count of data bytes for Compass -#define SENSIRON_DATA_LENGTH 10 // count of data bytes for Sensiron temp/humidity sensor -#define PING_DATA_LENGTH 8 // count of data bytes for Ping distance sensor -#define FLEX_DATA_LENGTH 8 // count of data bytes for Flexiforce pressure sensor -#define PIR_DATA_LENGTH 4 // count of data bytes for PIR -#define QTI_DATA_LENGTH 7 // count of data bytes for QTI -#define PIEZO_DATA_LENGTH 4 // count of data bytes for Piezo - -#define MEMSIC_AMOUNT_TO_READ (MEMSIC_DATA_LENGTH+INTERVAL_DATA_LENGTH) // total Memsic byte count -#define HITACHI_AMOUNT_TO_READ (HITACHI_DATA_LENGTH+INTERVAL_DATA_LENGTH) // total Hitachi byte count -#define COMPASS_AMOUNT_TO_READ (COMPASS_DATA_LENGTH+INTERVAL_DATA_LENGTH) // total Compass byte count -#define SENSIRON_AMOUNT_TO_READ (SENSIRON_DATA_LENGTH+INTERVAL_DATA_LENGTH) // total Sensiron byte count -#define PING_AMOUNT_TO_READ (PING_DATA_LENGTH+INTERVAL_DATA_LENGTH) // total Ping byte count -#define FLEX_AMOUNT_TO_READ (FLEX_DATA_LENGTH+INTERVAL_DATA_LENGTH) // total Flexiforce byte count -#define PIR_AMOUNT_TO_READ (PIR_DATA_LENGTH+INTERVAL_DATA_LENGTH) // total PIR byte count -#define QTI_AMOUNT_TO_READ (QTI_DATA_LENGTH+INTERVAL_DATA_LENGTH) // total QTI byte count -#define PIEZO_AMOUNT_TO_READ (PIEZO_DATA_LENGTH+INTERVAL_DATA_LENGTH) // total Piezo byte count - -#define DEVICE_ID 0 // byte 0 contains the Device ID -#define ELEMENT_SIZE 1 // byte 1 contains the Element Size -#define ELEMENT_COUNT 2 // byte 2 contains the Element Count - -// Update interval range in milliseconds -#define SENSOR_UPDATE_INTERVAL_MIN 10 // milliseconds -#define SENSOR_UPDATE_INTERVAL_MAX 60000 // milliseconds -#define SENSOR_UPDATE_INTERVAL_STEP 1 // milliseconds - -// TODO: Change these range values to match your sensor hardware -#define SENSOR_READING_MIN 1 // ?Units -#define SENSOR_READING_MAX 378 // ?Units -#define SENSOR_READING_STEP 1 // ?Units - -// TODO: Change this to match the default COM port to use -#define COM_PORT_NAME L"COM1" -#define NUM_READSTAT_HANDLES 4 -#define MAX_STATUS_LENGTH 100 - -// Ascii definitions -#define ASCII_BEL 0x07 -#define ASCII_BS 0x08 -#define ASCII_LF 0x0A -#define ASCII_CR 0x0D -#define ASCII_XON 0x11 -#define ASCII_XOFF 0x13 - -// Miscellaneous definitions -#define MAX_READ_BUFFER 2048 -#define MAX_WRITE_BUFFER 1024 -#define EVENTFLAGS_DEFAULT EV_BREAK | EV_CTS | EV_DSR | EV_ERR | EV_RING | EV_RLSD -#define FLAGCHAR_DEFAULT '\n' - -// Read states -#define RECEIVE_TTY 0x01 -#define RECEIVE_CAPTURED 0x02 - -class RS232Connection -{ - -public: - RS232Connection(); - - ~RS232Connection() - { - Disconnect(); - } - - HRESULT Connect(_In_ LPCWSTR wszPortName, _Out_ HANDLE *phCommPort); - void Disconnect(); - -private: - HRESULT SetPortState(); - -private: - - // - // Required for the RS232 initialization and communication. - // - - // TTY member variables and defines - HANDLE m_hCommPort; - DWORD m_dwEventFlags; - CHAR m_chFlag; - CHAR m_chXON; - CHAR m_chXOFF; - WORD m_wXONLimit; - WORD m_wXOFFLimit; - DWORD m_fRtsControl; - DWORD m_fDtrControl; - BOOL m_fConnected; - BOOL m_fTransferring; - BOOL m_fRepeating; - BOOL m_fLocalEcho; - BOOL m_fNewLine; - BOOL m_fDisplayErrors; - BOOL m_fAutowrap; - BOOL m_fCTSOutFlow; - BOOL m_fDSROutFlow; - BOOL m_fDSRInFlow; - BOOL m_fXonXoffOutFlow; - BOOL m_fXonXoffInFlow; - BOOL m_fTXafterXoffSent; - BOOL m_fNoReading; - BOOL m_fNoWriting; - BOOL m_fNoEvents; - BOOL m_fNoStatus; - BOOL m_fDisplayTimeouts; - BYTE m_bPort; - BYTE m_bByteSize; - BYTE m_bParity; - BYTE m_bStopBits; - DWORD m_dwBaudRate; - COMMTIMEOUTS m_timeoutsorig; - COMMTIMEOUTS m_timeoutsnew; - COMMTIMEOUTS m_TimeoutsDefault; - DWORD m_dwReceiveState; -}; \ No newline at end of file diff --git a/wpd/WpdBasicHardwareDriver/RS232Target.cpp b/wpd/WpdBasicHardwareDriver/RS232Target.cpp deleted file mode 100644 index bedfecd2..00000000 --- a/wpd/WpdBasicHardwareDriver/RS232Target.cpp +++ /dev/null @@ -1,433 +0,0 @@ -#include "stdafx.h" - -#include "RS232Target.tmh" - -RS232Target::RS232Target() : - m_cRef(1), m_pBaseDriver(NULL) -{ -} - -RS232Target::~RS232Target() -{ - Delete(); -} - -ULONG __stdcall RS232Target::AddRef() -{ - InterlockedIncrement((long*) &m_cRef); - return m_cRef; -} - -ULONG __stdcall RS232Target::Release() -{ - ULONG ulRefCount = m_cRef - 1; - - if (InterlockedDecrement((long*) &m_cRef) == 0) - { - delete this; - return 0; - } - return ulRefCount; -} - -HRESULT __stdcall RS232Target::QueryInterface( - REFIID riid, - void** ppv) -{ - HRESULT hr = S_OK; - - if(riid == IID_IUnknown) - { - *ppv = static_cast(this); - AddRef(); - } - if(riid == __uuidof(IRequestCallbackRequestCompletion)) - { - *ppv = static_cast(this); - AddRef(); - } - else - { - *ppv = NULL; - hr = E_NOINTERFACE; - } - return hr; -} - - - -/** - * This method is called to initialize the RS232 I/O Target - */ -HRESULT RS232Target::Create(_In_ WpdBaseDriver* pBaseDriver, - _In_ IWDFDevice* pDevice, - HANDLE hRS232Port) -{ - CComPtr pFileHandleTargetFactory; - - HRESULT hr = S_OK; - - if (pDevice == NULL) - { - hr = E_POINTER; - CHECK_HR(hr, "NULL parameter received for IWDFDevice"); - return hr; - } - - m_pWDFDevice = pDevice; - m_pBaseDriver = pBaseDriver; - - hr = m_pWDFDevice->QueryInterface(IID_PPV_ARGS(&pFileHandleTargetFactory)); - CHECK_HR(hr, "QI of IID_IWDFFileHandleTargetFactory failed"); - - if (hr == S_OK) - { - hr = pFileHandleTargetFactory->CreateFileHandleTarget(hRS232Port, &m_pFileTarget); - CHECK_HR(hr, "Failed to create an I/O Target for the port file handle"); - } - - if (hr == S_OK) - { - TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_FLAG_DEVICE, - "%!FUNC! Created win32 I/O target %p for handle %p", m_pFileTarget, hRS232Port); - } - - return hr; -} - -/** - * This method is called to remove the RS232 I/O Target object - * and do any cleanup - */ -void RS232Target::Delete() -{ - if (m_pFileTarget) - { - TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_FLAG_DEVICE, - "%!FUNC! Deleted win32 I/O target %p", m_pFileTarget); - m_pFileTarget = NULL; - } - - if (m_pWDFDevice) - { - m_pWDFDevice = NULL; - } - - if (m_pBaseDriver) - { - m_pBaseDriver = NULL; - } -} - -/** - * This method is called to start the RS232 I/O Target after it - * it has been created - */ -HRESULT RS232Target::Start() -{ - CComPtr pStateMgmt; - - HRESULT hr = S_OK; - - if (m_pFileTarget) - { - hr = m_pFileTarget->QueryInterface(IID_PPV_ARGS(&pStateMgmt)); - CHECK_HR(hr, "Failed to QI IWDFIoTargetStateManagement from the I/O target"); - - if (hr == S_OK) - { - hr = pStateMgmt->Start(); - CHECK_HR(hr, "Failed to start the I/O target"); - } - - if (hr == S_OK && IsReady()) - { - TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_FLAG_DEVICE, "%!FUNC! I/O target ready. Sending read request"); - hr = SendReadRequest(); - CHECK_HR(hr, "SendReadRequest failed"); - } - } - return hr; -} - -/** - * This method is called to stop the RS232 I/O Target - * if it is currently running - */ -HRESULT RS232Target::Stop() -{ - CComPtr pStateMgmt; - - HRESULT hr = S_OK; - - // Stop the target only if it is started. - if (m_pFileTarget && (WdfIoTargetStarted == GetState())) - { - hr = m_pFileTarget->QueryInterface(IID_PPV_ARGS(&pStateMgmt)); - CHECK_HR(hr, "Failed to QI IWDFIoTargetStateManagement from the I/O target"); - - if (hr == S_OK) - { - // Stop the target, and cancel sent I/O - hr = pStateMgmt->Stop(WdfIoTargetCancelSentIo); - CHECK_HR(hr, "Failed to stop the I/O target"); - } - - if (hr == S_OK) - { - TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_FLAG_DEVICE, "%!FUNC! S_OK"); - } - } - return hr; -} - -/** - * This method is called to return the current state of the RS232 I/O Target - */ -WDF_IO_TARGET_STATE RS232Target::GetState() -{ - CComPtr pStateMgmt; - - WDF_IO_TARGET_STATE State = WdfIoTargetStateUndefined; - HRESULT hr = S_OK; - - if (m_pFileTarget) - { - hr = m_pFileTarget->QueryInterface(IID_PPV_ARGS(&pStateMgmt)); - CHECK_HR(hr, "Failed to QI IWDFIoTargetStateManagement from the I/O target"); - - if (hr == S_OK) - { - State = pStateMgmt->GetState(); - } - } - return State; -} - - -/** - * This method returns TRUE is the target is ready to receive requests - */ -BOOL RS232Target::IsReady() -{ - if (WdfIoTargetStarted == GetState()) - { - return TRUE; - } - return FALSE; -} - - -/** - * This method is called to dispatch an asynchronous read request to the RS232 I/O Target - * with a completion callback - */ -HRESULT RS232Target::SendReadRequest() -{ - CComPtr pWdfDriver; - CComPtr pWdfFile; - CComPtr pWdfBuffer; - CComPtr pWdfReadRequest; - CComPtr pCompletionCallback; - - HRESULT hr = S_OK; - - if (m_pWDFDevice == NULL || m_pFileTarget == NULL) - { - hr = HRESULT_FROM_WIN32(ERROR_NOT_READY); - CHECK_HR(hr, "Device is not ready to receive read requests"); - return hr; - } - - m_pWDFDevice->GetDriver(&pWdfDriver); - - ZeroMemory((void*)m_pReadBuffer, sizeof(m_pReadBuffer)); - - // Create the WDF memory buffer - hr = pWdfDriver->CreatePreallocatedWdfMemory(m_pReadBuffer, - sizeof(m_pReadBuffer), - NULL, // no object event callback - NULL, // driver object as parent - &pWdfBuffer); - CHECK_HR(hr, "Failed to create the pre-allocaed WDF memory"); - - if (hr == S_OK) - { - hr = m_pWDFDevice->CreateRequest(NULL, // no object event callback - m_pWDFDevice, // device object as parent - &pWdfReadRequest); - - CHECK_HR(hr, "Failed to create a WDF request"); - } - - if (hr == S_OK) - { - // Format the read request - m_pFileTarget->GetTargetFile(&pWdfFile); - - hr = m_pFileTarget->FormatRequestForRead(pWdfReadRequest, - pWdfFile, - pWdfBuffer, - NULL, // no memory offset - NULL); // no device offset - - CHECK_HR(hr, "Failed to format the WDF request for read"); - } - - if (hr == S_OK) - { - this->QueryInterface(IID_PPV_ARGS(&pCompletionCallback)); - - // Set the completion callback - pWdfReadRequest->SetCompletionCallback(pCompletionCallback, NULL); - - hr = pWdfReadRequest->Send(m_pFileTarget, 0, 0); - CHECK_HR(hr, "Failed to send the read request"); - } - - if (FAILED(hr)) - { - // Cleanup on failure - if (pWdfReadRequest) - { - pWdfReadRequest->DeleteWdfObject(); - } - } - - return hr; -} - - -/** - * This method is called to dispatch an asynchronous write request to the RS232 I/O Target - * with a completion callback - */ -HRESULT RS232Target::SendWriteRequest( - _In_reads_(cbBufferSize) BYTE* pBuffer, - size_t cbBufferSize) -{ - CComPtr pWdfDriver; - CComPtr pWdfFile; - CComPtr pWdfBuffer; - CComPtr pWdfWriteRequest; - CComPtr pCompletionCallback; - - HRESULT hr = S_OK; - - if (pBuffer == NULL) - { - hr = E_POINTER; - CHECK_HR(hr, "A NULL buffer parameter was received"); - return hr; - } - - if (m_pWDFDevice == NULL || m_pFileTarget == NULL) - { - hr = HRESULT_FROM_WIN32(ERROR_NOT_READY); - CHECK_HR(hr, "Device is not ready to receive write requests"); - } - - m_pWDFDevice->GetDriver(&pWdfDriver); - m_pFileTarget->GetTargetFile(&pWdfFile); - - // Create the WDF memory buffer - hr = pWdfDriver->CreatePreallocatedWdfMemory(pBuffer, - cbBufferSize, - NULL, // no object event callback - NULL, // driver object as parent - &pWdfBuffer); - CHECK_HR(hr, "Failed to create a pre-allocaed Wdf memory buffer from the input buffer of size %d", static_cast(cbBufferSize)); - - if (hr == S_OK) - { - hr = m_pWDFDevice->CreateRequest(NULL, // no object event callback - m_pWDFDevice, // device object as parent - &pWdfWriteRequest); - - CHECK_HR(hr, "Failed to create a WDF request"); - } - - if (hr == S_OK) - { - hr = m_pFileTarget->FormatRequestForWrite(pWdfWriteRequest, - pWdfFile, - pWdfBuffer, - NULL, // no memory offset - NULL); // no device offset - - CHECK_HR(hr, "Failed to format the WDF request for write"); - } - - if (hr == S_OK) - { - this->QueryInterface(IID_PPV_ARGS(&pCompletionCallback)); - - // Set the completion callback - pWdfWriteRequest->SetCompletionCallback(pCompletionCallback, NULL); - - hr = pWdfWriteRequest->Send(m_pFileTarget, 0, 0); - CHECK_HR(hr, "Failed to send the write request"); - } - - if (FAILED(hr)) - { - // Cleanup on failure - if (pWdfWriteRequest) - { - pWdfWriteRequest->DeleteWdfObject(); - } - } - - return hr; -} - - -/** - * This callback method is called by UMDF on the completion of the asynchronous reads and writes - */ -void RS232Target::OnCompletion( - _In_ IWDFIoRequest* pWdfRequest, - _In_ IWDFIoTarget* pIoTarget, - _In_ IWDFRequestCompletionParams* pParams, - _In_ PVOID pContext) -{ - UNREFERENCED_PARAMETER(pIoTarget); - UNREFERENCED_PARAMETER(pContext); - UNREFERENCED_PARAMETER(pParams); - - CComPtr pCompletionParams; - HRESULT hr = S_OK; - - // Get the request completion status - pWdfRequest->GetCompletionParams(&pCompletionParams); - - HRESULT hrStatus = pCompletionParams->GetCompletionStatus(); - WDF_REQUEST_TYPE RequestType = pCompletionParams->GetCompletedRequestType(); - - if (RequestType == WdfRequestRead) - { - TraceEvents(TRACE_LEVEL_VERBOSE, TRACE_FLAG_DEVICE, "%!FUNC! Read Status %!HRESULT!", hrStatus); - - // Retrieve the data from the completed read request if successful - if (SUCCEEDED(hrStatus) && m_pBaseDriver) - { - m_pBaseDriver->ProcessReadData(m_pReadBuffer, sizeof(m_pReadBuffer)); - } - - // Send another read request if the target is not stopped or removed - if (IsReady()) - { - hr = SendReadRequest(); - CHECK_HR(hr, "SendReadRequest failed"); - } - - - } - else if (RequestType == WdfRequestWrite) - { - TraceEvents(TRACE_LEVEL_VERBOSE, TRACE_FLAG_DEVICE, "%!FUNC! Write Status %!HRESULT!", hrStatus); - } - - // Clean up the existing request - pWdfRequest->DeleteWdfObject(); -} diff --git a/wpd/WpdBasicHardwareDriver/RS232Target.h b/wpd/WpdBasicHardwareDriver/RS232Target.h deleted file mode 100644 index b4754639..00000000 --- a/wpd/WpdBasicHardwareDriver/RS232Target.h +++ /dev/null @@ -1,53 +0,0 @@ -#pragma once - -class RS232Target : - public IRequestCallbackRequestCompletion -{ -public: - RS232Target(); - - ~RS232Target(); - - HRESULT Create(_In_ WpdBaseDriver* pBaseDriver, - _In_ IWDFDevice* pDevice, - HANDLE hRS232Port); - - void Delete(); - - HRESULT Start(); - - HRESULT Stop(); - - BOOL IsReady(); - - WDF_IO_TARGET_STATE GetState(); - - HRESULT SendReadRequest(); - - HRESULT SendWriteRequest(_In_reads_(cbBufferSize) BYTE* pBuffer, - size_t cbBufferSize); - -public: // IUnknown - ULONG __stdcall AddRef(); - ULONG __stdcall Release(); - HRESULT __stdcall QueryInterface(REFIID riid, void** ppv); - - // - // IRequestCallbackRequestCompletion - // - STDMETHOD_ (void, OnCompletion)(_In_ IWDFIoRequest* pWdfRequest, - _In_ IWDFIoTarget* pIoTarget, - _In_ IWDFRequestCompletionParams* pParams, - _In_ PVOID pContext); - -private: - ULONG m_cRef; - - WpdBaseDriver* m_pBaseDriver; - - // Ensure ample buffer size - BYTE m_pReadBuffer[MAX_AMOUNT_TO_READ*2]; - - CComPtr m_pWDFDevice; - CComPtr m_pFileTarget; -}; \ No newline at end of file diff --git a/wpd/WpdBasicHardwareDriver/ReadMe.md b/wpd/WpdBasicHardwareDriver/ReadMe.md deleted file mode 100644 index 2db38601..00000000 --- a/wpd/WpdBasicHardwareDriver/ReadMe.md +++ /dev/null @@ -1,43 +0,0 @@ -WPD Basic Hardware Sample Driver (UMDF Version 1) -================================================= - -The WpdBasicHardwareDriver is a WPD driver that supports nine devices. These devices were selected because of their simplicity. This simplicity allowed the sample to focus on the tasks that are common to portable devices without getting bogged down in hardware complexities. - -This sample driver is based on the WpdHelloWorldDriver that is also included in the Windows Driver Kit (WDK). The "Supporting the WPD Infrastructure†sections for this driver show the changes that were made to the WpdHelloWorldDriver source so that it can communicate with basic hardware devices. Before you work through the topics in this section of the documentation, be familiar with the WpdHelloWorldDriver. - -The sensor devices that are supported by the WpdBasicHardwareDriver are described in the following table. - - ---- - - - - - - -
Device -DescriptionMemsic 2125 Accelerometer -Senses +/- 2g along the X-axis and Y-axis.
- -These nine sensors are sold by the Parallax Corporation in Rocklin, California. - -To use these sensors with the WpdBasicHardwareDriver, you must purchase the sensors, a programmable microcontroller (Parallax BS2), a test board (like the Parallax BASIC Stamp Homework Board), an RS232 cable, and miscellaneous parts. All of this hardware is available from Parallax and can be ordered through their Web site. - -The circuit designs are based on the sample circuits provided by Parallax in their sensor data sheets. These circuits are designed to integrate each sensor with the Parallax BS2 programmable microcontroller . - -The microcontroller firmware for each of the nine circuits is included in the src\\wpd\\WpdBasicHardwareDriver\\firmware subdirectory in the Windows Driver Kit (WDK). - -For a complete description of this sample and its underlying code and functionality, refer to the [WPD Basic Hardware Driver](http://msdn.microsoft.com/en-us/library/windows/hardware/ff597697) description in the Windows Driver Kit documentation. - - -Related topics --------------- - -[WPD Design Guide](http://msdn.microsoft.com/en-us/library/windows/hardware/ff597864) - -[WPD Driver Development Tools](http://msdn.microsoft.com/en-us/library/windows/hardware/ff597568) - -[WPD Programming Guide](http://msdn.microsoft.com/en-us/library/windows/hardware/) diff --git a/wpd/WpdBasicHardwareDriver/Stdafxsrc.cpp b/wpd/WpdBasicHardwareDriver/Stdafxsrc.cpp deleted file mode 100644 index 5105a28d..00000000 --- a/wpd/WpdBasicHardwareDriver/Stdafxsrc.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "Stdafx.h" \ No newline at end of file diff --git a/wpd/WpdBasicHardwareDriver/WpdBaseDriver.cpp b/wpd/WpdBasicHardwareDriver/WpdBaseDriver.cpp deleted file mode 100644 index cf1665c2..00000000 --- a/wpd/WpdBasicHardwareDriver/WpdBaseDriver.cpp +++ /dev/null @@ -1,506 +0,0 @@ -#include "stdafx.h" - -#include "WpdBaseDriver.tmh" - - -WpdBaseDriver::WpdBaseDriver() : - m_cRef(1) -{ -} - -WpdBaseDriver::~WpdBaseDriver() -{ -} - -ULONG __stdcall WpdBaseDriver::AddRef() -{ - InterlockedIncrement((long*) &m_cRef); - return m_cRef; -} - -_At_(this, __drv_freesMem(Mem)) -ULONG __stdcall WpdBaseDriver::Release() -{ - ULONG ulRefCount = m_cRef - 1; - - if (InterlockedDecrement((long*) &m_cRef) == 0) - { - delete this; - return 0; - } - return ulRefCount; -} - -HRESULT __stdcall WpdBaseDriver::QueryInterface( - REFIID riid, - void** ppv) -{ - HRESULT hr = S_OK; - - if(riid == IID_IUnknown) - { - *ppv = static_cast(this); - AddRef(); - } - else - { - *ppv = NULL; - hr = E_NOINTERFACE; - } - return hr; -} - -RS232Target* WpdBaseDriver::GetRS232Target() -{ - return &m_Target; -} - -HRESULT WpdBaseDriver::DispatchWpdMessage(_In_ IPortableDeviceValues* pParams, - _In_ IPortableDeviceValues* pResults) -{ - HRESULT hr = S_OK; - GUID guidCommandCategory = {0}; - DWORD dwCommandID = 0; - PROPERTYKEY CommandKey = WPD_PROPERTY_NULL; - - if (hr == S_OK) - { - hr = pParams->GetGuidValue(WPD_PROPERTY_COMMON_COMMAND_CATEGORY, &guidCommandCategory); - CHECK_HR(hr, "Failed to get WPD_PROPERTY_COMMON_COMMAND_CATEGORY from input parameters"); - } - - if (hr == S_OK) - { - hr = pParams->GetUnsignedIntegerValue(WPD_PROPERTY_COMMON_COMMAND_ID, &dwCommandID); - CHECK_HR(hr, "Failed to get WPD_PROPERTY_COMMON_COMMAND_ID from input parameters"); - } - - // If WPD_PROPERTY_COMMON_COMMAND_CATEGORY or WPD_PROPERTY_COMMON_COMMAND_ID could not be extracted - // properly then we should return E_INVALIDARG to the client. - if (FAILED(hr)) - { - hr = E_INVALIDARG; - CHECK_HR(hr, "Failed to get WPD_PROPERTY_COMMON_COMMAND_CATEGORY or WPD_PROPERTY_COMMON_COMMAND_ID from input parameters"); - } - - if (hr == S_OK) - { - CommandKey.fmtid = guidCommandCategory; - CommandKey.pid = dwCommandID; - - if (CommandKey.fmtid == WPD_CATEGORY_OBJECT_ENUMERATION) - { - hr = m_ObjectEnum.DispatchWpdMessage(CommandKey, pParams, pResults); - } - else if (CommandKey.fmtid == WPD_CATEGORY_OBJECT_PROPERTIES) - { - hr = m_ObjectProperties.DispatchWpdMessage(CommandKey, pParams, pResults); - } - else if (CommandKey.fmtid == WPD_CATEGORY_CAPABILITIES) - { - hr = m_Capabilities.DispatchWpdMessage(CommandKey, pParams, pResults); - } - else if (IsEqualPropertyKey(CommandKey, WPD_COMMAND_COMMON_GET_OBJECT_IDS_FROM_PERSISTENT_UNIQUE_IDS)) - { - hr = OnGetObjectIDsFromPersistentUniqueIDs(pParams, pResults); - } - else - { - hr = E_NOTIMPL; - CHECK_HR(hr, "Unknown command %ws.%d received",CComBSTR(CommandKey.fmtid), CommandKey.pid); - } - } - - HRESULT hrTemp = pResults->SetErrorValue(WPD_PROPERTY_COMMON_HRESULT, hr); - CHECK_HR(hrTemp, ("Failed to set WPD_PROPERTY_COMMON_HRESULT")); - - // Set to a success code, to indicate that the message was received. - // the return code for the actual command's results is stored in the - // WPD_PROPERTY_COMMON_HRESULT property. - hr = S_OK; - - return hr; -} - -/** - * This method is called to initialize the driver object. - * This is where the driver establishes a connection with the - * COM port, creates the IoTarget to forward read/write requests to, and - * starts the thread which monitors these events. - */ -HRESULT WpdBaseDriver::Initialize(_In_ IWDFDevice* pDevice) -{ - HRESULT hr = S_OK; - HANDLE hPort = NULL; - - TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_FLAG_DRIVER, "%!FUNC! Entry"); - - if (pDevice == NULL) - { - hr = E_POINTER; - CHECK_HR(hr, "A NULL IWDFDevice parameter was received."); - return hr; - } - - // Save the WDF device instance - m_pWDFDevice = pDevice; - m_ObjectProperties.Initialize(this); - m_ObjectEnum.Initialize(this); - - // Initialize the Wpd Serializer for posting events - hr = CoCreateInstance(CLSID_WpdSerializer, - NULL, - CLSCTX_INPROC_SERVER, - IID_IWpdSerializer, - (VOID**)&m_pWpdSerializer); - - CHECK_HR(hr, "Failed to CoCreate the Wpd Serializer."); - - - // Initialize a handle to the RS232 connection - hr = m_Connection.Connect(COM_PORT_NAME, &hPort); - CHECK_HR(hr, "Failed to connect to port: %ws", COM_PORT_NAME); - - // Initialize the IoTarget to wrap the opened handle - if (hr == S_OK) - { - hr = m_Target.Create(this, pDevice, hPort); - CHECK_HR(hr, "Failed to create the port I/O target."); - } - - return hr; -} - -/** - * This method is called to uninitialize the driver object. - * This is where the driver disables the connection with the - * COM port and performs the necessary cleanup. - */ -void WpdBaseDriver::Uninitialize() -{ - TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_FLAG_DRIVER, "%!FUNC! Entry"); - - m_Target.Delete(); - m_Connection.Disconnect(); - - m_pWDFDevice = NULL; -} - -/** - * This method is called to extract the sensor data and interval prop from the raw serial buffer - * and to post a new reading PnP event if valid data is received - */ -HRESULT WpdBaseDriver::ProcessReadData(_In_reads_(cbData) BYTE* pData, size_t cbData) -{ - HRESULT hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); - LONGLONG llSensorReading = 0; // was originally DWORD but the accelerometers required addt'l bytes - DWORD dwUpdateInterval = 0; - - // Parse the serial data - CHAR szInterval[INTERVAL_DATA_LENGTH + 1] = {0}; // last byte is always null - CHAR* szReading = NULL; // buffer containing the reading - - const SENSOR_INFO c_SensorInfoTable [] = { - {'1', COMPASS_DATA_LENGTH}, // Compass - {'2', SENSIRON_DATA_LENGTH}, // Temp/humidity sensor - {'3', FLEX_DATA_LENGTH}, // Flexiforce sensor - {'4', PING_DATA_LENGTH}, // Ultrasonic ping - {'5', PIR_DATA_LENGTH}, // Passive infrared - {'6', MEMSIC_DATA_LENGTH}, // 2-axis accelerometer - {'7', QTI_DATA_LENGTH}, // Light sensor - {'8', PIEZO_DATA_LENGTH}, // Vibration Sensor - {'9', HITACHI_DATA_LENGTH}, // 3-axis accelerometer - }; - - // Allocate the necessary bytes for collecting the sensor data. - // We'll examine the DEVICE_ID field of the batched serial data and allocate - // the necessary bytes accordingly... - // This is also where we set the sensor identifier and related properties). - - if (cbData > DEVICE_ID) - { - switch (pData[DEVICE_ID]){ - case '1': - m_SensorType = COMPASS; - szReading = (CHAR *)malloc(COMPASS_DATA_LENGTH + 1); // last byte is always null - hr = S_OK; - break; - case '2': - m_SensorType = SENSIRON; - szReading = (CHAR *)malloc(SENSIRON_DATA_LENGTH + 1); // last byte is always null - hr = S_OK; - break; - case '3': - m_SensorType = FLEX; - szReading = (CHAR *)malloc(FLEX_DATA_LENGTH + 1); // last byte is always null - hr = S_OK; - break; - case '4': - m_SensorType = PING; - szReading = (CHAR *)malloc(PING_DATA_LENGTH + 1); // last byte is always null - hr = S_OK; - break; - case '5': - m_SensorType = PIR; - szReading = (CHAR *)malloc(PIR_DATA_LENGTH + 1); // last byte is always null - hr = S_OK; - break; - case '6': - m_SensorType = MEMSIC; - szReading = (CHAR *)malloc(MEMSIC_AMOUNT_TO_READ + 1); // last byte is always null - hr = S_OK; - break; - case '7': - m_SensorType = QTI; - szReading = (CHAR *)malloc(QTI_DATA_LENGTH + 1); // last byte is always null - hr = S_OK; - break; - case '8': - m_SensorType = PIEZO; - szReading = (CHAR *)malloc(PIEZO_DATA_LENGTH + 1); // last byte is always null - hr = S_OK; - break; - case '9': - m_SensorType = HITACHI; - szReading = (CHAR *)malloc(HITACHI_DATA_LENGTH + 1); // last byte is always null - hr = S_OK; - break; - default: - break; - } - } - - if ((hr == S_OK) && (szReading == NULL)) - { - hr = E_OUTOFMEMORY; - } - - // Ensure we have sufficient input buffer size, and, if we do - // process the data for the given sensor. - if (hr == S_OK && (cbData >= (INTERVAL_DATA_LENGTH + MIN_DATA_LENGTH))) - { - for (int i=0; i pEventParams; - - TraceEvents(TRACE_LEVEL_VERBOSE, TRACE_FLAG_DRIVER, "%!FUNC! Reading: %I64d, Interval: %d", llSensorData, dwUpdateInterval); - - // Create the event parameters collection if it doesn't exist - if (m_pEventParams == NULL) - { - hr = CoCreateInstance(CLSID_PortableDeviceValues, - NULL, - CLSCTX_INPROC_SERVER, - IID_IPortableDeviceValues, - (VOID**)&m_pEventParams); - CHECK_HR(hr, "Failed to CoCreate CLSID_PortableDeviceValues"); - } - - if (hr == S_OK) - { - // Initialize the event parameters - m_pEventParams->Clear(); - - // Populate the event parameters - hr = m_pEventParams->SetGuidValue(WPD_EVENT_PARAMETER_EVENT_ID, EVENT_SENSOR_READING_UPDATED); - CHECK_HR(hr, "Failed to set the WPD_EVENT_PARAMETER_EVENT_ID"); - } - - if (hr == S_OK) - { - //hr = m_pEventParams->SetUnsignedIntegerValue(SENSOR_READING, dwTemperatureData); - hr = m_pEventParams->SetUnsignedLargeIntegerValue(SENSOR_READING, llSensorData); - CHECK_HR(hr, "Failed to set the sensor reading"); - } - - if (hr == S_OK) - { - hr = m_pEventParams->SetUnsignedIntegerValue(SENSOR_UPDATE_INTERVAL, dwUpdateInterval); - CHECK_HR(hr, "Failed to set the sensor update interval"); - } - - if (hr == S_OK) - { - // Create a buffer with the serialized parameters - hr = m_pWpdSerializer->GetBufferFromIPortableDeviceValues(m_pEventParams, &pBuffer, &cbBuffer); - CHECK_HR(hr, "Failed to get buffer from IPortableDeviceValues"); - } - - // Send the event - if (hr == S_OK && pBuffer != NULL) - { - hr = m_pWDFDevice->PostEvent(WPD_EVENT_NOTIFICATION, WdfEventBroadcast, pBuffer, cbBuffer); - CHECK_HR(hr, "Failed to post the WPD broadcast event"); - } - - // Free the memory - CoTaskMemFree(pBuffer); - pBuffer = NULL; - - return hr; -} - -/** - * This method is called when we receive a WPD_COMMAND_COMMON_GET_OBJECT_IDS_FROM_PERSISTENT_UNIQUE_IDS - * command. - * - * The parameters sent to us are: - * - WPD_PROPERTY_COMMON_PERSISTENT_UNIQUE_IDS: Contains an IPortableDevicePropVariantCollection of VT_LPWSTR, - * indicating the PersistentUniqueIDs. - * - * The driver should: - * - Iterate through the PersistentUniqueIDs, and convert to a currently valid object id. - * This object ID list should be returned as an IPortableDevicePropVariantCollection of VT_LPWSTR - * in WPD_PROPERTY_COMMON_OBJECT_IDS. - * Order is implicit, i.e. the first element in the Persistent Unique ID list corresponds to the - * to the first element of the ObjectID list and so on. - * - * For those elements where an existing ObjectID could not be found (e.g. the - * object is no longer present on the device), the element will contain the - * empty string (L""). - */ -HRESULT WpdBaseDriver::OnGetObjectIDsFromPersistentUniqueIDs( - _In_ IPortableDeviceValues* pParams, - _In_ IPortableDeviceValues* pResults) -{ - - HRESULT hr = S_OK; - DWORD dwCount = 0; - CComPtr pPersistentIDs; - CComPtr pObjectIDs; - - if((pParams == NULL) || - (pResults == NULL)) - { - hr = E_POINTER; - CHECK_HR(hr, "Cannot have NULL parameter"); - return hr; - } - - // Get the list of Persistent IDs - if (hr == S_OK) - { - hr = pParams->GetIPortableDevicePropVariantCollectionValue(WPD_PROPERTY_COMMON_PERSISTENT_UNIQUE_IDS, &pPersistentIDs); - CHECK_HR(hr, "Failed to get WPD_PROPERTY_COMMON_PERSISTENT_UNIQUE_IDS"); - } - - // Create the collection to hold the ObjectIDs - if (hr == S_OK) - { - hr = CoCreateInstance(CLSID_PortableDevicePropVariantCollection, - NULL, - CLSCTX_INPROC_SERVER, - IID_IPortableDevicePropVariantCollection, - (VOID**) &pObjectIDs); - CHECK_HR(hr, "Failed to CoCreate CLSID_PortableDevicePropVariantCollection"); - } - - // Iterate through the persistent ID list and add the equivalent object ID for each element. - if (hr == S_OK) - { - hr = pPersistentIDs->GetCount(&dwCount); - CHECK_HR(hr, "Failed to get count from persistent ID collection"); - - if (hr == S_OK) - { - DWORD dwIndex = 0; - PROPVARIANT pvPersistentID = {0}; - PROPVARIANT pvObjectID = {0}; - - PropVariantInit(&pvPersistentID); - PropVariantInit(&pvObjectID); - - for(dwIndex = 0; dwIndex < dwCount; dwIndex++) - { - pvObjectID.vt = VT_LPWSTR; - hr = pPersistentIDs->GetAt(dwIndex, &pvPersistentID); - CHECK_HR(hr, "Failed to get persistent ID at index %d", dwIndex); - - // Since our persistent unique identifier are identical to our object - // identifiers, we just return it back to the caller. - if (hr == S_OK) - { - pvObjectID.pwszVal = AtlAllocTaskWideString(pvPersistentID.pwszVal); - } - - if (hr == S_OK) - { - hr = pObjectIDs->Add(&pvObjectID); - CHECK_HR(hr, "Failed to add next Object ID"); - } - - PropVariantClear(&pvPersistentID); - PropVariantClear(&pvObjectID); - - if(FAILED(hr)) - { - break; - } - } - } - } - - if (hr == S_OK) - { - hr = pResults->SetIPortableDevicePropVariantCollectionValue(WPD_PROPERTY_COMMON_OBJECT_IDS, pObjectIDs); - CHECK_HR(hr, "Failed to set WPD_PROPERTY_COMMON_OBJECT_IDS"); - } - - return hr; -} diff --git a/wpd/WpdBasicHardwareDriver/WpdBaseDriver.h b/wpd/WpdBasicHardwareDriver/WpdBaseDriver.h deleted file mode 100644 index 13dd4694..00000000 --- a/wpd/WpdBasicHardwareDriver/WpdBaseDriver.h +++ /dev/null @@ -1,69 +0,0 @@ -#pragma once - -typedef struct tagSENSOR_INFO{ - unsigned char deviceID; - unsigned short dataLength; -} SENSOR_INFO; - -class WpdBaseDriver : - public IUnknown -{ -public: - WpdBaseDriver(); - virtual ~WpdBaseDriver(); - - HRESULT Initialize(_In_ IWDFDevice *pDevice); - void Uninitialize(); - - HRESULT DispatchWpdMessage(_In_ IPortableDeviceValues* pParams, - _In_ IPortableDeviceValues* pResults); - - HRESULT ProcessReadData(_In_reads_(cbData) BYTE* pData, size_t cbData); - - RS232Target* GetRS232Target(); - -public: // IUnknown - ULONG __stdcall AddRef(); - - _At_(this, __drv_freesMem(Mem)) - ULONG __stdcall Release(); - - HRESULT __stdcall QueryInterface(REFIID riid, void** ppv); - -private: - HRESULT OnGetObjectIDsFromPersistentUniqueIDs(_In_ IPortableDeviceValues* pParams, - _In_ IPortableDeviceValues* pResults); - - HRESULT PostSensorReadingEvent(LONGLONG llSensorData, DWORD dwUpdateInterval); - -public: - - enum SensorType{ - UNKNOWN, // Unknown - COMPASS, // Compass - SENSIRON, // Temp/humidity sensor - FLEX, // Flexiforce sensor - PING, // Ultrasonic ping - PIR, // Passive infrared - MEMSIC, // 2-axis accelerometer - QTI, // Light sensor - PIEZO, // Vibration Sensor - HITACHI, // 3-axis accelerometer - }; - - SensorType m_SensorType; // enum value specifying sensor type - -private: - WpdObjectEnumerator m_ObjectEnum; - WpdObjectProperties m_ObjectProperties; - WpdCapabilities m_Capabilities; - - ULONG m_cRef; - RS232Connection m_Connection; - RS232Target m_Target; - - CComPtr m_pWDFDevice; - CComPtr m_pWpdSerializer; - CComPtr m_pEventParams; -}; - diff --git a/wpd/WpdBasicHardwareDriver/WpdBasicHardwareDriver.cpp b/wpd/WpdBasicHardwareDriver/WpdBasicHardwareDriver.cpp deleted file mode 100644 index 2620e909..00000000 --- a/wpd/WpdBasicHardwareDriver/WpdBasicHardwareDriver.cpp +++ /dev/null @@ -1,60 +0,0 @@ -#include "stdafx.h" - -#include "WpdBasicHardwareDriver.tmh" - -HINSTANCE g_hInstance = NULL; - -class CWpdBasicHardwareDriverModule : public CAtlDllModuleT< CWpdBasicHardwareDriverModule > -{ -public : - DECLARE_REGISTRY_APPID_RESOURCEID(IDR_WpdBasicHardwareDriver, "{021AD204-6411-4698-8CFB-C1A72B581733}") - DECLARE_LIBID(LIBID_WpdBasicHardwareDriverLib) -}; - -CWpdBasicHardwareDriverModule _AtlModule; - -// DLL Entry Point -extern "C" BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) -{ - if(dwReason == DLL_PROCESS_ATTACH) - { - g_hInstance = hInstance; - - // Initialize tracing. - WPP_INIT_TRACING(MYDRIVER_TRACING_ID); - } - else if (dwReason == DLL_PROCESS_DETACH) - { - // Cleanup tracing. - WPP_CLEANUP(); - } - - return _AtlModule.DllMain(dwReason, lpReserved); -} - -// Used to determine whether the DLL can be unloaded by OLE -STDAPI DllCanUnloadNow(void) -{ - return _AtlModule.DllCanUnloadNow(); -} - -// Returns a class factory to create an object of the requested type -STDAPI DllGetClassObject(_In_ REFCLSID rclsid, _In_ REFIID riid, _Outptr_ LPVOID* ppv) -{ - return _AtlModule.DllGetClassObject(rclsid, riid, ppv); -} - -// DllRegisterServer - Adds entries to the system registry -STDAPI DllRegisterServer(void) -{ - // registers object, typelib and all interfaces in typelib - HRESULT hr = _AtlModule.DllRegisterServer(); - return hr; -} - -// DllUnregisterServer - Removes entries from the system registry -STDAPI DllUnregisterServer(void) -{ - HRESULT hr = _AtlModule.DllUnregisterServer(); - return hr; -} diff --git a/wpd/WpdBasicHardwareDriver/WpdBasicHardwareDriver.def b/wpd/WpdBasicHardwareDriver/WpdBasicHardwareDriver.def deleted file mode 100644 index 4af498d9..00000000 --- a/wpd/WpdBasicHardwareDriver/WpdBasicHardwareDriver.def +++ /dev/null @@ -1,9 +0,0 @@ -; WpdBasicHardwareDriver.def : Declares the module parameters. - -LIBRARY "WpdBasicHardwareDriver.DLL" - -EXPORTS - DllCanUnloadNow PRIVATE - DllGetClassObject PRIVATE - DllRegisterServer PRIVATE - DllUnregisterServer PRIVATE diff --git a/wpd/WpdBasicHardwareDriver/WpdBasicHardwareDriver.idl b/wpd/WpdBasicHardwareDriver/WpdBasicHardwareDriver.idl deleted file mode 100644 index 73ff16af..00000000 --- a/wpd/WpdBasicHardwareDriver/WpdBasicHardwareDriver.idl +++ /dev/null @@ -1,24 +0,0 @@ - -import "oaidl.idl"; -import "ocidl.idl"; - -import "wudfddi.idl"; - -[ - uuid(69A9B934-73F0-45AF-B3C5-1D5BC7BC982B), - version(1.0), - helpstring("Windows Portable Device Basic Hardware Driver Type Library") -] -library WpdBasicHardwareDriverLib -{ - importlib("stdole2.tlb"); - [ - uuid(EC7445EE-BC00-4CED-AFE7-A52849F10239), - helpstring("WpdBasicHardwareDriver Class") - ] - coclass WpdBasicHardwareDriver - { - [default] interface IDriverEntry; - }; -}; - diff --git a/wpd/WpdBasicHardwareDriver/WpdBasicHardwareDriver.inx b/wpd/WpdBasicHardwareDriver/WpdBasicHardwareDriver.inx deleted file mode 100644 index 84fd3faa..00000000 --- a/wpd/WpdBasicHardwareDriver/WpdBasicHardwareDriver.inx +++ /dev/null @@ -1,81 +0,0 @@ -; -; WpdBasicHardwareDriver.inf -; - -[Version] -Signature="$Windows NT$" -Class=WPD -ClassGuid={EEC5AD98-8080-425f-922A-DABF3DE3F69A} -Provider=%Provider% -CatalogFile=WpdBasicHardwareDriver.cat -DriverVer=01/24/2007,1.1.1.1 - -[Manufacturer] -%MSFTWUDF%=Microsoft,NT$ARCH$ - -[Microsoft.NT$ARCH$] -%BasicDeviceName%=Basic_Install,WUDF\WpdBasicHardware - -[SourceDisksFiles] -WudfUpdate_$UMDFCOINSTALLERVERSION$.dll=1 -WpdBasicHardwareDriver.dll=1 - -[SourceDisksNames] -1 = %MediaDescription% - -; =================== WPD Sample Device ================================== - -[Basic_Install] -CopyFiles=System32Copy - -[Basic_Install.hw] -AddReg=Device_AddReg - -[Basic_Install.Services] -AddService=WUDFRd,0x000001fa,WUDFRD_ServiceInstall - -[Basic_Install.CoInstallers] -AddReg=Basic_Install.CoInstallers_AddReg -CopyFiles=CoInstallers_CopyFiles - -[CoInstallers_CopyFiles] -WudfUpdate_$UMDFCOINSTALLERVERSION$.dll - -[Basic_Install.CoInstallers_AddReg] -HKR,,CoInstallers32,0x00010000,"WudfUpdate_$UMDFCOINSTALLERVERSION$.dll" - -[Basic_Install.Wdf] -UmdfService=WpdBasicHardwareDriver, WpdBasicHardwareDriver_Install -UmdfServiceOrder=WpdBasicHardwareDriver -; Enable file-handle-based I/O targets -UmdfDispatcher = FileHandle - -[WpdBasicHardwareDriver_Install] -UmdfLibraryVersion=$UMDFVERSION$ -DriverCLSID="{EC7445EE-BC00-4CED-AFE7-A52849F10239}" -ServiceBinary=%12%\UMDF\WpdBasicHardwareDriver.dll - -[Device_AddReg] -; HKR,,"EnableLegacySupport",0x10001,0 - -[WUDFRD_ServiceInstall] -ServiceType=1 -StartType=3 -ErrorControl=1 -ServiceBinary=%12%\WUDFRd.sys - -[DestinationDirs] -System32Copy=12,UMDF ; copy to system32\drivers\umdf -CoInstallers_CopyFiles=11 - -[System32Copy] -WpdBasicHardwareDriver.dll - - -; =================== Generic ================================== - -[Strings] -MSFTWUDF="Microsoft Windows Portable Devices" -Provider="Microsoft WPD" -MediaDescription="WPD Basic Hardware Driver Installation Media" -BasicDeviceName="WPD Basic Hardware Driver" diff --git a/wpd/WpdBasicHardwareDriver/WpdBasicHardwareDriver.rc b/wpd/WpdBasicHardwareDriver/WpdBasicHardwareDriver.rc deleted file mode 100644 index f743120a..00000000 --- a/wpd/WpdBasicHardwareDriver/WpdBasicHardwareDriver.rc +++ /dev/null @@ -1,15 +0,0 @@ -#include "resource.h" -#include -#include - -#define VER_FILETYPE VFT_DLL -#define VER_FILESUBTYPE VFT2_UNKNOWN -#define VER_FILEDESCRIPTION_STR "Windows Portable Device Basic Hardware Driver" -#define VER_INTERNALNAME_STR "WpdBasicHardwareDriver.dll" - -#include - -1 TYPELIB "WpdBasicHardwareDriver.tlb" - -IDR_WpdTempSensorDriver REGISTRY "WpdBasicHardwareDriver.rgs" - diff --git a/wpd/WpdBasicHardwareDriver/WpdBasicHardwareDriver.rgs b/wpd/WpdBasicHardwareDriver/WpdBasicHardwareDriver.rgs deleted file mode 100644 index 6b4ae538..00000000 --- a/wpd/WpdBasicHardwareDriver/WpdBasicHardwareDriver.rgs +++ /dev/null @@ -1,26 +0,0 @@ -HKCR -{ - WpdBasicHardwareDriver.WpdBasicHardwareDriver.1 = s 'WpdBasicHardwareDriver Class' - { - CLSID = s '{FB2CC0AD-6723-45D2-9EC6-7B603F9BCD17}' - } - WpdBasicHardwareDriver.WpdBasicHardwareDriver = s 'WpdBasicHardwareDriver Class' - { - CLSID = s '{FB2CC0AD-6723-45D2-9EC6-7B603F9BCD17}' - CurVer = s 'WpdBasicHardwareDriver.WpdBasicHardwareDriver.1' - } - NoRemove CLSID - { - ForceRemove {FB2CC0AD-6723-45D2-9EC6-7B603F9BCD17} = s 'WpdBasicHardwareDriver Class' - { - ProgID = s 'WpdBasicHardwareDriver.WpdBasicHardwareDriver.1' - VersionIndependentProgID = s 'WpdBasicHardwareDriver.WpdBasicHardwareDriver.1' - InprocServer32 = s '%MODULE%' - { - val ThreadingModel = s 'Free' - } - 'TypeLib' = s '{20E7797C-2981-49EE-8A78-85A11440785C}' - } - } -} - diff --git a/wpd/WpdBasicHardwareDriver/WpdBasicHardwareDriver.sln b/wpd/WpdBasicHardwareDriver/WpdBasicHardwareDriver.sln deleted file mode 100644 index 9894e0c6..00000000 --- a/wpd/WpdBasicHardwareDriver/WpdBasicHardwareDriver.sln +++ /dev/null @@ -1,28 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2013 -VisualStudioVersion = 12.0 -MinimumVisualStudioVersion = 12.0 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WpdBasicHardwareDriver", "WpdBasicHardwareDriver.vcxproj", "{1E5BF5A5-443A-4333-AE74-950BB47804C9}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Release|Win32 = Release|Win32 - Debug|x64 = Debug|x64 - Release|x64 = Release|x64 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {1E5BF5A5-443A-4333-AE74-950BB47804C9}.Debug|Win32.ActiveCfg = Debug|Win32 - {1E5BF5A5-443A-4333-AE74-950BB47804C9}.Debug|Win32.Build.0 = Debug|Win32 - {1E5BF5A5-443A-4333-AE74-950BB47804C9}.Release|Win32.ActiveCfg = Release|Win32 - {1E5BF5A5-443A-4333-AE74-950BB47804C9}.Release|Win32.Build.0 = Release|Win32 - {1E5BF5A5-443A-4333-AE74-950BB47804C9}.Debug|x64.ActiveCfg = Debug|x64 - {1E5BF5A5-443A-4333-AE74-950BB47804C9}.Debug|x64.Build.0 = Debug|x64 - {1E5BF5A5-443A-4333-AE74-950BB47804C9}.Release|x64.ActiveCfg = Release|x64 - {1E5BF5A5-443A-4333-AE74-950BB47804C9}.Release|x64.Build.0 = Release|x64 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/wpd/WpdBasicHardwareDriver/WpdBasicHardwareDriver.vcxproj b/wpd/WpdBasicHardwareDriver/WpdBasicHardwareDriver.vcxproj deleted file mode 100644 index 6c410150..00000000 --- a/wpd/WpdBasicHardwareDriver/WpdBasicHardwareDriver.vcxproj +++ /dev/null @@ -1,341 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - {1E5BF5A5-443A-4333-AE74-950BB47804C9} - $(MSBuildProjectName) - 1 - 1 - Debug - Win32 - {FCAFC154-953C-4F4F-A562-AC675D6DE454} - - - - Windows10 - False - Desktop - UMDF - WindowsUserModeDriver10.0 - DynamicLibrary - - - Windows10 - True - Desktop - UMDF - WindowsUserModeDriver10.0 - DynamicLibrary - - - Windows10 - False - Desktop - UMDF - WindowsUserModeDriver10.0 - DynamicLibrary - - - Windows10 - True - Desktop - UMDF - WindowsUserModeDriver10.0 - DynamicLibrary - - - - $(IntDir) - - - - - - - - - - - - - - - - true - true - stdafx.h - ;%(AdditionalIncludeDirectories) - Stdafx.h - Use - $(IntDir)\Stdafx.h.pch - - - true - true - stdafx.h - ;%(AdditionalIncludeDirectories) - Stdafx.h - Use - $(IntDir)\Stdafx.h.pch - - - true - true - stdafx.h - ;%(AdditionalIncludeDirectories) - Stdafx.h - Use - $(IntDir)\Stdafx.h.pch - - - true - true - stdafx.h - ;%(AdditionalIncludeDirectories) - Stdafx.h - Use - $(IntDir)\Stdafx.h.pch - - - true - true - stdafx.h - ;%(AdditionalIncludeDirectories) - Stdafx.h - Use - $(IntDir)\Stdafx.h.pch - - - true - true - stdafx.h - ;%(AdditionalIncludeDirectories) - Stdafx.h - Use - $(IntDir)\Stdafx.h.pch - - - true - true - stdafx.h - ;%(AdditionalIncludeDirectories) - Stdafx.h - Use - $(IntDir)\Stdafx.h.pch - - - true - true - stdafx.h - ;%(AdditionalIncludeDirectories) - Stdafx.h - Use - $(IntDir)\Stdafx.h.pch - - - true - true - stdafx.h - ;%(AdditionalIncludeDirectories) - Stdafx.h - Use - $(IntDir)\Stdafx.h.pch - - - true - true - stdafx.h - ;%(AdditionalIncludeDirectories) - Stdafx.h - Use - $(IntDir)\Stdafx.h.pch - - - $(InfArch) - true - .\$(IntDir)\WpdBasicHardwareDriver.inf - - - true - true - stdafx.h - - - - WpdBasicHardwareDriver - - - WpdBasicHardwareDriver - - - WpdBasicHardwareDriver - - - WpdBasicHardwareDriver - - - - _DllMainCRTStartup@12 - _DllMainCRTStartup - - - - - _DllMainCRTStartup@12 - _DllMainCRTStartup - - - - - _DllMainCRTStartup@12 - _DllMainCRTStartup - - - - - _DllMainCRTStartup@12 - _DllMainCRTStartup - - - - Dynamic - - - Dynamic - - - Dynamic - - - Dynamic - - - - Sync - true - Level4 - %(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH) - - - %(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH) - - - %(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH) - - - %(AdditionalDependencies);$(SDK_LIB_PATH)\strsafe.lib;$(SDK_LIB_PATH)\kernel32.lib;$(SDK_LIB_PATH)\ole32.lib;$(SDK_LIB_PATH)\oleaut32.lib;$(SDK_LIB_PATH)\uuid.lib;$(SDK_LIB_PATH)\user32.lib;$(SDK_LIB_PATH)\advapi32.lib;$(SDK_LIB_PATH)\shlwapi.lib;$(SDK_LIB_PATH)\PortableDeviceGuids.lib - - - - - Sync - true - Level4 - %(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH) - - - %(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH) - - - %(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH) - - - %(AdditionalDependencies);$(SDK_LIB_PATH)\strsafe.lib;$(SDK_LIB_PATH)\kernel32.lib;$(SDK_LIB_PATH)\ole32.lib;$(SDK_LIB_PATH)\oleaut32.lib;$(SDK_LIB_PATH)\uuid.lib;$(SDK_LIB_PATH)\user32.lib;$(SDK_LIB_PATH)\advapi32.lib;$(SDK_LIB_PATH)\shlwapi.lib;$(SDK_LIB_PATH)\PortableDeviceGuids.lib - - - - - Sync - true - Level4 - %(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH) - - - %(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH) - - - %(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH) - - - %(AdditionalDependencies);$(SDK_LIB_PATH)\strsafe.lib;$(SDK_LIB_PATH)\kernel32.lib;$(SDK_LIB_PATH)\ole32.lib;$(SDK_LIB_PATH)\oleaut32.lib;$(SDK_LIB_PATH)\uuid.lib;$(SDK_LIB_PATH)\user32.lib;$(SDK_LIB_PATH)\advapi32.lib;$(SDK_LIB_PATH)\shlwapi.lib;$(SDK_LIB_PATH)\PortableDeviceGuids.lib - - - - - Sync - true - Level4 - %(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH) - - - %(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH) - - - %(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH) - - - %(AdditionalDependencies);$(SDK_LIB_PATH)\strsafe.lib;$(SDK_LIB_PATH)\kernel32.lib;$(SDK_LIB_PATH)\ole32.lib;$(SDK_LIB_PATH)\oleaut32.lib;$(SDK_LIB_PATH)\uuid.lib;$(SDK_LIB_PATH)\user32.lib;$(SDK_LIB_PATH)\advapi32.lib;$(SDK_LIB_PATH)\shlwapi.lib;$(SDK_LIB_PATH)\PortableDeviceGuids.lib - - - - - WpdBasicHardwareDriver.def - - - - - WpdBasicHardwareDriver.def - - - - - WpdBasicHardwareDriver.def - - - - - WpdBasicHardwareDriver.def - - - - - ;%(AdditionalIncludeDirectories) - Stdafx.h - Create - $(IntDir)\Stdafx.h.pch - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/wpd/WpdBasicHardwareDriver/WpdBasicHardwareDriver.vcxproj.Filters b/wpd/WpdBasicHardwareDriver/WpdBasicHardwareDriver.vcxproj.Filters deleted file mode 100644 index 27c39646..00000000 --- a/wpd/WpdBasicHardwareDriver/WpdBasicHardwareDriver.vcxproj.Filters +++ /dev/null @@ -1,75 +0,0 @@ - - - - - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {CB45677C-7902-40FE-AD70-EA706EDEB72E} - - - h;hpp;hxx;hm;inl;inc;xsd - {C5FA4326-71CC-4479-B1A5-CD9DFDEA5EB8} - - - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {2B5296BE-5034-4FAE-9D34-F4116A2470F4} - - - inf;inv;inx;mof;mc; - {CD595C43-3553-40B9-A6A0-F00C1C4A379F} - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Driver Files - - - Driver Files - - - - - Resource Files - - - \ No newline at end of file diff --git a/wpd/WpdBasicHardwareDriver/WpdCapabilities.cpp b/wpd/WpdBasicHardwareDriver/WpdCapabilities.cpp deleted file mode 100644 index e14c53c2..00000000 --- a/wpd/WpdBasicHardwareDriver/WpdCapabilities.cpp +++ /dev/null @@ -1,505 +0,0 @@ -#include "stdafx.h" - -#include "WpdCapabilities.tmh" - -const PROPERTYKEY g_SupportedCommands[] = -{ - // WPD_CATEGORY_OBJECT_ENUMERATION - WPD_COMMAND_OBJECT_ENUMERATION_START_FIND, - WPD_COMMAND_OBJECT_ENUMERATION_FIND_NEXT, - WPD_COMMAND_OBJECT_ENUMERATION_END_FIND, - - // WPD_CATEGORY_OBJECT_PROPERTIES - WPD_COMMAND_OBJECT_PROPERTIES_GET_SUPPORTED, - WPD_COMMAND_OBJECT_PROPERTIES_GET, - WPD_COMMAND_OBJECT_PROPERTIES_GET_ALL, - WPD_COMMAND_OBJECT_PROPERTIES_SET, - WPD_COMMAND_OBJECT_PROPERTIES_GET_ATTRIBUTES, - WPD_COMMAND_OBJECT_PROPERTIES_DELETE, - - // WPD_CATEGORY_CAPABILITIES - WPD_COMMAND_CAPABILITIES_GET_SUPPORTED_COMMANDS, - WPD_COMMAND_CAPABILITIES_GET_COMMAND_OPTIONS, - WPD_COMMAND_CAPABILITIES_GET_SUPPORTED_FUNCTIONAL_CATEGORIES, - WPD_COMMAND_CAPABILITIES_GET_FUNCTIONAL_OBJECTS, - WPD_COMMAND_CAPABILITIES_GET_SUPPORTED_EVENTS, - WPD_COMMAND_CAPABILITIES_GET_EVENT_OPTIONS, -}; - -const GUID g_SupportedFunctionalCategories[] = -{ - WPD_FUNCTIONAL_CATEGORY_DEVICE, - FUNCTIONAL_CATEGORY_SENSOR_SAMPLE, // Our device's functional category -}; - -const GUID g_SupportedEvents[] = -{ - EVENT_SENSOR_READING_UPDATED, -}; - -WpdCapabilities::WpdCapabilities() -{ - -} - -WpdCapabilities::~WpdCapabilities() -{ - -} - -HRESULT WpdCapabilities::DispatchWpdMessage(_In_ REFPROPERTYKEY Command, - _In_ IPortableDeviceValues* pParams, - _In_ IPortableDeviceValues* pResults) -{ - HRESULT hr = S_OK; - - if (Command.fmtid != WPD_CATEGORY_CAPABILITIES) - { - hr = E_INVALIDARG; - CHECK_HR(hr, "This object does not support this command category %ws",CComBSTR(Command.fmtid)); - } - - if (hr == S_OK) - { - if (IsEqualPropertyKey(Command, WPD_COMMAND_CAPABILITIES_GET_SUPPORTED_COMMANDS)) - { - hr = OnGetSupportedCommands(pParams, pResults); - CHECK_HR(hr, "Failed to get supported commands"); - } - else if (IsEqualPropertyKey(Command, WPD_COMMAND_CAPABILITIES_GET_COMMAND_OPTIONS)) - { - hr = OnGetCommandOptions(pParams, pResults); - CHECK_HR(hr, "Failed to get command options"); - } - else if (IsEqualPropertyKey(Command, WPD_COMMAND_CAPABILITIES_GET_SUPPORTED_FUNCTIONAL_CATEGORIES)) - { - hr = OnGetFunctionalCategories(pParams, pResults); - CHECK_HR(hr, "Failed to get functional categories"); - } - else if (IsEqualPropertyKey(Command, WPD_COMMAND_CAPABILITIES_GET_FUNCTIONAL_OBJECTS)) - { - hr = OnGetFunctionalObjects(pParams, pResults); - CHECK_HR(hr, "Failed to get functional objects"); - } - else if (IsEqualPropertyKey(Command, WPD_COMMAND_CAPABILITIES_GET_SUPPORTED_EVENTS)) - { - hr = OnGetSupportedEvents(pParams, pResults); - CHECK_HR(hr, "Failed to get supported events"); - } - else if (IsEqualPropertyKey(Command, WPD_COMMAND_CAPABILITIES_GET_EVENT_OPTIONS)) - { - hr = OnGetEventOptions(pParams, pResults); - CHECK_HR(hr, "Failed to get event options"); - } - else - { - hr = E_NOTIMPL; - CHECK_HR(hr, "This object does not support this command id %d", Command.pid); - } - } - return hr; -} - -/** - * This method is called when we receive a WPD_COMMAND_CAPABILITIES_GET_SUPPORTED_COMMANDS - * command. - * - * The parameters sent to us are: - * - none. - * - * The driver should: - * - Return all commands supported by this driver as an - * IPortableDeviceKeyCollection in WPD_PROPERTY_CAPABILITIES_SUPPORTED_COMMANDS. - * This includes custom commands, if any. - * - * Note that certain commands require a "command target" to function correctly. - * (e.g. delete object command) It is understood that not all objects are necessarily - * valid targets (e.g. you cannot delete the device object). - */ -HRESULT WpdCapabilities::OnGetSupportedCommands( - _In_ IPortableDeviceValues* pParams, - _In_ IPortableDeviceValues* pResults) -{ - HRESULT hr = S_OK; - CComPtr pCommands; - UNREFERENCED_PARAMETER(pParams); - - // CoCreate a collection to store the supported commands. - if (hr == S_OK) - { - hr = CoCreateInstance(CLSID_PortableDeviceKeyCollection, - NULL, - CLSCTX_INPROC_SERVER, - IID_IPortableDeviceKeyCollection, - (VOID**) &pCommands); - CHECK_HR(hr, "Failed to CoCreate CLSID_PortableDeviceKeyCollection"); - } - - // Add the supported commands to the collection. - if (hr == S_OK) - { - for (DWORD dwIndex = 0; dwIndex < ARRAYSIZE(g_SupportedCommands); dwIndex++) - { - hr = pCommands->Add(g_SupportedCommands[dwIndex]); - CHECK_HR(hr, "Failed to add supported command at index %d", dwIndex); - if (FAILED(hr)) - { - break; - } - } - } - - // Set the WPD_PROPERTY_CAPABILITIES_SUPPORTED_COMMANDS value in the results. - if (hr == S_OK) - { - hr = pResults->SetIUnknownValue(WPD_PROPERTY_CAPABILITIES_SUPPORTED_COMMANDS, pCommands); - CHECK_HR(hr, "Failed to set WPD_PROPERTY_CAPABILITIES_SUPPORTED_COMMANDS"); - } - - return hr; -} - -/** - * This method is called when we receive a WPD_COMMAND_CAPABILITIES_GET_COMMAND_OPTIONS - * command. - * - * The parameters sent to us are: - * - WPD_PROPERTY_CAPABILITIES_COMMAND: a collection of property keys containing a single value, - * which identifies the specific command options are requested to return. - * - * The driver should: - * - Return an IPortableDeviceValues in WPD_PROPERTY_CAPABILITIES_COMMAND_OPTIONS, containing - * the relevant options. If no options are available for this command, the driver should - * return an IPortableDeviceValues with no elements in it. - */ -HRESULT WpdCapabilities::OnGetCommandOptions( - _In_ IPortableDeviceValues* pParams, - _In_ IPortableDeviceValues* pResults) -{ - HRESULT hr = S_OK; - PROPERTYKEY Command = WPD_PROPERTY_NULL; - CComPtr pOptions; - - // First get ALL parameters for this command. If we cannot get ALL parameters - // then E_INVALIDARG should be returned and no further processing should occur. - - // Get the command whose options have been requested - if (hr == S_OK) - { - hr = pParams->GetKeyValue(WPD_PROPERTY_CAPABILITIES_COMMAND, &Command); - CHECK_HR(hr, "Missing value for WPD_PROPERTY_CAPABILITIES_COMMAND"); - } - - // CoCreate a collection to store the command options. - if (hr == S_OK) - { - hr = CoCreateInstance(CLSID_PortableDeviceValues, - NULL, - CLSCTX_INPROC_SERVER, - IID_IPortableDeviceValues, - (VOID**) &pOptions); - CHECK_HR(hr, "Failed to CoCreateInstance CLSID_PortableDeviceValues"); - } - - // Add command options to the collection - if (hr == S_OK) - { - // If your driver supports command options, then they should be added here - // to the command options collection 'pOptions'. - } - - // Set the WPD_PROPERTY_CAPABILITIES_COMMAND_OPTIONS value in the results. - if (hr == S_OK) - { - hr = pResults->SetIUnknownValue(WPD_PROPERTY_CAPABILITIES_COMMAND_OPTIONS, pOptions); - CHECK_HR(hr, "Failed to set WPD_PROPERTY_CAPABILITIES_COMMAND_OPTIONS"); - } - - return hr; -} - -/** - * This method is called when we receive a WPD_COMMAND_CAPABILITIES_GET_SUPPORTED_FUNCTIONAL_CATEGORIES - * command. - * - * The parameters sent to us are: - * - none. - * - * The driver should: - * - Return an IPortableDevicePropVariantCollection (of type VT_CLSID) in - * WPD_PROPERTY_CAPABILITIES_FUNCTIONAL_CATEGORIES, containing - * the supported functional categories for this device. - */ -HRESULT WpdCapabilities::OnGetFunctionalCategories( - _In_ IPortableDeviceValues* pParams, - _In_ IPortableDeviceValues* pResults) -{ - HRESULT hr = S_OK; - CComPtr pFunctionalCategories; - - UNREFERENCED_PARAMETER(pParams); - - // CoCreate a collection to store the supported functional categories. - if (hr == S_OK) - { - hr = CoCreateInstance(CLSID_PortableDevicePropVariantCollection, - NULL, - CLSCTX_INPROC_SERVER, - IID_IPortableDevicePropVariantCollection, - (VOID**) &pFunctionalCategories); - CHECK_HR(hr, "Failed to CoCreate CLSID_PortableDevicePropVariantCollection"); - } - - // Add the supported functional categories to the collection. - if (hr == S_OK) - { - for (DWORD dwIndex = 0; dwIndex < ARRAYSIZE(g_SupportedFunctionalCategories); dwIndex++) - { - PROPVARIANT pv = {0}; - PropVariantInit(&pv); - // Don't call PropVariantClear, since we did not allocate the memory for these GUIDs - - pv.vt = VT_CLSID; - pv.puuid = (GUID*) &g_SupportedFunctionalCategories[dwIndex]; - - hr = pFunctionalCategories->Add(&pv); - CHECK_HR(hr, "Failed to add supported functional category at index %d", dwIndex); - if (FAILED(hr)) - { - break; - } - } - } - - // Set the WPD_PROPERTY_CAPABILITIES_FUNCTIONAL_CATEGORIES value in the results. - if (hr == S_OK) - { - hr = pResults->SetIUnknownValue(WPD_PROPERTY_CAPABILITIES_FUNCTIONAL_CATEGORIES, pFunctionalCategories); - CHECK_HR(hr, "Failed to set WPD_PROPERTY_CAPABILITIES_FUNCTIONAL_CATEGORIES"); - } - - return hr; -} - -/** - * This method is called when we receive a WPD_COMMAND_CAPABILITIES_GET_FUNCTIONAL_OBJECTS - * command. It is sent when the caller is interesting in finding the object IDs for all - * functional objects belonging to the specified functional category. - * Note: the number of functional objects is expected to be very small (less than 8 for the - * whole device). - * - * The parameters sent to us are: - * - WPD_PROPERTY_CAPABILITIES_FUNCTIONAL_CATEGORY - a GUID value containing the category - * the caller is looking for. If the value is WPD_FUNCTIONAL_CATEGORY_ALL, then the driver - * must return all functional objects, no matter which category they belong to. - * - * The driver should: - * - Return an IPortableDevicePropVariantCollection (of type VT_LPWSTR) in - * WPD_PROPERTY_CAPABILITIES_FUNCTIONAL_OBJECTS, containing - * the ids of the functional objects who belong to the specified functional category. - * If there are no objects in the specified category, the driver should return an - * empty collection. - */ -HRESULT WpdCapabilities::OnGetFunctionalObjects( - _In_ IPortableDeviceValues* pParams, - _In_ IPortableDeviceValues* pResults) -{ - HRESULT hr = S_OK; - GUID guidFunctionalCategory = GUID_NULL; - CComPtr pFunctionalObjects; - - // First get ALL parameters for this command. If we cannot get ALL parameters - // then E_INVALIDARG should be returned and no further processing should occur. - - // Get the functional category whose functional object identifiers have been requested - if (hr == S_OK) - { - hr = pParams->GetGuidValue(WPD_PROPERTY_CAPABILITIES_FUNCTIONAL_CATEGORY, &guidFunctionalCategory); - CHECK_HR(hr, "Missing value for WPD_PROPERTY_CAPABILITIES_FUNCTIONAL_CATEGORY"); - } - - // CoCreate a collection to store the supported functional object identifiers. - if (hr == S_OK) - { - hr = CoCreateInstance(CLSID_PortableDevicePropVariantCollection, - NULL, - CLSCTX_INPROC_SERVER, - IID_IPortableDevicePropVariantCollection, - (VOID**) &pFunctionalObjects); - CHECK_HR(hr, "Failed to CoCreate CLSID_PortableDevicePropVariantCollection"); - } - - // Add the supported functional object identifiers for the specified functional - // category to the collection. - if (hr == S_OK) - { - PROPVARIANT pv = {0}; - PropVariantInit(&pv); - // Don't call PropVariantClear, since we did not allocate the memory for these object identifiers - - // Add WPD_DEVICE_OBJECT_ID to the functional object identifiers collection - if (hr == S_OK) - { - - if ((guidFunctionalCategory == WPD_FUNCTIONAL_CATEGORY_DEVICE) || - (guidFunctionalCategory == WPD_FUNCTIONAL_CATEGORY_ALL)) - { - pv.vt = VT_LPWSTR; - pv.pwszVal = WPD_DEVICE_OBJECT_ID; - hr = pFunctionalObjects->Add(&pv); - CHECK_HR(hr, "Failed to add device object ID"); - } - } - - // Add FUNCTIONAL_CATEGORY_SENSOR_SAMPLE to the functional object - // identifiers collection - if (hr == S_OK) - { - if ((guidFunctionalCategory == FUNCTIONAL_CATEGORY_SENSOR_SAMPLE) || - (guidFunctionalCategory == WPD_FUNCTIONAL_CATEGORY_ALL)) - { - pv.vt = VT_LPWSTR; - pv.pwszVal = SENSOR_OBJECT_ID; - hr = pFunctionalObjects->Add(&pv); - CHECK_HR(hr, "Failed to add sensor object ID"); - } - } - } - - // Set the WPD_PROPERTY_CAPABILITIES_FUNCTIONAL_OBJECTS value in the results. - if (hr == S_OK) - { - hr = pResults->SetIUnknownValue(WPD_PROPERTY_CAPABILITIES_FUNCTIONAL_OBJECTS, pFunctionalObjects); - CHECK_HR(hr, "Failed to set WPD_PROPERTY_CAPABILITIES_FUNCTIONAL_OBJECTS"); - } - - return hr; -} - - -/** - * This method is called when we receive a WPD_COMMAND_CAPABILITIES_GET_SUPPORTED_EVENTS - * command. - * - * The parameters sent to us are: - * - none. - * - * The driver should: - * - Return all events supported by this driver should be returned as an - * IPortableDeviceKeyCollection in WPD_PROPERTY_CAPABILITIES_SUPPORTED_EVENTS. - * That includes custom commands, if any. - */ -HRESULT WpdCapabilities::OnGetSupportedEvents( - _In_ IPortableDeviceValues* pParams, - _In_ IPortableDeviceValues* pResults) -{ - HRESULT hr = S_OK; - CComPtr pEvents; - UNREFERENCED_PARAMETER(pParams); - - // CoCreate a collection to store the supported events. - if (hr == S_OK) - { - hr = CoCreateInstance(CLSID_PortableDevicePropVariantCollection, - NULL, - CLSCTX_INPROC_SERVER, - IID_IPortableDevicePropVariantCollection, - (VOID**) &pEvents); - CHECK_HR(hr, "Failed to CoCreate CLSID_PortableDevicePropVariantCollection"); - } - - // Add the supported events to the collection. - if (hr == S_OK) - { - // populate the supported events collection - for (DWORD dwIndex = 0; dwIndex < ARRAYSIZE(g_SupportedEvents); dwIndex++) - { - PROPVARIANT pv = {0}; - PropVariantInit(&pv); - // Don't call PropVariantClear, since we did not allocate the memory for these GUIDs - - pv.vt = VT_CLSID; - pv.puuid = (GUID*) &g_SupportedEvents[dwIndex]; - - hr = pEvents->Add(&pv); - CHECK_HR(hr, "Failed to add supported event at index %d", dwIndex); - if (FAILED(hr)) - { - break; - } - } - } - - // Set the WPD_PROPERTY_CAPABILITIES_SUPPORTED_EVENTS value in the results. - if (hr == S_OK) - { - hr = pResults->SetIUnknownValue(WPD_PROPERTY_CAPABILITIES_SUPPORTED_EVENTS, pEvents); - CHECK_HR(hr, "Failed to set WPD_PROPERTY_CAPABILITIES_SUPPORTED_EVENTS"); - } - - return hr; -} - -/** - * This method is called when we receive a WPD_COMMAND_CAPABILITIES_GET_EVENT_OPTIONS - * command. - * - * The parameters sent to us are: - * - WPD_PROPERTY_CAPABILITIES_EVENT: a GUID value indicating the Event whose options should be returned. - * - * The driver should: - * - Return an IPortableDeviceValues in WPD_PROPERTY_CAPABILITIES_EVENT_OPTIONS, containing - * the relevant options. - */ -HRESULT WpdCapabilities::OnGetEventOptions( - _In_ IPortableDeviceValues* pParams, - _In_ IPortableDeviceValues* pResults) -{ - HRESULT hr = S_OK; - GUID Event = GUID_NULL; - CComPtr pOptions; - - // First get ALL parameters for this command. If we cannot get ALL parameters - // then E_INVALIDARG should be returned and no further processing should occur. - - // Get the event whose options have been requested - if (hr == S_OK) - { - hr = pParams->GetGuidValue(WPD_PROPERTY_CAPABILITIES_EVENT, &Event); - CHECK_HR(hr, "Missing value for WPD_PROPERTY_CAPABILITIES_EVENT"); - } - - // CoCreate a collection to store the event options. - if (hr == S_OK) - { - hr = CoCreateInstance(CLSID_PortableDeviceValues, - NULL, - CLSCTX_INPROC_SERVER, - IID_IPortableDeviceValues, - (VOID**) &pOptions); - CHECK_HR(hr, "Failed to CoCreateInstance CLSID_PortableDeviceValues"); - } - - // Add event options to the collection - if (hr == S_OK) - { - // Check for the events we support - if (Event == EVENT_SENSOR_READING_UPDATED) - { - // These events are broadcast events - hr = pOptions->SetBoolValue(WPD_EVENT_OPTION_IS_BROADCAST_EVENT, TRUE); - CHECK_HR(hr, "Failed to set WPD_EVENT_OPTION_IS_BROADCAST_EVENT"); - } - } - - // Set the WPD_PROPERTY_CAPABILITIES_EVENT_OPTIONS value in the results. - if (hr == S_OK) - { - hr = pResults->SetIUnknownValue(WPD_PROPERTY_CAPABILITIES_EVENT_OPTIONS, pOptions); - CHECK_HR(hr, "Failed to set WPD_PROPERTY_CAPABILITIES_EVENT_OPTIONS"); - } - - return hr; -} - - diff --git a/wpd/WpdBasicHardwareDriver/WpdCapabilities.h b/wpd/WpdBasicHardwareDriver/WpdCapabilities.h deleted file mode 100644 index b7435830..00000000 --- a/wpd/WpdBasicHardwareDriver/WpdCapabilities.h +++ /dev/null @@ -1,41 +0,0 @@ -#pragma once - -class WpdCapabilities -{ -public: - WpdCapabilities(); - virtual ~WpdCapabilities(); - - HRESULT Initialize(); - - HRESULT DispatchWpdMessage( - _In_ REFPROPERTYKEY Command, - _In_ IPortableDeviceValues* pParams, - _In_ IPortableDeviceValues* pResults); - - HRESULT OnGetSupportedCommands( - _In_ IPortableDeviceValues* pParams, - _In_ IPortableDeviceValues* pResults); - - HRESULT OnGetCommandOptions( - _In_ IPortableDeviceValues* pParams, - _In_ IPortableDeviceValues* pResults); - - HRESULT OnGetFunctionalCategories( - _In_ IPortableDeviceValues* pParams, - _In_ IPortableDeviceValues* pResults); - - HRESULT OnGetFunctionalObjects( - _In_ IPortableDeviceValues* pParams, - _In_ IPortableDeviceValues* pResults); - - HRESULT OnGetSupportedEvents( - _In_ IPortableDeviceValues* pParams, - _In_ IPortableDeviceValues* pResults); - - HRESULT OnGetEventOptions( - _In_ IPortableDeviceValues* pParams, - _In_ IPortableDeviceValues* pResults); - -}; - diff --git a/wpd/WpdBasicHardwareDriver/WpdObjectEnum.cpp b/wpd/WpdBasicHardwareDriver/WpdObjectEnum.cpp deleted file mode 100644 index d804802e..00000000 --- a/wpd/WpdBasicHardwareDriver/WpdObjectEnum.cpp +++ /dev/null @@ -1,431 +0,0 @@ -#include "stdafx.h" - -#include "WpdObjectEnum.tmh" - -WpdObjectEnumerator::WpdObjectEnumerator() -{ - -} - -WpdObjectEnumerator::~WpdObjectEnumerator() -{ - -} - -HRESULT WpdObjectEnumerator::Initialize(_In_ WpdBaseDriver* pBaseDriver) -{ - m_pBaseDriver = pBaseDriver; - return S_OK; -} - -HRESULT WpdObjectEnumerator::DispatchWpdMessage(_In_ REFPROPERTYKEY Command, - _In_ IPortableDeviceValues* pParams, - _In_ IPortableDeviceValues* pResults) -{ - HRESULT hr = S_OK; - - if (Command.fmtid != WPD_CATEGORY_OBJECT_ENUMERATION) - { - hr = E_INVALIDARG; - CHECK_HR(hr, "This object does not support this command category %ws",CComBSTR(Command.fmtid)); - } - - if (hr == S_OK) - { - if (Command.pid == WPD_COMMAND_OBJECT_ENUMERATION_START_FIND.pid) - { - hr = OnStartFind(pParams, pResults); - CHECK_HR(hr, "Failed to begin enumeration"); - } - else if (Command.pid == WPD_COMMAND_OBJECT_ENUMERATION_FIND_NEXT.pid) - { - hr = OnFindNext(pParams, pResults); - if(FAILED(hr)) - { - CHECK_HR(hr, "Failed to find next object"); - } - } - else if (Command.pid == WPD_COMMAND_OBJECT_ENUMERATION_END_FIND.pid) - { - hr = OnEndFind(pParams, pResults); - CHECK_HR(hr, "Failed to end enumeration"); - } - else - { - hr = E_NOTIMPL; - CHECK_HR(hr, "This object does not support this command id %d", Command.pid); - } - } - - return hr; -} - -/** - * This method is called when we receive a WPD_COMMAND_OBJECT_ENUMERATION_START_FIND - * command. - * - * The parameters sent to us are: - * - WPD_PROPERTY_OBJECT_ENUMERATION_PARENT_ID: the parent where we should start - * the enumeration. - * - WPD_PROPERTY_OBJECT_ENUMERATION_FILTER: the filter to use when doing - * enumeration. Since this parameter is optional, it may not exist. - * This driver currently ignores the filter parameter. - * - * The driver should: - * - Create a new context for this enumeration. - * - Set the string identifier in WPD_PROPERTY_OBJECT_ENUMERATION_CONTEXT for the newly created enumeration context. - * This value will be passed back during OnFindNext and OnEndFind. - */ -HRESULT WpdObjectEnumerator::OnStartFind(_In_ IPortableDeviceValues* pParams, - _In_ IPortableDeviceValues* pResults) -{ - HRESULT hr = S_OK; - LPWSTR wszParentID = NULL; - ContextMap* pContextMap = NULL; - CAtlStringW strEnumContext; - - // First get ALL parameters for this command. If we cannot get ALL parameters - // then E_INVALIDARG should be returned and no further processing should occur. - - // Get the object identifier of the parent where the enumeration is starting from. - hr = pParams->GetStringValue(WPD_PROPERTY_OBJECT_ENUMERATION_PARENT_ID, &wszParentID); - if (hr != S_OK) - { - hr = E_INVALIDARG; - CHECK_HR(hr, "Missing value for WPD_PROPERTY_OBJECT_ENUMERATION_PARENT_ID"); - } - - // Get the client context map so we can store an enumeration context for this enumeration - // operation. - if (hr == S_OK) - { - hr = pParams->GetIUnknownValue(PRIVATE_SAMPLE_DRIVER_CLIENT_CONTEXT_MAP, (IUnknown**)&pContextMap); - CHECK_HR(hr, "Failed to get PRIVATE_SAMPLE_DRIVER_CLIENT_CONTEXT_MAP"); - } - - // Create and initialize a new enumeration context. - // Add the new enumertion context to the client context map. This context is used to - // keep track of this particular enumeration operation. - if (hr == S_OK) - { - WpdObjectEnumeratorContext* pEnumeratorContext = new WpdObjectEnumeratorContext(); - if (pEnumeratorContext != NULL) - { - // Initialize the enumeration context - InitializeEnumerationContext(pEnumeratorContext, wszParentID); - - // Add the enumeration context to the client context map. - pContextMap->Add(pEnumeratorContext, strEnumContext); - - // Release the context because Add AddRef's it - SAFE_RELEASE(pEnumeratorContext); - } - else - { - hr = E_OUTOFMEMORY; - CHECK_HR(hr, "Failed to allocate enumeration context"); - } - } - - // Set the WPD_PROPERTY_OBJECT_ENUMERATION_CONTEXT value in the results. - // This context identifier will be passed back during OnFindNext and OnEndFind to allow the driver to access it. - if (hr == S_OK) - { - hr = pResults->SetStringValue(WPD_PROPERTY_OBJECT_ENUMERATION_CONTEXT, strEnumContext); - CHECK_HR(hr, "Failed to set WPD_PROPERTY_OBJECT_ENUMERATION_CONTEXT"); - } - - // Free the memory. - CoTaskMemFree(wszParentID); - wszParentID = NULL; - - SAFE_RELEASE(pContextMap); - - return hr; -} - -HRESULT WpdObjectEnumerator::OnFindNext(_In_ IPortableDeviceValues* pParams, - _In_ IPortableDeviceValues* pResults) -{ - HRESULT hr = S_OK; - LPWSTR wszEnumContext = NULL; - DWORD dwNumObjectsRequested = 0; - ContextMap* pContextMap = NULL; - WpdObjectEnumeratorContext* pEnumeratorContext = NULL; - DWORD NumObjectsEnumerated = 0; - - CComPtr pObjectIDCollection; - - // First get ALL parameters for this command. If we cannot get ALL parameters - // then E_INVALIDARG should be returned and no further processing should occur. - - // Get the enumeration context identifier for this enumeration operation. - // The enumeration context identifier is needed to lookup the specific - // enumeration context in the client context map for this enumeration operation. - // NOTE that more than one enumeration may be in progress. - hr = pParams->GetStringValue(WPD_PROPERTY_OBJECT_ENUMERATION_CONTEXT, &wszEnumContext); - if (hr != S_OK) - { - hr = E_INVALIDARG; - CHECK_HR(hr, "Missing value for WPD_PROPERTY_OBJECT_ENUMERATION_CONTEXT"); - } - - // Get the number of objects requested for this enumeration call. - // The driver should always attempt to meet this requested value. - // If there are fewer children than requested, the driver should return the remaining - // children and a return code of S_FALSE. - hr = pParams->GetUnsignedIntegerValue(WPD_PROPERTY_OBJECT_ENUMERATION_NUM_OBJECTS_REQUESTED, &dwNumObjectsRequested); - if (hr != S_OK) - { - hr = E_INVALIDARG; - CHECK_HR(hr, "Missing value for WPD_PROPERTY_OBJECT_ENUMERATION_NUM_OBJECTS_REQUESTED"); - } - - // Get the client context map so we can retrieve the enumeration context for this enumeration - // operation. - if (hr == S_OK) - { - hr = pParams->GetIUnknownValue(PRIVATE_SAMPLE_DRIVER_CLIENT_CONTEXT_MAP, (IUnknown**)&pContextMap); - CHECK_HR(hr, "Failed to get PRIVATE_SAMPLE_DRIVER_CLIENT_CONTEXT_MAP"); - } - - if (hr == S_OK) - { - pEnumeratorContext = (WpdObjectEnumeratorContext*)pContextMap->GetContext(wszEnumContext); - if (pEnumeratorContext == NULL) - { - hr = E_INVALIDARG; - CHECK_HR(hr, "Missing enumeration context"); - } - } - - // CoCreate a collection to store the object identifiers being returned for this enumeration call. - if (hr == S_OK) - { - hr = CoCreateInstance(CLSID_PortableDevicePropVariantCollection, - NULL, - CLSCTX_INPROC_SERVER, - IID_IPortableDevicePropVariantCollection, - (VOID**) &pObjectIDCollection); - CHECK_HR(hr, "Failed to CoCreate CLSID_PortableDevicePropVariantCollection"); - } - - // If the enumeration context reports that their are more objects to return, then continue, if not, - // return an empty results set. - if ((hr == S_OK) && (pEnumeratorContext != NULL) && (pEnumeratorContext->HasMoreChildrenToEnumerate() == TRUE)) - { - if (pEnumeratorContext->m_strParentObjectID.CompareNoCase(L"") == 0) - { - // We are being asked for the WPD_DEVICE_OBJECT_ID - hr = AddStringValueToPropVariantCollection(pObjectIDCollection, WPD_DEVICE_OBJECT_ID); - CHECK_HR(hr, "Failed to add 'DEVICE' object ID to enumeration collection"); - - // Update the the number of children we are returning for this enumeration call - NumObjectsEnumerated++; - } - else if (pEnumeratorContext->m_strParentObjectID.CompareNoCase(WPD_DEVICE_OBJECT_ID) == 0) - { - - // We are being asked for direct children of the WPD_DEVICE_OBJECT_ID - switch (m_pBaseDriver->m_SensorType) - { - case WpdBaseDriver::UNKNOWN: - hr = AddStringValueToPropVariantCollection(pObjectIDCollection, SENSOR_OBJECT_ID); - break; - case WpdBaseDriver::COMPASS: - hr = AddStringValueToPropVariantCollection(pObjectIDCollection, COMPASS_SENSOR_OBJECT_ID); - break; - case WpdBaseDriver::SENSIRON: - hr = AddStringValueToPropVariantCollection(pObjectIDCollection, TEMP_SENSOR_OBJECT_ID); - break; - case WpdBaseDriver::FLEX: - hr = AddStringValueToPropVariantCollection(pObjectIDCollection, FLEX_SENSOR_OBJECT_ID); - break; - case WpdBaseDriver::PING: - hr = AddStringValueToPropVariantCollection(pObjectIDCollection, PING_SENSOR_OBJECT_ID); - break; - case WpdBaseDriver::PIR: - hr = AddStringValueToPropVariantCollection(pObjectIDCollection, PIR_SENSOR_OBJECT_ID); - break; - case WpdBaseDriver::MEMSIC: - hr = AddStringValueToPropVariantCollection(pObjectIDCollection, MEMSIC_SENSOR_OBJECT_ID); - break; - case WpdBaseDriver::QTI: - hr = AddStringValueToPropVariantCollection(pObjectIDCollection, QTI_SENSOR_OBJECT_ID); - break; - case WpdBaseDriver::PIEZO: - hr = AddStringValueToPropVariantCollection(pObjectIDCollection, PIEZO_SENSOR_OBJECT_ID); - break; - case WpdBaseDriver::HITACHI: - hr = AddStringValueToPropVariantCollection(pObjectIDCollection, HITACHI_SENSOR_OBJECT_ID); - break; - default: - break; - } - CHECK_HR(hr, "Failed to add storage object ID to enumeration collection"); - - // Update the the number of children we are returning for this enumeration call - NumObjectsEnumerated++; - - } - } - - // Set the collection of object identifiers enumerated in the results - if (hr == S_OK) - { - hr = pResults->SetIPortableDevicePropVariantCollectionValue(WPD_PROPERTY_OBJECT_ENUMERATION_OBJECT_IDS, pObjectIDCollection); - CHECK_HR(hr, "Failed to set WPD_PROPERTY_OBJECT_ENUMERATION_OBJECT_IDS"); - } - - // If the enumeration context reports that their are no more objects to return then return S_FALSE indicating to the - // caller that we are finished. - if (hr == S_OK) - { - if (pEnumeratorContext != NULL) - { - // Update the number of children we have enumerated and returned to the caller - pEnumeratorContext->m_ChildrenEnumerated += NumObjectsEnumerated; - - // Check the number requested against the number enumerated and set the HRESULT - // accordingly. - if (NumObjectsEnumerated < dwNumObjectsRequested) - { - // We returned less than the number of objects requested to the caller - hr = S_FALSE; - } - else - { - // We returned exactly the number of objects requested to the caller - hr = S_OK; - } - } - } - - // Free the memory. - CoTaskMemFree(wszEnumContext); - wszEnumContext = NULL; - - SAFE_RELEASE(pContextMap); - SAFE_RELEASE(pEnumeratorContext); - - return hr; -} - -/** - * This method is called when we receive a WPD_COMMAND_OBJECT_ENUMERATION_END_FIND - * command. - * - * The parameters sent to us are: - * - WPD_PROPERTY_OBJECT_ENUMERATION_CONTEXT: the context the driver returned to - * the client in OnStartFind. - * - * The driver should: - * - Destroy any data associated with this context. - */ -HRESULT WpdObjectEnumerator::OnEndFind(_In_ IPortableDeviceValues* pParams, - _In_ IPortableDeviceValues* pResults) -{ - HRESULT hr = S_OK; - LPWSTR wszEnumContext = NULL; - ContextMap* pContextMap = NULL; - - UNREFERENCED_PARAMETER(pResults); - - // First get ALL parameters for this command. If we cannot get ALL parameters - // then E_INVALIDARG should be returned and no further processing should occur. - - // Get the enumeration context identifier for this enumeration operation. We will - // need this to lookup the specific enumeration context in the client context map. - hr = pParams->GetStringValue(WPD_PROPERTY_OBJECT_ENUMERATION_CONTEXT, &wszEnumContext); - if (hr != S_OK) - { - hr = E_INVALIDARG; - CHECK_HR(hr, "Missing value for WPD_PROPERTY_OBJECT_ENUMERATION_CONTEXT"); - } - - // Get the client context map so we can retrieve the enumeration context for this enumeration - // operation using the WPD_PROPERTY_OBJECT_ENUMERATION_CONTEXT property value obtained above. - if (hr == S_OK) - { - hr = pParams->GetIUnknownValue(PRIVATE_SAMPLE_DRIVER_CLIENT_CONTEXT_MAP, (IUnknown**)&pContextMap); - CHECK_HR(hr, "Failed to get PRIVATE_SAMPLE_DRIVER_CLIENT_CONTEXT_MAP"); - } - - // Destroy any data allocated/associated with the enumeration context and then remove it from the context map. - // We no longer need to keep this context around because the enumeration has been ended. - if (hr == S_OK) - { - pContextMap->Remove(wszEnumContext); - } - - // Free the memory. - CoTaskMemFree(wszEnumContext); - wszEnumContext = NULL; - - SAFE_RELEASE(pContextMap); - - return hr; -} - -// Initialize the enumeration context -VOID WpdObjectEnumerator::InitializeEnumerationContext( - _In_ WpdObjectEnumeratorContext* pEnumeratorContext, - _In_ LPCWSTR wszParentObjectID) -{ - if (pEnumeratorContext == NULL) - { - return; - } - - // Initialize the enumeration context with the parent object identifier - pEnumeratorContext->m_strParentObjectID = wszParentObjectID; - - // Our sample driver has a very simple object structure where we know - // how many children are under each parent. - // The eumeration context is initialized below with this information. - if (pEnumeratorContext->m_strParentObjectID.CompareNoCase(L"") == 0) - { - // Clients passing an 'empty' string for the parent are asking for the - // 'DEVICE' object. We should return 1 child in this case. - pEnumeratorContext->m_TotalChildren = 1; - } - else if (pEnumeratorContext->m_strParentObjectID.CompareNoCase(WPD_DEVICE_OBJECT_ID) == 0) - { - // The device object contains 1 child (the storage object). - pEnumeratorContext->m_TotalChildren = 1; - } - // If the sensor objects have children, add them here... - else - { - // The sensor object contains 0 children. - pEnumeratorContext->m_TotalChildren = 0; - } -} - -HRESULT WpdObjectEnumerator::AddStringValueToPropVariantCollection( - _In_ IPortableDevicePropVariantCollection* pCollection, - _In_ LPCWSTR wszValue) -{ - HRESULT hr = S_OK; - - if ((pCollection == NULL) || - (wszValue == NULL)) - { - hr = E_INVALIDARG; - return hr; - } - - PROPVARIANT pv = {0}; - PropVariantInit(&pv); - - pv.vt = VT_LPWSTR; - pv.pwszVal = (LPWSTR)wszValue; - - // The wszValue will be copied into the collection, keeping the ownership - // of the string belonging to the caller. - // Don't call PropVariantClear, since we did not allocate the memory for these string values - - hr = pCollection->Add(&pv); - - return hr; -} diff --git a/wpd/WpdBasicHardwareDriver/WpdObjectEnum.h b/wpd/WpdBasicHardwareDriver/WpdObjectEnum.h deleted file mode 100644 index e6dc0542..00000000 --- a/wpd/WpdBasicHardwareDriver/WpdObjectEnum.h +++ /dev/null @@ -1,107 +0,0 @@ -#pragma once - -// This class is used to store the context for a specific enumeration. -class WpdObjectEnumeratorContext : public IUnknown -{ -public: - WpdObjectEnumeratorContext() : - m_cRef(1), - m_TotalChildren(0), - m_ChildrenEnumerated(0) - { - - } - - ~WpdObjectEnumeratorContext() - { - - } - -public: // IUnknown - ULONG __stdcall AddRef() - { - InterlockedIncrement((long*) &m_cRef); - return m_cRef; - } - - _At_(this, __drv_freesMem(Mem)) - ULONG __stdcall Release() - { - ULONG ulRefCount = m_cRef - 1; - - if (InterlockedDecrement((long*) &m_cRef) == 0) - { - delete this; - return 0; - } - return ulRefCount; - } - - HRESULT __stdcall QueryInterface( - REFIID riid, - void** ppv) - { - HRESULT hr = S_OK; - - if(riid == IID_IUnknown) - { - *ppv = static_cast(this); - AddRef(); - } - else - { - *ppv = NULL; - hr = E_NOINTERFACE; - } - - return hr; - } - -private: - DWORD m_cRef; - -public: - BOOL HasMoreChildrenToEnumerate() - { - return (m_TotalChildren > m_ChildrenEnumerated)?TRUE:FALSE; - } - -// WpdObjectEnumeratorContext specific data -public: - CAtlStringW m_strParentObjectID; // object identifier of the object whose children are being enumerated - DWORD m_TotalChildren; // number of bytes transferred from the resource to the caller - DWORD m_ChildrenEnumerated; // number of children returned during the enumeration operation -}; - -class WpdObjectEnumerator -{ -public: - WpdObjectEnumerator(); - virtual ~WpdObjectEnumerator(); - - HRESULT Initialize(_In_ WpdBaseDriver* pBaseDriver); - - HRESULT DispatchWpdMessage(_In_ REFPROPERTYKEY Command, - _In_ IPortableDeviceValues* pParams, - _In_ IPortableDeviceValues* pResults); - - HRESULT OnStartFind(_In_ IPortableDeviceValues* pParams, - _In_ IPortableDeviceValues* pResults); - - HRESULT OnFindNext(_In_ IPortableDeviceValues* pParams, - _In_ IPortableDeviceValues* pResults); - - HRESULT OnEndFind(_In_ IPortableDeviceValues* pParams, - _In_ IPortableDeviceValues* pResults); - -private: - WpdBaseDriver* m_pBaseDriver; - - VOID InitializeEnumerationContext( - _In_ WpdObjectEnumeratorContext* pEnumeratorContext, - _In_ LPCWSTR wszParentObjectID); - - HRESULT AddStringValueToPropVariantCollection( - _In_ IPortableDevicePropVariantCollection* pCollection, - _In_ LPCWSTR wszValue); -}; diff --git a/wpd/WpdBasicHardwareDriver/WpdObjectProperties.cpp b/wpd/WpdBasicHardwareDriver/WpdObjectProperties.cpp deleted file mode 100644 index 927b8a19..00000000 --- a/wpd/WpdBasicHardwareDriver/WpdObjectProperties.cpp +++ /dev/null @@ -1,1314 +0,0 @@ -#include "stdafx.h" - -#include "WpdObjectProperties.tmh" - -const PROPERTYKEY g_SupportedCommonProperties[] = -{ - WPD_OBJECT_ID, - WPD_OBJECT_PERSISTENT_UNIQUE_ID, - WPD_OBJECT_PARENT_ID, - WPD_OBJECT_NAME, - WPD_OBJECT_FORMAT, - WPD_OBJECT_CONTENT_TYPE, - WPD_OBJECT_CAN_DELETE, -}; - -const PROPERTYKEY g_SupportedDeviceProperties[] = -{ - WPD_DEVICE_FIRMWARE_VERSION, - WPD_DEVICE_POWER_LEVEL, - WPD_DEVICE_POWER_SOURCE, - WPD_DEVICE_PROTOCOL, - WPD_DEVICE_MODEL, - WPD_DEVICE_SERIAL_NUMBER, - WPD_DEVICE_SUPPORTS_NON_CONSUMABLE, - WPD_DEVICE_MANUFACTURER, - WPD_DEVICE_FRIENDLY_NAME, - WPD_DEVICE_TYPE, - WPD_FUNCTIONAL_OBJECT_CATEGORY, -}; - -const PROPERTYKEY g_SupportedSensorProperties[] = -{ - SENSOR_READING, - SENSOR_UPDATE_INTERVAL, - WPD_FUNCTIONAL_OBJECT_CATEGORY, -}; - - -WpdObjectProperties::WpdObjectProperties() : - m_dwUpdateInterval(0), - m_llSensorReading(0) -{ - -} - -WpdObjectProperties::~WpdObjectProperties() -{ - m_pBaseDriver = NULL; -} - -HRESULT WpdObjectProperties::Initialize(_In_ WpdBaseDriver* pBaseDriver) -{ - m_pBaseDriver = pBaseDriver; - return S_OK; -} - -HRESULT WpdObjectProperties::DispatchWpdMessage( - _In_ REFPROPERTYKEY Command, - _In_ IPortableDeviceValues* pParams, - _In_ IPortableDeviceValues* pResults) -{ - HRESULT hr = S_OK; - - if (Command.fmtid != WPD_CATEGORY_OBJECT_PROPERTIES) - { - hr = E_INVALIDARG; - CHECK_HR(hr, "This object does not support this command category %ws",CComBSTR(Command.fmtid)); - } - - if (hr == S_OK) - { - if (IsEqualPropertyKey(Command, WPD_COMMAND_OBJECT_PROPERTIES_GET_SUPPORTED)) - { - hr = OnGetSupportedProperties(pParams, pResults); - CHECK_HR(hr, "Failed to get supported properties"); - } - else if(IsEqualPropertyKey(Command, WPD_COMMAND_OBJECT_PROPERTIES_GET)) - { - hr = OnGetPropertyValues(pParams, pResults); - if(FAILED(hr)) - { - CHECK_HR(hr, "Failed to get properties"); - } - } - else if(IsEqualPropertyKey(Command, WPD_COMMAND_OBJECT_PROPERTIES_GET_ALL)) - { - hr = OnGetAllPropertyValues(pParams, pResults); - if(FAILED(hr)) - { - CHECK_HR(hr, "Failed to get all properties"); - } - } - else if(IsEqualPropertyKey(Command, WPD_COMMAND_OBJECT_PROPERTIES_SET)) - { - hr = OnSetPropertyValues(pParams, pResults); - if(FAILED(hr)) - { - CHECK_HR(hr, "Failed to set properties"); - } - } - else if(IsEqualPropertyKey(Command, WPD_COMMAND_OBJECT_PROPERTIES_GET_ATTRIBUTES)) - { - hr = OnGetPropertyAttributes(pParams, pResults); - if(FAILED(hr)) - { - CHECK_HR(hr, "Failed to get property attributes"); - } - } - else if(IsEqualPropertyKey(Command, WPD_COMMAND_OBJECT_PROPERTIES_DELETE)) - { - hr = OnDeleteProperties(pParams, pResults); - if(FAILED(hr)) - { - CHECK_HR(hr, "Failed to delete properties"); - } - } - else - { - hr = E_NOTIMPL; - CHECK_HR(hr, "This object does not support this command id %d", Command.pid); - } - } - return hr; -} - -/** - * This method is called when we receive a WPD_COMMAND_OBJECT_PROPERTIES_GET_SUPPORTED - * command. - * - * The parameters sent to us are: - * - WPD_PROPERTY_OBJECT_PROPERTIES_OBJECT_ID: identifies the object whose supported properties have - * been requested. - * - * - WPD_PROPERTY_OBJECT_PROPERTIES_FILTER: the filter to use when returning supported properties. - * Since this parameter is optional, it may not exist. - * ! This driver currently ignores the filter parameter. ! - * - * The driver should: - * - Return supported property keys for the specified object in WPD_PROPERTY_OBJECT_PROPERTIES_PROPERTY_KEYS - */ -HRESULT WpdObjectProperties::OnGetSupportedProperties( - _In_ IPortableDeviceValues* pParams, - _In_ IPortableDeviceValues* pResults) -{ - HRESULT hr = S_OK; - LPWSTR wszObjectID = NULL; - CComPtr pKeys; - - // First get ALL parameters for this command. If we cannot get ALL parameters - // then E_INVALIDARG should be returned and no further processing should occur. - - // Get the object identifier whose supported properties have been requested - hr = pParams->GetStringValue(WPD_PROPERTY_OBJECT_PROPERTIES_OBJECT_ID, &wszObjectID); - if (hr != S_OK) - { - hr = E_INVALIDARG; - CHECK_HR(hr, "Missing string value for WPD_PROPERTY_OBJECT_PROPERTIES_OBJECT_ID"); - } - - // CoCreate a collection to store the supported property keys. - if (hr == S_OK) - { - hr = CoCreateInstance(CLSID_PortableDeviceKeyCollection, - NULL, - CLSCTX_INPROC_SERVER, - IID_IPortableDeviceKeyCollection, - (VOID**) &pKeys); - CHECK_HR(hr, "Failed to CoCreate CLSID_PortableDeviceKeyCollection"); - } - - // Add supported property keys for the specified object to the collection - if (hr == S_OK) - { - hr = AddSupportedPropertyKeys(wszObjectID, pKeys); - CHECK_HR(hr, "Failed to add supported property keys for object '%ws'", wszObjectID); - } - - // Set the WPD_PROPERTY_OBJECT_PROPERTIES_PROPERTY_KEYS value in the results. - if (hr == S_OK) - { - hr = pResults->SetIPortableDeviceKeyCollectionValue(WPD_PROPERTY_OBJECT_PROPERTIES_PROPERTY_KEYS, pKeys); - CHECK_HR(hr, "Failed to set WPD_PROPERTY_OBJECT_PROPERTIES_PROPERTY_KEYS"); - } - - // Free the memory. - CoTaskMemFree(wszObjectID); - wszObjectID = NULL; - - return hr; -} - -/** - * This method is called when we receive a WPD_COMMAND_OBJECT_PROPERTIES_GET - * command. - * - * The parameters sent to us are: - * - WPD_PROPERTY_OBJECT_PROPERTIES_OBJECT_ID: identifies the object whose property values have been requested. - * - WPD_PROPERTY_OBJECT_PROPERTIES_PROPERTY_KEYS: a collection of property keys, identifying which - * specific property values we are requested to return. - * - * The driver should: - * - Return all requested property values in WPD_PROPERTY_OBJECT_PROPERTIES_PROPERTY_VALUES. If any property read failed, the corresponding value should be - * set to type VT_ERROR with the 'scode' member holding the HRESULT reason for the failure. - * - S_OK should be returned if all properties were read successfully. - * - S_FALSE should be returned if any property read failed. - * - Any error return indicates that the driver did not fill in any results, and the caller will - * not attempt to unpack any property values. - */ -HRESULT WpdObjectProperties::OnGetPropertyValues( - _In_ IPortableDeviceValues* pParams, - _In_ IPortableDeviceValues* pResults) -{ - HRESULT hr = S_OK; - LPWSTR wszObjectID = NULL; - CComPtr pValues; - CComPtr pKeys; - - // First get ALL parameters for this command. If we cannot get ALL parameters - // then E_INVALIDARG should be returned and no further processing should occur. - - // Get the object identifier whose property values have been requested - if (hr == S_OK) - { - hr = pParams->GetStringValue(WPD_PROPERTY_OBJECT_PROPERTIES_OBJECT_ID, &wszObjectID); - CHECK_HR(hr, "Missing value for WPD_PROPERTY_OBJECT_PROPERTIES_OBJECT_ID"); - } - - // Get the list of property keys for the property values the caller wants to retrieve from the specified object - if (hr == S_OK) - { - hr = pParams->GetIPortableDeviceKeyCollectionValue(WPD_PROPERTY_OBJECT_PROPERTIES_PROPERTY_KEYS, &pKeys); - CHECK_HR(hr, "Missing value for WPD_PROPERTY_OBJECT_PROPERTIES_PROPERTY_KEYS"); - } - - // CoCreate a collection to store the property values. - if (hr == S_OK) - { - hr = CoCreateInstance(CLSID_PortableDeviceValues, - NULL, - CLSCTX_INPROC_SERVER, - IID_IPortableDeviceValues, - (VOID**) &pValues); - CHECK_HR(hr, "Failed to CoCreate CLSID_PortableDeviceValues"); - } - - // Read the specified properties on the specified object and add the property values to the collection. - if (hr == S_OK) - { - hr = GetPropertyValuesForObject(wszObjectID, pKeys, pValues); - CHECK_HR(hr, "Failed to get property values for object '%ws'", wszObjectID); - } - - // S_OK or S_FALSE can be returned from GetPropertyValuesForObject( ). - // S_FALSE means that 1 or more property values could not be retrieved successfully. - // The value for the specified property should be set to an error HRESULT of - // the reason why the property could not be read. - // (e.g. If the property being requested is not supported on the object then an error of - // HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED) should be set as the value. - if (SUCCEEDED(hr)) - { - // Set the WPD_PROPERTY_OBJECT_PROPERTIES_PROPERTY_VALUES value in the results. - HRESULT hrTemp = S_OK; - hrTemp = pResults->SetIPortableDeviceValuesValue(WPD_PROPERTY_OBJECT_PROPERTIES_PROPERTY_VALUES, pValues); - CHECK_HR(hrTemp, ("Failed to set WPD_PROPERTY_OBJECT_PROPERTIES_PROPERTY_VALUES")); - - if(FAILED(hrTemp)) - { - hr = hrTemp; - } - } - - // Free the memory. - CoTaskMemFree(wszObjectID); - wszObjectID = NULL; - - return hr; -} - -/** - * This method is called when we receive a WPD_COMMAND_OBJECT_PROPERTIES_GET_ALL - * command. - * - * The parameters sent to us are: - * - WPD_PROPERTY_OBJECT_PROPERTIES_OBJECT_ID: identifies the object whose property values have been requested. - * - * The driver should: - * - Return all property values in WPD_PROPERTY_OBJECT_PROPERTIES_PROPERTY_VALUES. If any property read failed, the corresponding value should be - * set to type VT_ERROR with the 'scode' member holding the HRESULT reason for the failure. - * - S_OK should be returned if all properties were read successfully. - * - S_FALSE should be returned if any property read failed. - * - Any error return indicates that the driver did not fill in any results, and the caller will - * not attempt to unpack any property values. - */ -HRESULT WpdObjectProperties::OnGetAllPropertyValues( - _In_ IPortableDeviceValues* pParams, - _In_ IPortableDeviceValues* pResults) -{ - HRESULT hr = S_OK; - LPWSTR wszObjectID = NULL; - CComPtr pValues; - CComPtr pKeys; - - // First get ALL parameters for this command. If we cannot get ALL parameters - // then E_INVALIDARG should be returned and no further processing should occur. - - // Get the object identifier whose property values have been requested - if (hr == S_OK) - { - hr = pParams->GetStringValue(WPD_PROPERTY_OBJECT_PROPERTIES_OBJECT_ID, &wszObjectID); - CHECK_HR(hr, "Missing value for WPD_PROPERTY_OBJECT_PROPERTIES_OBJECT_ID"); - } - - // CoCreate a collection to store the property values. - if (hr == S_OK) - { - hr = CoCreateInstance(CLSID_PortableDeviceValues, - NULL, - CLSCTX_INPROC_SERVER, - IID_IPortableDeviceValues, - (VOID**) &pValues); - CHECK_HR(hr, "Failed to CoCreate CLSID_PortableDeviceValues"); - } - - // CoCreate a collection to store the property keys we are going to use - // to request the property values of. - if (hr == S_OK) - { - hr = CoCreateInstance(CLSID_PortableDeviceKeyCollection, - NULL, - CLSCTX_INPROC_SERVER, - IID_IPortableDeviceKeyCollection, - (VOID**) &pKeys); - CHECK_HR(hr, "Failed to CoCreate CLSID_PortableDeviceKeyCollection"); - } - - // First we make a request for ALL supported property keys for the specified object. - // Next, we delegate to our helper function GetPropertyValuesForObject( ) passing - // the entire property key collection. This will reuse existing implementation - // in our driver to perform the GetAllPropertyValues operation. - if (hr == S_OK) - { - hr = AddSupportedPropertyKeys(wszObjectID, pKeys); - CHECK_HR(hr, "Failed to get ALL supported properties for object '%ws'", wszObjectID); - if (hr == S_OK) - { - hr = GetPropertyValuesForObject(wszObjectID, pKeys, pValues); - CHECK_HR(hr, "Failed to get property values for object '%ws'", wszObjectID); - } - } - - // S_OK or S_FALSE can be returned from GetPropertyValuesForObject( ). - // S_FALSE means that 1 or more property values could not be retrieved successfully. - // The value for the specified property key should be set to the error HRESULT of - // the reason why the property could not be read. - // (i.e. an error of HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED) if a property value was - // requested and is not supported by the specified object.) - if (SUCCEEDED(hr)) - { - // Set the WPD_PROPERTY_OBJECT_PROPERTIES_PROPERTY_VALUES value in the results - HRESULT hrTemp = S_OK; - hrTemp = pResults->SetIPortableDeviceValuesValue(WPD_PROPERTY_OBJECT_PROPERTIES_PROPERTY_VALUES, pValues); - CHECK_HR(hrTemp, ("Failed to set WPD_PROPERTY_OBJECT_PROPERTIES_PROPERTY_VALUES")); - - if(FAILED(hrTemp)) - { - hr = hrTemp; - } - } - - // Free the memory. - CoTaskMemFree(wszObjectID); - wszObjectID = NULL; - - return hr; -} - -/** - * This method is called when we receive a WPD_COMMAND_OBJECT_PROPERTIES_SET - * command. - * - * The parameters sent to us are: - * - WPD_PROPERTY_OBJECT_PROPERTIES_OBJECT_ID: identifies the object whose property values we want to return. - * - WPD_PROPERTY_OBJECT_PROPERTIES_PROPERTY_VALUES: an IPortableDeviceValues of values, identifying which - * specific property values we are requested to write. - * - * The driver should: - * - Write all requested property values. For each property, a write result should be returned in the - * write result property store. - * - If any property write failed, the corresponding write result value should be - * set to type VT_ERROR with the 'scode' member holding the HRESULT reason for the failure. - * - S_OK should be returned if all properties were written successfully. - * - S_FALSE should be returned if any property write failed. - * - Any error return indicates that the driver did not write any results, and the caller will - * not attempt to unpack any property write results. - */ -HRESULT WpdObjectProperties::OnSetPropertyValues( - _In_ IPortableDeviceValues* pParams, - _In_ IPortableDeviceValues* pResults) -{ - HRESULT hr = S_OK; - HRESULT hrResult = S_OK; - LPWSTR wszObjectID = NULL; - DWORD cValues = 0; - CAtlStringW strObjectID; - - CComPtr pValues; - CComPtr pWriteResults; - CComPtr pEventParams; - - - // First get ALL parameters for this command. If we cannot get ALL parameters - // then E_INVALIDARG should be returned and no further processing should occur. - - // Get the object identifier whose property values are being set - if (hr == S_OK) - { - hr = pParams->GetStringValue(WPD_PROPERTY_OBJECT_PROPERTIES_OBJECT_ID, &wszObjectID); - CHECK_HR(hr, "Missing value for WPD_PROPERTY_OBJECT_PROPERTIES_OBJECT_ID"); - } - - // Get the caller-supplied property values requested to be set on the object - if (hr == S_OK) - { - strObjectID = wszObjectID; - - hr = pParams->GetIPortableDeviceValuesValue(WPD_PROPERTY_OBJECT_PROPERTIES_PROPERTY_VALUES, &pValues); - CHECK_HR(hr, "Missing value for WPD_PROPERTY_OBJECT_PROPERTIES_PROPERTY_VALUES"); - } - - // CoCreate a collection to store the property set operation results. - if (hr == S_OK) - { - hr = CoCreateInstance(CLSID_PortableDeviceValues, - NULL, - CLSCTX_INPROC_SERVER, - IID_IPortableDeviceValues, - (VOID**) &pWriteResults); - CHECK_HR(hr, "Failed to CoCreate CLSID_PortableDeviceValues"); - } - - // Set the property values on the specified object - if (hr == S_OK) - { - // Since this driver does not support setting any properties, all property set operation - // results will be set to E_ACCESSDENIED. - if (hr == S_OK) - { - hr = pValues->GetCount(&cValues); - CHECK_HR(hr, "Failed to get total number of values"); - } - - if (hr == S_OK) - { - for (DWORD dwIndex = 0; dwIndex < cValues; dwIndex++) - { - PROPERTYKEY Key = WPD_PROPERTY_NULL; - PROPVARIANT Value = {0}; - - PropVariantInit(&Value); - - hr = pValues->GetAt(dwIndex, &Key, &Value); - CHECK_HR(hr, "Failed to get PROPERTYKEY at index %d", dwIndex); - - if (hr == S_OK) - { - // TODO: Add other ...OBJECT_ID strings where applicable - if ( - (strObjectID.CompareNoCase(SENSOR_OBJECT_ID) == 0) || - (strObjectID.CompareNoCase(TEMP_SENSOR_OBJECT_ID) == 0) || - (strObjectID.CompareNoCase(FLEX_SENSOR_OBJECT_ID) == 0) || - (strObjectID.CompareNoCase(PIR_SENSOR_OBJECT_ID) == 0) || - (strObjectID.CompareNoCase(PING_SENSOR_OBJECT_ID) == 0) || - (strObjectID.CompareNoCase(QTI_SENSOR_OBJECT_ID) == 0) || - (strObjectID.CompareNoCase(MEMSIC_SENSOR_OBJECT_ID) == 0) || - (strObjectID.CompareNoCase(HITACHI_SENSOR_OBJECT_ID) == 0) || - (strObjectID.CompareNoCase(PIEZO_SENSOR_OBJECT_ID) == 0) || - (strObjectID.CompareNoCase(COMPASS_SENSOR_OBJECT_ID) == 0) - ) - { - if (IsEqualPropertyKey(Key, SENSOR_UPDATE_INTERVAL)) - { - if (Value.vt == VT_UI4) - { - hr = SendUpdateIntervalToDevice(Value.ulVal); - CHECK_HR(hr, "Failed to send the new SENSOR_UPDATE_INTERVAL %d on the device", Value.ulVal); - } - else - { - // property failed to be set as it is an invalid vartype - hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); - CHECK_HR(hr, "Failed to update the SENSOR_UPDATE_INTERVAL because the vartype is invalid. Expected VT_UI4, got %d", Value.vt); - } - - // An error has occurred, set the overall result to S_FALSE - if (hr != S_OK) - { - hrResult = S_FALSE; - } - - hr = pWriteResults->SetErrorValue(Key, hr); - CHECK_HR(hr, "Failed to set error result value of SENSOR_UPDATE_INTERVAL for '%ws'", wszObjectID); - } - else - { - // Other properties for the sensor object are read only - hr = pWriteResults->SetErrorValue(Key, E_ACCESSDENIED); - CHECK_HR(hr, "Failed to set error result value at index %d for '%ws'", dwIndex, wszObjectID); - hrResult = S_FALSE; - } - } - else - { - // Properties for all other objects are read only - hr = pWriteResults->SetErrorValue(Key, E_ACCESSDENIED); - CHECK_HR(hr, "Failed to set error result value at index %d for '%ws'", dwIndex, wszObjectID); - hrResult = S_FALSE; - } - } - - PropVariantClear(&Value); - - } // end for - } // end if - } - - // At least one property failed to be set - if (hrResult != S_OK) - { - hr = hrResult; - } - - if (SUCCEEDED(hr)) - { - // Set the WPD_PROPERTY_OBJECT_PROPERTIES_PROPERTY_WRITE_RESULTS value in the results - HRESULT hrTemp = pResults->SetIPortableDeviceValuesValue(WPD_PROPERTY_OBJECT_PROPERTIES_PROPERTY_WRITE_RESULTS, pWriteResults); - CHECK_HR(hrTemp, ("Failed to set WPD_PROPERTY_OBJECT_PROPERTIES_PROPERTY_WRITE_RESULTS")); - - // Don't override the S_FALSE hresult that indicates at least one property had failed - if (hr == S_OK) - { - hr = hrTemp; - } - } - - // Free the memory. - CoTaskMemFree(wszObjectID); - wszObjectID = NULL; - - return hr; -} - -/** - * This method is called when we receive a WPD_COMMAND_OBJECT_PROPERTIES_GET_ATTRIBUTES - * command. - * - * The parameters sent to us are: - * - WPD_PROPERTY_OBJECT_PROPERTIES_OBJECT_ID: identifies the object whose property attributes we want to return. - * - WPD_PROPERTY_OBJECT_PROPERTIES_PROPERTY_KEYS: a collection of property keys containing a single value, - * which is the key identifying the specific property attributes we are requested to return. - * - * The driver should: - * - Return the requested property attributes. If any property attributes failed to be retrieved, - * the corresponding value should be set to type VT_ERROR with the 'scode' member holding the - * HRESULT reason for the failure. - * - S_OK should be returned if all property attributes were read successfully. - * - S_FALSE should be returned if any property attribute failed. - * - Any error return indicates that the driver did not fill in any results, and the caller will - * not attempt to unpack any property values. - */ -HRESULT WpdObjectProperties::OnGetPropertyAttributes( - _In_ IPortableDeviceValues* pParams, - _In_ IPortableDeviceValues* pResults) -{ - HRESULT hr = S_OK; - LPWSTR wszObjectID = NULL; - PROPERTYKEY Key = WPD_PROPERTY_NULL; - CComPtr pAttributes; - - // First get ALL parameters for this command. If we cannot get ALL parameters - // then E_INVALIDARG should be returned and no further processing should occur. - - // Get the object identifier whose property attributes have been requested - if (hr == S_OK) - { - hr = pParams->GetStringValue(WPD_PROPERTY_OBJECT_PROPERTIES_OBJECT_ID, &wszObjectID); - CHECK_HR(hr, "Missing value for WPD_PROPERTY_OBJECT_PROPERTIES_OBJECT_ID"); - } - - // Get the list of property keys whose attributes are being requested - if (hr == S_OK) - { - hr = pParams->GetKeyValue(WPD_PROPERTY_OBJECT_PROPERTIES_PROPERTY_KEYS, &Key); - CHECK_HR(hr, "Missing value for WPD_PROPERTY_OBJECT_PROPERTIES_PROPERTY_KEYS"); - } - - // CoCreate a collection to store the property attributes. - if (hr == S_OK) - { - hr = CoCreateInstance(CLSID_PortableDeviceValues, - NULL, - CLSCTX_INPROC_SERVER, - IID_IPortableDeviceValues, - (VOID**) &pAttributes); - CHECK_HR(hr, "Failed to CoCreate CLSID_PortableDeviceValues"); - } - - // Get the attributes for the specified properties on the specified object and add them - // to the collection. - if (hr == S_OK) - { - hr = GetPropertyAttributesForObject(wszObjectID, Key, pAttributes); - CHECK_HR(hr, "Failed to get property attributes"); - } - - if (SUCCEEDED(hr)) - { - // Set the WPD_PROPERTY_OBJECT_PROPERTIES_PROPERTY_ATTRIBUTES value in the results - HRESULT hrTemp = S_OK; - hrTemp = pResults->SetIPortableDeviceValuesValue(WPD_PROPERTY_OBJECT_PROPERTIES_PROPERTY_ATTRIBUTES, pAttributes); - CHECK_HR(hrTemp, ("Failed to set WPD_PROPERTY_OBJECT_PROPERTIES_PROPERTY_ATTRIBUTES")); - - if(FAILED(hrTemp)) - { - hr = hrTemp; - } - } - - // Free the memory. - CoTaskMemFree(wszObjectID); - wszObjectID = NULL; - - return hr; -} - -/** - * This method is called when we receive a WPD_COMMAND_OBJECT_PROPERTIES_DELETE - * command. - * - * The parameters sent to us are: - * - WPD_PROPERTY_OBJECT_PROPERTIES_OBJECT_ID: identifies the object whose properties should be deleted. - * - WPD_PROPERTY_OBJECT_PROPERTIES_PROPERTY_KEYS: a collection of property keys indicating which - * properties to delete. - * - * The driver should: - * - Delete the specified properties from the object. - * - S_OK should be returned if all specified properties were successfully deleted. - * - E_ACCESSDENIED should be returned if the client attempts to delete a property which is not deletable (i.e. - * WPD_PROPERTY_ATTRIBUTE_CAN_DELETE is FALSE for that property.) - */ -HRESULT WpdObjectProperties::OnDeleteProperties( - _In_ IPortableDeviceValues* pParams, - _In_ IPortableDeviceValues* pResults) -{ - HRESULT hr = E_ACCESSDENIED; - - UNREFERENCED_PARAMETER(pParams); - UNREFERENCED_PARAMETER(pResults); - - // This driver has no properties which can be deleted. - - return hr; -} - -/** - * This method is called to populate supported PROPERTYKEYs found on objects. - * - * The parameters sent to us are: - * wszObjectID - the object whose supported property keys are being requested - * pKeys - An IPortableDeviceKeyCollection to be populated with supported PROPERTYKEYs - * - * The driver should: - * Add PROPERTYKEYs pertaining to the specified object. - */ -HRESULT AddSupportedPropertyKeys( - _In_ LPCWSTR wszObjectID, - _In_ IPortableDeviceKeyCollection* pKeys) -{ - HRESULT hr = S_OK; - CAtlStringW strObjectID = wszObjectID; - - // Add Common PROPERTYKEYs for ALL WPD objects - AddCommonPropertyKeys(pKeys); - - if (strObjectID.CompareNoCase(WPD_DEVICE_OBJECT_ID) == 0) - { - // Add the PROPERTYKEYs for the 'DEVICE' object - AddDevicePropertyKeys(pKeys); - } - - // Add other PROPERTYKEYs for other supported objects... - // TODO: Add comparison to other ..._OBJECT_IDs where applicable - if ( - (strObjectID.CompareNoCase(SENSOR_OBJECT_ID) == 0) || - (strObjectID.CompareNoCase(TEMP_SENSOR_OBJECT_ID) == 0) || - (strObjectID.CompareNoCase(FLEX_SENSOR_OBJECT_ID) == 0) || - (strObjectID.CompareNoCase(PIR_SENSOR_OBJECT_ID) == 0) || - (strObjectID.CompareNoCase(PING_SENSOR_OBJECT_ID) == 0) || - (strObjectID.CompareNoCase(QTI_SENSOR_OBJECT_ID) == 0) || - (strObjectID.CompareNoCase(MEMSIC_SENSOR_OBJECT_ID) == 0) || - (strObjectID.CompareNoCase(HITACHI_SENSOR_OBJECT_ID) == 0) || - (strObjectID.CompareNoCase(PIEZO_SENSOR_OBJECT_ID) == 0) || - (strObjectID.CompareNoCase(COMPASS_SENSOR_OBJECT_ID) == 0) - ) - { - // Add the PROPERTYKEYs for the Sensor object - AddSensorPropertyKeys(pKeys); - } - - - - return hr; -} - -/** - * This method is called to populate common PROPERTYKEYs found on ALL objects. - * - * The parameters sent to us are: - * pKeys - An IPortableDeviceKeyCollection to be populated with PROPERTYKEYs - * - * The driver should: - * Add PROPERTYKEYs pertaining to the ALL objects. - */ -VOID AddCommonPropertyKeys( - _In_ IPortableDeviceKeyCollection* pKeys) -{ - if (pKeys != NULL) - { - for (DWORD dwIndex = 0; dwIndex < ARRAYSIZE(g_SupportedCommonProperties); dwIndex++) - { - HRESULT hr = S_OK; - hr = pKeys->Add(g_SupportedCommonProperties[dwIndex] ); - CHECK_HR(hr, "Failed to add common property"); - } - } -} - -/** - * This method is called to populate PROPERTYKEYs found on the SENSOR object. - * - * The parameters sent to us are: - * pKeys - An IPortableDeviceKeyCollection to be populated with PROPERTYKEYs - * - * The driver should: - * Add PROPERTYKEYs pertaining to the DEVICE object. - */ -VOID AddSensorPropertyKeys( - _In_ IPortableDeviceKeyCollection* pKeys) -{ - if (pKeys != NULL) - { - for (DWORD dwIndex = 0; dwIndex < ARRAYSIZE(g_SupportedSensorProperties); dwIndex++) - { - HRESULT hr = S_OK; - hr = pKeys->Add(g_SupportedSensorProperties[dwIndex] ); - CHECK_HR(hr, "Failed to add sensor property"); - } - } -} - -/** - * This method is called to populate common PROPERTYKEYs found on the DEVICE object. - * - * The parameters sent to us are: - * pKeys - An IPortableDeviceKeyCollection to be populated with PROPERTYKEYs - * - * The driver should: - * Add PROPERTYKEYs pertaining to the DEVICE object. - */ -VOID AddDevicePropertyKeys( - _In_ IPortableDeviceKeyCollection* pKeys) -{ - if (pKeys != NULL) - { - for (DWORD dwIndex = 0; dwIndex < ARRAYSIZE(g_SupportedDeviceProperties); dwIndex++) - { - HRESULT hr = S_OK; - hr = pKeys->Add(g_SupportedDeviceProperties[dwIndex] ); - CHECK_HR(hr, "Failed to add device property"); - } - } -} - - -/** - * This method is called to populate property values for the object specified. - * - * The parameters sent to us are: - * wszObjectID - the object whose properties are being requested. - * pKeys - the list of property keys of the properties to request from the object - * pValues - an IPortableDeviceValues which will contain the property values retreived from the object - * - * The driver should: - * Read the specified properties for the specified object and populate pValues with the - * results. - */ -HRESULT WpdObjectProperties::GetPropertyValuesForObject( - _In_ LPCWSTR wszObjectID, - _In_ IPortableDeviceKeyCollection* pKeys, - _In_ IPortableDeviceValues* pValues) -{ - HRESULT hr = S_OK; - CAtlStringW strObjectID = wszObjectID; - DWORD cKeys = 0; - - if ((wszObjectID == NULL) || - (pKeys == NULL) || - (pValues == NULL)) - { - hr = E_INVALIDARG; - return hr; - } - - hr = pKeys->GetCount(&cKeys); - CHECK_HR(hr, "Failed to number of PROPERTYKEYs in collection"); - - if (hr == S_OK) - { - // Get values for the DEVICE object - if (strObjectID.CompareNoCase(WPD_DEVICE_OBJECT_ID) == 0) - { - for (DWORD dwIndex = 0; dwIndex < cKeys; dwIndex++) - { - PROPERTYKEY Key = WPD_PROPERTY_NULL; - hr = pKeys->GetAt(dwIndex, &Key); - CHECK_HR(hr, "Failed to get PROPERTYKEY at index %d in collection", dwIndex); - - if (hr == S_OK) - { - // Preset the property value to 'error not supported'. The actual value - // will replace this value, if read from the device. - pValues->SetErrorValue(Key, HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED)); - - // Set DEVICE object properties - if (IsEqualPropertyKey(Key, WPD_DEVICE_FIRMWARE_VERSION)) - { - hr = pValues->SetStringValue(WPD_DEVICE_FIRMWARE_VERSION, DEVICE_FIRMWARE_VERSION_VALUE); - CHECK_HR(hr, "Failed to set WPD_DEVICE_FIRMWARE_VERSION"); - } - - else if (IsEqualPropertyKey(Key, WPD_DEVICE_POWER_LEVEL)) - { - hr = pValues->SetUnsignedIntegerValue(WPD_DEVICE_POWER_LEVEL, DEVICE_POWER_LEVEL_VALUE); - CHECK_HR(hr, "Failed to set WPD_DEVICE_POWER_LEVEL"); - } - - else if (IsEqualPropertyKey(Key, WPD_DEVICE_POWER_SOURCE)) - { - hr = pValues->SetUnsignedIntegerValue(WPD_DEVICE_POWER_SOURCE, WPD_POWER_SOURCE_EXTERNAL); - CHECK_HR(hr, "Failed to set WPD_DEVICE_POWER_SOURCE"); - } - - else if (IsEqualPropertyKey(Key, WPD_DEVICE_PROTOCOL)) - { - hr = pValues->SetStringValue(WPD_DEVICE_PROTOCOL, DEVICE_PROTOCOL_VALUE); - CHECK_HR(hr, "Failed to set WPD_DEVICE_PROTOCOL"); - } - - else if (IsEqualPropertyKey(Key, WPD_DEVICE_MODEL)) - { - hr = pValues->SetStringValue(WPD_DEVICE_MODEL, DEVICE_MODEL_VALUE); - CHECK_HR(hr, "Failed to set WPD_DEVICE_MODEL"); - } - - else if (IsEqualPropertyKey(Key, WPD_DEVICE_SERIAL_NUMBER)) - { - hr = pValues->SetStringValue(WPD_DEVICE_SERIAL_NUMBER, DEVICE_SERIAL_NUMBER_VALUE); - CHECK_HR(hr, "Failed to set WPD_DEVICE_SERIAL_NUMBER"); - } - - else if (IsEqualPropertyKey(Key, WPD_DEVICE_SUPPORTS_NON_CONSUMABLE)) - { - hr = pValues->SetBoolValue(WPD_DEVICE_SUPPORTS_NON_CONSUMABLE, DEVICE_SUPPORTS_NONCONSUMABLE_VALUE); - CHECK_HR(hr, "Failed to set WPD_DEVICE_SUPPORTS_NON_CONSUMABLE"); - } - - else if (IsEqualPropertyKey(Key, WPD_DEVICE_MANUFACTURER)) - { - hr = pValues->SetStringValue(WPD_DEVICE_MANUFACTURER, DEVICE_MANUFACTURER_VALUE); - CHECK_HR(hr, "Failed to set WPD_DEVICE_MANUFACTURER"); - } - - else if (IsEqualPropertyKey(Key, WPD_DEVICE_FRIENDLY_NAME)) - { - hr = pValues->SetStringValue(WPD_DEVICE_FRIENDLY_NAME, DEVICE_FRIENDLY_NAME_VALUE); - CHECK_HR(hr, "Failed to set WPD_DEVICE_FRIENDLY_NAME"); - } - - else if (IsEqualPropertyKey(Key, WPD_DEVICE_TYPE)) - { - hr = pValues->SetUnsignedIntegerValue(WPD_DEVICE_TYPE, WPD_DEVICE_TYPE_GENERIC); - CHECK_HR(hr, "Failed to set WPD_DEVICE_TYPE"); - } - - // Set general properties for DEVICE - else if (IsEqualPropertyKey(Key, WPD_OBJECT_ID)) - { - hr = pValues->SetStringValue(WPD_OBJECT_ID, WPD_DEVICE_OBJECT_ID); - CHECK_HR(hr, "Failed to set WPD_OBJECT_ID"); - } - - else if (IsEqualPropertyKey(Key, WPD_OBJECT_NAME)) - { - // Retrieves the "DEVICE" string that identifies the root device - hr = pValues->SetStringValue(WPD_OBJECT_NAME, WPD_DEVICE_OBJECT_ID); - CHECK_HR(hr, "Failed to set WPD_OBJECT_NAME"); - } - - else if (IsEqualPropertyKey(Key, WPD_OBJECT_PERSISTENT_UNIQUE_ID)) - { - hr = pValues->SetStringValue(WPD_OBJECT_PERSISTENT_UNIQUE_ID, WPD_DEVICE_OBJECT_ID); - CHECK_HR(hr, "Failed to set WPD_OBJECT_PERSISTENT_UNIQUE_ID"); - } - - else if (IsEqualPropertyKey(Key, WPD_OBJECT_PARENT_ID)) - { - hr = pValues->SetStringValue(WPD_OBJECT_PARENT_ID, L""); - CHECK_HR(hr, "Failed to set WPD_OBJECT_PARENT_ID"); - } - - else if (IsEqualPropertyKey(Key, WPD_OBJECT_FORMAT)) - { - hr = pValues->SetGuidValue(WPD_OBJECT_FORMAT, WPD_OBJECT_FORMAT_UNSPECIFIED); - CHECK_HR(hr, "Failed to set WPD_OBJECT_FORMAT"); - } - - else if (IsEqualPropertyKey(Key, WPD_OBJECT_CONTENT_TYPE)) - { - hr = pValues->SetGuidValue(WPD_OBJECT_CONTENT_TYPE, WPD_CONTENT_TYPE_FUNCTIONAL_OBJECT); - CHECK_HR(hr, "Failed to set WPD_OBJECT_CONTENT_TYPE"); - } - - else if (IsEqualPropertyKey(Key, WPD_OBJECT_CAN_DELETE)) - { - hr = pValues->SetBoolValue(WPD_OBJECT_CAN_DELETE, FALSE); - CHECK_HR(hr, "Failed to set WPD_OBJECT_CAN_DELETE"); - } - - else if (IsEqualPropertyKey(Key, WPD_FUNCTIONAL_OBJECT_CATEGORY)) - { - hr = pValues->SetGuidValue(WPD_FUNCTIONAL_OBJECT_CATEGORY, WPD_FUNCTIONAL_CATEGORY_DEVICE); - CHECK_HR(hr, "Failed to set WPD_FUNCTIONAL_OBJECT_CATEGORY"); - } - } - } - } - // Retrieve the temperature sensor properties - else if ( - (strObjectID.CompareNoCase(SENSOR_OBJECT_ID) == 0) || - (strObjectID.CompareNoCase(TEMP_SENSOR_OBJECT_ID) == 0) || - (strObjectID.CompareNoCase(FLEX_SENSOR_OBJECT_ID) == 0) || - (strObjectID.CompareNoCase(PIR_SENSOR_OBJECT_ID) == 0) || - (strObjectID.CompareNoCase(PING_SENSOR_OBJECT_ID) == 0) || - (strObjectID.CompareNoCase(QTI_SENSOR_OBJECT_ID) == 0) || - (strObjectID.CompareNoCase(MEMSIC_SENSOR_OBJECT_ID) == 0) || - (strObjectID.CompareNoCase(HITACHI_SENSOR_OBJECT_ID) == 0) || - (strObjectID.CompareNoCase(PIEZO_SENSOR_OBJECT_ID) == 0) || - (strObjectID.CompareNoCase(COMPASS_SENSOR_OBJECT_ID) == 0) - ) - { - for (DWORD dwIndex = 0; dwIndex < cKeys; dwIndex++) - { - PROPERTYKEY Key = WPD_PROPERTY_NULL; - hr = pKeys->GetAt(dwIndex, &Key); - CHECK_HR(hr, "Failed to get PROPERTYKEY at index %d in collection", dwIndex); - - if (hr == S_OK) - { - // Preset the property value to 'error not supported'. The actual value - // will replace this value, if read from the device. - pValues->SetErrorValue(Key, HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED)); - if (IsEqualPropertyKey(Key, WPD_OBJECT_ID)) - { - hr = pValues->SetStringValue(WPD_OBJECT_ID, strObjectID); - CHECK_HR(hr, "Failed to set WPD_OBJECT_ID"); - } - - else if (IsEqualPropertyKey(Key, WPD_OBJECT_PERSISTENT_UNIQUE_ID)) - { - - // Retrieve the ID of the sensor using the m_SensorType member of the - // basedriver that is set during the data-read operation. - hr = pValues->SetStringValue(WPD_OBJECT_PERSISTENT_UNIQUE_ID, strObjectID); - CHECK_HR(hr, "Failed to set WPD_OBJECT_PERSISTENT_UNIQUE_ID"); - } - - else if (IsEqualPropertyKey(Key, WPD_OBJECT_PARENT_ID)) - { - hr = pValues->SetStringValue(WPD_OBJECT_PARENT_ID, WPD_DEVICE_OBJECT_ID); - CHECK_HR(hr, "Failed to set WPD_OBJECT_PARENT_ID"); - } - - else if (IsEqualPropertyKey(Key, WPD_OBJECT_NAME)) - { - // Retrieve the name of the sensor using the m_SensorType member of the - // basedriver that is set during the data-read operation. - if (m_pBaseDriver->m_SensorType == 0) - hr = pValues->SetStringValue(WPD_OBJECT_NAME, SENSOR_OBJECT_NAME_VALUE); - else if (m_pBaseDriver->m_SensorType == 2) - hr = pValues->SetStringValue(WPD_OBJECT_NAME, TEMP_SENSOR_OBJECT_NAME_VALUE); - else if (m_pBaseDriver->m_SensorType == 3) - hr = pValues->SetStringValue(WPD_OBJECT_NAME, FLEX_SENSOR_OBJECT_NAME_VALUE); - else if (m_pBaseDriver->m_SensorType == 4) - hr = pValues->SetStringValue(WPD_OBJECT_NAME, PING_SENSOR_OBJECT_NAME_VALUE); - else if (m_pBaseDriver->m_SensorType == 5) - hr = pValues->SetStringValue(WPD_OBJECT_NAME, PIR_SENSOR_OBJECT_NAME_VALUE); - else if (m_pBaseDriver->m_SensorType == 6) - hr = pValues->SetStringValue(WPD_OBJECT_NAME, MEMSIC_SENSOR_OBJECT_NAME_VALUE); - else if (m_pBaseDriver->m_SensorType == 7) - hr = pValues->SetStringValue(WPD_OBJECT_NAME, QTI_SENSOR_OBJECT_NAME_VALUE); - else if (m_pBaseDriver->m_SensorType == 8) - hr = pValues->SetStringValue(WPD_OBJECT_NAME, PIEZO_SENSOR_OBJECT_NAME_VALUE); - else if (m_pBaseDriver->m_SensorType == 9) - hr = pValues->SetStringValue(WPD_OBJECT_NAME, HITACHI_SENSOR_OBJECT_NAME_VALUE); - CHECK_HR(hr, "Failed to set WPD_OBJECT_NAME"); - } - - else if (IsEqualPropertyKey(Key, WPD_OBJECT_FORMAT)) - { - hr = pValues->SetGuidValue(WPD_OBJECT_FORMAT, WPD_OBJECT_FORMAT_UNSPECIFIED); - CHECK_HR(hr, "Failed to set WPD_OBJECT_FORMAT"); - } - - else if (IsEqualPropertyKey(Key, WPD_OBJECT_CONTENT_TYPE)) - { - hr = pValues->SetGuidValue(WPD_OBJECT_CONTENT_TYPE, WPD_CONTENT_TYPE_FUNCTIONAL_OBJECT); - CHECK_HR(hr, "Failed to set WPD_OBJECT_CONTENT_TYPE"); - } - - else if (IsEqualPropertyKey(Key, WPD_OBJECT_CAN_DELETE)) - { - hr = pValues->SetBoolValue(WPD_OBJECT_CAN_DELETE, FALSE); - CHECK_HR(hr, "Failed to set WPD_OBJECT_CAN_DELETE"); - } - - else if (IsEqualPropertyKey(Key, SENSOR_READING)) - { - hr = pValues->SetUnsignedLargeIntegerValue(SENSOR_READING, GetSensorReading()); - CHECK_HR(hr, "Failed to set SENSOR_READING"); - } - - else if (IsEqualPropertyKey(Key, SENSOR_UPDATE_INTERVAL)) - { - hr = pValues->SetUnsignedLargeIntegerValue(SENSOR_UPDATE_INTERVAL, GetUpdateInterval()); - CHECK_HR(hr, "Failed to set SENSOR_UPDATE_INTERVAL"); - } - else if (IsEqualPropertyKey(Key, WPD_FUNCTIONAL_OBJECT_CATEGORY)) - { - hr = pValues->SetGuidValue(WPD_FUNCTIONAL_OBJECT_CATEGORY, FUNCTIONAL_CATEGORY_SENSOR_SAMPLE); - CHECK_HR(hr, "Failed to set WPD_FUNCTIONAL_OBJECT_CATEGORY"); - } - } - } // end for - } // end else if - } - - return hr; -} - -/** - * This method is called to populate property attributes for the object and property specified. - * - * The parameters sent to us are: - * wszObjectID - the object whose property attributes are being requested. - * Key - the property whose attributes are being requested - * pAttributes - an IPortableDeviceValues which will contain the resulting property attributes - * - * The driver should: - * Read the property attributes for the specified property on the specified object and - * populate pAttributes with the results. - */ -HRESULT WpdObjectProperties::GetPropertyAttributesForObject( - _In_ LPCWSTR wszObjectID, - _In_ REFPROPERTYKEY Key, - _In_ IPortableDeviceValues* pAttributes) -{ - HRESULT hr = S_OK; - - if ((wszObjectID == NULL) || - (pAttributes == NULL)) - { - hr = E_INVALIDARG; - return hr; - } - - // - // Since ALL of our properties have the same attributes, we are ignoring the - // passed in wszObjectID parameter. This parameter allows you to - // customize attributes for properties on specific objects. (i.e. WPD_OBJECT_ORIGINAL_FILE_NAME - // may be READ/WRITE on some objects and READONLY on others. ) - // - - if (hr == S_OK) - { - hr = pAttributes->SetBoolValue(WPD_PROPERTY_ATTRIBUTE_CAN_DELETE, FALSE); - CHECK_HR(hr, "Failed to set WPD_PROPERTY_ATTRIBUTE_CAN_DELETE"); - } - - if (hr == S_OK) - { - hr = pAttributes->SetBoolValue(WPD_PROPERTY_ATTRIBUTE_CAN_READ, TRUE); - CHECK_HR(hr, "Failed to set WPD_PROPERTY_ATTRIBUTE_CAN_READ"); - } - - if (hr == S_OK) - { - // Allow writes for the update interval property - if (IsEqualPropertyKey(Key, SENSOR_UPDATE_INTERVAL)) - { - hr = pAttributes->SetBoolValue(WPD_PROPERTY_ATTRIBUTE_CAN_WRITE, TRUE); - CHECK_HR(hr, "Failed to set WPD_PROPERTY_ATTRIBUTE_CAN_WRITE for SENSOR_UPDATE_INTERVAL"); - } - else - { - hr = pAttributes->SetBoolValue(WPD_PROPERTY_ATTRIBUTE_CAN_WRITE, FALSE); - CHECK_HR(hr, "Failed to set WPD_PROPERTY_ATTRIBUTE_CAN_WRITE"); - } - } - - if (hr == S_OK) - { - hr = pAttributes->SetBoolValue(WPD_PROPERTY_ATTRIBUTE_FAST_PROPERTY, TRUE); - CHECK_HR(hr, "Failed to set WPD_PROPERTY_ATTRIBUTE_FAST_PROPERTY"); - } - - if (hr == S_OK) - { - if (IsEqualPropertyKey(Key, SENSOR_UPDATE_INTERVAL)) - { - // Form range attributes for the update interval property - hr = pAttributes->SetUnsignedIntegerValue(WPD_PROPERTY_ATTRIBUTE_FORM, WPD_PROPERTY_ATTRIBUTE_FORM_RANGE); - CHECK_HR(hr, "Failed to set WPD_PROPERTY_ATTRIBUTE_RANGE_MIN for SENSOR_UPDATE_INTERVAL"); - - hr = pAttributes->SetUnsignedIntegerValue(WPD_PROPERTY_ATTRIBUTE_RANGE_MIN, SENSOR_UPDATE_INTERVAL_MIN); - CHECK_HR(hr, "Failed to set WPD_PROPERTY_ATTRIBUTE_RANGE_MIN for SENSOR_UPDATE_INTERVAL"); - - hr = pAttributes->SetUnsignedIntegerValue(WPD_PROPERTY_ATTRIBUTE_RANGE_MAX, SENSOR_UPDATE_INTERVAL_MAX); - CHECK_HR(hr, "Failed to set WPD_PROPERTY_ATTRIBUTE_RANGE_MAX for SENSOR_UPDATE_INTERVAL"); - - hr = pAttributes->SetUnsignedIntegerValue(WPD_PROPERTY_ATTRIBUTE_RANGE_STEP, SENSOR_UPDATE_INTERVAL_STEP); - CHECK_HR(hr, "Failed to set WPD_PROPERTY_ATTRIBUTE_RANGE_STEP for SENSOR_UPDATE_INTERVAL"); - } - else if (IsEqualPropertyKey(Key, SENSOR_READING)) - { - // Form range attributes for the reading property - hr = pAttributes->SetUnsignedIntegerValue(WPD_PROPERTY_ATTRIBUTE_FORM, WPD_PROPERTY_ATTRIBUTE_FORM_RANGE); - CHECK_HR(hr, "Failed to set WPD_PROPERTY_ATTRIBUTE_RANGE_MIN for SENSOR_READING"); - - hr = pAttributes->SetUnsignedIntegerValue(WPD_PROPERTY_ATTRIBUTE_RANGE_MIN, SENSOR_READING_MIN); - CHECK_HR(hr, "Failed to set WPD_PROPERTY_ATTRIBUTE_RANGE_MIN for SENSOR_READING"); - - hr = pAttributes->SetUnsignedIntegerValue(WPD_PROPERTY_ATTRIBUTE_RANGE_MAX, SENSOR_READING_MAX); - CHECK_HR(hr, "Failed to set WPD_PROPERTY_ATTRIBUTE_RANGE_MAX for SENSOR_READING"); - - hr = pAttributes->SetUnsignedIntegerValue(WPD_PROPERTY_ATTRIBUTE_RANGE_STEP, SENSOR_READING_STEP); - CHECK_HR(hr, "Failed to set WPD_PROPERTY_ATTRIBUTE_RANGE_STEP for SENSOR_READING"); - } - else - { - hr = pAttributes->SetUnsignedIntegerValue(WPD_PROPERTY_ATTRIBUTE_FORM, WPD_PROPERTY_ATTRIBUTE_FORM_UNSPECIFIED); - CHECK_HR(hr, "Failed to set WPD_PROPERTY_ATTRIBUTE_FORM"); - } - } - - return hr; -} - - -/** - * This method is called to update the sensor reading - * - * The parameters sent to us are: - * dwNewReading - the temperature reading to set - * - * The driver should: - * Update the sensor reading. - */ -VOID WpdObjectProperties::SetSensorReading(LONGLONG llNewReading) -{ - // Ensure that this value isn't currently being accessed by another thread - CComCritSecLock Lock(m_SensorReadingCriticalSection); - - m_llSensorReading = llNewReading; -} - - -/** - * This method is called to retrieve the sensor reading - * - * The parameters sent to us are: - * - * The driver should: - * Return the saved sensor reading. - */ -LONGLONG WpdObjectProperties::GetSensorReading() -{ - // Ensure that this value isn't currently being accessed by another thread - CComCritSecLock Lock(m_SensorReadingCriticalSection); - - return m_llSensorReading; -} - - -/** - * This method is called to set the cached sensor interval - * - * The parameters sent to us are: - * dwNewInterval - the sensor update interval to set - * - * The driver should: - * Update the cached sensor interval property. - */ -VOID WpdObjectProperties::SetUpdateInterval(DWORD dwNewInterval) -{ - m_dwUpdateInterval = dwNewInterval; -} - - -/** - * This method is called to retrieve the sensor update interval - * - * The parameters sent to us are: - * - * The driver should: - * Return the interval property. - */ -DWORD WpdObjectProperties::GetUpdateInterval() -{ - return m_dwUpdateInterval; -} - - -/** - * This method is called to update the sensor interval on the device - * - * The parameters sent to us are: - * dwNewInterval - the sensor update interval to set - * - * The driver should: - * Update the cached sensor property and send a write request to the device - */ -HRESULT WpdObjectProperties::SendUpdateIntervalToDevice(DWORD dwNewInterval) -{ - HRESULT hr = S_OK; - RS232Target* pDeviceTarget = NULL; - - CHAR szInterval[INTERVAL_DATA_LENGTH+1] = {0}; - - // Check the input value - if (IsValidUpdateInterval(dwNewInterval) == FALSE) - { - hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); - CHECK_HR(hr, "Invalid update interval: %d", dwNewInterval); - } - - // Format a write request with the input value - if (hr == S_OK) - { - hr = StringCchPrintfA(szInterval, ARRAYSIZE(szInterval), "%u", dwNewInterval); - CHECK_HR(hr, "Failed to convert the new interval to a CHAR string"); - } - - // Send the write request to the device - if (hr == S_OK) - { - pDeviceTarget = m_pBaseDriver->GetRS232Target(); - - if (pDeviceTarget->IsReady()) - { - hr = pDeviceTarget->SendWriteRequest((BYTE *)szInterval, sizeof(szInterval)); - CHECK_HR(hr, "Failed to send the write request to set the new sensor update interval"); - - if (hr == S_OK) - { - TraceEvents(TRACE_LEVEL_VERBOSE, TRACE_FLAG_DRIVER, "%!FUNC! Sent new interval: %s", szInterval); - } - } - else - { - hr = HRESULT_FROM_WIN32(ERROR_NOT_READY); - CHECK_HR(hr, "Device is not ready to receive write requests"); - } - } - - if (hr == S_OK) - { - // Update the cached value on the driver - SetUpdateInterval(dwNewInterval); - } - - return hr; -} - - -/** - * This method is called to check that interval value falls within the accepted range - * of 2000 to 60000 milliseconds - * - * The parameters sent to us are: - * wszInterval - the sensor update interval to check - * - * The driver should: - * Return TRUE if the interval is within range - */ -BOOL WpdObjectProperties::IsValidUpdateInterval(DWORD dwInterval) -{ - if ((dwInterval >= SENSOR_UPDATE_INTERVAL_MIN) && - (dwInterval <= SENSOR_UPDATE_INTERVAL_MAX)) - { - return TRUE; - } - - return FALSE; -} - diff --git a/wpd/WpdBasicHardwareDriver/WpdObjectProperties.h b/wpd/WpdBasicHardwareDriver/WpdObjectProperties.h deleted file mode 100644 index 1860e0ad..00000000 --- a/wpd/WpdBasicHardwareDriver/WpdObjectProperties.h +++ /dev/null @@ -1,111 +0,0 @@ -#pragma once - -#define DEVICE_PROTOCOL_VALUE L"Sensor Protocol ver 1.00" -#define DEVICE_FIRMWARE_VERSION_VALUE L"1.0.0.0" -#define DEVICE_POWER_LEVEL_VALUE 100 -#define DEVICE_MODEL_VALUE L"RS232 Sensor" -#define DEVICE_FRIENDLY_NAME_VALUE L"Parallax BS2 Sensor" -#define DEVICE_MANUFACTURER_VALUE L"Windows Portable Devices Group" -#define DEVICE_SERIAL_NUMBER_VALUE L"01234567890123-45676890123456" -#define DEVICE_SUPPORTS_NONCONSUMABLE_VALUE FALSE - -#define SENSOR_OBJECT_ID L"Sensor" -#define SENSOR_OBJECT_NAME_VALUE L"Parallax Sensor" -#define COMPASS_SENSOR_OBJECT_ID L"Compass" -#define COMPASS_SENSOR_OBJECT_NAME_VALUE L"HM55B Compass Sensor" -#define PIR_SENSOR_OBJECT_ID L"PIR" -#define PIR_SENSOR_OBJECT_NAME_VALUE L"Passive Infra-Red Sensor" -#define QTI_SENSOR_OBJECT_ID L"QTI" -#define QTI_SENSOR_OBJECT_NAME_VALUE L"QTI Light Sensor" -#define FLEX_SENSOR_OBJECT_ID L"Flex" -#define FLEX_SENSOR_OBJECT_NAME_VALUE L"Flex Force Sensor" -#define PING_SENSOR_OBJECT_ID L"Ping" -#define PING_SENSOR_OBJECT_NAME_VALUE L"Ultrasonic Distance Sensor" -#define PIEZO_SENSOR_OBJECT_ID L"Piezo" -#define PIEZO_SENSOR_OBJECT_NAME_VALUE L"Piezo Vibration Sensor" -#define TEMP_SENSOR_OBJECT_ID L"TempHumidity" -#define TEMP_SENSOR_OBJECT_NAME_VALUE L"Sensiron Temperature and Humidity Sensor" -#define MEMSIC_SENSOR_OBJECT_ID L"Memsic" -#define MEMSIC_SENSOR_OBJECT_NAME_VALUE L"Memsic Dual-Axis G-Force Sensor" -#define HITACHI_SENSOR_OBJECT_ID L"Hitachi" -#define HITACHI_SENSOR_OBJECT_NAME_VALUE L"Hitachi Tri-Axis G-Force Sensor" -// INSERT ID and NAME definitions for other sensors here!! - - -GUID GetObjectFormat(CAtlStringW strObjectID); -GUID GetObjectContentType(CAtlStringW strObjectID); -HRESULT AddSupportedPropertyKeys(_In_ LPCWSTR wszObjectID, - _In_ IPortableDeviceKeyCollection* pKeys); - -VOID AddCommonPropertyKeys(_In_ IPortableDeviceKeyCollection* pKeys); -VOID AddDevicePropertyKeys(_In_ IPortableDeviceKeyCollection* pKeys); - -VOID AddSensorPropertyKeys(_In_ IPortableDeviceKeyCollection* pKeys); //Required for sensor props - -class WpdObjectProperties -{ -public: - - WpdObjectProperties(); - virtual ~WpdObjectProperties(); - - HRESULT Initialize(_In_ WpdBaseDriver* pBaseDriver); - - HRESULT DispatchWpdMessage(_In_ REFPROPERTYKEY Command, - _In_ IPortableDeviceValues* pParams, - _In_ IPortableDeviceValues* pResults); - - HRESULT OnGetSupportedProperties(_In_ IPortableDeviceValues* pParams, - _In_ IPortableDeviceValues* pResults); - - HRESULT OnGetPropertyValues(_In_ IPortableDeviceValues* pParams, - _In_ IPortableDeviceValues* pResults); - - HRESULT OnGetAllPropertyValues(_In_ IPortableDeviceValues* pParams, - _In_ IPortableDeviceValues* pResults); - - HRESULT OnSetPropertyValues(_In_ IPortableDeviceValues* pParams, - _In_ IPortableDeviceValues* pResults); - - HRESULT OnGetPropertyAttributes(_In_ IPortableDeviceValues* pParams, - _In_ IPortableDeviceValues* pResults); - - HRESULT OnDeleteProperties(_In_ IPortableDeviceValues* pParams, - _In_ IPortableDeviceValues* pResults); - - VOID SetSensorReading(LONGLONG llNewReading); - - LONGLONG GetSensorReading(); - - VOID SetUpdateInterval(DWORD dwNewInterval); - - DWORD GetUpdateInterval(); - - HRESULT SendUpdateIntervalToDevice(DWORD dwNewInterval); - - BOOL IsValidUpdateInterval(DWORD dwInterval); - -private: - - HRESULT GetPropertyValuesForObject(_In_ LPCWSTR wszObjectID, - _In_ IPortableDeviceKeyCollection* pKeys, - _In_ IPortableDeviceValues* pValues); - - HRESULT GetPropertyAttributesForObject(_In_ LPCWSTR wszObjectID, - _In_ REFPROPERTYKEY Key, - _In_ IPortableDeviceValues* pAttributes); - - -private: - WpdBaseDriver* m_pBaseDriver; - - // This critical section protects the sensor reading from concurrent access - // by the application (which reads it) and the read request callback (which updates it) - CComAutoCriticalSection m_SensorReadingCriticalSection; - LONGLONG m_llSensorReading; - - // A critical section is not needed for the update interval because it is accessed - // by the client application, and set/get requests from the application arrive serially - // through the sequential WDF queue. - DWORD m_dwUpdateInterval; -}; diff --git a/wpd/WpdBasicHardwareDriver/firmware/compass_wpd_enabled.bs2 b/wpd/WpdBasicHardwareDriver/firmware/compass_wpd_enabled.bs2 deleted file mode 100644 index 335d2c7e..00000000 --- a/wpd/WpdBasicHardwareDriver/firmware/compass_wpd_enabled.bs2 +++ /dev/null @@ -1,94 +0,0 @@ -' Compass_wpd_enabled.bs2 -' -' Displays x (N/S) and y (W/E) axis measurements along with the direction the -' Compass Module is pointing, measured in degrees clockwise from north. -' -' THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF -' ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO -' THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A -' PARTICULAR PURPOSE. -' -' Copyright (c) Microsoft Corporation. All rights reserved -' -' {$STAMP BS2} -' {$PBASIC 2.5} -' ============================================================================ - -' -----[ Pins/Constants/Variables ]------------------------------------------- -DinDout PIN 6 ' P6 transceives to/from Din/Dout -Clk PIN 5 ' P5 sends pulses to HM55B's Clk -En PIN 4 ' P4 controls HM55B's /EN(ABLE) - -Reset CON %0000 ' Reset command for HM55B -Measure CON %1000 ' Start measurement command -Report CON %1100 ' Get status/axis values command -Ready CON %1100 ' 11 -> Done, 00 -> no errors -NegMask CON %1111100000000000 ' For 11-bit negative to 16-bits - -x VAR Word ' x-axis data -y VAR Word ' y-axis data -status VAR Nib ' Status flags -angle VAR Word ' Store angle measurement - -SensorID VAR Byte 'Sensor identifier = 5 for PIR -ElementSize VAR Byte 'Size (in bytes) of each element -ElementCount VAR Byte 'Count of elements in packet -Padding VAR Byte 'Padding for the 8-byte element - -SensorID = 1 -ElementSize = 1 -ElementCount = 3 '3-bytes for compass data; - -NewInterval VAR Word 'New interval requested by user -Interval VAR Word 'Interval value utlized by firmware - -LFD CON $10 'Linefeed character - -Interval = 200 '.20 of a second interval -NewInterval = 200 - -' -----[ Main Routine ]------------------------------------------------------- - -Main: - GOSUB PollSensor 'Was motion detected? - GOSUB RetrieveInterval 'Retrieve units data - -' -----[ Subroutines ]-------------------------------------------------------- - -Timeout: - SEROUT 16, 16468, [DEC1 SensorID, DEC1 ElementSize, DEC1 ElementCount, DEC3 angle, DEC5 Interval,LFD] - GOTO Main - -PollSensor: ' Compass module subroutine - - HIGH En: LOW En ' Send reset command to HM55B - SHIFTOUT DinDout,clk,MSBFIRST,[Reset\4] - - HIGH En: LOW En ' HM55B start measurement command - SHIFTOUT DinDout,clk,MSBFIRST,[Measure\4] - status = 0 ' Clear previous status flags - - DO ' Status flag checking loop - HIGH En: LOW En ' Measurement status command - SHIFTOUT DinDout,clk,MSBFIRST,[Report\4] - SHIFTIN DinDout,clk,MSBPOST,[Status\4] ' Get Status - LOOP UNTIL status = Ready ' Exit loop when status is ready - - SHIFTIN DinDout,clk,MSBPOST,[x\11,y\11] ' Get x & y axis values - HIGH En ' Disable module - - IF (y.BIT10 = 1) THEN y = y | NegMask ' Store 11-bits as signed word - IF (x.BIT10 = 1) THEN x = x | NegMask ' Repeat for other axis - - angle = x ATN -y ' Convert x and y to brads - angle = angle */ 360 ' Convert brads to degrees - - RETURN - - -RetrieveInterval: - SERIN 16, 16468, Interval, Timeout, [DEC NewInterval] 'Retrieve interval - IF NewInterval >= 10 AND NewInterval <= 60000 THEN - Interval = NewInterval - ENDIF - RETURN \ No newline at end of file diff --git a/wpd/WpdBasicHardwareDriver/firmware/flex_force_wpd_enabled.bs2 b/wpd/WpdBasicHardwareDriver/firmware/flex_force_wpd_enabled.bs2 deleted file mode 100644 index 9b9e5b2c..00000000 --- a/wpd/WpdBasicHardwareDriver/firmware/flex_force_wpd_enabled.bs2 +++ /dev/null @@ -1,60 +0,0 @@ -' Flex_force_wpd_enabled.bs2 -' -' Displays R/C Discharge Time in BASIC Stamp DEBUG Window -' -' THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF -' ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO -' THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A -' PARTICULAR PURPOSE. -' -' Copyright (c) Microsoft Corporation. All rights reserved -' -' {$STAMP BS2} -' {$PBASIC 2.5} -' ========================================================================= - -' -----[ Declarations ]---------------------------------------------------- - -rawForce VAR Word ' Stores raw output -sensorPin CON 15 ' Flexiforce sensor circuit - -' -----[ Main Routine ]---------------------------------------------------- - -SensorID VAR Byte 'Sensor identifier = 5 for PIR -ElementSize VAR Byte 'Size (in bytes) of each element -ElementCount VAR Byte 'Count of elements in packet -Padding VAR Byte 'Padding for the 8-byte element - -SensorID = 3 -ElementSize = 1 -ElementCount = 5 '4-bytes for pressure data; 5 for interval - -NewInterval VAR Word 'New interval requested by user -Interval VAR Word 'Interval value utlized by firmware - -Interval = 200 -NewInterval = 200 - -LFD CON $10 'Linefeed character - -Main: - - GOSUB PollSensor 'Was motion detected? - GOSUB RetrieveInterval 'Retrieve units data - -Timeout: - SEROUT 16, 16468, [DEC1 SensorID, DEC1 ElementSize, DEC1 ElementCount, DEC5 rawForce, DEC5 Interval, LFD] - GOTO Main - -PollSensor: - HIGH sensorPin ' Discharge the capacitor - PAUSE 2 - RCTIME sensorPin,1,rawForce ' Measure RC charge time - RETURN - -RetrieveInterval: - SERIN 16, 16468, Interval, Timeout, [DEC NewInterval] 'Retrieve interval - IF NewInterval >= 10 AND NewInterval <= 60000 THEN - Interval = NewInterval - ENDIF - RETURN diff --git a/wpd/WpdBasicHardwareDriver/firmware/h48c_3-axis_wpd_enabled.bs2 b/wpd/WpdBasicHardwareDriver/firmware/h48c_3-axis_wpd_enabled.bs2 deleted file mode 100644 index daba0fc9..00000000 --- a/wpd/WpdBasicHardwareDriver/firmware/h48c_3-axis_wpd_enabled.bs2 +++ /dev/null @@ -1,175 +0,0 @@ -' h48c_3-axis_wpd_enabled.bs2 -' -' THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF -' ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO -' THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A -' PARTICULAR PURPOSE. -' -' Copyright (c) Microsoft Corporation. All rights reserved -' -' {$STAMP BS2} -' {$PBASIC 2.5} -' -' ========================================================================= - -' -----[ Program Description ]--------------------------------------------- -' -' Test program for the H48C 3-Axis Accelerometer module. -' -' Connections: -' -' +------------+ -' | * | -' CLK | o o | Vdd (+5v) -' | +--+ | -' DIO [ o | | o | CS\ -' | +--+ | -' Vss | o o | 0G (free-fall indication) -' | | -' +------------+ -' -' How it Works: -' -' An onboard MCP3204 12-bit ADC is used to read the VRef, X-, Y-, and -' Z-axis outputs from the Hitachi H48C accelerometer. The reference -' voltage output from H48C is 1.65 volts (3.3 / 2). -' -' After reading the reference voltage and an output channel the g-force -' for the channel is calculated with this formula: -' -' axis - vref 3.3 -' G = ----------- x ------ -' 4095 0.3663 -' -' For use in the program the forumla can be simplified to: -' -' G = (axis - vref) x 0.0022 -' -' To allow the display of fractional g-force in the integer system of the -' BASIC Stamp we multiply 0.0022 by 100 -- this will allow us to display -' g-force in 0.01g units. - - - -' -----[ I/O Definitions ]------------------------------------------------- - -Dio PIN 15 ' data to/from module -Clk PIN 14 ' clock output -CS PIN 13 ' active-low chip select - - -' -----[ Constants ]------------------------------------------------------- - -XAxis CON 0 ' adc channels -YAxis CON 1 -ZAxis CON 2 -VRef CON 3 - -Cnt2Mv CON $CE4C ' counts to millivolts - ' 0.80586 with ** -GfCnv CON $3852 ' g-force conversion - ' 0.22 with ** - -' -----[ Variables ]------------------------------------------------------- - -axis VAR Nib ' axis selection -rvCount VAR Word ' ref voltage adc counts -axCount VAR Word ' axis voltage adc counts -mVolts VAR Word ' millivolts -Gforce VAR Word ' axis g-force - -xGforce VAR Word ' x-axis force -yGforce VAR Word ' y-axis force -zGforce VAR Word ' z-axis force - -dValue VAR Word ' display value -dPad VAR Nib ' display pad - -' Below lines are WPD additions - -SensorID VAR Byte 'Sensor identifier = 9 for Hitachi -ElementCount VAR Byte 'Count of elements in packet -ElementSize VAR Byte 'Size (in bytes) of each element - - -NewInterval VAR Word 'New interval requested by user -Interval VAR Word 'Interval value utlized by firmware - -SensorID = 9 -ElementSize = 4 'Each element contains a sign byte, followed by a G-force integer value, followed by a G-force fraction (in hundredths). -ElementCount = 3 'Each element corresponds to one of the three axis (X, Y, and Z) - -Interval = 2000 -NewInterval = 2000 - - -' -----[ EEPROM Data ]----------------------------------------------------- - - -' -----[ Initialization ]-------------------------------------------------- - -Reset: - HIGH CS ' deselect module - -' -----[ Program Code ]---------------------------------------------------- - -Main: - GOSUB GetGforces 'Retrieves G-forces along 3 axis - GOSUB RetrieveInterval 'Retrieves event-interval data - - Timeout: - SEROUT 16, 16780, [DEC1 SensorID, DEC1 ElementSize, DEC1 ElementCount, DEC1(xGforce.BIT15), DEC1(ABS xGforce/100),DEC2(ABS xGforce),DEC1(yGforce.BIT15),DEC1(ABS yGforce/100),DEC2(ABS yGforce),DEC1(zGforce.BIT15),DEC1(ABS zGforce/100),DEC2(ABS zGforce),DEC5 Interval ] - GOTO Main - - GOTO Main - - -' -----[ Subroutines ]----------------------------------------------------- - -' Retrieves the event-interval property from the WPD driver -RetrieveInterval: - SERIN 16, 16780, Interval, Timeout, [DEC NewInterval] 'Retrieve interval - IF NewInterval >= 10 AND NewInterval <= 60000 THEN - Interval = NewInterval - ENDIF - -' Retrieves G forces along all three axis -GetGforces: - FOR axis = XAxis TO ZAxis ' loop through each axis - GOSUB Get_H48C ' read vRef & axis counts - ' calculate g-force - ' -- "Gforce" is signed word - IF (axCount >= rvCount) THEN - Gforce = (axCount - rvCount) ** GfCnv ' positive g-force - ELSE - Gforce = -((rvCount - axCount) ** GfCnv) ' negative g-force - ENDIF - IF (axis = XAxis) THEN - xGforce = Gforce - ENDIF - IF (axis = YAxis) THEN - yGforce = Gforce - ENDIF - IF (axis = ZAxis) THEN - zGforce = Gforce - ENDIF - NEXT - RETURN - -' Reads VRef and selected H48C axis through an MCP3204 ADC -' -- pass axis (0 - 2) in "axis" -' -- returns reference voltage counts in "rvCount" -' -- returns axis voltage counts in "axCounts" - -Get_H48C: - LOW CS - SHIFTOUT Dio, Clk, MSBFIRST, [%11\2, VRef\3] ' select vref register - SHIFTIN Dio, Clk, MSBPOST, [rvCount\13] ' read ref voltage counts - HIGH CS - PAUSE 1 - LOW CS - SHIFTOUT Dio, Clk, MSBFIRST, [%11\2, axis\3] ' select axis - SHIFTIN Dio, Clk, MSBPOST, [axCount\13] ' read axis voltage counts - HIGH CS - RETURN - diff --git a/wpd/WpdBasicHardwareDriver/firmware/memsic2125_wpd_enabled.bs2 b/wpd/WpdBasicHardwareDriver/firmware/memsic2125_wpd_enabled.bs2 deleted file mode 100644 index 80449357..00000000 --- a/wpd/WpdBasicHardwareDriver/firmware/memsic2125_wpd_enabled.bs2 +++ /dev/null @@ -1,107 +0,0 @@ -' memsic2125_wpd_enabled.bs2 -' -' THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF -' ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO -' THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A -' PARTICULAR PURPOSE. -' -' Copyright (c) Microsoft Corporation. All rights reserved -' -' {$STAMP BS2} -' {$PBASIC 2.5} -' -' ========================================================================= - -' -----[ Program Description ]--------------------------------------------- -' -' Read the pulse outputs from a Memsic 2125 accelerometer and converts to -' G-force -' -' g = ((t1 / 10 ms) - 0.5) / 12.5% -' -' www.memsic.com - - -' -----[ Revision History ]------------------------------------------------ - - -' -----[ I/O Definitions ]------------------------------------------------- - -Xin PIN 8 ' X input from Memsic 2125 -Yin PIN 9 ' Y input from Memsic 2125 - - -' -----[ Constants ]------------------------------------------------------- - -' Set scale factor for PULSIN - -#SELECT $STAMP - #CASE BS2, BS2E - Scale CON $200 ' 2.0 us per unit - #CASE BS2SX - Scale CON $0CC ' 0.8 us per unit - #CASE BS2P - Scale CON $0C0 ' 0.75 us per unit - #CASE BS2PE - Scale CON $1E1 ' 1.88 us per unit -#ENDSELECT - -HiPulse CON 1 ' measure high-going pulse -LoPulse CON 0 - -' -----[ Variables ]------------------------------------------------------- - -xRaw VAR Word ' pulse from Memsic 2125 -xmG VAR Word ' g force (1000ths) - -yRaw VAR Word -ymG VAR Word - -'disp VAR Byte ' displacement (0.0 - 0.99) - - -' Below lines are WPD additions - -SensorID VAR Byte 'Sensor identifier = 1 for memsic -ElementSize VAR Byte 'Size (in bytes) of each element -ElementCount VAR Byte 'Count of elements in packet - -NewInterval VAR Word 'New interval requested by user -Interval VAR Word 'Interval value utlized by firmware - -SensorID = 6 -ElementSize = 1 -ElementCount = 6 '6-bytes for g-force - -LFD CON $10 'Linefeed character - -Interval = 100 '.10 of a second interval -NewInterval = 100 - -' -----[ Program Code ]---------------------------------------------------- - -Main: - GOSUB Read_G_Force 'reads G-force - GOSUB RetrieveInterval 'Retrieve units data - - Timeout: - SEROUT 16, 16468, [DEC1 SensorID, DEC1 ElementSize, DEC1 ElementCount, DEC1(xmG.BIT15), DEC1(ABS xmG/1000),DEC1(ABS xmG/10),DEC1(ymG.BIT15),DEC1(ABS ymG/1000),DEC1(ABS ymG/10),DEC5 Interval,LFD] - GOTO Main - - - RetrieveInterval: - SERIN 16, 16468, Interval, Timeout, [DEC NewInterval] 'Retrieve interval - IF NewInterval >= 10 AND NewInterval <= 60000 THEN - Interval = NewInterval - ENDIF - -' -----[ Subroutines ]----------------------------------------------------- - -Read_G_Force: - PULSIN Xin, HiPulse, xRaw ' read pulse output - xRaw = xRaw */ Scale ' convert to uSecs - xmG = ((xRaw / 10) - 500) * 8 ' calc 1/1000 g - PULSIN Yin, HiPulse, yRaw - yRaw = yRaw */ Scale - ymG = ((yRaw / 10) - 500) * 8 - RETURN \ No newline at end of file diff --git a/wpd/WpdBasicHardwareDriver/firmware/piezo_wpd_enabled.bs2 b/wpd/WpdBasicHardwareDriver/firmware/piezo_wpd_enabled.bs2 deleted file mode 100644 index ff5a7b55..00000000 --- a/wpd/WpdBasicHardwareDriver/firmware/piezo_wpd_enabled.bs2 +++ /dev/null @@ -1,55 +0,0 @@ -' Piezo_wpd_enabled.bs2 -' -' This program demonstrates using the LDT0 as a switch/trigger -' -' THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF -' ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO -' THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A -' PARTICULAR PURPOSE. -' -' Copyright (c) Microsoft Corporation. All rights reserved -' -' {$STAMP BS2} -' {$PBASIC 2.5} -' ========================================================================= - -SensorID VAR Byte 'Sensor identifier = 8 for piezo -ElementSize VAR Byte 'Size (in bytes) of each element -ElementCount VAR Byte 'Count of elements in packet -bVibration VAR Byte 'Vibration-detection variable (single element for PIR) -Padding VAR Byte 'Padding for the 8-byte element - -SensorID = 8 -ElementSize = 1 -ElementCount = 1 '1-byte for motion data; 5 for interval - -NewInterval VAR Word 'New interval requested by user -Interval VAR Word 'Interval value utlized by firmware - -Interval = 500 -NewInterval = 500 - -LFD CON $10 'Linefeed character - - -' -----[ Program Code ]---------------------------------------------------- - -Main: - - GOSUB PollSensor 'Was motion detected? - GOSUB RetrieveInterval 'Retrieve units data - -Timeout: - SEROUT 16, 16468, [DEC1 SensorID, DEC1 ElementSize, DEC1 ElementCount, DEC1 bVibration, DEC5 Interval, LFD] - GOTO Main - -PollSensor: - bVibration = IN0 ' Assign status of P0 to bMotion - RETURN - -RetrieveInterval: - SERIN 16, 16468, Interval, Timeout, [DEC NewInterval] 'Retrieve interval - IF NewInterval >= 10 AND NewInterval <= 60000 THEN - Interval = NewInterval - ENDIF - RETURN diff --git a/wpd/WpdBasicHardwareDriver/firmware/ping_wpd_enabled.bs2 b/wpd/WpdBasicHardwareDriver/firmware/ping_wpd_enabled.bs2 deleted file mode 100644 index e2af29a7..00000000 --- a/wpd/WpdBasicHardwareDriver/firmware/ping_wpd_enabled.bs2 +++ /dev/null @@ -1,57 +0,0 @@ -' Ping_wpd_enabled.bs2 -' -' Measure distance with Ping))) sensor and display in both in & cm -' -' THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF -' ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO -' THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A -' PARTICULAR PURPOSE. -' -' Copyright (c) Microsoft Corporation. All rights reserved -' -' {$STAMP BS2} -' {$PBASIC 2.5} -' ========================================================================= - -' Conversion constants for room temperature measurements. -CmConstant CON 2260 -cmDistance VAR Word -time VAR Word -SensorID VAR Byte 'Sensor identifier = 5 for PIR -ElementSize VAR Byte 'Size (in bytes) of each element -ElementCount VAR Byte 'Count of elements in packet -Padding VAR Byte 'Padding for the 8-byte element - -SensorID = 4 -ElementSize = 1 -ElementCount = 5 '4-bytes for pressure data; 5 for interval - -NewInterval VAR Word 'New interval requested by user -Interval VAR Word 'Interval value utlized by firmware - - -LFD CON $10 'Linefeed character - -Interval = 200 '.20 of a second interval -NewInterval = 200 - -Main: - GOSUB PollSensor 'Was motion detected? - GOSUB RetrieveInterval 'Retrieve units data - -Timeout: - SEROUT 16, 16468, [DEC1 SensorID, DEC1 ElementSize, DEC1 ElementCount, DEC5 cmDistance, DEC5 Interval,LFD] -GOTO Main - -PollSensor: - PULSOUT 0, 5 - PULSIN 0, 1, time - cmDistance = cmConstant ** time -RETURN - -RetrieveInterval: - SERIN 16, 16468, Interval, Timeout, [DEC NewInterval] 'Retrieve interval - IF NewInterval >= 10 AND NewInterval <= 60000 THEN - Interval = NewInterval - ENDIF -RETURN \ No newline at end of file diff --git a/wpd/WpdBasicHardwareDriver/firmware/pir_wpd_enabled.bs2 b/wpd/WpdBasicHardwareDriver/firmware/pir_wpd_enabled.bs2 deleted file mode 100644 index 259c5025..00000000 --- a/wpd/WpdBasicHardwareDriver/firmware/pir_wpd_enabled.bs2 +++ /dev/null @@ -1,50 +0,0 @@ -' Pir_wpd_enabled.bs2 -' -' THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF -' ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO -' THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A -' PARTICULAR PURPOSE. -' -' Copyright (c) Microsoft Corporation. All rights reserved -' -' {$STAMP BS2} -' {$PBASIC 2.5} -' ========================================================================= - -SensorID VAR Byte 'Sensor identifier = 5 for PIR -ElementSize VAR Byte 'Size (in bytes) of each element -ElementCount VAR Byte 'Count of elements in packet -bMotion VAR Byte 'Motion-detection variable (single element for PIR) -Padding VAR Byte 'Padding for the 8-byte element - -SensorID = 5 -ElementSize = 1 -ElementCount = 1 '1-byte for motion data; 5 for interval - -NewInterval VAR Word 'New interval requested by user -Interval VAR Word 'Interval value utlized by firmware - -LFD CON $10 'Linefeed character - -Interval = 500 '.500 of a second interval -NewInterval = 500 - -Main: - - GOSUB PollSensor 'Was motion detected? - GOSUB RetrieveInterval 'Retrieve units data - -Timeout: - SEROUT 16, 16468, [DEC1 SensorID, DEC1 ElementSize, DEC1 ElementCount, DEC1 bMotion, DEC5 Interval,LFD] - GOTO Main - -PollSensor: - bMotion = IN0 ' Assign status of P0 to bMotion - RETURN - -RetrieveInterval: - SERIN 16, 16468, Interval, Timeout, [DEC NewInterval] 'Retrieve interval - IF NewInterval >= 10 AND NewInterval <= 60000 THEN - Interval = NewInterval - ENDIF - RETURN \ No newline at end of file diff --git a/wpd/WpdBasicHardwareDriver/firmware/qti_wpd_enabled.bs2 b/wpd/WpdBasicHardwareDriver/firmware/qti_wpd_enabled.bs2 deleted file mode 100644 index fdfdff7c..00000000 --- a/wpd/WpdBasicHardwareDriver/firmware/qti_wpd_enabled.bs2 +++ /dev/null @@ -1,63 +0,0 @@ -' Qti_wpd_enabled.bs2 -' -' THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF -' ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO -' THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A -' PARTICULAR PURPOSE. -' -' Copyright (c) Microsoft Corporation. All rights reserved -' -' {$STAMP BS2} -' {$PBASIC 2.5} -' ========================================================================= - -' -----[ I/O Definitions ]------------------------------------------------------ -LineSnsrPwr CON 10 ' line sensor power -LineSnsrIn CON 9 ' line sensor input - -' -----[ Constants ]------------------------------------------------------------ -'CLREOL CON 11 ' clear to end of line (DEBUG) - -' -----[ Variables ]------------------------------------------------------------ -Sense VAR Word ' sensor raw reading - -SensorID VAR Byte 'Sensor identifier = 5 for PIR -ElementSize VAR Byte 'Size (in bytes) of each element -ElementCount VAR Byte 'Count of elements in packet -Padding VAR Byte 'Padding for the 8-byte element -NewInterval VAR Word 'New interval requested by user -Interval VAR Word 'Interval value utlized by firmware - -SensorID = 7 -ElementSize = 1 -ElementCount = 4 '4-bytes for sensor data -Interval = 200 -NewInterval = 200 - -LFD CON $10 'Linefeed character - -' -----[ Main Code ]------------------------------------------------------------ -Main: - - GOSUB PollSensor 'Retrieve sensor value - GOSUB RetrieveInterval 'Retrieve units data - -Timeout: - SEROUT 16, 16468, [DEC1 SensorID, DEC1 ElementSize, DEC1 ElementCount, DEC4 Sense, DEC5 Interval, LFD] - GOTO Main - -PollSensor: - HIGH LineSnsrPwr ' activate sensor - HIGH LineSnsrIn ' discharge QTI cap - PAUSE 1 - RCTIME LineSnsrIn, 1, Sense ' read sensor value - LOW LineSnsrPwr ' deactivate sensor -RETURN - -RetrieveInterval: - SERIN 16, 16468, Interval, Timeout, [DEC NewInterval] 'Retrieve interval - IF NewInterval >= 10 AND NewInterval <= 60000 THEN - Interval = NewInterval - ENDIF - RETURN - diff --git a/wpd/WpdBasicHardwareDriver/firmware/temp_humidity_wpd_enabled.bs2 b/wpd/WpdBasicHardwareDriver/firmware/temp_humidity_wpd_enabled.bs2 deleted file mode 100644 index bc2982f7..00000000 --- a/wpd/WpdBasicHardwareDriver/firmware/temp_humidity_wpd_enabled.bs2 +++ /dev/null @@ -1,225 +0,0 @@ -' Temp_humidity_wpd_enabled.BS2 -' This program demonstrates the interface and conversion of SHT11/15 data -' to usable program values. This program uses advanced math features of -' PBASIC, specifically the ** operator. -' -' THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF -' ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO -' THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A -' PARTICULAR PURPOSE. -' -' Copyright (c) Microsoft Corporation. All rights reserved -' -' {$STAMP BS2} -' {$PBASIC 2.5} - -' -' ========================================================================= -' ------------------------------------------------------------------------- -' I/O Definitions -' ------------------------------------------------------------------------- -ShtData PIN 1 ' bi-directional data -Clock PIN 0 -' ------------------------------------------------------------------------- -' Constants -' ------------------------------------------------------------------------- -ShtTemp CON %00011 ' read temperature -ShtHumi CON %00101 ' read humidity -ShtStatW CON %00110 ' status register write -ShtStatR CON %00111 ' status register read -ShtReset CON %11110 ' soft reset -Ack CON 0 -NoAck CON 1 -No CON 0 -Yes CON 1 -DegSym CON 186 ' degrees symbol for DEBUG -' ------------------------------------------------------------------------- -' Variables -' ------------------------------------------------------------------------- -ioByte VAR Byte ' data from/to SHT11 -ackBit VAR Bit ' ack/nak from/to SHT11 -toDelay VAR Byte ' timeout delay timer -timeOut VAR Bit ' timeout status -soT VAR Word ' temp counts from SHT11 -tC VAR Word ' temp - Celcius -tF VAR Word ' temp - Fahrenheit -soRH VAR Word ' humidity counts -rhLin VAR Word ' humidity; linearized -rhTrue VAR Word ' humidity; compensated -status VAR Byte ' status byte - -'------------------------------------------------------------------------- -' WPD Variables -'------------------------------------------------------------------------- -SensorID VAR Byte 'Sensor identifier = 2 for Sensiron Temp/Humidity -ElementSize VAR Byte 'Size (in bytes) of each element -ElementCount VAR Byte 'Count of elements in packet -Padding VAR Byte 'Padding for the 8-byte element - -SensorID = 2 -ElementSize = 1 -ElementCount = 7 '4-bytes for temp, 3-bytes for relative humidity - -NewInterval VAR Word 'New interval requested by user -Interval VAR Word 'Interval value utlized by firmware - -LFD CON $10 'Linefeed character - -Interval = 2000 -NewInterval = 2000 - -' ------------------------------------------------------------------------- -' EEPROM Data -' ------------------------------------------------------------------------- -' ------------------------------------------------------------------------- -' Initialization -' ------------------------------------------------------------------------- -Initialize: -GOSUB SHT_Connection_Reset ' reset device connection -' ------------------------------------------------------------------------- -' Program Code -' ------------------------------------------------------------------------- -Main: - GOSUB SHT_Measure_Temp 'Retrieve temperature - GOSUB SHT_Measure_Humidity 'Retrieve humidity - GOSUB RetrieveInterval 'Retrieve interval data - -SendData: - SEROUT 16, 16468, [DEC1 SensorID, DEC1 ElementSize, DEC1 ElementCount, DEC4 (tF), DEC3 (rhTrue), DEC5 Interval, LFD] - GOTO Main - -RetrieveInterval: - SERIN 16, 16468, Interval, SendData, [DEC NewInterval] 'Retrieve interval - IF NewInterval >= 10 AND NewInterval <= 60000 THEN - Interval = NewInterval - ENDIF -RETURN - -' ------------------------------------------------------------------------- -' Subroutines -' ------------------------------------------------------------------------- -' connection reset: 9 clock cyles with ShtData high, then start sequence -' -SHT_Connection_Reset: -SHIFTOUT ShtData, Clock, LSBFIRST, [$FFF\9] -' generates SHT11 "start" sequence -' _____ _____ -' ShtData |_______| -' ___ ___ -' Clock ___| |___| |___ -' -SHT_Start: -INPUT ShtData ' let pull-up take high -LOW Clock -HIGH Clock -LOW ShtData -LOW Clock -HIGH Clock -INPUT ShtData -LOW Clock -RETURN -' measure temperature -' -- celcius = raw * 0.01 - 40 -' -- fahrenheit = raw * 0.018 - 40 -' -SHT_Measure_Temp: -GOSUB SHT_Start ' alert device -ioByte = ShtTemp ' temperature command -GOSUB SHT_Write_Byte ' send command -GOSUB SHT_Wait ' wait for measurement -ackBit = Ack ' another read follows -GOSUB SHT_Read_Byte ' get MSB -soT.HIGHBYTE = ioByte -ackBit = NoAck ' last read -GOSUB SHT_Read_Byte ' get LSB -soT.LOWBYTE = ioByte -' Note: Conversion factors are multiplied by 10 to return the -' temperature values in tenths of degrees -tC = soT ** $1999 - 400 ' convert to tenths C -tF = soT ** $2E14 - 400 ' convert to tenths F -RETURN -' measure humidity -' -SHT_Measure_Humidity: -GOSUB SHT_Start ' alert device -ioByte = ShtHumi ' humidity command -GOSUB SHT_Write_Byte ' send command -GOSUB SHT_Wait ' wait for measurement -ackBit = Ack ' another read follows -GOSUB SHT_Read_Byte ' get MSB -soRH.HIGHBYTE = ioByte -ackBit = NoAck ' last read -GOSUB SHT_Read_Byte ' get LSB -soRH.LOWBYTE = ioByte -' linearize humidity -' rhLin = (soRH * 0.0405) - (soRH^2 * 0.0000028) - 4 -' -' for the BASIC Stamp: -' rhLin = (soRH * 0.0405) - (soRH * 0.002 * soRH * 0.0014) - 4 -' -' Conversion factors are multiplied by 10 to return tenths -' -rhLin = (soRH ** $67AE) - (soRH ** $83 * soRH ** $5B) - 40 -' temperature compensated humidity -' rhTrue = (tc - 25) * (soRH * 0.00008 + 0.01) + rhLin -' -' Conversion factors are multiplied by 10 to return tenths -' -- simplified -' -rhTrue = (tC - 250) * (soRH ** $34) + rhLin -RETURN -' sends "status" -' -SHT_Write_Status: -GOSUB SHT_Start ' alert device -ioByte = ShtStatW ' write to status reg cmd -GOSUB SHT_Write_Byte ' send command -ioByte = status -GOSUB SHT_Write_Byte -RETURN -' returns "status" -' -SHT_Read_Status: -GOSUB SHT_Start ' alert device -ioByte = ShtStatW ' write to status reg cmd -GOSUB SHT_Read_Byte ' send command -ackBit = NoAck ' only one byte to read -GOSUB SHT_Read_Byte -RETURN -' sends "ioByte" -' returns "ackBit" -' -SHT_Write_Byte: -SHIFTOUT ShtData, Clock, MSBFIRST, [ioByte] ' send byte -SHIFTIN ShtData, Clock, LSBPRE, [ackBit\1] ' get ack bit -RETURN -' returns "ioByte" -' sends "ackBit" -' -SHT_Read_Byte: -SHIFTIN ShtData, Clock, MSBPRE, [ioByte] ' get byte -SHIFTOUT ShtData, Clock, LSBFIRST, [ackBit\1] ' send ack bit -INPUT ShtData ' release data line -RETURN -' wait for device to finish measurement (pulls data line low) -' -- timeout after ~1/4 second -' -SHT_Wait: -INPUT ShtData ' data line is input -timeOut = No ' assume no timeout -FOR toDelay = 1 TO 250 ' wait ~1/4 second -IF (ShtData = 0) THEN EXIT -PAUSE 1 -NEXT -IF (toDelay = 250) THEN timeOut = Yes ' loop completed = timeout -RETURN - -' reset SHT11/15 with soft reset -' -SHT_Soft_Reset: -GOSUB SHT_Connection_Reset ' reset the connection -ioByte = ShtReset ' reset command -ackBit = NoAck ' only one byte to send -GOSUB SHT_Write_Byte ' send it -PAUSE 11 ' wait at least 11 ms -RETURN \ No newline at end of file diff --git a/wpd/WpdBasicHardwareDriver/resource.h b/wpd/WpdBasicHardwareDriver/resource.h deleted file mode 100644 index 21979556..00000000 --- a/wpd/WpdBasicHardwareDriver/resource.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once -#define IDR_WpdBasicHardwareDriver 101 - diff --git a/wpd/WpdBasicHardwareDriver/stdafx.h b/wpd/WpdBasicHardwareDriver/stdafx.h deleted file mode 100644 index 56150a64..00000000 --- a/wpd/WpdBasicHardwareDriver/stdafx.h +++ /dev/null @@ -1,320 +0,0 @@ -#pragma once - -#include "resource.h" -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif - -#define STRSAFE_NO_DEPRECATE - -#include -#include - -#include -#include -#include -#include -#include - -// This driver is entirely user-mode -_Analysis_mode_(_Analysis_code_type_user_code_); - -// -// Driver specific tracing #defines - -// -// TODO: Change these values to be appropriate for your driver. -// -#define MYDRIVER_TRACING_ID L"Microsoft\\WPD\\BasicHardwareDriver" - -// -// TODO: Choose a different trace control GUID -// - -#define WPP_CONTROL_GUIDS \ - WPP_DEFINE_CONTROL_GUID(BasicHardwareDriverCtlGuid,(80068de5,197d,4db6,b77c,29ee3cca4537), \ - WPP_DEFINE_BIT(TRACE_FLAG_ALL) \ - WPP_DEFINE_BIT(TRACE_FLAG_DEVICE) \ - WPP_DEFINE_BIT(TRACE_FLAG_DRIVER) \ - WPP_DEFINE_BIT(TRACE_FLAG_QUEUE) \ - ) - -#define WPP_LEVEL_FLAGS_LOGGER(lvl,flags) \ - WPP_LEVEL_LOGGER(flags) - -#define WPP_LEVEL_FLAGS_ENABLED(lvl, flags) \ - (WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level >= lvl) - -// -// This comment block is scanned by the trace preprocessor to define our -// TraceEvents function. -// -// begin_wpp config -// FUNC Trace{FLAG=TRACE_FLAG_ALL}(LEVEL, MSG, ...); -// FUNC TraceEvents(LEVEL, FLAGS, MSG, ...); -// end_wpp - -// -// This comment block is scanned by the trace preprocessor to define our -// CHECK_HR function. -// -// -// begin_wpp config -// USEPREFIX (CHECK_HR,"%!STDPREFIX!"); -// FUNC CHECK_HR{FLAG=TRACE_FLAG_ALL}(hrCheck, MSG, ...); -// USESUFFIX (CHECK_HR, " hr= %!HRESULT!", hrCheck); -// end_wpp - -// -// PRE macro: The name of the macro includes the condition arguments FLAGS and EXP -// define in FUNC above -// -#define WPP_FLAG_hrCheck_PRE(FLAGS, hrCheck) {if(hrCheck != S_OK) { - -// -// POST macro -// The name of the macro includes the condition arguments FLAGS and EXP -// define in FUNC above -#define WPP_FLAG_hrCheck_POST(FLAGS, hrCheck) ; } } - -// -// The two macros below are for checking if the event should be logged and for -// choosing the logger handle to use when calling the ETW trace API -// -#define WPP_FLAG_hrCheck_ENABLED(FLAGS, hrCheck) WPP_FLAG_ENABLED(FLAGS) -#define WPP_FLAG_hrCheck_LOGGER(FLAGS, hrCheck) WPP_FLAG_LOGGER(FLAGS) - - -#include -#include -#include - -#include // Required to access the DEFINE_GUID macro -#include // Required to access the DEFINE_PROPERTYKEY macro - -// {CDD18979-A7B0-4D5E-9EB2-0A826805CBBD} -DEFINE_PROPERTYKEY(PRIVATE_SAMPLE_DRIVER_WUDF_DEVICE_OBJECT, 0xCDD18979, 0xA7B0, 0x4D5E, 0x9E, 0xB2, 0x0A, 0x82, 0x68, 0x05, 0xCB, 0xBD, 2); -// {9BD949E5-59CF-41AE-90A9-BE1D044F578F} -DEFINE_PROPERTYKEY(PRIVATE_SAMPLE_DRIVER_WPD_SERIALIZER_OBJECT, 0x9BD949E5, 0x59CF, 0x41AE, 0x90, 0xA9, 0xBE, 0x1D, 0x04, 0x4F, 0x57, 0x8F, 2); -// {4DF6C8C7-2CE5-457C-9F53-EFCECAA95C04} -DEFINE_PROPERTYKEY(PRIVATE_SAMPLE_DRIVER_CLIENT_CONTEXT_MAP, 0x4DF6C8C7, 0x2CE5, 0x457C, 0x9F, 0x53, 0xEF, 0xCE, 0xCA, 0xA9, 0x5C, 0x04, 2); - -/**************************************************************************** -* This section defines the Functional Category associated with the sensor object -****************************************************************************/ - -// -// FUNCTIONAL_CATEGORY_SENSOR_SAMPLE -// Indicates this object encapsulates sensor functionality on the device -DEFINE_GUID (FUNCTIONAL_CATEGORY_SENSOR_SAMPLE, 0x09b93609, 0xd5c1,0x497b,0xb2, 0x52, 0xb4, 0x92, 0xcb, 0x5e, 0xfe, 0x52); - - -/**************************************************************************** -* This section defines all Commands, Parameters and Options associated with: -* SENSOR_PROPERTIES_V1 -* -* This category is for properties common to all sensor objects. -****************************************************************************/ -DEFINE_GUID (SENSOR_PROPERTIES_V1, 0xa7ef4367, 0x6550, 0x4055, 0xb6, 0x6f, 0xbe, 0x6f, 0xda, 0xcf, 0x4e, 0x9f); - -// -// SENSOR_READING -// [ VT_UI4 ] Indicates the sensor reading in degrees Kelvin. -DEFINE_PROPERTYKEY(SENSOR_READING, 0xa7ef4367, 0x6550, 0x4055, 0xb6, 0x6f, 0xbe, 0x6f, 0xda, 0xcf, 0x4e, 0x9f, 2); -// -// SENSOR_UPDATE_INTERVAL -// [ VT_UI4 ] Indicates the sensor update interval in milliseconds. -DEFINE_PROPERTYKEY(SENSOR_UPDATE_INTERVAL, 0xa7ef4367, 0x6550, 0x4055, 0xb6, 0x6f, 0xbe, 0x6f, 0xda, 0xcf, 0x4e, 0x9f, 3); - -/**************************************************************************** -* This section defines all Events associated with the sensor object -****************************************************************************/ -// -// EVENT_SENSOR_READING_UPDATED -// This event is sent after a new sensor reading is available on the device. -DEFINE_GUID (EVENT_SENSOR_READING_UPDATED, 0xada23b0b, 0xce13, 0x4e11, 0x9d, 0x2f, 0x15, 0xfe, 0x10, 0xd6, 0x63, 0x37); - - -// -// Macro Definitions -// - -#ifndef SAFE_RELEASE - #define SAFE_RELEASE(p) if( NULL != p ) { ( p )->Release(); p = NULL; } -#endif - -class ContextMap : public IUnknown -{ -public: - ContextMap() : - m_cRef(1) - { - - } - - ~ContextMap() - { - CComCritSecLock Lock(m_CriticalSection); - - IUnknown* pUnk = NULL; - POSITION elementPosition = NULL; - - elementPosition = m_Map.GetStartPosition(); - while(elementPosition != NULL) - { - pUnk = m_Map.GetNextValue(elementPosition); - if(pUnk != NULL) - { - pUnk->Release(); - } - } - } - -public: // IUnknown - ULONG __stdcall AddRef() - { - InterlockedIncrement((long*) &m_cRef); - return m_cRef; - } - - _At_(this, __drv_freesMem(Mem)) - ULONG __stdcall Release() - { - ULONG ulRefCount = m_cRef - 1; - - if (InterlockedDecrement((long*) &m_cRef) == 0) - { - delete this; - return 0; - } - return ulRefCount; - } - - HRESULT __stdcall QueryInterface( - REFIID riid, - void** ppv) - { - HRESULT hr = S_OK; - - if(riid == IID_IUnknown) - { - *ppv = static_cast(this); - AddRef(); - } - else - { - *ppv = NULL; - hr = E_NOINTERFACE; - } - return hr; - } - - -public: // Context accessor methods - - // If successful, this method AddRef's the context and returns - // a context key - HRESULT Add( - _In_ IUnknown* pContext, - _Out_ CAtlStringW& key) - { - CComCritSecLock Lock(m_CriticalSection); - HRESULT hr = S_OK; - GUID guidContext = GUID_NULL; - CComBSTR bstrContext; - key = L""; - - // Create a unique context key - hr = CoCreateGuid(&guidContext); - if (hr == S_OK) - { - bstrContext = guidContext; - if(bstrContext.Length() > 0) - { - key = bstrContext; - } - else - { - hr = E_OUTOFMEMORY; - } - } - - if (hr == S_OK) - { - // Insert this into the map - POSITION elementPosition = m_Map.SetAt(key, pContext); - if(elementPosition != NULL) - { - // AddRef since we are holding onto it - pContext->AddRef(); - } - else - { - hr = E_OUTOFMEMORY; - } - } - return hr; - } - - void Remove( - _In_ const CAtlStringW& key) - { - CComCritSecLock Lock(m_CriticalSection); - // Get the element - IUnknown* pContext = NULL; - - if (m_Map.Lookup(key, pContext) == true) - { - // Remove the entry for it - m_Map.RemoveKey(key); - - // Release it - pContext->Release(); - } - } - - // Returns the context pointer. If not found, return value is NULL. - // If non-NULL, caller is responsible for Releasing when it is done, - // since this method will AddRef the context. - IUnknown* GetContext( - _In_ const CAtlStringW& key) - { - CComCritSecLock Lock(m_CriticalSection); - // Get the element - IUnknown* pContext = NULL; - - if (m_Map.Lookup(key, pContext) == true) - { - // AddRef - pContext->AddRef(); - } - return pContext; - } - -private: - CComAutoCriticalSection m_CriticalSection; - CAtlMap m_Map; - DWORD m_cRef; -}; - -HRESULT UpdateDeviceFriendlyName( - _In_ IPortableDeviceClassExtension* pPortableDeviceClassExtension, - _In_ LPCWSTR wszDeviceFriendlyName); - - -// Forward declaration of WpdBaseDriver as it is accessed by other classes -class WpdBaseDriver; - -#include "WpdBasicHardwareDriver.h" -#include "RS232Connection.h" -#include "RS232Target.h" -#include "WpdObjectEnum.h" -#include "WpdObjectProperties.h" -#include "WpdCapabilities.h" -#include "WpdBaseDriver.h" -#include "Device.h" -#include "Driver.h" -#include "Queue.h" - -extern HINSTANCE g_hInstance; - diff --git a/wpd/WpdHelloWorldDriver/WpdHelloWorldDriver.htm b/wpd/WpdHelloWorldDriver/WpdHelloWorldDriver.htm new file mode 100644 index 00000000..a26ab340 --- /dev/null +++ b/wpd/WpdHelloWorldDriver/WpdHelloWorldDriver.htm @@ -0,0 +1,536 @@ + + + + + + + + +WPD Sample Driver + + + + + + + + + +
+ +

Windows Portable Device (WPD) “Hello +World” Sample Driver

+ +

Summary

+ +

This sample contains +working source code for a WPD driver.  +WPD Drivers are built using the Windows User-Mode Driver Foundation with +special processing added to handle WPD messages.

+ +

Building a new WPD Driver

+ +

You are encouraged to use +this sample code to start building your own WPD Driver. Modify the sample to +add your own features.

+ +

The following is a +suggested roadmap to developing your driver:

+ +

*       Create WPD driver shell

+ +

*       Use sample driver as base

+ +

*       Update the INF to install this +driver for your device (it will not actually do anything with the device yet)

+ +

*       Start implementing +functionality.  This is where the driver +will start interacting with the device:

+ +

*       Object Enumeration

+ +

*       WPD_CATEGORY_OBJECT_ENUMERATION

+ +

*       Properties

+ +

*       Implement Reads, Writes

+ +

*       WPD_CATEGORY_OBJECT_PROPERTIES

+ +

*       Transfer

+ +

*       Implement Resource enumeration, +reads, writes

+ +

*       WPD_CATEGORY_OBJECT_RESOURCES

+ +

*       Capabilities

+ +

*       WPD_CATEGORY_CAPABILITIES

+ +

*       Remaining commands

+ +

Building the Sample

+ +

Open a free or checked +DDK build environment, go to this directory, and run build. This creates +WpdHelloWorldDriver.dll in the Objfre or Objchk directory. Before the sample can be used, it must be +installed by running the “Add Hardware” Wizard from Control Panel:

+ +

1. Launch the Windows +"Control Panel".

+ +

2. Double Click the +"Add Hardware" icon (Click “Classic View” link on the left hand pane +if you can’t find it).

+ +

3. The "Add +hardware" Wizard should launch, press the "Next" button. (The +wizard will do a quick search for devices already installed on the system.  It may take a minute or two.)

+ +

4. Choose the +"Install the hardware that I manually select from a list (Advanced)" +option and press the "Next" button.

+ +

5. A list of device +categories will be shown.  Scroll to the +very end of the list and select "Windows Portable Devices" option, +and click “Next”.

+ +

6. Press the "Have +Disk" button and browse to the location of the device .INF file.

+ +

7. Choose the appropriate +device to install ("Microsoft WPD Sample” for example) and press the +"Next" button.

+ +

8. After the files have +been copied to the system, the device should be installed (you can verify this +by looking in “Device Manager”).  You can +now run WPD applications.

+ +

Testing the WPD Driver

+ +

To test the WPD Driver, +double click the appropriate WPD device icon in “My Computer” to start browsing +the sample device contents.  Or use the WpdInfo +development tool included in this kit.

+ +

Supported Configurations

+ +

The WPD DDK sample driver +has been tested in checked and free builds for both 32 and 64-bit platforms.

+ +

CODE TOUR

+ +

File Manifest

+ +
File                                Description
Device.cpp                          Driver's IWDFDevice implementation
Device.h                            Header file for driver's IWDFDevice implementation
Driver.cpp                          Driver’s IDriverEntry implementation 
Driver.h                            Header file for driver's IDriverEntry implementation
helpers.cpp                         Miscellaneous helper functions
helpers.h                           Miscellaneous helper function definitions
MAKEFILE                            Makefile
makefile.inc                        Makefile
Queue.cpp                           Driver's queue implementation
Queue.h                             Header file for driver’s queue implementation
resource.h                          Resource header
sources                             Sources file
stdafx.h                            Precompiled header file
WpdBaseDriver.cpp                   Implements the main WPD message handler which unpacks and dispatches WPD messages
WpdBaseDriver.h                     Header file for the main WPD message handler
WpdCapabilities.cpp                 Implements the commands related to Capabilities
WpdCapabilities.h                   Header file for Capabilities implementation
WpdObjectEnum.cpp                   Implements the commands related to enumerating contents
WpdObjectEnum.h                     Header file for content enumeration implementation
WpdObjectProperties.cpp             Implements the commands related to handling object meta-data
WpdObjectProperties.h               Header file for commands related to handling object meta-data
WpdObjectResources.cpp              Implements the commands related to transferring data
WpdObjectResources.h                Header file for commands related to transferring data
WpdHelloWorldDriver.cpp             Main DLL file
WpdHelloWorldDriver.def             Exports
WpdHelloWorldDriver.idl             Component Interface file
WpdHelloWorldDriver.inf             Sample Device INF file
WpdHelloWorldDriver.rc              Resource file
WpdHelloWorldDriver.rgs             ATL Self registration file
 
 
+ +

Top of page +

+ +
 
+ + + + + +
+

 

+
+ +
 
 
+ +

© +2006 Microsoft Corporation

+ +
+ + + + diff --git a/wpd/WpdHelloWorldDriver/WpdHelloWorldDriver.sln b/wpd/WpdHelloWorldDriver/WpdHelloWorldDriver.sln index 064c604f..c9b35721 100644 --- a/wpd/WpdHelloWorldDriver/WpdHelloWorldDriver.sln +++ b/wpd/WpdHelloWorldDriver/WpdHelloWorldDriver.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WpdHelloWorldDriver", "WpdHelloWorldDriver.vcxproj", "{669637EF-68AA-49C8-95FE-97A28D97E22C}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WpdHelloWorldDriver", "WpdHelloWorldDriver.vcxproj", "{B0C86FEC-87BE-4E10-A509-C182F1C2F6F5}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +13,14 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {669637EF-68AA-49C8-95FE-97A28D97E22C}.Debug|Win32.ActiveCfg = Debug|Win32 - {669637EF-68AA-49C8-95FE-97A28D97E22C}.Debug|Win32.Build.0 = Debug|Win32 - {669637EF-68AA-49C8-95FE-97A28D97E22C}.Release|Win32.ActiveCfg = Release|Win32 - {669637EF-68AA-49C8-95FE-97A28D97E22C}.Release|Win32.Build.0 = Release|Win32 - {669637EF-68AA-49C8-95FE-97A28D97E22C}.Debug|x64.ActiveCfg = Debug|x64 - {669637EF-68AA-49C8-95FE-97A28D97E22C}.Debug|x64.Build.0 = Debug|x64 - {669637EF-68AA-49C8-95FE-97A28D97E22C}.Release|x64.ActiveCfg = Release|x64 - {669637EF-68AA-49C8-95FE-97A28D97E22C}.Release|x64.Build.0 = Release|x64 + {B0C86FEC-87BE-4E10-A509-C182F1C2F6F5}.Debug|Win32.ActiveCfg = Debug|Win32 + {B0C86FEC-87BE-4E10-A509-C182F1C2F6F5}.Debug|Win32.Build.0 = Debug|Win32 + {B0C86FEC-87BE-4E10-A509-C182F1C2F6F5}.Release|Win32.ActiveCfg = Release|Win32 + {B0C86FEC-87BE-4E10-A509-C182F1C2F6F5}.Release|Win32.Build.0 = Release|Win32 + {B0C86FEC-87BE-4E10-A509-C182F1C2F6F5}.Debug|x64.ActiveCfg = Debug|x64 + {B0C86FEC-87BE-4E10-A509-C182F1C2F6F5}.Debug|x64.Build.0 = Debug|x64 + {B0C86FEC-87BE-4E10-A509-C182F1C2F6F5}.Release|x64.ActiveCfg = Release|x64 + {B0C86FEC-87BE-4E10-A509-C182F1C2F6F5}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/wpd/WpdHelloWorldDriver/WpdHelloWorldDriver.vcxproj b/wpd/WpdHelloWorldDriver/WpdHelloWorldDriver.vcxproj index 0df5997e..2f3c2f81 100644 --- a/wpd/WpdHelloWorldDriver/WpdHelloWorldDriver.vcxproj +++ b/wpd/WpdHelloWorldDriver/WpdHelloWorldDriver.vcxproj @@ -19,13 +19,13 @@
- {669637EF-68AA-49C8-95FE-97A28D97E22C} + {B0C86FEC-87BE-4E10-A509-C182F1C2F6F5} $(MSBuildProjectName) 1 1 Debug Win32 - {FD409E4D-BEDF-4C56-A200-69194115BFD6} + {76BA4347-D2B6-4F3B-BBB1-5EC4A2FEEB14} diff --git a/wpd/WpdHelloWorldDriver/WpdHelloWorldDriver.vcxproj.Filters b/wpd/WpdHelloWorldDriver/WpdHelloWorldDriver.vcxproj.Filters index a47241f0..07e1689c 100644 --- a/wpd/WpdHelloWorldDriver/WpdHelloWorldDriver.vcxproj.Filters +++ b/wpd/WpdHelloWorldDriver/WpdHelloWorldDriver.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {8EDC10B0-562C-43D2-AA2C-EECACC61ED5E} + {D130D47E-6427-4218-8931-B9A76438E407} h;hpp;hxx;hm;inl;inc;xsd - {7FA34110-834B-470B-B9F9-C8A7DCD0B841} + {37543692-66C2-483A-B887-DCCCF1E54940} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {59D3C056-5E21-4771-8D2F-6BF1CFE72DC3} + {7BA26A24-C6A3-4FFC-AD61-E52574E57C45} inf;inv;inx;mof;mc; - {BD74AA3E-E959-4EE3-A15C-9A20145D9E3E} + {9D6CD385-5C3A-4727-AB21-03D755F75101} diff --git a/wpd/WpdMultiTransportDriver/WpdMultiTransportDriver.htm b/wpd/WpdMultiTransportDriver/WpdMultiTransportDriver.htm new file mode 100644 index 00000000..ad2abad3 --- /dev/null +++ b/wpd/WpdMultiTransportDriver/WpdMultiTransportDriver.htm @@ -0,0 +1,535 @@ + + + + + + + + +WPD Sample Driver + + + + + + + + + +
+ +

Windows Portable Device (WPD) Multi-Transport Sample Driver

+ +

Summary

+ +

This sample contains +working source code for a WPD driver.  +WPD Drivers are built using the Windows User-Mode Driver Foundation with +special processing added to handle WPD messages.

+ +

Building a new WPD Driver

+ +

You are encouraged to use +this sample code to start building your own WPD Driver. Modify the sample to +add your own features.

+ +

The following is a +suggested roadmap to developing your driver:

+ +

*       Create WPD driver shell

+ +

*       Use sample driver as base

+ +

*       Update the INF to install this +driver for your device (it will not actually do anything with the device yet)

+ +

*       Start implementing +functionality.  This is where the driver +will start interacting with the device:

+ +

*       Object Enumeration

+ +

*       WPD_CATEGORY_OBJECT_ENUMERATION

+ +

*       Properties

+ +

*       Implement Reads, Writes

+ +

*       WPD_CATEGORY_OBJECT_PROPERTIES

+ +

*       Transfer

+ +

*       Implement Resource enumeration, +reads, writes

+ +

*       WPD_CATEGORY_OBJECT_RESOURCES

+ +

*       Capabilities

+ +

*       WPD_CATEGORY_CAPABILITIES

+ +

*       Remaining commands

+ +

Building the Sample

+ +

Open a free or checked +DDK build environment, go to this directory, and run build. This creates +WpdMultiTransportDriver.dll in the Objfre or Objchk directory. Before the sample can be used, it must be +installed by running the “Add Hardware” Wizard from Control Panel:

+ +

1. Launch the Windows +"Control Panel".

+ +

2. Double Click the +"Add Hardware" icon (Click “Classic View” link on the left hand pane +if you can’t find it).

+ +

3. The "Add +hardware" Wizard should launch, press the "Next" button. (The +wizard will do a quick search for devices already installed on the system.  It may take a minute or two.)

+ +

4. Choose the +"Install the hardware that I manually select from a list (Advanced)" +option and press the "Next" button.

+ +

5. A list of device +categories will be shown.  Scroll to the +very end of the list and select "Windows Portable Devices" option, +and click “Next”.

+ +

6. Press the "Have +Disk" button and browse to the location of the device .INF file.

+ +

7. Choose the appropriate +device to install ("Microsoft WPD Sample” for example) and press the +"Next" button.

+ +

8. After the files have +been copied to the system, the device should be installed (you can verify this +by looking in “Device Manager”).  You can +now run WPD applications.

+ +

Testing the WPD Driver

+ +

To test the WPD Driver, +double click the appropriate WPD device icon in “My Computer” to start browsing +the sample device contents.  Or use the WpdInfo +development tool included in this kit.

+ +

Supported Configurations

+ +

The WPD DDK sample driver +has been tested in checked and free builds for both 32 and 64-bit platforms.

+ +

CODE TOUR

+ +

File Manifest

+ +
File                                Description
Device.cpp                          Driver's IWDFDevice implementation
Device.h                            Header file for driver's IWDFDevice implementation
Driver.cpp                          Driver’s IDriverEntry implementation 
Driver.h                            Header file for driver's IDriverEntry implementation
helpers.cpp                         Miscellaneous helper functions
helpers.h                           Miscellaneous helper function definitions
MAKEFILE                            Makefile
makefile.inc                        Makefile
Queue.cpp                           Driver's queue implementation
Queue.h                             Header file for driver’s queue implementation
resource.h                          Resource header
sources                             Sources file
stdafx.h                            Precompiled header file
WpdBaseDriver.cpp                   Implements the main WPD message handler which unpacks and dispatches WPD messages
WpdBaseDriver.h                     Header file for the main WPD message handler
WpdCapabilities.cpp                 Implements the commands related to Capabilities
WpdCapabilities.h                   Header file for Capabilities implementation
WpdObjectEnum.cpp                   Implements the commands related to enumerating contents
WpdObjectEnum.h                     Header file for content enumeration implementation
WpdObjectProperties.cpp             Implements the commands related to handling object meta-data
WpdObjectProperties.h               Header file for commands related to handling object meta-data
WpdObjectResources.cpp              Implements the commands related to transferring data
WpdObjectResources.h                Header file for commands related to transferring data
WpdMultiTransportDriver.cpp             Main DLL file
WpdMultiTransportDriver.def             Exports
WpdMultiTransportDriver.idl             Component Interface file
WpdMultiTransportDriver.inf             Sample Device INF file
WpdMultiTransportDriver.rc              Resource file
WpdMultiTransportDriver.rgs             ATL Self registration file
 
 
+ +

Top of page +

+ +
 
+ + + + + +
+

 

+
+ +
 
 
+ +

© +2006 Microsoft Corporation

+ +
+ + + + diff --git a/wpd/WpdMultiTransportDriver/WpdMultiTransportDriver.sln b/wpd/WpdMultiTransportDriver/WpdMultiTransportDriver.sln index a1edc764..229bda81 100644 --- a/wpd/WpdMultiTransportDriver/WpdMultiTransportDriver.sln +++ b/wpd/WpdMultiTransportDriver/WpdMultiTransportDriver.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WpdMultiTransportDriver", "WpdMultiTransportDriver.vcxproj", "{37907AAA-43FE-46C8-A20E-522C4B9F6502}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WpdMultiTransportDriver", "WpdMultiTransportDriver.vcxproj", "{0431FFA9-4A12-4072-914A-F46F86F9EC99}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +13,14 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {37907AAA-43FE-46C8-A20E-522C4B9F6502}.Debug|Win32.ActiveCfg = Debug|Win32 - {37907AAA-43FE-46C8-A20E-522C4B9F6502}.Debug|Win32.Build.0 = Debug|Win32 - {37907AAA-43FE-46C8-A20E-522C4B9F6502}.Release|Win32.ActiveCfg = Release|Win32 - {37907AAA-43FE-46C8-A20E-522C4B9F6502}.Release|Win32.Build.0 = Release|Win32 - {37907AAA-43FE-46C8-A20E-522C4B9F6502}.Debug|x64.ActiveCfg = Debug|x64 - {37907AAA-43FE-46C8-A20E-522C4B9F6502}.Debug|x64.Build.0 = Debug|x64 - {37907AAA-43FE-46C8-A20E-522C4B9F6502}.Release|x64.ActiveCfg = Release|x64 - {37907AAA-43FE-46C8-A20E-522C4B9F6502}.Release|x64.Build.0 = Release|x64 + {0431FFA9-4A12-4072-914A-F46F86F9EC99}.Debug|Win32.ActiveCfg = Debug|Win32 + {0431FFA9-4A12-4072-914A-F46F86F9EC99}.Debug|Win32.Build.0 = Debug|Win32 + {0431FFA9-4A12-4072-914A-F46F86F9EC99}.Release|Win32.ActiveCfg = Release|Win32 + {0431FFA9-4A12-4072-914A-F46F86F9EC99}.Release|Win32.Build.0 = Release|Win32 + {0431FFA9-4A12-4072-914A-F46F86F9EC99}.Debug|x64.ActiveCfg = Debug|x64 + {0431FFA9-4A12-4072-914A-F46F86F9EC99}.Debug|x64.Build.0 = Debug|x64 + {0431FFA9-4A12-4072-914A-F46F86F9EC99}.Release|x64.ActiveCfg = Release|x64 + {0431FFA9-4A12-4072-914A-F46F86F9EC99}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/wpd/WpdMultiTransportDriver/WpdMultiTransportDriver.vcxproj b/wpd/WpdMultiTransportDriver/WpdMultiTransportDriver.vcxproj index 046e9ebf..b89e9d1a 100644 --- a/wpd/WpdMultiTransportDriver/WpdMultiTransportDriver.vcxproj +++ b/wpd/WpdMultiTransportDriver/WpdMultiTransportDriver.vcxproj @@ -19,13 +19,13 @@
- {37907AAA-43FE-46C8-A20E-522C4B9F6502} + {0431FFA9-4A12-4072-914A-F46F86F9EC99} $(MSBuildProjectName) 1 1 Debug Win32 - {28A8601E-0288-45E2-A8FF-B23C3D163E06} + {56F5B6B8-E50F-45EE-A52E-D99FA98256AA} diff --git a/wpd/WpdMultiTransportDriver/WpdMultiTransportDriver.vcxproj.Filters b/wpd/WpdMultiTransportDriver/WpdMultiTransportDriver.vcxproj.Filters index e67dfaf4..e051fd40 100644 --- a/wpd/WpdMultiTransportDriver/WpdMultiTransportDriver.vcxproj.Filters +++ b/wpd/WpdMultiTransportDriver/WpdMultiTransportDriver.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {27130F09-0148-4D17-AE7E-2E9EC7C0E975} + {66A9D3F7-7136-483B-A3B0-0B71F39E1A4D} h;hpp;hxx;hm;inl;inc;xsd - {6D2BBEB1-D05B-4EE1-AD68-9D02DA2AD058} + {E6663B10-722E-421B-BE1F-D2450D721956} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {0FD7410D-0B64-463C-97F0-1766C80EC6AA} + {F2C470A6-B9EF-4AD0-8AB3-3A38A05C42CD} inf;inv;inx;mof;mc; - {6307E7D9-A903-4A0E-ACF9-24B41E12D183} + {CF4D8378-7A1D-49EC-AE7C-220F975A42A2} diff --git a/wpd/WpdServiceSampleDriver/WpdServiceSampleDriver.sln b/wpd/WpdServiceSampleDriver/WpdServiceSampleDriver.sln index 5106e4d4..4e97814f 100644 --- a/wpd/WpdServiceSampleDriver/WpdServiceSampleDriver.sln +++ b/wpd/WpdServiceSampleDriver/WpdServiceSampleDriver.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WpdServiceSampleDriver", "WpdServiceSampleDriver.vcxproj", "{31C8E589-7E7D-4F83-BE09-7831A94E3D07}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WpdServiceSampleDriver", "WpdServiceSampleDriver.vcxproj", "{060767D3-7EB1-4EC2-B2E2-6239DAEB712A}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +13,14 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {31C8E589-7E7D-4F83-BE09-7831A94E3D07}.Debug|Win32.ActiveCfg = Debug|Win32 - {31C8E589-7E7D-4F83-BE09-7831A94E3D07}.Debug|Win32.Build.0 = Debug|Win32 - {31C8E589-7E7D-4F83-BE09-7831A94E3D07}.Release|Win32.ActiveCfg = Release|Win32 - {31C8E589-7E7D-4F83-BE09-7831A94E3D07}.Release|Win32.Build.0 = Release|Win32 - {31C8E589-7E7D-4F83-BE09-7831A94E3D07}.Debug|x64.ActiveCfg = Debug|x64 - {31C8E589-7E7D-4F83-BE09-7831A94E3D07}.Debug|x64.Build.0 = Debug|x64 - {31C8E589-7E7D-4F83-BE09-7831A94E3D07}.Release|x64.ActiveCfg = Release|x64 - {31C8E589-7E7D-4F83-BE09-7831A94E3D07}.Release|x64.Build.0 = Release|x64 + {060767D3-7EB1-4EC2-B2E2-6239DAEB712A}.Debug|Win32.ActiveCfg = Debug|Win32 + {060767D3-7EB1-4EC2-B2E2-6239DAEB712A}.Debug|Win32.Build.0 = Debug|Win32 + {060767D3-7EB1-4EC2-B2E2-6239DAEB712A}.Release|Win32.ActiveCfg = Release|Win32 + {060767D3-7EB1-4EC2-B2E2-6239DAEB712A}.Release|Win32.Build.0 = Release|Win32 + {060767D3-7EB1-4EC2-B2E2-6239DAEB712A}.Debug|x64.ActiveCfg = Debug|x64 + {060767D3-7EB1-4EC2-B2E2-6239DAEB712A}.Debug|x64.Build.0 = Debug|x64 + {060767D3-7EB1-4EC2-B2E2-6239DAEB712A}.Release|x64.ActiveCfg = Release|x64 + {060767D3-7EB1-4EC2-B2E2-6239DAEB712A}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/wpd/WpdServiceSampleDriver/WpdServiceSampleDriver.vcxproj b/wpd/WpdServiceSampleDriver/WpdServiceSampleDriver.vcxproj index fc4d1554..e3538b91 100644 --- a/wpd/WpdServiceSampleDriver/WpdServiceSampleDriver.vcxproj +++ b/wpd/WpdServiceSampleDriver/WpdServiceSampleDriver.vcxproj @@ -19,13 +19,13 @@ - {31C8E589-7E7D-4F83-BE09-7831A94E3D07} + {060767D3-7EB1-4EC2-B2E2-6239DAEB712A} $(MSBuildProjectName) 1 1 Debug Win32 - {1777FF3E-D86C-4053-B3FE-DB0C55459BAA} + {632F78B7-F73E-4B6D-959D-587356021B6B} diff --git a/wpd/WpdServiceSampleDriver/WpdServiceSampleDriver.vcxproj.Filters b/wpd/WpdServiceSampleDriver/WpdServiceSampleDriver.vcxproj.Filters index bae147dc..0b484774 100644 --- a/wpd/WpdServiceSampleDriver/WpdServiceSampleDriver.vcxproj.Filters +++ b/wpd/WpdServiceSampleDriver/WpdServiceSampleDriver.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {EE35ADBF-437F-44A1-AEB4-3D19EF5C2780} + {F5AD514F-9337-4FD2-8AF1-76095351A7A3} h;hpp;hxx;hm;inl;inc;xsd - {410E5228-572D-4CA9-9BE0-7E6253581D2C} + {E3137EB0-EA19-4B3F-AF8F-D7A0B1CCE331} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {9CC2DED3-ECF7-44E8-9B14-0E15C5605D38} + {CB0E2DC6-C230-433C-BC67-FFE4DFA85526} inf;inv;inx;mof;mc; - {EFFDD7BB-33E7-46CF-970E-ECC2FEA081D5} + {10D2CAE8-0888-4817-81AC-55927D716283} diff --git a/wpd/WpdWudfSampleDriver/WpdWudfSampleDriver.htm b/wpd/WpdWudfSampleDriver/WpdWudfSampleDriver.htm new file mode 100644 index 00000000..6468554e --- /dev/null +++ b/wpd/WpdWudfSampleDriver/WpdWudfSampleDriver.htm @@ -0,0 +1,496 @@ + + + + + + + + +WPD Sample Driver + + + + + + + + + +
+ +

Windows Portable Device (WPD) Sample +Driver

+ +

Summary

+ +

This sample contains +working source code for a WPD driver.  +WPD Drivers are built using the Windows User-Mode Driver Foundation with +special processing added to handle WPD messages.

+ +

Building a new WPD Driver

+ +

You are encouraged to use +this sample code to start building your own WPD Driver. Modify the sample to +add your own features.

+ +

The following is a +suggested roadmap to developing your driver:

+ +

*       +Create +WPD driver shell

+ +

*       +Use +sample driver as base

+ +

*       +Update +the INF to install this driver for your device (it will not actually do +anything with the device yet)

+ +

*       +Start +implementing functionality.  This is +where the driver will start interacting with the device:

+ +

*       +Object +Enumeration

+ +

*       +WPD_CATEGORY_OBJECT_ENUMERATION

+ +

*       +Properties

+ +

*       +Implement +Reads, Writes

+ +

*       +WPD_CATEGORY_OBJECT_PROPERTIES

+ +

*       +Transfer

+ +

*       +Implement +Resource enumeration, reads, writes

+ +

*       +WPD_CATEGORY_OBJECT_RESOURCES

+ +

*       +Capabilities

+ +

*       +WPD_CATEGORY_CAPABILITIES

+ +

*       +Remaining +commands

+ +

Building the Sample

+ +

Open a free or checked +DDK build environment, go to this directory, and run build. This creates +WpdWudfSampleDriver.dll in the Objfre or Objchk directory. Before the sample can be used, it must be +installed by running the “Add Hardware” Wizard from Control Panel:

+ +

1. Launch the Windows +"Control Panel".

+ +

2. Double Click the +"Add Hardware" icon (Click “Classic View” link on the left hand pane +if you can’t find it).

+ +

3. The "Add +hardware" Wizard should launch, press the "Next" button. (The +wizard will do a quick search for devices already installed on the system.  It may take a minute or two.)

+ +

4. Choose the +"Install the hardware that I manually select from a list (Advanced)" +option and press the "Next" button.

+ +

5. A list of device +categories will be shown.  Scroll to the +very end of the list and select "Windows Portable Devices" option, +and click “Next”.

+ +

6. Press the "Have +Disk" button and browse to the location of the device .INF file.

+ +

7. Choose the appropriate +device to install ("Microsoft WPD Sample” for example) and press the +"Next" button.

+ +

8. After the files have +been copied to the system, the device should be installed (you can verify this +by looking in “Device Manager”).  You can +now run WPD applications.

+ +

Testing the WPD Driver

+ +

To test the WPD Driver, double +click the appropriate WPD device icon in “My Computer” to start browsing the +sample device contents.  Or use the WpdInfo +development tool included in this kit.

+ +

Supported Configurations

+ +

The WPD DDK sample driver +has been tested in checked and free builds for both 32 and 64-bit platforms.

+ +

CODE TOUR

+ +

File Manifest

+ +
File                                Description
ContextMap.h                        Data structure for storing and retrieving driver contexts
Device.cpp                          Driver's IWDFDevice implementation
Device.h                            Header file for driver's IWDFDevice implementation
DeviceObjectFakeContent.h           Encapsulates the WPD device object
Driver.cpp                          Driver’s IDriverEntry implementation 
Driver.h                            Header file for driver's IDriverEntry implementation
FakeContactContent.h                Encapsulates a contact entry
FakeContent.h                       Encapsulates a generic entry
FakeDevice.h                        Implementation of an abstract device (this sample does not talk to real hardware)
FakeImageContent.h                  Encapsulates an image data entry
FakeMusicContent.h                  Encapsulates a music data entry
FakeVideoContent.h                  Encapsulates a video data entry
helpers.cpp                         Miscellaneous helper functions
helpers.h                           Miscellaneous helper function definitions
MAKEFILE                            Makefile
makefile.inc                        Makefile
Queue.cpp                           Driver's queue implementation
NetworkConfigFakeContent.h          Encapsulates a NetworkConfiguration functional object
Queue.h                             Header file for driver’s queue implementation
RenderingInformationFakeContent.h   Encapsulates a RenderinfInformation functional object
resource.h                          Resource header
SampleAudioAnnotation.wav           Sample audio annotation data
SampleContactPhoto.png              Sample photo for a contact
SampleDeviceIcon.ico                Sample device icon
SampleExternalStorageIcon.ico       Sample storage icon
SampleImage.jpg                     Sample image data
SampleImageThumbnail.jpg            Sample thumbnail
SampleInternalStorageIcon.ico       Sample storage icon
SampleMusic.wma                     Sample music data
SampleVideo.wmv                     Sample video data
sources                             Sources file
stdafx.h                            Precompiled header file
StorageObjectFakeContent.h          Encapsulates the behavior for a Storage functional object
WpdBaseDriver.cpp                   Implements the main WPD message handler which unpacks and dispatches WPD messages
WpdBaseDriver.h                     Header file for the main WPD message handler
WpdCapabilities.cpp                 Implements the commands related to Capabilities
WpdCapabilities.h                   Header file for Capabilities implementation
WpdNetworkConfig.cpp                Implements the commands related to Network Configuration functional object
WpdNetworkConfig.h                  Header file for commands related to Network Configuration functional object
WpdObjectEnum.cpp                   Implements the commands related to enumerating contents
WpdObjectEnum.h                     Header file for content enumeration implementation
WpdObjectManagement.cpp             Implements the commands related to managing contents
WpdObjectManagement.h               Header file for commands related to managing contents
WpdObjectProperties.cpp             Implements the commands related to handling object meta-data
WpdObjectProperties.h               Header file for commands related to handling object meta-data
WpdObjectPropertiesBulk.cpp         Implements the commands related to bulk handling of object meta-data
WpdObjectPropertiesBulk.h           Header file for commands related to bulk handling of object meta-data
WpdObjectResources.cpp              Implements the commands related to transferring data
WpdObjectResources.h                Header file for commands related to transferring data
WpdStorage.cpp                      Implements the commands related to Storage functional object
WpdStorage.h                        Header file for commands related to Storage functional object
WpdWudfSampleDriver.cpp             Main DLL file
WpdWudfSampleDriver.def             Exports
WpdWudfSampleDriver.idl             Component Interface file
WpdWudfSampleDriver.inf             Sample Device INF file
WpdWudfSampleDriver.rc              Resource file
WpdWudfSampleDriver.rgs             ATL Self registration file
 
 
+ +

Top of page +

+ +
 
+ + + + + +
+

 

+
+ +
 
 
+ +

© +1999 Microsoft Corporation

+ +
+ + + + diff --git a/wpd/WpdWudfSampleDriver/WpdWudfSampleDriver.sln b/wpd/WpdWudfSampleDriver/WpdWudfSampleDriver.sln index 58705fa8..84cd07d7 100644 --- a/wpd/WpdWudfSampleDriver/WpdWudfSampleDriver.sln +++ b/wpd/WpdWudfSampleDriver/WpdWudfSampleDriver.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WpdWudfSampleDriver", "WpdWudfSampleDriver.vcxproj", "{1B4BD322-6FB3-46C9-87CD-D0CFED5EC3A2}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WpdWudfSampleDriver", "WpdWudfSampleDriver.vcxproj", "{5FE7B5AC-67C9-42B7-B687-D775D7721761}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +13,14 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {1B4BD322-6FB3-46C9-87CD-D0CFED5EC3A2}.Debug|Win32.ActiveCfg = Debug|Win32 - {1B4BD322-6FB3-46C9-87CD-D0CFED5EC3A2}.Debug|Win32.Build.0 = Debug|Win32 - {1B4BD322-6FB3-46C9-87CD-D0CFED5EC3A2}.Release|Win32.ActiveCfg = Release|Win32 - {1B4BD322-6FB3-46C9-87CD-D0CFED5EC3A2}.Release|Win32.Build.0 = Release|Win32 - {1B4BD322-6FB3-46C9-87CD-D0CFED5EC3A2}.Debug|x64.ActiveCfg = Debug|x64 - {1B4BD322-6FB3-46C9-87CD-D0CFED5EC3A2}.Debug|x64.Build.0 = Debug|x64 - {1B4BD322-6FB3-46C9-87CD-D0CFED5EC3A2}.Release|x64.ActiveCfg = Release|x64 - {1B4BD322-6FB3-46C9-87CD-D0CFED5EC3A2}.Release|x64.Build.0 = Release|x64 + {5FE7B5AC-67C9-42B7-B687-D775D7721761}.Debug|Win32.ActiveCfg = Debug|Win32 + {5FE7B5AC-67C9-42B7-B687-D775D7721761}.Debug|Win32.Build.0 = Debug|Win32 + {5FE7B5AC-67C9-42B7-B687-D775D7721761}.Release|Win32.ActiveCfg = Release|Win32 + {5FE7B5AC-67C9-42B7-B687-D775D7721761}.Release|Win32.Build.0 = Release|Win32 + {5FE7B5AC-67C9-42B7-B687-D775D7721761}.Debug|x64.ActiveCfg = Debug|x64 + {5FE7B5AC-67C9-42B7-B687-D775D7721761}.Debug|x64.Build.0 = Debug|x64 + {5FE7B5AC-67C9-42B7-B687-D775D7721761}.Release|x64.ActiveCfg = Release|x64 + {5FE7B5AC-67C9-42B7-B687-D775D7721761}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/wpd/WpdWudfSampleDriver/WpdWudfSampleDriver.vcxproj b/wpd/WpdWudfSampleDriver/WpdWudfSampleDriver.vcxproj index 8a233df1..34a93630 100644 --- a/wpd/WpdWudfSampleDriver/WpdWudfSampleDriver.vcxproj +++ b/wpd/WpdWudfSampleDriver/WpdWudfSampleDriver.vcxproj @@ -19,13 +19,13 @@
- {1B4BD322-6FB3-46C9-87CD-D0CFED5EC3A2} + {5FE7B5AC-67C9-42B7-B687-D775D7721761} $(MSBuildProjectName) 1 1 Debug Win32 - {ADD979C5-C00B-421A-BFE9-D2F1CEFB4506} + {E027B7B1-FCC5-49F8-BC8F-EEEFDECC6064} diff --git a/wpd/WpdWudfSampleDriver/WpdWudfSampleDriver.vcxproj.Filters b/wpd/WpdWudfSampleDriver/WpdWudfSampleDriver.vcxproj.Filters index 1e97b94a..35ee711f 100644 --- a/wpd/WpdWudfSampleDriver/WpdWudfSampleDriver.vcxproj.Filters +++ b/wpd/WpdWudfSampleDriver/WpdWudfSampleDriver.vcxproj.Filters @@ -3,19 +3,19 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* - {86FFE4D5-28B8-426F-95B1-81FDB79E3429} + {A0952C7E-AD1D-4BDC-A5D4-23AB2CCA70DB} h;hpp;hxx;hm;inl;inc;xsd - {1B74CA7F-AADA-48C5-A07E-613B12552F0A} + {6C6CAD3E-05C8-49A0-A643-041976D083AC} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml - {32ED42ED-1EA9-4DEC-BC65-D8A230B6FE7B} + {09BED7DF-74CB-49CC-B3E3-BD05003E23F5} inf;inv;inx;mof;mc; - {86D6608F-9073-44EF-A27B-7885C3084EAB} + {882CF447-FA9C-4E3F-AB69-826D25BD8F1D} -- cgit v1.3.1