Skip to content

04 ExtendedUniversalCppSupport

JackHeeley edited this page Mar 27, 2022 · 14 revisions

Extended Support Library

This library exists to demonstrate the principle of preserving the minimal viable feature set for the Basic Support Library. That principle (and therefore a separation betweeen basic and extended features) is important to manage the reuse costs. Basic support provides a single homogenized approach to writing modern C++ business logic 'anywhere'. So it deliberately excludes important technologies needed by fully formed solutions, things like database support, GUI tooling, and hardware manipulation and so on. What you happen to need from this extended set varies from project to project. The ExtendedUniversalCppSupport library exists as a structural response to this need. The library content is limited and determined by the goals of this training example.

Features

This particular Extended Support Library example adds features needed to achieve access to kernel devices (on Windows) and to allow efficient data capture from device to disk file. It does this mainly to show that modular decomposition based on recognizing conceptually different capabilities, or sets of features has value. It is worth the initial effort just for the for ease of maintenance that arises by decomposing support logic into manageable sets of features that are related in a strong way.

This library supplies device_discoverer - a feature that allow kernel drivers for hardware to be identified on the system; and device - an object presenting a generic representation of the basic interactions (open close seek read write and i/o control) that programs need when they interoperate with kernel devices. It also supplies (windows) memory mapped file support in memory_mapped_file as an efficient way to provide and save a large data buffer. The memory mapped file feature avoids a large memory copy. memory_mapped_file uses gsl::span as a modern c++ language way to represent the (single) memory buffer without resorting to widespread use of raw pointers.

device_type_directory is a singleton look-up table (std::map) to relate a plaform agnostic way to reference a class of devices to the (Windows) platform specific GUID string form used.

There are also two lock objects RAII_cd_exclusive_access_lock and RAII_cd_physical_lock supplied in headers.

The availability of these features in this library makes the building of cd_rom_device very easy to write, use, follow and maintain. This arises partly because the extended library approach achieves a good level of 'complexity encapsulation'. Much of that is down to discipline of applying the PIMPL idiom in widespread fashion.

Remarks and Limitations

On Windows, if you know that the optical drive has been mounted, of course you could 'rip' it with less code, simply by using E.g. deviceName = "\\\\.\\X:" where X is the drive letter for a known mounted volume. But this library code is intended to demonstrate how a user mode program can find, enumerate and access any windows kernel mode device driver, provided that it registers a PnP name in the orthodox way, (e.g. WDM drivers use IoRegisterDeviceInterface), and how you can filter and combine the low-level features that such a device driver exports into user space, and exploit them to build logical features that are tailored to the exact needs of your program.

cd_rom_device builds a set of features which are limited to the purpose of this sample. It is in no way intended to expose the full functionality of the windows CDROM driver stack. Some CDROM devices do not support lock, eject and load by program.

device, as implemented by App3Dev, offers only synchronous device access (asynchronous device i/o has been dropped). This is because modern C++ offers a more general way to build asynchronous behaviour (std::async) that addresses a broader set of objectives (see SampleProgram main.cpp for an example).