├── .gitignore
├── CONTRIBUTORS
├── CryptoSettings.props
├── CustomBuild
├── mc.props
├── mc.targets
└── mc.xml
├── Globals
├── Globals.vcxproj
├── Globals.vcxproj.filters
├── Interface.h
├── ReadMe.txt
├── Version.h
├── stdafx.cpp
├── stdafx.h
└── targetver.h
├── HIDEmulator.sln
├── HidEmulator
├── Driver.props
├── Driver32.props
├── Driver64.props
├── Emulator.cpp
├── Emulator.h
├── EmulatorContext.cpp
├── EmulatorContext.h
├── EmulatorState.cpp
├── EmulatorState.h
├── HID.h
├── HIDReportData.h
├── HidDescriptor.h
├── HidEmulator.cpp
├── HidEmulator.hid
├── HidEmulator.rc
├── HidEmulator.vcxproj
├── HidEmulator.vcxproj.filters
├── HidEmulatorCodes.h
├── HidEmulatorKmdf.cpp
├── HidEmulatorKmdf.def
├── HidEmulatorKmdf.rc
├── HidEmulatorKmdf.vcxproj
├── HidEmulatorKmdf.vcxproj.filters
├── HidEmulatorKmdfCodes.mc
├── HidReportDescriptor.h
├── Signer.vcxproj
├── Signer.vcxproj.filters
├── StdDescriptors.h
├── WdfObjectDeleter.cpp
├── WdfObjectDeleter.h
├── WdfObjectLock.cpp
├── WdfObjectLock.h
├── WdfRequestCompleter.cpp
├── WdfRequestCompleter.h
├── WdfRequestRequeuer.cpp
├── WdfRequestRequeuer.h
├── inf
│ ├── amd64
│ │ └── HidEmulator.inf
│ └── i386
│ │ └── HidEmulator.inf
├── stdafx.cpp
└── stdafx.h
├── Installer
├── DriverPackage.cpp
├── DriverPackage.h
├── Installer.cpp
├── Installer.def
├── Installer.h
├── Installer.vcxproj
├── Installer.vcxproj.filters
├── InstallerBase.cpp
├── InstallerBase.h
├── InstallerCodes.mc
├── InstanceEnumerator.cpp
├── InstanceEnumerator.h
├── LastErrorPreserver.cpp
├── LastErrorPreserver.h
├── NonPnpDevnode.cpp
├── NonPnpDevnode.h
├── PreprocFlags.h
├── ReadMe.txt
├── RestartRequiredTracker.h
├── ServiceControlManager.cpp
├── ServiceControlManager.h
├── ServiceHandle.cpp
├── ServiceHandle.h
├── SystemInfoClass.cpp
├── SystemInfoClass.h
├── stdafx.cpp
├── stdafx.h
└── targetver.h
├── InstallerApp
├── InstallerApp.cpp
├── InstallerApp.rc
├── InstallerApp.vcxproj
├── InstallerApp.vcxproj.filters
├── ReadMe.txt
├── stdafx.cpp
├── stdafx.h
└── targetver.h
├── LICENSE
├── OcuInterface
├── AutoLocker.cpp
├── AutoLocker.h
├── FocusAppInfo.cpp
├── FocusAppInfo.h
├── ObjPool.cpp
├── ObjPool.h
├── OcuHidInstance.cpp
├── OcuHidInstance.h
├── OcuIcon.cpp
├── OcuIcon.h
├── OcuIconWindowClass.cpp
├── OcuIconWindowClass.h
├── OcuImage.cpp
├── OcuImage.h
├── OcuInterface.cpp
├── OcuInterface.h
├── OcuInterface.vcxproj
├── OcuInterface.vcxproj.filters
├── OcuInterfaceCodes.mc
├── Overlapped.cpp
├── Overlapped.h
├── PreprocFlags.h
├── ReadMe.txt
├── hidpi.h
├── hidsdi.h
├── hidusage.h
├── stdafx.cpp
├── stdafx.h
└── targetver.h
├── OverlayHarness
├── GdiplusInitializer.cpp
├── GdiplusInitializer.h
├── OverlayHarness.cpp
├── OverlayHarness.rc
├── OverlayHarness.vcxproj
├── OverlayHarness.vcxproj.filters
├── ReadMe.txt
├── ResourcePng.cpp
├── ResourcePng.h
├── ResourceStream.cpp
├── ResourceStream.h
├── circle_icons
│ ├── circle_01.png
│ ├── circle_02.png
│ ├── circle_03.png
│ ├── circle_04.png
│ ├── circle_05.png
│ ├── circle_06.png
│ ├── circle_07.png
│ ├── circle_08.png
│ ├── circle_09.png
│ ├── circle_10.png
│ ├── circle_11.png
│ ├── circle_12.png
│ ├── circle_13.png
│ ├── circle_14.png
│ ├── circle_15.png
│ └── circle_16.png
├── resource.h
├── stdafx.cpp
├── stdafx.h
└── targetver.h
├── Resource
└── Certificate
│ ├── DigiCert Assured ID Root CA.crt
│ ├── MakeTestCert.bat
│ └── Readme.txt
├── TestHarness
├── ReadMe.txt
├── TestHarness.cpp
├── TestHarness.vcxproj
├── TestHarness.vcxproj.filters
├── stdafx.cpp
├── stdafx.h
└── targetver.h
├── TouchDisplay
├── ReadMe.txt
├── TouchDisplay.cpp
├── TouchDisplay.h
├── TouchDisplay.ico
├── TouchDisplay.rc
├── TouchDisplay.vcxproj
├── TouchDisplay.vcxproj.filters
├── TouchRepresentation.cpp
├── TouchRepresentation.h
├── resource.h
├── small.ico
├── stdafx.cpp
├── stdafx.h
└── targetver.h
├── WinDDK.props
├── contrib
├── amd64
│ └── hid.lib
└── i386
│ └── hid.lib
├── newdev
├── ReadMe.txt
├── newdev.cpp
├── newdev.def
├── newdev.h
├── newdev.vcxproj
├── newdev.vcxproj.filters
├── stdafx.cpp
└── stdafx.h
└── tools
├── HCLIENT.EXE
└── dt
├── BatSys.upg
├── Dt.exe
├── PwrDev.upg
├── Tparse.dll
├── Tparse.lib
├── VESACmnd.upg
├── VESAVC.upg
├── andisp.upg
├── andisply.hid
├── button.upg
├── consume.upg
├── delimit.hid
├── desktop.upg
├── digit.hid
├── digit.upg
├── display.hid
├── dt.ini
├── gaming.upg
├── joystk.hid
├── kbd.upg
├── keybrd.hid
├── leds.upg
├── mon_enum.upg
├── monitor.hid
├── monitor.upg
├── mouse.hid
├── ordinal.upg
├── pwr.hid
├── readme.txt
├── remote.hid
├── sim.upg
├── sports.upg
├── tele.hid
├── tele.upg
├── unicode.upg
├── vendor1.upg
└── vr.upg
/.gitignore:
--------------------------------------------------------------------------------
1 | *.swp
2 | *.log
3 | *.dbg
4 | *.opensdf
5 | *.sdf
6 | Release/
7 | Debug/
8 | *.CppClean.log
9 | *.unsuccessfulbuild
10 | *.suo
11 | ipch
12 | MSG00001.bin
13 | HidEmulator/HidEmulatorKmdfCodes.h
14 | HidEmulator/HidEmulatorKmdfCodes.rc
15 | Installer/InstallerCodes.h
16 | Installer/InstallerCodes.rc
17 | OcuInterface/OcuInterfaceCodes.h
18 | OcuInterface/OcuInterfaceCodes.rc
19 | *.user
20 | InstallerApp/InstallerApp.aps
21 | *.aps
22 |
--------------------------------------------------------------------------------
/CryptoSettings.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | En1Fm1ksp;
6 | $(SolutionDir)Resource\Certificate\DigiCert Assured ID Root CA.crt
7 | 1
8 |
9 |
10 |
11 |
12 |
13 | $(CertPass)
14 |
15 |
16 | $(XSCPath)
17 |
18 |
19 | $(CrossSign)
20 |
21 |
22 |
--------------------------------------------------------------------------------
/CustomBuild/mc.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 | BeforeClCompile
6 |
7 |
8 |
9 | _SelectedFiles;ResolveAssemblyReferences;$(McCompilerDependsOn)
10 |
11 |
12 |
13 | true
14 | $(TargetFileName)
15 | $(ProjectDir)
16 | $(ProjectDir)
17 | $(ProjectDir)
18 |
19 | h
20 |
21 | mc.exe [AllOptions] [AdditionalOptions] [Inputs]
22 | %(HeaderOutputPath)%(Filename).%(HFileExtension)
23 | %(ResourceOutputPath)%(Filename).rc
24 | %(DbgCDest)%(Filename).dbg
25 | true
26 | Compiling messages...
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/CustomBuild/mc.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
6 |
7 | McCompile
8 |
9 |
10 |
11 |
12 | $(ComputeLinkInputsTargets);
13 | ComputeMcCompilerOutput;
14 |
15 |
16 |
20 | $(MSBuildThisFileDirectory)$(MSBuildThisFileName).xml
21 |
22 |
30 |
31 |
32 |
33 |
34 |
35 | @(McCompiler, '|')
36 |
37 |
38 |
39 |
40 |
41 |
42 |
45 |
49 |
67 |
68 |
69 |
70 |
71 |
74 |
75 | <_EmbedManagedResourceFile Include="@(McCompiler->Metadata('Outputs')->Distinct()->ClearMetadata())" Condition="'%(McCompiler.ExcludedFromBuild)' != 'true'"/>
76 |
77 |
78 |
79 |
--------------------------------------------------------------------------------
/Globals/Globals.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hpp;hxx;hm;inl;inc;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | Header Files
23 |
24 |
25 | Header Files
26 |
27 |
28 | Header Files
29 |
30 |
31 | Header Files
32 |
33 |
34 |
35 |
36 | Source Files
37 |
38 |
39 |
--------------------------------------------------------------------------------
/Globals/Interface.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | // HID vendor ID:
4 | #define OCUHID_VENDOR_ID 0xF182
5 |
6 | // Leap Motion HID Product ID
7 | #define OCUHID_EMULATED_DEVICE 0x1000
8 |
9 | // HID Interface
10 | #define OCUHID_INTERFACE_VERSION 1
11 |
12 | // Maximum simaltaneous touch report count
13 | #define MAX_TOUCHREPORT_COUNT 2
14 |
15 | // Report identifiers:
16 | enum
17 | {
18 | REPORTID_FINGERS = 1,
19 | REPORTID_MAXIMUMCOUNT,
20 | REPORTID_FEATURE,
21 | REPORTID_MOUSE,
22 | REPORTID_SYNTHESIZE,
23 | REPORTID_RESETTOUCHSTATE,
24 | REPORTID_RESETMOUSESTATE,
25 | REPORTID_NULL
26 | };
27 |
28 | // This is the mode of operation that the HidEmulator is going to operate in.
29 | // These modes are documented in MSDN, but their operating mode is pretty straightforward:
30 | //
31 | // The mouse input mode means that the device will be treated like a mouse with a continuous
32 | // presence on screen. Signalling may be differential or absolute (but is typically absolute).
33 | // Mouse input mode also means that the mouse report descriptor is used, instead of the touch
34 | // descriptor.
35 | //
36 | // The single touch input mode means that only one contact point is interpreted, and the other
37 | // inputs will be ignored. Otherwise it functions the same as multitouch.
38 | //
39 | // In mulititouch mode, full multitouch capabilities are available. More than one contact is
40 | // supported, as long as each contact has its own contact identifier.
41 | enum DevInMode
42 | {
43 | MODE_MOUSE,
44 | MODE_SINGLE_TOUCH,
45 | MODE_MULTI_TOUCH
46 | };
47 |
48 | #pragma pack(push, 1)
49 |
50 | ///
51 | /// Feature report header, included as a base class in feature reporting
52 | /// types. This choice allows feature reports to be written to directly
53 | /// without clobbering the ReportID, which is required for the OS to process
54 | /// the feature report correctly.
55 | ///
56 | struct HID_INPUT_REPORT
57 | {
58 | UCHAR ReportID;
59 | };
60 |
61 | ///
62 | /// Report used to describe the maximum number of contact points this device supports
63 | ///
64 | struct HID_MAXIMUM_COUNT:
65 | HID_INPUT_REPORT
66 | {
67 | UCHAR MaxCount;
68 | UCHAR DeviceIndex;
69 | };
70 |
71 | ///
72 | /// Report used to assign the input mode or, optionally, query the current input mode
73 | ///
74 | struct HID_INPUT_MODE:
75 | HID_INPUT_REPORT
76 | {
77 | UCHAR InputMode;
78 | UCHAR DeviceIndex;
79 | };
80 |
81 | // Logical maximum for finger report. The logical maximum is used to refer to the domain of report coordinates.
82 | #define FINGER_REPORT_LMAX 4095
83 |
84 | ///
85 | /// A finger report. This is a single discrete input event, describing an atomic state of a single finger.
86 | ///
87 | union HID_FINGER_REPORT
88 | {
89 | struct
90 | {
91 | unsigned TipSwitch:1;
92 | unsigned InRange:1;
93 | unsigned Reserved2:6;
94 | };
95 | struct
96 | {
97 | UCHAR bStatus;
98 | UCHAR bContactId;
99 | USHORT cxData;
100 | USHORT cyData;
101 | USHORT wXData;
102 | USHORT wYData;
103 | };
104 | };
105 |
106 | ///
107 | /// This is a full gesture report. It includes a report identifier and up to MAX_TOUCHREPORT_COUNT
108 | /// touch reports.
109 | ///
110 | struct HID_GESTURE_REPORT:
111 | HID_INPUT_REPORT
112 | {
113 | // The actual contact structures
114 | HID_FINGER_REPORT contacts[MAX_TOUCHREPORT_COUNT];
115 |
116 | // The actual number of inputs in the contacts structure
117 | UCHAR ActualInputs;
118 | };
119 |
120 | // Assert some properties about the gesture report:
121 | static_assert( (long long)(char*)&((HID_FINGER_REPORT*)0)->cxData == 2ULL, "Offsets incorrect for the HID gesture report." );
122 |
123 | // The logical maximum of mouse report payload
124 | #define MOUSE_REPORT_LMAX 32767
125 |
126 | ///
127 | /// The mouse report structure, for use when the device input mode is set to mouse
128 | ///
129 | struct HID_MOUSE_REPORT:
130 | HID_INPUT_REPORT
131 | {
132 | union
133 | {
134 | struct
135 | {
136 | // Left mouse button
137 | unsigned Button1:1;
138 |
139 | // Right mouse button
140 | unsigned Button2:1;
141 |
142 | // Ignored, set to zero
143 | unsigned Reserved:6;
144 | };
145 | struct
146 | {
147 | // Flags, corresponding to the first structure in this union
148 | BYTE Flags;
149 | WORD x;
150 | WORD y;
151 | };
152 | };
153 | };
154 |
155 | ///
156 | /// This is used when the report is REPORTID_RESETTOUCHSTATE. It indicates
157 | /// the contact ID of the touch input to be reset. Up to MAX_TOUCHREPORT_COUNT
158 | /// may be sent at once.
159 | ///
160 | struct HID_RESET_REPORT
161 | {
162 | UCHAR ResetContactID[MAX_TOUCHREPORT_COUNT];
163 | UCHAR ActualInputs;
164 | };
165 |
166 | // Validate position:
167 | static_assert( (long long)(char*)&((HID_MOUSE_REPORT*)0)->x == 2ULL, "Incorrect offset in mouse report descriptor" );
168 |
169 | ///
170 | /// Synthesis report. The synthesis report is an omnibus structure that includes a report identifier and all
171 | /// of the possible reports that may either be generated by the HID emulator.
172 | ///
173 | struct HID_SYNTEHSIZE_REPORT:
174 | HID_INPUT_REPORT
175 | {
176 | union
177 | {
178 | UCHAR SynthesizedReportID;
179 |
180 | HID_GESTURE_REPORT GestureReport;
181 | HID_MOUSE_REPORT MouseReport;
182 | HID_RESET_REPORT ResetReport;
183 |
184 | // This field is not used directly; rather, its presence here is to ensure that the length
185 | // of the parent structure is 64 bytes.
186 | UCHAR RawInput[64];
187 | };
188 | };
189 |
190 | #pragma pack(pop)
191 |
--------------------------------------------------------------------------------
/Globals/ReadMe.txt:
--------------------------------------------------------------------------------
1 | ========================================================================
2 | STATIC LIBRARY : Globals Project Overview
3 | ========================================================================
4 |
5 | AppWizard has created this Globals library project for you.
6 |
7 | This file contains a summary of what you will find in each of the files that
8 | make up your Globals application.
9 |
10 |
11 | Globals.vcxproj
12 | This is the main project file for VC++ projects generated using an Application Wizard.
13 | It contains information about the version of Visual C++ that generated the file, and
14 | information about the platforms, configurations, and project features selected with the
15 | Application Wizard.
16 |
17 | Globals.vcxproj.filters
18 | This is the filters file for VC++ projects generated using an Application Wizard.
19 | It contains information about the association between the files in your project
20 | and the filters. This association is used in the IDE to show grouping of files with
21 | similar extensions under a specific node (for e.g. ".cpp" files are associated with the
22 | "Source Files" filter).
23 |
24 |
25 | /////////////////////////////////////////////////////////////////////////////
26 |
27 | StdAfx.h, StdAfx.cpp
28 | These files are used to build a precompiled header (PCH) file
29 | named Globals.pch and a precompiled types file named StdAfx.obj.
30 |
31 | /////////////////////////////////////////////////////////////////////////////
32 | Other notes:
33 |
34 | AppWizard uses "TODO:" comments to indicate parts of the source code you
35 | should add to or customize.
36 |
37 | /////////////////////////////////////////////////////////////////////////////
38 |
--------------------------------------------------------------------------------
/Globals/Version.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | // Version information used everywhere
4 | #define OCS_MAJ(x) (((x) & 0xF0000000) >> 28)
5 | #define OCS_MIN(x) (((x) & 0x0F000000) >> 24)
6 | #define OCS_REV(x) (((x) & 0x00FFFFFF) >> 0)
7 |
8 | #define OCS_VER(maj, min, rev) (((maj) << 28) | ((min) << 24) | rev)
9 |
10 | #define HIDEMULATOR_VERSION OCS_VER(0, 8, 2)
11 |
--------------------------------------------------------------------------------
/Globals/stdafx.cpp:
--------------------------------------------------------------------------------
1 | #include "stdafx.h"
2 |
--------------------------------------------------------------------------------
/Globals/stdafx.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "targetver.h"
4 |
--------------------------------------------------------------------------------
/Globals/targetver.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 |
--------------------------------------------------------------------------------
/HidEmulator/Driver.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | $(WINDDK)bin\selfsign;$(ExecutablePath)
7 | $(WINDDK)inc\crt;$(WINDDK)inc\api;$(WINDDK)inc\ddk;$(IncludePath)
8 |
9 |
10 |
11 | $(WinDDK)inc\ddk;$(WinDDK)inc\api;$(WinDDK)inc\crt;$(WinDDK)inc\wdf\kmdf\1.9;%(AdditionalIncludeDirectories)
12 |
13 |
14 | BufferOverflowK.lib;ntoskrnl.lib;hal.lib;wmilib.lib;sehupd.lib;nt.lib;hidclass.lib;%(AdditionalDependencies)
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/HidEmulator/Driver32.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | $(WinDDK)lib\Crt\i386;$(WinDDK)lib\wnet\i386;$(WinDDK)lib\wdf\kmdf\i386\1.9;%(AdditionalLibraryDirectories)
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/HidEmulator/Driver64.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | $(WinDDK)lib\Crt\amd64;$(WinDDK)lib\wnet\amd64;$(WinDDK)lib\wdf\kmdf\amd64\1.9;%(AdditionalLibraryDirectories)
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/HidEmulator/Emulator.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "HIDDescriptor.h"
3 | #include "EmulatorState.h"
4 |
5 | ///
6 | /// The core implementation of the HidEmulator
7 | ///
8 | ///
9 | /// The HidEmulator works using two ping-pong queues: One from the synthesis source, and one from the
10 | /// HID class driver. Requests from the client are put in the synthesis queue, and as read requests
11 | /// come in from the HID class driver, packets are dequeued from the synthesis queue and read into the
12 | /// requests from the class driver. A typical idle state is for the ReadQueue to have a few packets
13 | /// (typically two, but the number of read packets is system-configuable) and for the SynthQueue to
14 | /// be empty. If the ReadQueue is empty and the number of packets in the SynthQueue is increasing,
15 | /// it indicates that the system is being overdriven. You really need to drive the system quite fast
16 | /// to achive this case, but if it happens, severe performance penalties will be the result.
17 | ///
18 | class CEmulator
19 | {
20 | public:
21 | ///
22 | /// Constructs a new emulator with the given device object as the hDevice of that emulator
23 | ///
24 | CEmulator(WDFDEVICE hDevice);
25 | ~CEmulator(void);
26 |
27 | private:
28 | // Reflexive device pointer:
29 | WDFDEVICE m_hDevice;
30 |
31 | // Reflexive IO target
32 | WDFIOTARGET IoTarget;
33 |
34 | // Collection of IO operations to be fed into hidclass
35 | WDFQUEUE SynthQueue;
36 |
37 | // Collection of IRPs awaiting fulfillment from hidclass
38 | WDFQUEUE ReadQueue;
39 |
40 | // Input mode:
41 | DevInMode InputMode;
42 |
43 | // Emulator state:
44 | CEmulatorState m_state;
45 |
46 | private:
47 | ///
48 | /// Satisfies a matched read request and synthesis request
49 | ///
50 | /// Set to true if the initiator is a synthesis operation
51 | void Satisfy(WDFREQUEST ReadRequest, WDFREQUEST SynthRequest, bool bSynthesisInitiator);
52 |
53 | ///
54 | /// Either queues the specified request to the specified queue, or attempts to use the request to
55 | /// synthesize an input
56 | ///
57 | template
58 | void SatisfyOrEnqueue(WDFREQUEST Request);
59 |
60 | ///
61 | /// Gets the descriptor that describes the device, including an indication of the number of
62 | /// report descriptors.
63 | ///
64 | void GetDeviceDescriptor(WDFREQUEST Request);
65 |
66 | ///
67 | /// Gets general attributes describe the device
68 | ///
69 | void GetDeviceAttributes(WDFREQUEST Request);
70 |
71 | ///
72 | /// Gets the one and only report descriptor describing the reports generated by the device.
73 | /// The output of this handler is used by the HID class to create child devices.
74 | ///
75 | void GetReportDescriptor(WDFREQUEST Request);
76 |
77 | ///
78 | /// String recovery request handler
79 | ///
80 | void GetString(WDFREQUEST Request);
81 |
82 | ///
83 | /// Feature get method
84 | ///
85 | void GetFeature(WDFREQUEST Request);
86 |
87 | ///
88 | /// Feature set method
89 | ///
90 | void SetFeature(WDFREQUEST Request);
91 |
92 | public:
93 | const CEmulatorState& GetState(void) const {return m_state;}
94 |
95 | ///
96 | /// Causes a request to be pended to this emulator's own internal queue for later synthesis.
97 | /// Useful for debugging, but also used by CEmulatorContext to restore state in the event of
98 | /// unexpected client termination.
99 | ///
100 | NTSTATUS QueueSynthesisToSelf(const HID_SYNTEHSIZE_REPORT& report);
101 |
102 | // Generic handlers:
103 | NTSTATUS DeviceControlInternal(PDEVICE_OBJECT DeviceObject, PIRP Irp);
104 | EVT_WDF_IO_QUEUE_IO_INTERNAL_DEVICE_CONTROL EvtInternalDeviceControl;
105 | };
106 |
107 | // Make type information available:
108 | WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(CEmulator, GetDeviceContext)
109 |
110 | // Forward declarations:
111 | EVT_WDF_OBJECT_CONTEXT_CLEANUP EvtEmulatorCleanup;
112 | EVT_WDF_IO_QUEUE_IO_INTERNAL_DEVICE_CONTROL EvtInternalDeviceControl;
113 |
--------------------------------------------------------------------------------
/HidEmulator/EmulatorContext.cpp:
--------------------------------------------------------------------------------
1 | #include "StdAfx.h"
2 | #include "EmulatorContext.h"
3 | #include "Emulator.h"
4 |
5 | CEmulatorContext::CEmulatorContext(CEmulator* pParent):
6 | m_pParent(pParent)
7 | {
8 | }
9 |
10 | CEmulatorContext::~CEmulatorContext(void)
11 | {
12 | HID_SYNTEHSIZE_REPORT report;
13 | memset(&report, 0, sizeof(report));
14 | report.SynthesizedReportID = REPORTID_RESETTOUCHSTATE;
15 |
16 | // Run through each state in the touchState array:
17 | for(BYTE i = 0; i < ARRAYSIZE(m_state.touchState); i++)
18 | {
19 | auto& cur = m_state.touchState[i];
20 | if(!cur.TipSwitch)
21 | // No need to reset this finger:
22 | continue;
23 |
24 | // The finger needs to have a regenerated state that is equal
25 | // to the current position, minus whatever keys are assigned at
26 | // this moment.
27 | auto& reset = report.ResetReport;
28 | reset.ResetContactID[reset.ActualInputs] = i;
29 |
30 | if(++reset.ActualInputs == 2)
31 | // Emulate this report.
32 | {
33 | m_pParent->QueueSynthesisToSelf(report);
34 | reset.ActualInputs = 0;
35 | }
36 | }
37 |
38 | // Tail case, if there's anything still unsynthesized
39 | if(report.ResetReport.ActualInputs)
40 | m_pParent->QueueSynthesisToSelf(report);
41 |
42 | // Reset mouse events as needed
43 | if(m_state.mouseState.Button1 || m_state.mouseState.Button2)
44 | {
45 | report.SynthesizedReportID = REPORTID_RESETMOUSESTATE;
46 | m_pParent->QueueSynthesisToSelf(report);
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/HidEmulator/EmulatorContext.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "EmulatorState.h"
3 |
4 | class CEmulator;
5 |
6 | ///
7 | /// Unused. If a way was needed to track individual clients, this class would provide it.
8 | /// Currently, it is difficult to track who has handles open to the HidEmualtor because the
9 | /// HID class driver does not allow direct handles to be opened to the device, nor does it
10 | /// notify the device when a handle is opened or closed.
11 | ///
12 | class CEmulatorContext
13 | {
14 | public:
15 | CEmulatorContext(CEmulator* pParent);
16 | ~CEmulatorContext(void);
17 |
18 | private:
19 | // The parent emulator of this context
20 | CEmulator* m_pParent;
21 |
22 | // State known to the system that is due to this emulator context:
23 | CEmulatorState m_state;
24 | };
25 |
26 | WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(CEmulatorContext, GetFileObjectContext)
27 |
--------------------------------------------------------------------------------
/HidEmulator/EmulatorState.cpp:
--------------------------------------------------------------------------------
1 | #include "StdAfx.h"
2 | #include "EmulatorState.h"
3 |
4 | CEmulatorState::CEmulatorState(void)
5 | {
6 | }
7 |
8 | CEmulatorState::~CEmulatorState(void)
9 | {
10 | }
11 |
--------------------------------------------------------------------------------
/HidEmulator/EmulatorState.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | ///
4 | /// Kernel-mode state tracking structure of the HID emulator.
5 | ///
6 | ///
7 | /// In the event that a client goes away, it may be necessary to reset the state of the HID emualtor.
8 | /// In that case, up-events are sent to the operating system for each contact point currently down
9 | /// on the screen, thereby freeing any "stuck mouse" situation that may arise if an application crashes
10 | /// while synthesizing a touch event.
11 | ///
12 | /// Note also that only those states that are due to a particular client are reset. No touch events
13 | /// are synthesized to an "up" state if a client crashes, provided that client is not currently the cause
14 | /// of a finger press.
15 | ///
16 | class CEmulatorState
17 | {
18 | public:
19 | CEmulatorState(void);
20 | ~CEmulatorState(void);
21 |
22 | public:
23 | // Current state of each fingertip. This is defined as the last input synthesized on the interface.
24 | HID_FINGER_REPORT touchState[16];
25 |
26 | // Current mouse state, as synthesized by the client.
27 | HID_MOUSE_REPORT mouseState;
28 | };
29 |
30 |
--------------------------------------------------------------------------------
/HidEmulator/HidDescriptor.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #pragma pack(push, 1)
3 |
4 | #define __INCLUDE_FROM_USB_DRIVER
5 | #define __INCLUDE_FROM_HID_DRIVER
6 | #define USB_CAN_BE_DEVICE
7 |
8 | #include "HID.h"
9 | #include "HIDReportData.h"
10 | #include "HidReportDescriptor.h"
11 |
12 | ///
13 | /// This is a static global definition of the HID descriptor.
14 | ///
15 | ///
16 | /// The HID descriptor is a top-level descriptor that provides one piece of information:
17 | /// A description of the report descriptor. The report descriptor has the rest of the
18 | /// information about the device.
19 | ///
20 | static USB_HID_StdDescriptor_HID_t g_hidDesc =
21 | {
22 | 0x09, // length of HID descriptor
23 | 0x21, // descriptor type == HID 0x21
24 | 0x0100, // hid spec release
25 | 0x00, // country code == Not Specified
26 | 0x01, // number of HID class descriptors
27 |
28 | HID_DTYPE_Report, // descriptor type
29 | sizeof(g_reportDesc) // total length of report descriptor
30 | };
31 |
32 | // The length of the report descriptor is pretty important as it is a spec-defined value.
33 | // This assertion ensures that the length constraint is met.
34 | static_assert(sizeof(g_hidDesc) == 9, "HID descriptor size not precisely 9");
35 |
36 | #pragma pack(pop)
37 |
--------------------------------------------------------------------------------
/HidEmulator/HidEmulator.cpp:
--------------------------------------------------------------------------------
1 | #include "stdafx.h"
2 |
3 | // Forward declarations:
4 | void Unload(PDRIVER_OBJECT DriverObject);
5 | NTSTATUS AddDevice(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT PhysicalDeviceObject);
6 | NTSTATUS PassThrough(PDEVICE_OBJECT DeviceObject, PIRP Irp);
7 | NTSTATUS PowerPassThrough(PDEVICE_OBJECT DeviceObject, PIRP Irp);
8 |
9 | // Driver entrypoint
10 | extern "C"
11 | NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
12 | {
13 | NTSTATUS status;
14 |
15 | // Default almost everything:
16 | for each(auto*& p in DriverObject->MajorFunction)
17 | p = PassThrough;
18 |
19 | // Power IRP is special:
20 | DriverObject->MajorFunction[IRP_MJ_POWER] = PowerPassThrough;
21 |
22 | // AddDevice and Unload methods must be added, but here, do nothing.
23 | DriverObject->DriverExtension->AddDevice = AddDevice;
24 | DriverObject->DriverUnload = Unload;
25 |
26 | // Register with the HID minidriver. No driver extension is required so its size is
27 | // set to zero.
28 | HID_MINIDRIVER_REGISTRATION reg;
29 | memset(®, 0, sizeof(reg));
30 | reg.Revision = HID_REVISION;
31 | reg.DriverObject = DriverObject;
32 | reg.RegistryPath = RegistryPath;
33 | reg.DeviceExtensionSize = 0;
34 | reg.DevicesArePolled = false;
35 |
36 | // Invoke the minidriver registration routine. The reason we don't implement this
37 | // whole driver with the KMDF is because of this call: The HID port driver wants
38 | // ownership of the device extension, and KMDF wants the same thing, so the two
39 | // contend. Resolution of this contention is had by installing the KMDF driver as
40 | // a lower filter to this driver.
41 | status = HidRegisterMinidriver(®);
42 | if(!NT_SUCCESS(status))
43 | {
44 | OcsDebugPrint("Failed to register the mini driver (0x%08x)", status);
45 | return status;
46 | }
47 |
48 | OcsDebugPrint("OcuSpec WDF HID Emulator loaded");
49 | return status;
50 | }
51 |
52 | ///
53 | /// Unload routine for the driver
54 | ///
55 | void Unload(PDRIVER_OBJECT DriverObject)
56 | {
57 | OcsDebugPrint("OcuSpec HID Emulator unloaded");
58 | }
59 |
60 | NTSTATUS AddDevice(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT FunctionalDeviceObject)
61 | {
62 | // Do nothing except return success
63 | OcsDebugPrint("WDF AddDevice invoked");
64 | return STATUS_SUCCESS;
65 | }
66 |
67 | NTSTATUS PassThrough(PDEVICE_OBJECT DeviceObject, PIRP Irp)
68 | {
69 | // The passthrough routine does just that: It copies the current IRP stack location
70 | // to the next one, and allows the next driver in the chain to handle the request.
71 | IoSkipCurrentIrpStackLocation(Irp);
72 | return IoCallDriver(GET_NEXT_DEVICE_OBJECT(DeviceObject), Irp);
73 | }
74 |
75 | NTSTATUS PowerPassThrough(PDEVICE_OBJECT DeviceObject, PIRP Irp)
76 | {
77 | // The power pass-through operation is a little different. We need to indicate to
78 | // the power manager that it can start the next power IRP (for this driver), and then
79 | // we copy the current stack location to next and handle things as expected.
80 | PoStartNextPowerIrp(Irp);
81 | IoCopyCurrentIrpStackLocationToNext(Irp);
82 | return PoCallDriver(GET_NEXT_DEVICE_OBJECT(DeviceObject), Irp);
83 | }
--------------------------------------------------------------------------------
/HidEmulator/HidEmulator.hid:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leapmotion/mt-windows/74854757730c9801766883d13ed97bd9fb1b45bf/HidEmulator/HidEmulator.hid
--------------------------------------------------------------------------------
/HidEmulator/HidEmulator.rc:
--------------------------------------------------------------------------------
1 | #include "../Globals/Version.h"
2 | #include "afxres.h"
3 |
4 | /////////////////////////////////////////////////////////////////////////////
5 | //
6 | // Version
7 | //
8 |
9 | #undef OCS_VER
10 | #define OCS_VER(maj, min, rev) maj,min,rev
11 |
12 | VS_VERSION_INFO VERSIONINFO
13 | FILEVERSION HIDEMULATOR_VERSION
14 | PRODUCTVERSION HIDEMULATOR_VERSION
15 | FILEFLAGSMASK 0x17L
16 | #ifdef _DEBUG
17 | FILEFLAGS 0x1L
18 | #else
19 | FILEFLAGS 0x0L
20 | #endif
21 | FILEOS 0x4L
22 | FILETYPE 0x3L
23 | FILESUBTYPE 0x7L
24 | BEGIN
25 | BLOCK "StringFileInfo"
26 | BEGIN
27 | #undef OCS_VER
28 | #define OCS_VER(maj, min, rev) #maj ", " #min ", " #rev
29 | BLOCK "040904b0"
30 | BEGIN
31 | VALUE "CompanyName", "Leap Motion, Inc."
32 | VALUE "FileDescription", "Touch input emulation driver"
33 | VALUE "FileVersion", HIDEMULATOR_VERSION
34 | VALUE "InternalName", "HIDEmulator"
35 | VALUE "LegalCopyright", "Copyright (C) 2012-2013"
36 | VALUE "OriginalFilename", "HidEmulator.sys"
37 | VALUE "ProductName", "HidEmulator"
38 | VALUE "ProductVersion", HIDEMULATOR_VERSION
39 | END
40 | END
41 | BLOCK "VarFileInfo"
42 | BEGIN
43 | VALUE "Translation", 0x409, 1200
44 | END
45 | END
--------------------------------------------------------------------------------
/HidEmulator/HidEmulator.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {aa41bb4f-d699-4469-a8d3-7797e281c709}
6 |
7 |
8 | {f009a1e1-6122-48a4-8681-90f15d0148b7}
9 |
10 |
11 | {f12ff0da-5a37-4f56-ba29-41e2283ee589}
12 |
13 |
14 |
15 |
16 | Resource Files
17 |
18 |
19 |
20 |
21 | Source Files
22 |
23 |
24 | Source Files
25 |
26 |
27 |
28 |
29 | Header Files
30 |
31 |
32 | Header Files
33 |
34 |
35 |
--------------------------------------------------------------------------------
/HidEmulator/HidEmulatorCodes.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | //
3 | // Status values are 32 bit values layed out as follows:
4 | //
5 | // 3 2 1 0
6 | // 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
7 | // +---+-+-------------------------+-------------------------------+
8 | // |Sev|C| Facility | Code |
9 | // +---+-+-------------------------+-------------------------------+
10 | //
11 | // where
12 | //
13 | // Sev - is the severity code
14 | //
15 | // 00 - Success
16 | // 01 - Informational
17 | // 10 - Warning
18 | // 11 - Error
19 | //
20 | // C - is the Customer code flag
21 | //
22 | // Facility - is the facility code
23 | //
24 | // Code - is the facility's status code
25 | //
26 | //
27 | // Values are 32 bit values laid out as follows:
28 | //
29 | // 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
30 | // 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
31 | // +---+-+-+-----------------------+-------------------------------+
32 | // |Sev|C|R| Facility | Code |
33 | // +---+-+-+-----------------------+-------------------------------+
34 | //
35 | // where
36 | //
37 | // Sev - is the severity code
38 | //
39 | // 00 - Success
40 | // 01 - Informational
41 | // 10 - Warning
42 | // 11 - Error
43 | //
44 | // C - is the Customer code flag
45 | //
46 | // R - is a reserved bit
47 | //
48 | // Facility - is the facility code
49 | //
50 | // Code - is the facility's status code
51 | //
52 | //
53 | // Define the facility codes
54 | //
55 |
56 |
57 | //
58 | // Define the severity codes
59 | //
60 | #define OVL_STATUS_WARNING 0x2
61 | #define OVL_STATUS_SUCCESS 0x0
62 | #define OVL_STATUS_INFORMATION 0x1
63 | #define OVL_STATUS_ERROR 0x3
64 |
65 |
66 | //
67 | // MessageId: eHidInstFailure
68 | //
69 | // MessageText:
70 | //
71 | // General failure condition
72 | //
73 | #define eHidInstFailure ((eHidStatus)0xE0000000L)
74 |
75 |
--------------------------------------------------------------------------------
/HidEmulator/HidEmulatorKmdf.def:
--------------------------------------------------------------------------------
1 | LIBRARY
2 | EXPORTS
3 | DriverEntry
--------------------------------------------------------------------------------
/HidEmulator/HidEmulatorKmdf.rc:
--------------------------------------------------------------------------------
1 | #include "../Globals/Version.h"
2 |
3 | /////////////////////////////////////////////////////////////////////////////
4 | //
5 | // Version
6 | //
7 |
8 | #undef OCS_VER
9 | #define OCS_VER(maj, min, rev) maj,min,rev
10 |
11 | VS_VERSION_INFO VERSIONINFO
12 | FILEVERSION HIDEMULATOR_VERSION
13 | PRODUCTVERSION HIDEMULATOR_VERSION
14 | FILEFLAGSMASK 0x17L
15 | #ifdef _DEBUG
16 | FILEFLAGS 0x1L
17 | #else
18 | FILEFLAGS 0x0L
19 | #endif
20 | FILEOS 0x4L
21 | FILETYPE 0x3L
22 | FILESUBTYPE 0x7L
23 | BEGIN
24 | BLOCK "StringFileInfo"
25 | BEGIN
26 | #undef OCS_VER
27 | #define OCS_VER(maj, min, rev) #maj ", " #min ", " #rev
28 | BLOCK "040904b0"
29 | BEGIN
30 | VALUE "CompanyName", "Leap Motion, Inc."
31 | VALUE "FileDescription", "Kernel-mode user input redirection driver"
32 | VALUE "FileVersion", HIDEMULATOR_VERSION
33 | VALUE "InternalName", "KuirKbdFltr"
34 | VALUE "LegalCopyright", "Copyright (C) 2012-2013"
35 | VALUE "OriginalFilename", "HidEmulator.sys"
36 | VALUE "ProductName", "HidEmulator"
37 | VALUE "ProductVersion", HIDEMULATOR_VERSION
38 | END
39 | END
40 | BLOCK "VarFileInfo"
41 | BEGIN
42 | VALUE "Translation", 0x409, 1200
43 | END
44 | END
--------------------------------------------------------------------------------
/HidEmulator/HidEmulatorKmdf.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {aa41bb4f-d699-4469-a8d3-7797e281c709}
6 |
7 |
8 | {f009a1e1-6122-48a4-8681-90f15d0148b7}
9 |
10 |
11 | {f12ff0da-5a37-4f56-ba29-41e2283ee589}
12 |
13 |
14 | {a7e18323-5f56-48ba-b204-a45de42f3ea9}
15 |
16 |
17 |
18 |
19 | Resource Files
20 |
21 |
22 | Resource Files
23 |
24 |
25 |
26 |
27 | Source Files
28 |
29 |
30 | Source Files
31 |
32 |
33 | Source Files
34 |
35 |
36 | Source Files
37 |
38 |
39 | Source Files
40 |
41 |
42 | Source Files
43 |
44 |
45 | Source Files
46 |
47 |
48 | Source Files
49 |
50 |
51 | Source Files
52 |
53 |
54 |
55 |
56 | Header Files
57 |
58 |
59 | Header Files
60 |
61 |
62 | Header Files
63 |
64 |
65 | HID
66 |
67 |
68 | HID
69 |
70 |
71 | Header Files
72 |
73 |
74 | HID
75 |
76 |
77 | Header Files
78 |
79 |
80 | Header Files
81 |
82 |
83 | Header Files
84 |
85 |
86 | Header Files
87 |
88 |
89 | Header Files
90 |
91 |
92 | Header Files
93 |
94 |
95 | Header Files
96 |
97 |
98 |
99 |
100 | Resource Files
101 |
102 |
103 |
104 |
105 | Resource Files
106 |
107 |
108 |
--------------------------------------------------------------------------------
/HidEmulator/HidEmulatorKmdfCodes.mc:
--------------------------------------------------------------------------------
1 | ;#pragma once
2 | ;//
3 | ;// Status values are 32 bit values layed out as follows:
4 | ;//
5 | ;// 3 2 1 0
6 | ;// 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
7 | ;// +---+-+-------------------------+-------------------------------+
8 | ;// |Sev|C| Facility | Code |
9 | ;// +---+-+-------------------------+-------------------------------+
10 | ;//
11 | ;// where
12 | ;//
13 | ;// Sev - is the severity code
14 | ;//
15 | ;// 00 - Success
16 | ;// 01 - Informational
17 | ;// 10 - Warning
18 | ;// 11 - Error
19 | ;//
20 | ;// C - is the Customer code flag
21 | ;//
22 | ;// Facility - is the facility code
23 | ;//
24 | ;// Code - is the facility's status code
25 | ;//
26 |
27 | MessageIdTypedef=eHidStatus
28 |
29 | SeverityNames=(
30 | Success = 0x0 : OCUHID_STATUS_SUCCESS
31 | Informational = 0x1 : OCUHID_STATUS_INFORMATION
32 | Warning = 0x2 : OCUHID_STATUS_WARNING
33 | Error = 0x3 : OCUHID_STATUS_ERROR
34 | )
35 |
36 | FacilityNames=(
37 | HidEm = 0x0
38 | )
39 |
40 | MessageId=0
41 | Severity=Error
42 | Facility=HidEm
43 | SymbolicName=eHidInstFailure
44 | Language=English
45 | General failure condition
46 | .
47 |
--------------------------------------------------------------------------------
/HidEmulator/Signer.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {24de9df6-b408-4edf-a900-6d1d09815be4}
6 |
7 |
8 | {cf825af8-972d-454f-81ef-53ad28c03ece}
9 |
10 |
11 |
12 |
13 | i386
14 |
15 |
16 | amd64
17 |
18 |
19 |
--------------------------------------------------------------------------------
/HidEmulator/WdfObjectDeleter.cpp:
--------------------------------------------------------------------------------
1 | #include "StdAfx.h"
2 | #include "WdfObjectDeleter.h"
3 |
4 | CWdfObjectDeleter::CWdfObjectDeleter(WDFOBJECT Object):
5 | Object(Object)
6 | {
7 | }
8 |
9 | CWdfObjectDeleter::~CWdfObjectDeleter(void)
10 | {
11 | if(Object)
12 | // Delete the object
13 | WdfObjectDelete(Object);
14 | }
15 |
--------------------------------------------------------------------------------
/HidEmulator/WdfObjectDeleter.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | ///
4 | /// RAII object deleter
5 | ///
6 | class CWdfObjectDeleter
7 | {
8 | public:
9 | ///
10 | /// Deletes the passed object if it's still attached when this deleter is destroyed
11 | ///
12 | /// The object to be deleted
13 | CWdfObjectDeleter(WDFOBJECT Object);
14 | ~CWdfObjectDeleter(void);
15 |
16 | private:
17 | // The object to be deleted
18 | WDFOBJECT Object;
19 |
20 | public:
21 | ///
22 | /// Prevents this deleter from deleting the underlying request
23 | ///
24 | void Steal(void)
25 | {
26 | Object = nullptr;
27 | }
28 | };
29 |
30 |
--------------------------------------------------------------------------------
/HidEmulator/WdfObjectLock.cpp:
--------------------------------------------------------------------------------
1 | #include "StdAfx.h"
2 | #include "WdfObjectLock.h"
3 |
4 | CWdfObjectLock::CWdfObjectLock(WDFOBJECT obj):
5 | m_obj(obj)
6 | {
7 | // Acquire a lock on the object
8 | WdfObjectAcquireLock(m_obj);
9 | }
10 |
11 | CWdfObjectLock::~CWdfObjectLock(void)
12 | {
13 | // Logical inverse: Release the already-acquired lock
14 | WdfObjectReleaseLock(m_obj);
15 | }
16 |
--------------------------------------------------------------------------------
/HidEmulator/WdfObjectLock.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | ///
4 | /// RAII-style object lock
5 | ///
6 | class CWdfObjectLock
7 | {
8 | public:
9 | ///
10 | /// Locks the passed object, and saves it to be unlocked on destruction
11 | ///
12 | /// The object to be locked
13 | CWdfObjectLock(WDFOBJECT obj);
14 | ~CWdfObjectLock(void);
15 |
16 | WDFOBJECT m_obj;
17 | };
18 |
19 |
--------------------------------------------------------------------------------
/HidEmulator/WdfRequestCompleter.cpp:
--------------------------------------------------------------------------------
1 | #include "StdAfx.h"
2 | #include "WdfRequestCompleter.h"
3 |
4 | CWdfRequestCompleter::CWdfRequestCompleter(WDFREQUEST Request):
5 | Request(Request),
6 | Status(STATUS_SUCCESS)
7 | {
8 | }
9 |
10 | CWdfRequestCompleter::~CWdfRequestCompleter(void)
11 | {
12 | // Complete the packet unconditionally based on the current status value.
13 | WdfRequestComplete(Request, Status);
14 | }
15 |
--------------------------------------------------------------------------------
/HidEmulator/WdfRequestCompleter.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | ///
4 | /// Enables a request to be completed automatically at scope exit
5 | ///
6 | class CWdfRequestCompleter
7 | {
8 | public:
9 | CWdfRequestCompleter(WDFREQUEST Request);
10 | ~CWdfRequestCompleter(void);
11 |
12 | WDFREQUEST Request;
13 | NTSTATUS Status;
14 |
15 | ///
16 | /// Sets the status that the attached request should be completed with
17 | /// when this instance is destroyed
18 | ///
19 | /// The status to be assigned
20 | void SetStatus(NTSTATUS status) {Status = status;}
21 | };
22 |
23 |
--------------------------------------------------------------------------------
/HidEmulator/WdfRequestRequeuer.cpp:
--------------------------------------------------------------------------------
1 | #include "StdAfx.h"
2 | #include "WdfRequestRequeuer.h"
3 |
4 | CWdfRequestRequeuer::CWdfRequestRequeuer(WDFREQUEST Request, WDFQUEUE Queue):
5 | Request(Request),
6 | Queue(Queue)
7 | {
8 | }
9 |
10 | CWdfRequestRequeuer::~CWdfRequestRequeuer(void)
11 | {
12 | // Based on the status code (presumably of some other operation) we decide
13 | // what to do with our packet. Broadly, we only want to complete the packet
14 | // if the status was successful. Otherwise we put it into the queue, or if
15 | // the packet needs to go back to the queue it came from, we can just use
16 | // the requeue request.
17 |
18 | if(NT_SUCCESS(Status))
19 | // Gets completed successfully
20 | WdfRequestComplete(Request, Status);
21 | else if(Queue)
22 | // Goes on to a new queue
23 | WdfRequestForwardToIoQueue(Request, Queue);
24 | else
25 | // Goes back to where it came from.
26 | WdfRequestRequeue(Request);
27 | }
28 |
--------------------------------------------------------------------------------
/HidEmulator/WdfRequestRequeuer.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | ///
4 | /// Enables automatic requeuing of a request to the specified queue under certain conditions.
5 | ///
6 | ///
7 | /// NT_STATUS(Success) -> Complete Request with a status value of Success
8 | /// otherwise -> Return Request to the specified queue, based on queueing behavior
9 | ///
10 | class CWdfRequestRequeuer
11 | {
12 | public:
13 | /// The request to be managed
14 | ///
15 | /// The queue to which should be returned, or nullptr if WdfRequestRequeue
16 | /// should be called instead
17 | ///
18 | CWdfRequestRequeuer(WDFREQUEST Request, WDFQUEUE Queue = nullptr);
19 | ~CWdfRequestRequeuer(void);
20 |
21 | private:
22 | // This is the request that will be queued
23 | WDFREQUEST Request;
24 |
25 | // This is the queue to which the request will be queued
26 | WDFQUEUE Queue;
27 |
28 | public:
29 | NTSTATUS Status;
30 | };
31 |
32 |
--------------------------------------------------------------------------------
/HidEmulator/inf/amd64/HidEmulator.inf:
--------------------------------------------------------------------------------
1 | ; Copyright (c) 2012-2013 Leap Motion, Inc. All rights Reserved
2 | [Version]
3 | Signature="$WINDOWS NT$"
4 | Class=System
5 | ClassGuid={4D36E97D-E325-11CE-BFC1-08002BE10318}
6 | Provider=%MSFT%
7 | DriverVer=07/15/2013,1.0.1.4
8 | CatalogFile=HidEmulator.cat
9 |
10 | [DestinationDirs]
11 | DefaultDestDir = 12
12 |
13 | [SourceDisksNames]
14 | 1 = %DiskId1%,,,""
15 |
16 | [SourceDisksFiles]
17 | HidEmulator.sys = 1,,
18 | HidEmulatorKmdf.sys = 1,,
19 |
20 | ;*****************************************
21 | ; HidEmulator Install Section
22 | ;*****************************************
23 |
24 | [Manufacturer]
25 | %StdMfg%=Standard,NTamd64
26 |
27 | [Standard.NTamd64]
28 | ; HidEmulator fake device node pnp id
29 | %HidEmulator_Device.DeviceDesc%=HidEmulator_Device,HID\OcsEmulator
30 |
31 | [HidEmulator_Device.NT]
32 | CopyFiles=Drivers_Dir
33 |
34 | [HidEmulator_Device.NT.HW]
35 | AddReg=LowerFilter_AddReg
36 |
37 | [Drivers_Dir]
38 | HidEmulator.sys
39 | HidEmulatorKmdf.sys
40 |
41 | ;--------------
42 | ; Kmdf is installed as a lower filter to the HidEmulator driver
43 | [LowerFilter_AddReg]
44 | HKR,,LowerFilters,0x00010000,HidEmulatorKmdf
45 |
46 | ;-------------- Service installation
47 | [HidEmulator_Device.NT.Services]
48 | AddService = HidEmulator,803,HidEmulator_Service_Inst ; SPSVCINST_TAGTOFRONT | SPSVCINST_ASSOCSERVICE | SPSVCSINST_STARTSERVICE
49 | AddService = HidEmulatorKmdf,0,HidEmulatorKmdf_Service_Inst
50 |
51 | ; -------------- HID Emulator driver service install sections
52 | [HidEmulator_Service_Inst]
53 | DisplayName = %HidEmulator.SVCDESC%
54 | ServiceType = 1 ; SERVICE_KERNEL_DRIVER
55 | StartType = 3 ; SERVICE_DEMAND_START
56 | ErrorControl = 1 ; SERVICE_ERROR_NORMAL
57 | ServiceBinary = %12%\HidEmulator.sys
58 | AddReg = HidEmulator_Service_Inst.Reg
59 |
60 | [HidEmulator_Service_Inst.Reg]
61 | HKR,,Tag,0x00010001,0x00000001
62 | HKR,,EventMessageFile,0x00000000,%12%\HidEmulator.sys
63 | HKR,,TypesSupported,0x00010001,7
64 |
65 | ; -------------- HID Emulator Kmdf driver service install sections
66 | [HidEmulatorKmdf_Service_Inst]
67 | DisplayName = %HidEmulatorKmdf.SVCDESC%
68 | ServiceType = 1 ; SERVICE_KERNEL_DRIVER
69 | StartType = 3 ; SERVICE_DEMAND_START
70 | ErrorControl = 1 ; SERVICE_ERROR_NORMAL
71 | ServiceBinary = %12%\HidEmulatorKmdf.sys
72 | AddReg = HidEmulatorKmdf_Service_Inst.Reg
73 |
74 | [HidEmulatorKmdf_Service_Inst.Reg]
75 | HKR,,Tag,0x00010001,0x00000001
76 | HKR,,EventMessageFile,0x00000000,%12%\HidEmulatorKmdf.sys
77 | HKR,,TypesSupported,0x00010001,7
78 |
79 | [Strings]
80 | MSFT = "Leap Motion, Inc."
81 | StdMfg = "Leap Motion, Inc."
82 | DiskId1 = "Leap Motion Installation Disk #1"
83 | HidEmulator_Device.DeviceDesc = "Leap Motion gesture emulation device driver"
84 | HidEmulator.SVCDESC = "HidEmulator Leap Motion Miniport"
85 | HidEmulatorKmdf.SVCDESC = "HidEmulatorKmdf Lower Filter"
86 |
--------------------------------------------------------------------------------
/HidEmulator/inf/i386/HidEmulator.inf:
--------------------------------------------------------------------------------
1 | ; Copyright (c) 2012-2013 Leap Motion, Inc. All rights Reserved
2 | [Version]
3 | Signature="$WINDOWS NT$"
4 | Class=System
5 | ClassGuid={4D36E97D-E325-11CE-BFC1-08002BE10318}
6 | Provider=%MSFT%
7 | DriverVer=07/15/2013,1.0.1.4
8 | CatalogFile=HidEmulator.cat
9 |
10 | [DestinationDirs]
11 | DefaultDestDir = 12
12 |
13 | [SourceDisksNames]
14 | 1 = %DiskId1%,,,""
15 |
16 | [SourceDisksFiles]
17 | HidEmulator.sys = 1,,
18 | HidEmulatorKmdf.sys = 1,,
19 |
20 | ;*****************************************
21 | ; HidEmulator Install Section
22 | ;*****************************************
23 |
24 | [Manufacturer]
25 | %StdMfg%=Standard
26 |
27 | [Standard]
28 | ; HidEmulator fake device node pnp id
29 | %HidEmulator_Device.DeviceDesc%=HidEmulator_Device,HID\OcsEmulator
30 |
31 | [HidEmulator_Device.NT]
32 | CopyFiles=Drivers_Dir
33 |
34 | [HidEmulator_Device.NT.HW]
35 | AddReg=LowerFilter_AddReg
36 |
37 | [Drivers_Dir]
38 | HidEmulator.sys
39 | HidEmulatorKmdf.sys
40 |
41 | ;--------------
42 | ; Kmdf is installed as a lower filter to the HidEmulator driver
43 | [LowerFilter_AddReg]
44 | HKR,,LowerFilters,0x00010000,HidEmulatorKmdf
45 |
46 | ;-------------- Service installation
47 | [HidEmulator_Device.NT.Services]
48 | AddService = HidEmulator,803,HidEmulator_Service_Inst ; SPSVCINST_TAGTOFRONT | SPSVCINST_ASSOCSERVICE | SPSVCSINST_STARTSERVICE
49 | AddService = HidEmulatorKmdf,0,HidEmulatorKmdf_Service_Inst
50 |
51 | ; -------------- HID Emulator driver service install sections
52 | [HidEmulator_Service_Inst]
53 | DisplayName = %HidEmulator.SVCDESC%
54 | ServiceType = 1 ; SERVICE_KERNEL_DRIVER
55 | StartType = 3 ; SERVICE_DEMAND_START
56 | ErrorControl = 1 ; SERVICE_ERROR_NORMAL
57 | ServiceBinary = %12%\HidEmulator.sys
58 | AddReg = HidEmulator_Service_Inst.Reg
59 |
60 | [HidEmulator_Service_Inst.Reg]
61 | HKR,,Tag,0x00010001,0x00000001
62 | HKR,,EventMessageFile,0x00000000,%12%\HidEmulator.sys
63 | HKR,,TypesSupported,0x00010001,7
64 |
65 | ; -------------- HID Emulator Kmdf driver service install sections
66 | [HidEmulatorKmdf_Service_Inst]
67 | DisplayName = %HidEmulatorKmdf.SVCDESC%
68 | ServiceType = 1 ; SERVICE_KERNEL_DRIVER
69 | StartType = 3 ; SERVICE_DEMAND_START
70 | ErrorControl = 1 ; SERVICE_ERROR_NORMAL
71 | ServiceBinary = %12%\HidEmulatorKmdf.sys
72 | AddReg = HidEmulatorKmdf_Service_Inst.Reg
73 |
74 | [HidEmulatorKmdf_Service_Inst.Reg]
75 | HKR,,Tag,0x00010001,0x00000001
76 | HKR,,EventMessageFile,0x00000000,%12%\HidEmulatorKmdf.sys
77 | HKR,,TypesSupported,0x00010001,7
78 |
79 | [Strings]
80 | MSFT = "Leap Motion, Inc."
81 | StdMfg = "Leap Motion, Inc."
82 | DiskId1 = "Leap Motion Installation Disk #1"
83 | HidEmulator_Device.DeviceDesc = "Leap Motion gesture emulation device driver"
84 | HidEmulator.SVCDESC = "HidEmulator Leap Motion Miniport"
85 | HidEmulatorKmdf.SVCDESC = "HidEmulatorKmdf Lower Filter"
86 |
--------------------------------------------------------------------------------
/HidEmulator/stdafx.cpp:
--------------------------------------------------------------------------------
1 | #include "stdafx.h"
2 |
3 | // Standard destructor. Not used, and so, not implemented. Should assert in debug mode.
4 | void __cdecl operator delete(void* pMemory)
5 | {
6 | ASSERT(false);
7 | }
--------------------------------------------------------------------------------
/HidEmulator/stdafx.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #define KMDF_VERSION_MAJOR 1
4 |
5 | #include
6 | #include
7 | #include
8 |
9 | // WDF stuff:
10 | #include
11 | #include "usbdi.h"
12 | #include "usbdlib.h"
13 | #include
14 |
15 | extern "C" {
16 | #include
17 | }
18 |
19 | #if DBG
20 | #define OcsDebugPrint(msg, ...) DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, msg "\n", __VA_ARGS__)
21 | #else
22 | #define OcsDebugPrint(msg, ...)
23 | #endif
24 |
25 | // Marker definitions, defined to nothing here to prevent compilation malfunctions
26 | #define __INCLUDE_FROM_USB_DRIVER
27 | #define __INCLUDE_FROM_HID_DRIVER
28 | #define USB_CAN_BE_DEVICE
29 |
30 | #define ATTR_PACKED
31 | #define ATTR_CONST
32 | #define ATTR_NON_NULL_PTR_ARG(x)
33 |
34 | #define GET_NEXT_DEVICE_OBJECT(DO) \
35 | (((PHID_DEVICE_EXTENSION)(DO)->DeviceExtension)->NextDeviceObject)
36 |
37 | // Vendor identifier (must be requested)
38 | #define OEM_VENDOR_ID 'SUCO'
39 |
40 | // Some generic typdefs, for use by the HID headers
41 | typedef char int8_t;
42 | typedef BYTE uint8_t;
43 | typedef WORD uint16_t;
44 | typedef DWORD uint32_t;
45 |
46 | // Forward declaration of placement new
47 | inline void* operator new(size_t, void* p) {return p;}
48 |
49 | // Internal headers:
50 | #include "../Globals/Interface.h"
51 |
--------------------------------------------------------------------------------
/Installer/DriverPackage.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include "DriverPackage.h"
5 |
6 | DWORD DoInstallPackage(const wchar_t* infPath, BOOL& needReboot) {
7 | // Use DifX to install drivers on the new devnode:
8 | return DriverPackageInstallW(
9 | infPath,
10 | DRIVER_PACKAGE_ONLY_IF_DEVICE_PRESENT,
11 | nullptr,
12 | &needReboot
13 | );
14 | }
15 |
16 | DWORD DoUninstallPackage(const wchar_t* infPath, BOOL& needReboot) {
17 | DWORD err = DriverPackageUninstallW(
18 | infPath,
19 | DRIVER_PACKAGE_DELETE_FILES,
20 | nullptr,
21 | &needReboot
22 | );
23 |
24 | switch(err) {
25 | case ERROR_DRIVER_PACKAGE_NOT_IN_STORE:
26 | // That's OK, it wasn't installed so it cannot be removed. No problem.
27 | break;
28 | default:
29 | return err;
30 | }
31 | return 0;
32 | }
--------------------------------------------------------------------------------
/Installer/DriverPackage.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | DWORD DoInstallPackage(const wchar_t* infPath, BOOL& needReboot);
4 |
5 | DWORD DoUninstallPackage(const wchar_t* infPath, BOOL& needReboot);
--------------------------------------------------------------------------------
/Installer/Installer.cpp:
--------------------------------------------------------------------------------
1 | #include "stdafx.h"
2 | #include "Installer.h"
3 | #include "InstallerBase.h"
4 | #include "LastErrorPreserver.h"
5 |
6 | enum eHidStatus {
7 | };
8 |
9 | eHidStatus PerformOperation(const wchar_t* pInfPath, void (CInstallerBase::*pMember)())
10 | {
11 | // This class is declared first to ensure that its destructor is called last
12 | CLastErrorPreserver gle;
13 |
14 | try {
15 | // Installer base initialization:
16 | CInstallerBase base(pInfPath);
17 |
18 | // Perform the operation proper
19 | (base.*pMember)();
20 |
21 | // If restart is required we'll return here to indicate that:
22 | if(base.IsRestartRequired())
23 | throw eHidInstRestartRequired;
24 | } catch(eHidStatus rs) {
25 | // Done, capture the last error so it's restored after the CInstallerBase destructor
26 | // call is made and then return here.
27 | return gle.CaptureLastError(), rs;
28 | }
29 |
30 | return (eHidStatus)0;
31 | }
32 |
33 | eHidStatus OcuHidInstall(const wchar_t* pInfPath)
34 | {
35 | return PerformOperation(pInfPath, &CInstallerBase::Install);
36 | }
37 |
38 | eHidStatus OcuHidUpdate(const wchar_t* pInfPath)
39 | {
40 | return PerformOperation(pInfPath, &CInstallerBase::Update);
41 | }
42 |
43 | eHidStatus OcuHidUninstall(const wchar_t* pInfPath)
44 | {
45 | return PerformOperation(pInfPath, &CInstallerBase::Uninstall);
46 | }
47 |
--------------------------------------------------------------------------------
/Installer/Installer.def:
--------------------------------------------------------------------------------
1 | LIBRARY
2 | EXPORTS
3 | OcuHidInstall
4 | OcuHidUpdate
5 | OcuHidUninstall
--------------------------------------------------------------------------------
/Installer/Installer.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "InstallerCodes.h"
3 |
4 | struct OcuHidInfo {
5 | DWORD version;
6 | };
7 |
8 | ///
9 | /// Installs the HidEmulator nondevice driver
10 | ///
11 | /// The path to the HidEmulator INF file
12 | /// A HID status value
13 | extern "C" eHidStatus OcuHidInstall(const wchar_t* pInfPath);
14 |
15 | ///
16 | /// Updates the HidEmulator nondevice driver
17 | ///
18 | /// The path to the HidEmulator INF file
19 | /// A HID status value
20 | extern "C" eHidStatus OcuHidUpdate(const wchar_t* pInfPath);
21 |
22 | ///
23 | /// Uninstalls the HidEmulator nondevice driver
24 | ///
25 | /// The path to the HidEmulator INF file
26 | /// A HID status value
27 | extern "C" eHidStatus OcuHidUninstall(const wchar_t* pInfPath);
--------------------------------------------------------------------------------
/Installer/Installer.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hpp;hxx;hm;inl;inc;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
15 |
16 |
17 |
18 |
19 |
20 | Resource Files
21 |
22 |
23 |
24 |
25 | Header Files
26 |
27 |
28 | Header Files
29 |
30 |
31 | Header Files
32 |
33 |
34 | Header Files
35 |
36 |
37 | Header Files
38 |
39 |
40 | Header Files
41 |
42 |
43 | Header Files
44 |
45 |
46 | Header Files
47 |
48 |
49 | Header Files
50 |
51 |
52 | Header Files
53 |
54 |
55 | Header Files
56 |
57 |
58 | Header Files
59 |
60 |
61 | Header Files
62 |
63 |
64 | Header Files
65 |
66 |
67 |
68 |
69 | Source Files
70 |
71 |
72 | Source Files
73 |
74 |
75 | Source Files
76 |
77 |
78 | Source Files
79 |
80 |
81 | Source Files
82 |
83 |
84 | Source Files
85 |
86 |
87 | Source Files
88 |
89 |
90 | Source Files
91 |
92 |
93 | Source Files
94 |
95 |
96 | Source Files
97 |
98 |
99 |
100 |
101 | Resource Files
102 |
103 |
104 |
105 |
106 | Resource Files
107 |
108 |
109 |
--------------------------------------------------------------------------------
/Installer/InstallerBase.cpp:
--------------------------------------------------------------------------------
1 | #include "StdAfx.h"
2 | #include "InstallerBase.h"
3 | #include "DriverPackage.h"
4 | #include "InstanceEnumerator.h"
5 | #include "NonPnpDevnode.h"
6 | #include "ServiceControlManager.h"
7 | #include "SystemInfoClass.h"
8 | #include
9 | #include
10 |
11 | using namespace std;
12 |
13 | CInstallerBase::CInstallerBase(const wchar_t* pInfPath):
14 | m_infPath(pInfPath ? pInfPath : L"HidEmulator.inf"),
15 | m_bMustCopy(false)
16 | {
17 | // Convert the INF path to an absolute path, if needed:
18 | if(PathIsRelative(m_infPath.c_str()))
19 | {
20 | wchar_t relToWhat[MAX_PATH + 1];
21 | if(!GetModuleFileNameW(nullptr, relToWhat, NUMBER_OF(relToWhat)))
22 | // Assume that we must copy.
23 | {
24 | m_bMustCopy = true;
25 | return;
26 | }
27 |
28 | // Extract the name portion of the executable path:
29 | wchar_t* pName = PathFindFileNameW(relToWhat);
30 |
31 | // Kill the filename part if it is set:
32 | size_t len;
33 | if(pName != relToWhat)
34 | len = pName - relToWhat;
35 | else
36 | // Otherwise, use the CWD as the path name:
37 | {
38 | // Get the current working directory
39 | GetCurrentDirectory(MAX_PATH, relToWhat);
40 |
41 | // Get the length of the working directory
42 | len = wcslen(relToWhat);
43 |
44 | // Add a trailing backslash
45 | relToWhat[len++] = '\\';
46 | }
47 |
48 | // Null-terminate
49 | relToWhat[len] = 0;
50 |
51 | // Prepend the inf path with the relative location:
52 | m_infPath.insert(m_infPath.begin(), relToWhat, relToWhat + len);
53 | }
54 |
55 | // Determine if the supplied path is on a network drive. PNP cannot install drivers
56 | // from networked locations, so copying to a local device becomes necessary.
57 | m_bMustCopy = !!PathIsNetworkPath(m_infPath.c_str());
58 | }
59 |
60 | CInstallerBase::~CInstallerBase(void)
61 | {
62 | }
63 |
64 | void CInstallerBase::Install(void)
65 | {
66 | // Destroy all existing devices. This triggers an unload of our driver and enables us to tinker
67 | // safely with the device configuration.
68 | {
69 | InstanceEnumerator ie;
70 | while(ie.Next())
71 | ie.DestroyCurrent();
72 |
73 | if(ie.IsRestartRequired())
74 | RequireRestart();
75 | }
76 |
77 | // The SYSTEM device class is where the device will be installed
78 | std::shared_ptr hInfo(new SystemInfoClass);
79 |
80 | // We next create an empty devnode where the ocuhid legacy device may be attached.
81 | // This empty devnode will then be characterized with a PNPID (by us) and then we let PNP
82 | // find and load the driver from there. This is basically what the add/remove hardware wizard
83 | // does when you add legacy hardware.
84 | NonPnpDevnode devNode(hInfo);
85 |
86 | // Perform the actual installation:
87 | BOOL needReboot;
88 | DWORD rs = DoInstallPackage(m_infPath.c_str(), needReboot);
89 | switch(rs)
90 | {
91 | case ERROR_NO_SUCH_DEVINST:
92 | break;
93 | default:
94 | if(FAILED(rs))
95 | {
96 | SetLastError(rs);
97 | throw eHidInstDriverPackageRejected;
98 | }
99 | }
100 |
101 | // Now we can release the devnode:
102 | devNode.Release();
103 |
104 | // Now we'll select the device:
105 | if(needReboot)
106 | RequireRestart();
107 | }
108 |
109 | void CInstallerBase::Update(void)
110 | {
111 | InstanceEnumerator ie;
112 | if(!ie.Next())
113 | throw eHidInstNoDevsToUpdate;
114 |
115 | // Now we just perform an installation:
116 | Install();
117 | }
118 |
119 | void CInstallerBase::Uninstall(void)
120 | {
121 | // Removal of all detected devices:
122 | {
123 | InstanceEnumerator ie;
124 | while(ie.Next())
125 | ie.DestroyCurrent();
126 | if(ie.IsRestartRequired())
127 | RequireRestart();
128 | }
129 |
130 | {
131 | // Service destruction:
132 | ServiceControlManager scm;
133 |
134 | // Now the services proper may be deleted--we don't care if this operation fails:
135 | try {
136 | scm.DeleteOcuHidService(L"HidEmulator");
137 | } catch(...) {}
138 |
139 | try {
140 | scm.DeleteOcuHidService(L"HidEmulatorKmdf");
141 | } catch(...) {}
142 |
143 | // Propagate the restart flag out:
144 | if(scm.IsRestartRequired())
145 | RequireRestart();
146 | }
147 |
148 | // Package uninstallation:
149 | BOOL needReboot;
150 | DWORD rs = DoUninstallPackage(m_infPath.c_str(), needReboot);
151 | if(FAILED(rs))
152 | {
153 | SetLastError(rs);
154 | throw eHidInstFailedToRemovePackage;
155 | }
156 |
157 | if(needReboot)
158 | RequireRestart();
159 | }
160 |
--------------------------------------------------------------------------------
/Installer/InstallerBase.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "RestartRequiredTracker.h"
3 | #include
4 | #include
5 |
6 | using namespace std;
7 | using namespace std::tr1;
8 |
9 | enum eHidStatus;
10 |
11 | class CInstallerBase:
12 | public RestartRequiredTracker
13 | {
14 | public:
15 | ///
16 | /// Initialization for the initializer base
17 | ///
18 | /// The path to the HidEmulator INF file.
19 | CInstallerBase(const wchar_t* pInfPath);
20 | ~CInstallerBase(void);
21 |
22 | private:
23 | // Set if the INF path is in a directory that PNP cannot install from, such as a network drive.
24 | bool m_bMustCopy;
25 |
26 | // INF path:
27 | wstring m_infPath;
28 |
29 | private:
30 | ///
31 | /// Utility routine for deleting services
32 | ///
33 | void DeleteOcuHidService(const wchar_t* lpwcsName);
34 |
35 | public:
36 | // Mutator methods:
37 | void SetInfPath(const wchar_t* pwcsInfPath);
38 |
39 | ///
40 | /// Obtains the version number of the currently installed HID emulator, or zero if one could not be found
41 | ///
42 | DWORD GetDriverVersion(void);
43 |
44 | ///
45 | /// Installs the HidEmulator nondevice driver
46 | ///
47 | void Install(void);
48 |
49 | ///
50 | /// Updates the HidEmulator nondevice driver
51 | ///
52 | void Update(void);
53 |
54 | ///
55 | /// Uninstalls the HidEmulator nondevice driver
56 | ///
57 | void Uninstall(void);
58 | };
59 |
60 |
--------------------------------------------------------------------------------
/Installer/InstallerCodes.mc:
--------------------------------------------------------------------------------
1 | ;#pragma once
2 | ;enum eHidStatus;
3 |
4 | MessageIdTypedef=eHidStatus
5 |
6 | SeverityNames=(
7 | Success = 0x0 : OCUHID_STATUS_SUCCESS
8 | Informational = 0x1 : OCUHID_STATUS_INFORMATION
9 | Warning = 0x2 : OCUHID_STATUS_WARNING
10 | Error = 0x3 : OCUHID_STATUS_ERROR
11 | )
12 |
13 | FacilityNames=(
14 | HidInst = 0x1
15 | )
16 |
17 | MessageId=0
18 | Severity=Success
19 | Facility=HidInst
20 | SymbolicName=eHidInstSuccess
21 | Language=English
22 | Installation operation was successful
23 | .
24 |
25 |
26 | MessageId=0
27 | Severity=Informational
28 | Facility=HidInst
29 | SymbolicName=eHidInstRestartRequired
30 | Language=English
31 | Installation operation was successful, but a reboot will be required
32 | .
33 |
34 | MessageId=
35 | SymbolicName=eHidInstNoDevsToUpdate
36 | Language=English
37 | The update operation did not update anything because no OcuHid devices were identified
38 | .
39 |
40 |
41 | MessageId=0
42 | Severity=Warning
43 | SymbolicName=eHidInstServiceConfQueryFail
44 | Language=English
45 | Failed to query the service configuration in order to determine the binaries that must be deleted. The service was removed, but its binaries
46 | may still be present on the system.
47 | .
48 |
49 |
50 | MessageId=0
51 | Severity=Error
52 | Facility=HidInst
53 | SymbolicName=eHidInstRequiresElevation
54 | Language=English
55 | Installation, upgrade, and uninstallation operations all require Administrator privileges to succeed
56 | .
57 |
58 | MessageId=
59 | SymbolicName=eHidInstNewdevNotFound
60 | Language=English
61 | Could not find and/or load newdev.dll
62 | .
63 |
64 | MessageId=
65 | SymbolicName=eHidInstNewdevEntrypointNotFound
66 | Language=English
67 | Could not find UpdateDriverForPlugAndPlayDevicesW in newdev.dll
68 | .
69 |
70 | MessageId=
71 | SymbolicName=eHidInstSysClassNotFound
72 | Language=English
73 | The built-in SYSTEM device class could not be loaded with a call to SetupDiCreateDeviceInfoListExW
74 | .
75 |
76 | MessageId=
77 | SymbolicName=eHidInstDevCreateFail
78 | Language=English
79 | Failed to create an empty device node
80 | .
81 |
82 | MessageId=
83 | SymbolicName=eHidInstDevIDAssignFail
84 | Language=English
85 | Failed to assign the hardware ID to the null devnode created as part of the install process
86 | .
87 |
88 | MessageId=
89 | SymbolicName=eHidInstUserCancel
90 | Language=English
91 | Failed to install the device due to a user cancellation
92 | .
93 |
94 | MessageId=
95 | SymbolicName=eHidInstSCManOpenFailed
96 | Language=English
97 | Failed to open the service control manager for administrative access
98 | .
99 |
100 | MessageId=
101 | SymbolicName=eHidInstServiceOpenFailed
102 | Language=English
103 | Failed to open the OcuHid service itself for deletion
104 | .
105 |
106 | MessageId=
107 | SymbolicName=eHidInstServiceDeleteFailed
108 | Language=English
109 | Failed to delete the service, or mark it for deletion at next reboot
110 | .
111 |
112 | MessageId=
113 | SymbolicName=eHidInstTempPathCreateFail
114 | Language=English
115 | Failed to create a temporary path for installer files, you might try copying these files manually to a
116 | local directory and running the install operation again.
117 | .
118 |
119 | MessageId=
120 | SymbolicName=eHidInstCompatDriverFindFail
121 | Language=English
122 | Failed to find a compatible driver for a null device node.
123 | .
124 |
125 | MessageId=
126 | SymbolicName=eHidInstDriverSelectFail
127 | Language=English
128 | Failed to set the selected driver after the install process was completed
129 | .
130 |
131 | MessageId=
132 | SymbolicName=eHidInstInfoListBuildFail
133 | Language=English
134 | Failed to build a list of compatible drivers for the created null device node.
135 | .
136 |
137 | MessageId=
138 | SymbolicName=eHidInstCopyOEMFail
139 | Language=English
140 | Failed to copy the INF into the local machine's INF repository, the INF file appears
141 | to be missing.
142 | .
143 |
144 | MessageId=
145 | SymbolicName=eHidInstINFDependencyMissing
146 | Language=English
147 | The INF file appears to be present, but one or more of its dependencies is missing.
148 | Cannot copy the INF unless all of its dependencies are present. Check the inf's CAT
149 | file to verify that all files are present and available.
150 | .
151 |
152 | MessageId=
153 | SymbolicName=eHidInstInstallSelectionFailed
154 | Language=English
155 | Failed to install a driver, even after successfully indicating the device where the
156 | driver was to be placed and the driver to be placed on that device. This may indicate
157 | that the driver is not actually compatible with the hardware it's being installed on.
158 | .
159 |
160 | MessageId=
161 | SymbolicName=eHidInstUpdateFailFromNetwork
162 | Language=English
163 | Cannot install the specified driver; it is on a network share. Move the driver to
164 | a local directory and try again.
165 | .
166 |
167 | MessageId=
168 | SymbolicName=eHidInstFailedToSelectDevice
169 | Language=English
170 | Failed to select a located device driver to a created HidEmulator devnode
171 | .
172 |
173 | MessageId=
174 | SymbolicName=eHidInstDeviceRegistrationFailed
175 | Language=English
176 | Failed to register a device after successfully creating it
177 | .
178 |
179 | MessageId=
180 | SymbolicName=eHidInstDriverPackageRejected
181 | Language=English
182 | The DIFxAPI rejected our request to install the driver package. Manual installation will
183 | be necessary.
184 | .
185 |
186 |
187 | MessageId=
188 | SymbolicName=eHidInstFailedToRemovePackage
189 | Language=English
190 | The DIFxAPI refused to uninstall the driver package
191 | .
192 |
--------------------------------------------------------------------------------
/Installer/InstanceEnumerator.cpp:
--------------------------------------------------------------------------------
1 | #include "stdafx.h"
2 | #include "InstanceEnumerator.h"
3 |
4 | InstanceEnumerator::InstanceEnumerator(std::shared_ptr hInfo):
5 | m_hInfo(hInfo),
6 | m_i(0)
7 | {
8 | // Set up the info structure that we will use to query for information
9 | memset(&m_info, 0, sizeof(m_info));
10 | m_info.cbSize = sizeof(m_info);
11 | }
12 |
13 | InstanceEnumerator::~InstanceEnumerator(void)
14 | {
15 | }
16 |
17 | bool InstanceEnumerator::Next(void) {
18 | // Enumerate to the devnode matching our device ID:
19 | while(SetupDiEnumDeviceInfo(*m_hInfo, m_i++, &m_info))
20 | {
21 | wchar_t buf[MAX_PATH];
22 | DWORD dwType = REG_SZ;
23 | DWORD reqSize;
24 |
25 | // This is a routine that gets a requested device property. The device
26 | // property we're interested in for this call is the hardware identifier,
27 | // because we'd like to match the hardware identifier to the hardware ID
28 | // that the Hid emulator uses
29 | if(!SetupDiGetDeviceRegistryPropertyW(
30 | *m_hInfo,
31 | &m_info,
32 | SPDRP_HARDWAREID,
33 | &dwType,
34 | (LPBYTE)buf,
35 | sizeof(buf),
36 | &reqSize
37 | )
38 | )
39 | // Failed to get this HWID, try the next one.
40 | continue;
41 |
42 | if(!wcscmp(buf, gc_pnpID))
43 | return true;
44 | }
45 | return false;
46 | }
47 |
48 | void InstanceEnumerator::DestroyCurrent(void) {
49 | SetupDiCallClassInstaller(DIF_REMOVE, *this, &Current());
50 |
51 | // Do we need to restart now?
52 | SP_DEVINSTALL_PARAMS params;
53 | params.cbSize = sizeof(params);
54 | SetupDiGetDeviceInstallParams(*this, &Current(), ¶ms);
55 |
56 | if(params.Flags & (DI_NEEDREBOOT | DI_NEEDRESTART))
57 | RequireRestart();
58 | }
--------------------------------------------------------------------------------
/Installer/InstanceEnumerator.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 | #include "RestartRequiredTracker.h"
4 | #include "SystemInfoClass.h"
5 |
6 | class InstanceEnumerator:
7 | public RestartRequiredTracker
8 | {
9 | public:
10 | InstanceEnumerator(std::shared_ptr hInfo = std::shared_ptr(new SystemInfoClass(L"root\\system")));
11 | ~InstanceEnumerator(void);
12 |
13 | private:
14 | // Infoclass, used during enumeration
15 | std::shared_ptr m_hInfo;
16 |
17 | // The index, and the last-recovered SP_DEVINFO_DATA
18 | DWORD m_i;
19 | SP_DEVINFO_DATA m_info;
20 |
21 | public:
22 | // Accessor methods:
23 | SP_DEVINFO_DATA& Current(void) {return m_info;}
24 |
25 | ///
26 | /// Finds the next matching Leap ID
27 | ///
28 | bool Next(void);
29 |
30 | ///
31 | /// Destroyes the currently enumerated device
32 | ///
33 | void DestroyCurrent(void);
34 |
35 | operator std::shared_ptr(void) const {return m_hInfo;}
36 | operator HDEVINFO(void) const {return *m_hInfo;}
37 | };
38 |
39 |
--------------------------------------------------------------------------------
/Installer/LastErrorPreserver.cpp:
--------------------------------------------------------------------------------
1 | #include "StdAfx.h"
2 | #include "LastErrorPreserver.h"
3 |
4 | CLastErrorPreserver::~CLastErrorPreserver(void)
5 | {
6 | // Restore the last error code
7 | SetLastError(m_lastError);
8 | }
9 |
--------------------------------------------------------------------------------
/Installer/LastErrorPreserver.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | ///
4 | /// This ensures that the last error recovered in the constructor call
5 | /// is preserved when the function exit. This is imporant for functions
6 | /// that must preserve error information, but must also run cleanup logic
7 | /// that may change the thread error code.
8 | ///
9 | class CLastErrorPreserver
10 | {
11 | public:
12 | ~CLastErrorPreserver(void);
13 |
14 | private:
15 | DWORD m_lastError;
16 |
17 | public:
18 | void CaptureLastError(void)
19 | {
20 | m_lastError = GetLastError();
21 | }
22 | };
23 |
24 |
--------------------------------------------------------------------------------
/Installer/NonPnpDevnode.cpp:
--------------------------------------------------------------------------------
1 | #include "stdafx.h"
2 | #include "NonPnpDevnode.h"
3 | #include "SystemInfoClass.h"
4 |
5 | NonPnpDevnode::NonPnpDevnode(void):
6 | m_hInfo(nullptr),
7 | released(false)
8 | {
9 | }
10 |
11 | NonPnpDevnode::NonPnpDevnode(std::shared_ptr hInfo):
12 | m_hInfo(hInfo),
13 | released(false)
14 | {
15 | memset((PSP_DEVINFO_DATA)this, 0, sizeof(SP_DEVINFO_DATA));
16 | cbSize = sizeof(SP_DEVINFO_DATA);
17 |
18 | // Create an infoset to hold our single device:
19 | if(!SetupDiCreateDeviceInfoW(*hInfo, L"SYSTEM", &GUID_DEVCLASS_SYSTEM, nullptr, nullptr, DICD_GENERATE_ID, this))
20 | throw eHidInstDevCreateFail;
21 |
22 | // Here's where the HWID is assigned. This is how PNP knows what to attach to the newly created devnode.
23 | if(!SetupDiSetDeviceRegistryPropertyW(*m_hInfo, this, SPDRP_HARDWAREID, (LPCBYTE)gc_pnpID, gc_pnpIDLen))
24 | throw eHidInstDevIDAssignFail;
25 |
26 | // Now, we need to let PNP know that this is a device, so that it will actually try to find drivers
27 | if(!SetupDiCallClassInstaller(DIF_REGISTERDEVICE, *m_hInfo, this))
28 | throw eHidInstDeviceRegistrationFailed;
29 | }
30 |
31 | NonPnpDevnode::NonPnpDevnode(std::shared_ptr hInfo, const SP_DEVINFO_DATA& data):
32 | SP_DEVINFO_DATA(data),
33 | m_hInfo(hInfo),
34 | released(false)
35 | {
36 | }
37 |
38 |
39 | NonPnpDevnode::~NonPnpDevnode(void)
40 | {
41 | if(!released)
42 | SetupDiCallClassInstaller(DIF_REMOVE, *m_hInfo, this);
43 | }
44 |
45 | void NonPnpDevnode::Associate(void) {
46 | // Construct a set of supported drivers. This list will include the driver that we installed earlier with
47 | // the earlier call to SetupCopyOEMInf.
48 | if(!SetupDiBuildDriverInfoList(*m_hInfo, this, SPDIT_COMPATDRIVER))
49 | throw eHidInstInfoListBuildFail;
50 |
51 | // Arbitrarily select the first driver. There really should be only one driver anyway
52 | SP_DRVINFO_DATA driverInfo;
53 | memset(&driverInfo, 0, sizeof(driverInfo));
54 | driverInfo.cbSize = sizeof(driverInfo);
55 |
56 | DWORD i = 0;
57 | for(; SetupDiEnumDriverInfo(*m_hInfo, this, SPDIT_COMPATDRIVER, i, &driverInfo); i++) {
58 | }
59 |
60 | if(!i)
61 | throw eHidInstCompatDriverFindFail;
62 |
63 | // Assign the selected driver to this device.
64 | if(!SetupDiSetSelectedDriver(*m_hInfo, this, &driverInfo))
65 | throw eHidInstDriverSelectFail;
66 |
67 | DWORD bReboot = false;
68 |
69 | // Now, even though we have been operating on devInfo for most of this function, we still need
70 | // to indicate to the SetupAPI that we want to call some class installers on this device by making
71 | // this call. That's what this call does--it tells SetupAPI about our intent.
72 | if(!SetupDiSetSelectedDevice(*m_hInfo, this))
73 | throw eHidInstFailedToSelectDevice;
74 | }
--------------------------------------------------------------------------------
/Installer/NonPnpDevnode.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 |
4 | class SystemInfoClassBase;
5 |
6 | class NonPnpDevnode:
7 | public SP_DEVINFO_DATA
8 | {
9 | public:
10 | NonPnpDevnode(void);
11 | NonPnpDevnode(std::shared_ptr hInfo);
12 | NonPnpDevnode(std::shared_ptr hInfo, const SP_DEVINFO_DATA& data);
13 | ~NonPnpDevnode(void);
14 |
15 | private:
16 | std::shared_ptr m_hInfo;
17 | bool released;
18 |
19 | public:
20 | ///
21 | /// Attempts to associate this non-PNP DevNode with the HidEmulator device driver
22 | ///
23 | void Associate(void);
24 |
25 | ///
26 | /// Prevents the destructor from attempting to delete this devnode
27 | ///
28 | void Release(void) {
29 | released = true;
30 | }
31 |
32 | void operator=(NonPnpDevnode&& rhs) {
33 | *(PSP_DEVINFO_DATA)this = rhs;
34 | m_hInfo = rhs.m_hInfo;
35 | released = rhs.released;
36 | rhs.released = true;
37 | }
38 | };
39 |
40 |
--------------------------------------------------------------------------------
/Installer/PreprocFlags.h:
--------------------------------------------------------------------------------
1 | // This contains preprocessor flags that may be used to control how installation
2 | // operations perform.
3 |
--------------------------------------------------------------------------------
/Installer/ReadMe.txt:
--------------------------------------------------------------------------------
1 | ========================================================================
2 | STATIC LIBRARY : InstallerLib Project Overview
3 | ========================================================================
4 |
5 | AppWizard has created this InstallerLib library project for you.
6 |
7 | This file contains a summary of what you will find in each of the files that
8 | make up your InstallerLib application.
9 |
10 |
11 | InstallerLib.vcxproj
12 | This is the main project file for VC++ projects generated using an Application Wizard.
13 | It contains information about the version of Visual C++ that generated the file, and
14 | information about the platforms, configurations, and project features selected with the
15 | Application Wizard.
16 |
17 | InstallerLib.vcxproj.filters
18 | This is the filters file for VC++ projects generated using an Application Wizard.
19 | It contains information about the association between the files in your project
20 | and the filters. This association is used in the IDE to show grouping of files with
21 | similar extensions under a specific node (for e.g. ".cpp" files are associated with the
22 | "Source Files" filter).
23 |
24 |
25 | /////////////////////////////////////////////////////////////////////////////
26 |
27 | StdAfx.h, StdAfx.cpp
28 | These files are used to build a precompiled header (PCH) file
29 | named InstallerLib.pch and a precompiled types file named StdAfx.obj.
30 |
31 | /////////////////////////////////////////////////////////////////////////////
32 | Other notes:
33 |
34 | AppWizard uses "TODO:" comments to indicate parts of the source code you
35 | should add to or customize.
36 |
37 | /////////////////////////////////////////////////////////////////////////////
38 |
--------------------------------------------------------------------------------
/Installer/RestartRequiredTracker.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | class RestartRequiredTracker
3 | {
4 | public:
5 | RestartRequiredTracker(void):
6 | m_restartRequired(false)
7 | {}
8 |
9 | private:
10 | bool m_restartRequired;
11 |
12 | protected:
13 | void RequireRestart(void) {
14 | m_restartRequired = true;
15 | }
16 |
17 | public:
18 | // Accessor methods:
19 | bool IsRestartRequired(void) const {return m_restartRequired;}
20 | };
21 |
22 |
--------------------------------------------------------------------------------
/Installer/ServiceControlManager.cpp:
--------------------------------------------------------------------------------
1 | #include "stdafx.h"
2 | #include "ServiceControlManager.h"
3 | #include "ServiceHandle.h"
4 | #include
5 |
6 | using namespace std;
7 |
8 | ServiceControlManager::ServiceControlManager(void):
9 | m_hMngr(OpenSCManagerW(nullptr, SERVICES_ACTIVE_DATABASEW, SC_MANAGER_ALL_ACCESS))
10 | {
11 | if(!m_hMngr)
12 | throw eHidInstSCManOpenFailed;
13 | }
14 |
15 | ServiceControlManager::~ServiceControlManager(void)
16 | {
17 | if(m_hMngr)
18 | CloseServiceHandle(m_hMngr);
19 | }
20 |
21 | void ServiceControlManager::DeleteOcuHidService(const wchar_t* lpwcsName)
22 | {
23 | vector configBuf;
24 | QUERY_SERVICE_CONFIGW config;
25 | {
26 | // Open a handle to the HidEmulator service proper.
27 | ServiceHandle hSrv(*this, lpwcsName);
28 |
29 | // Determine how many bytes will be needed to our service binaries.
30 | DWORD cbNeeded;
31 | QueryServiceConfigW(hSrv, NULL, 0, &cbNeeded);
32 | if(!cbNeeded)
33 | throw eHidInstServiceConfQueryFail;
34 |
35 | // Path length acquired, query the service configuration, which will get us
36 | // the path to service binaries.
37 | configBuf.resize(cbNeeded + 1);
38 | if(
39 | cbNeeded &&
40 | !QueryServiceConfigW(
41 | hSrv,
42 | (LPQUERY_SERVICE_CONFIG)&configBuf[0],
43 | cbNeeded,
44 | &cbNeeded
45 | )
46 | )
47 | throw eHidInstServiceConfQueryFail;
48 | config = (QUERY_SERVICE_CONFIGW&)configBuf[0];
49 |
50 | // Attempt to delete the service:
51 | if(!DeleteService(hSrv))
52 | switch(GetLastError())
53 | {
54 | case ERROR_SERVICE_MARKED_FOR_DELETE:
55 | // Service already marked for deletion, nothing further required at this point.
56 | break;
57 | default:
58 | throw eHidInstServiceDeleteFailed;
59 | }
60 | }
61 |
62 | // Delete the service binaries from the system:
63 | {
64 | TCHAR wcSysRoot[MAX_PATH];
65 | TCHAR wcFullPath[MAX_PATH];
66 |
67 | // Recover system root
68 | GetWindowsDirectoryW(wcSysRoot, MAX_PATH);
69 |
70 | // Create the full path:
71 | swprintf_s(wcFullPath, ARRAYSIZE(wcFullPath), L"%s\\%s", wcSysRoot, config.lpBinaryPathName);
72 |
73 | // Verify that the full path exists before we try to delete it.
74 | if(PathFileExistsW(wcFullPath))
75 | // Delete the file now if we can
76 | if(!DeleteFileW(wcFullPath))
77 | // File in use. Delay deletion until reboot.
78 | MoveFileEx(wcFullPath, NULL, MOVEFILE_DELAY_UNTIL_REBOOT);
79 | }
80 | }
--------------------------------------------------------------------------------
/Installer/ServiceControlManager.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "RestartRequiredTracker.h"
3 |
4 | class ServiceControlManager:
5 | public RestartRequiredTracker
6 | {
7 | public:
8 | ServiceControlManager(void);
9 | ~ServiceControlManager(void);
10 |
11 | private:
12 | // Service manager handle:
13 | SC_HANDLE m_hMngr;
14 |
15 | public:
16 | ///
17 | /// Deletes a HIDEmulator driver service
18 | ///
19 | /// The driver service name
20 | void DeleteOcuHidService(const wchar_t* lpwcsName);
21 |
22 | operator SC_HANDLE(void) const {return m_hMngr;}
23 | };
24 |
25 |
--------------------------------------------------------------------------------
/Installer/ServiceHandle.cpp:
--------------------------------------------------------------------------------
1 | #include "stdafx.h"
2 | #include "ServiceHandle.h"
3 | #include "ServiceControlManager.h"
4 |
5 | ServiceHandle::ServiceHandle(ServiceControlManager& scm, const wchar_t* name):
6 | m_hSrv(OpenServiceW(scm, name, GENERIC_ALL))
7 | {
8 | if(!m_hSrv)
9 | throw eHidInstServiceOpenFailed;
10 | }
11 |
12 | ServiceHandle::~ServiceHandle(void)
13 | {
14 | if(m_hSrv)
15 | CloseServiceHandle(m_hSrv);
16 | }
17 |
--------------------------------------------------------------------------------
/Installer/ServiceHandle.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | class ServiceControlManager;
4 |
5 | class ServiceHandle
6 | {
7 | public:
8 | ServiceHandle(ServiceControlManager& scm, const wchar_t* name);
9 | ~ServiceHandle(void);
10 |
11 | private:
12 | SC_HANDLE m_hSrv;
13 |
14 | public:
15 | operator SC_HANDLE(void) const {return m_hSrv;}
16 | };
17 |
18 |
--------------------------------------------------------------------------------
/Installer/SystemInfoClass.cpp:
--------------------------------------------------------------------------------
1 | #include "stdafx.h"
2 | #include "SystemInfoClass.h"
3 |
4 | SystemInfoClassBase::SystemInfoClassBase(void):
5 | m_hInfo(INVALID_HANDLE_VALUE)
6 | {
7 | }
8 |
9 | SystemInfoClassBase::~SystemInfoClassBase(void) {
10 | if(m_hInfo != INVALID_HANDLE_VALUE)
11 | SetupDiDestroyDeviceInfoList(m_hInfo);
12 | }
--------------------------------------------------------------------------------
/Installer/SystemInfoClass.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | class __declspec(uuid("4d36e97d-e325-11ce-bfc1-08002be10318")) SystemSetupClass;
4 | class __declspec(uuid("88bae032-5a81-49f0-bc3d-a4ff138216d6")) UsbSetupClass;
5 |
6 | class SystemInfoClassBase {
7 | protected:
8 | SystemInfoClassBase(void);
9 |
10 | public:
11 | virtual ~SystemInfoClassBase(void);
12 |
13 | protected:
14 | HDEVINFO m_hInfo;
15 |
16 | public:
17 | operator HDEVINFO(void) const {return m_hInfo;}
18 | };
19 |
20 | template
21 | class SystemInfoClass:
22 | public SystemInfoClassBase
23 | {
24 | public:
25 | ///
26 | /// Creates an empty infoclass based on the SYSTEM infoclass
27 | ///
28 | SystemInfoClass(void) {
29 | // The SYSTEM device class is where the device will be installed
30 | m_hInfo = SetupDiCreateDeviceInfoListExW(&__uuidof(T), nullptr, nullptr, nullptr);
31 | if(m_hInfo == INVALID_HANDLE_VALUE)
32 | throw eHidInstSysClassNotFound;
33 | }
34 |
35 | ///
36 | /// Creates a system device information set based on the passed enumerator
37 | ///
38 | SystemInfoClass(const wchar_t* enumerator) {
39 | // Enumerate the root tree to find the one that must be updated
40 | m_hInfo = SetupDiGetClassDevsW(&__uuidof(T), L"root\\system", nullptr, 0);
41 | if(m_hInfo == INVALID_HANDLE_VALUE)
42 | throw eHidInstSysClassNotFound;
43 | }
44 | };
45 |
--------------------------------------------------------------------------------
/Installer/stdafx.cpp:
--------------------------------------------------------------------------------
1 | #include "stdafx.h"
2 |
3 | const wchar_t gc_pnpID[] = L"HID\\OcsEmulator";
4 | const DWORD gc_pnpIDLen = sizeof(gc_pnpID);
--------------------------------------------------------------------------------
/Installer/stdafx.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "targetver.h"
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include "../newdev/newdev.h"
9 | #include "PreprocFlags.h"
10 | #include
11 | #include "InstallerCodes.h"
12 |
13 | #define NUMBER_OF(x) (sizeof(x) / sizeof((x)[0]))
14 |
15 | // The PNP ID that the HIDEmulator uses:
16 | extern const wchar_t gc_pnpID[];
17 | extern const DWORD gc_pnpIDLen;
--------------------------------------------------------------------------------
/Installer/targetver.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 |
--------------------------------------------------------------------------------
/InstallerApp/InstallerApp.cpp:
--------------------------------------------------------------------------------
1 | #include "stdafx.h"
2 | #include "../Installer/Installer.h"
3 | #include
4 | #include
5 | #include
6 |
7 | using namespace std;
8 |
9 | void PrintUsage(size_t argc, const wchar_t* argv[])
10 | {
11 | wcout
12 | << "Usage: " << argv[0] << " [{install | update | uninstall | show} [infname]]" << endl
13 | << endl
14 | << " This application installs the Leap Motion HID legacy device. It MUST be run in" << endl
15 | << " administrator mode, because it has to create a new device. By default, if no" << endl
16 | << " option is specified, an installation will be attempted" << endl
17 | << endl
18 | << " The only difference between the install and update operations is that update" << endl
19 | << " will fail if the driver is not currently installed." << endl;
20 | }
21 |
22 | int wmain(int argc, const wchar_t* argv[])
23 | {
24 | eHidStatus rs;
25 | auto op = argc < 2 ? L"install" : argv[1];
26 | auto op2 = argc < 3 ? nullptr : argv[2];
27 |
28 | // Switch based on the requested operation
29 | if(!wcscmp(op, L"install"))
30 | {
31 | cout << "Installing, this could take a few minutes...";
32 | rs = OcuHidInstall(op2);
33 | }
34 | else if(!wcscmp(op, L"update"))
35 | {
36 | cout << "Updating, this could take a few minutes and may require a reboot...";
37 | rs = OcuHidUpdate(op2);
38 | }
39 | else if(!wcscmp(op, L"uninstall"))
40 | {
41 | cout << "Uninstalling, this could take a few minutes and may require a reboot...";
42 | rs = OcuHidUninstall(op2);
43 | }
44 | else if(!wcscmp(op, L"toggle"))
45 | {
46 | cout << "Installing, and then immediately uninstalling...";
47 | rs = OcuHidInstall(op2);
48 | if(SUCCEEDED(rs))
49 | rs = OcuHidUninstall(op2);
50 | }
51 | else
52 | {
53 | PrintUsage(argc, argv);
54 | return -1;
55 | }
56 |
57 | // Show some error information based on the results of the install
58 | int gle = GetLastError();
59 | if(SUCCEEDED(rs))
60 | if(rs == eHidInstRestartRequired)
61 | cout << "Successful, but a reboot will be required" << endl;
62 | else
63 | cout << "Successful" << endl;
64 | else
65 | {
66 | wchar_t* errmsg = nullptr;
67 |
68 | // Installer.dll has error message strings compiled in as a resource section. We
69 | // can use FormatMessage to get this information and format the return code correctly.
70 | FormatMessage(
71 | FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ALLOCATE_BUFFER,
72 | GetModuleHandle(L"Installer.dll"),
73 | rs,
74 | 0,
75 | (LPWSTR)&errmsg,
76 | 0,
77 | nullptr
78 | );
79 |
80 | // Print the result literals:
81 | cout << "Error, result was 0x" << setw(8) << setfill('0') << hex << rs << endl;
82 | wcout << L"Error text: " << (errmsg ? errmsg : L"(null)");
83 | if(errmsg)
84 | LocalFree(errmsg);
85 |
86 | if(gle)
87 | {
88 | // Format the system error code
89 | FormatMessage(
90 | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER,
91 | nullptr,
92 | gle,
93 | 0,
94 | (LPWSTR)&errmsg,
95 | 0,
96 | nullptr
97 | );
98 | cout << "GetLastError: " << gle << endl;
99 | wcout << L"System error text: " << (errmsg ? errmsg : L"(null)");
100 | if(errmsg)
101 | LocalFree(errmsg);
102 | }
103 | else
104 | cout << "No GetLastError information" << endl;
105 | }
106 |
107 | return rs;
108 | }
109 |
110 |
--------------------------------------------------------------------------------
/InstallerApp/InstallerApp.rc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leapmotion/mt-windows/74854757730c9801766883d13ed97bd9fb1b45bf/InstallerApp/InstallerApp.rc
--------------------------------------------------------------------------------
/InstallerApp/InstallerApp.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hpp;hxx;hm;inl;inc;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | Header Files
23 |
24 |
25 | Header Files
26 |
27 |
28 | Header Files
29 |
30 |
31 |
32 |
33 | Source Files
34 |
35 |
36 | Source Files
37 |
38 |
39 |
40 |
41 | Resource Files
42 |
43 |
44 |
45 |
46 | Resource Files
47 |
48 |
49 |
--------------------------------------------------------------------------------
/InstallerApp/ReadMe.txt:
--------------------------------------------------------------------------------
1 | ========================================================================
2 | CONSOLE APPLICATION : Installer Project Overview
3 | ========================================================================
4 |
5 | AppWizard has created this Installer application for you.
6 |
7 | This file contains a summary of what you will find in each of the files that
8 | make up your Installer application.
9 |
10 |
11 | Installer.vcxproj
12 | This is the main project file for VC++ projects generated using an Application Wizard.
13 | It contains information about the version of Visual C++ that generated the file, and
14 | information about the platforms, configurations, and project features selected with the
15 | Application Wizard.
16 |
17 | Installer.vcxproj.filters
18 | This is the filters file for VC++ projects generated using an Application Wizard.
19 | It contains information about the association between the files in your project
20 | and the filters. This association is used in the IDE to show grouping of files with
21 | similar extensions under a specific node (for e.g. ".cpp" files are associated with the
22 | "Source Files" filter).
23 |
24 | Installer.cpp
25 | This is the main application source file.
26 |
27 | /////////////////////////////////////////////////////////////////////////////
28 | Other standard files:
29 |
30 | StdAfx.h, StdAfx.cpp
31 | These files are used to build a precompiled header (PCH) file
32 | named Installer.pch and a precompiled types file named StdAfx.obj.
33 |
34 | /////////////////////////////////////////////////////////////////////////////
35 | Other notes:
36 |
37 | AppWizard uses "TODO:" comments to indicate parts of the source code you
38 | should add to or customize.
39 |
40 | /////////////////////////////////////////////////////////////////////////////
41 |
--------------------------------------------------------------------------------
/InstallerApp/stdafx.cpp:
--------------------------------------------------------------------------------
1 | #include "stdafx.h"
2 |
--------------------------------------------------------------------------------
/InstallerApp/stdafx.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "targetver.h"
4 | #include
5 | #include
--------------------------------------------------------------------------------
/InstallerApp/targetver.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 |
--------------------------------------------------------------------------------
/OcuInterface/AutoLocker.cpp:
--------------------------------------------------------------------------------
1 | #include "StdAfx.h"
2 | #include "AutoLocker.h"
3 |
4 | CAutoLocker::CAutoLocker(HANDLE hLock):
5 | m_hLock(hLock)
6 | {
7 | // Acquire the passed lock
8 | WaitForSingleObject(m_hLock, INFINITE);
9 | }
10 |
11 | CAutoLocker::~CAutoLocker(void)
12 | {
13 | // Release the mutex. This makes the assumption that the mutex was acquired,
14 | // which is typically a safe assumption unless the application is shutting down.
15 | ReleaseMutex(m_hLock);
16 | }
17 |
--------------------------------------------------------------------------------
/OcuInterface/AutoLocker.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | ///
4 | /// RIAA autolocker class, which locks the passed mutex on initialization,
5 | /// and unlocks it when it leaves scope
6 | ///
7 | class CAutoLocker
8 | {
9 | public:
10 | ///
11 | /// Locks the passed mutex
12 | ///
13 | /// The lock handle to be locked. The wait timeout is set to INFINITE.
14 | CAutoLocker(HANDLE hLock);
15 | ~CAutoLocker(void);
16 |
17 | // The handle to the lock which will be release
18 | HANDLE m_hLock;
19 | };
20 |
21 |
--------------------------------------------------------------------------------
/OcuInterface/FocusAppInfo.cpp:
--------------------------------------------------------------------------------
1 | #include "StdAfx.h"
2 | #include "FocusAppInfo.h"
3 |
4 | CFocusAppInfo::CFocusAppInfo(void):
5 | m_hFocus(nullptr)
6 | {
7 | }
8 |
9 | CFocusAppInfo::~CFocusAppInfo(void)
10 | {
11 | }
12 |
13 | eHidStatus CFocusAppInfo::Update(void)
14 | {
15 | // Get the actual top window:
16 | m_hFocus = GetForegroundWindow();
17 | if(!m_hFocus)
18 | return eHidIntrNoFocusWindow;
19 |
20 | // Get the root parent of the top window:
21 | m_hFocus = GetAncestor(m_hFocus, GA_ROOT);
22 |
23 | // Get the PID and TID about the window:
24 | m_tid = GetWindowThreadProcessId(m_hFocus, &m_pid);
25 |
26 | // Window position and extent information:
27 | WINDOWINFO wi;
28 | wi.cbSize = sizeof(wi);
29 |
30 | // Get information about the focus window
31 | GetWindowInfo(m_hFocus, &wi);
32 | m_rcWindow = wi.rcWindow;
33 | m_rcClient = wi.rcClient;
34 |
35 | // Title window acquisition:
36 | m_windowTitle.resize(MAX_PATH);
37 | m_windowTitle.resize(
38 | GetWindowTextW(
39 | m_hFocus,
40 | &m_windowTitle[0],
41 | MAX_PATH
42 | )
43 | );
44 |
45 | // Owner path acquisition:
46 | HANDLE hProcess = OpenProcess(
47 | PROCESS_VM_READ | PROCESS_QUERY_LIMITED_INFORMATION,
48 | false,
49 | m_pid
50 | );
51 | if(hProcess)
52 | {
53 | // Owner EXE path allows a maximum of MAX_PATH characters
54 | m_ownerExePath.resize(MAX_PATH);
55 |
56 | // Resize the path according to the number of returned characters
57 | m_ownerExePath.resize(
58 | // Get the module name of the process we just opened
59 | GetProcessImageFileNameW(
60 | hProcess,
61 | &m_ownerExePath[0],
62 | MAX_PATH
63 | )
64 | );
65 |
66 | // Done with the process, close the handle
67 | CloseHandle(hProcess);
68 |
69 | // Extract just the process name:
70 | m_ownerExeName = PathFindFileNameW(m_ownerExePath.c_str());
71 | }
72 |
73 | return eHidIntrSuccess;
74 | }
75 |
76 | wostream& operator<<(wostream& wos, CFocusAppInfo& rhs)
77 | {
78 | // Just output details about the focus application.
79 | return
80 | wos << "Extent: " << "(" << rhs.m_rcWindow.left << ", " << rhs.m_rcWindow.top << ") to ("
81 | << rhs.m_rcWindow.right << ", " << rhs.m_rcWindow.bottom << ")" << endl
82 | << "Window title: " << rhs.m_windowTitle << endl
83 | << "Process name: " << rhs.m_ownerExeName << endl
84 | << "Process path: " << rhs.m_ownerExePath << endl;
85 | }
86 |
--------------------------------------------------------------------------------
/OcuInterface/FocusAppInfo.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 | #include
4 |
5 | using namespace std;
6 |
7 | enum eHidStatus;
8 |
9 | ///
10 | /// Stores and retrieves information about the currently focused window
11 | ///
12 | class CFocusAppInfo
13 | {
14 | public:
15 | CFocusAppInfo(void);
16 | ~CFocusAppInfo(void);
17 |
18 | public:
19 | ///
20 | /// A handle to the window that currently has focus
21 | ///
22 | HWND m_hFocus;
23 |
24 | ///
25 | /// The process ID of the process that owns this window
26 | ///
27 | DWORD m_pid;
28 |
29 | ///
30 | /// The thread ID of the thread that owns this window
31 | ///
32 | DWORD m_tid;
33 |
34 | // Window extent information
35 | RECT m_rcWindow;
36 | RECT m_rcClient;
37 |
38 | ///
39 | /// The title of the target window
40 | ///
41 | wstring m_windowTitle;
42 |
43 | ///
44 | /// The name of the process that owns the focus window
45 | ///
46 | wstring m_ownerExeName;
47 |
48 | ///
49 | /// The full path to the process's executable
50 | ///
51 | wstring m_ownerExePath;
52 |
53 | public:
54 | ///
55 | /// Gets information about the currently focused window
56 | ///
57 | eHidStatus Update(void);
58 | };
59 |
60 | ///
61 | /// Debug stream manipulator for dumping the contents of this structure
62 | ///
63 | wostream& operator<<(wostream& os, CFocusAppInfo& rhs);
--------------------------------------------------------------------------------
/OcuInterface/ObjPool.cpp:
--------------------------------------------------------------------------------
1 | #include "StdAfx.h"
2 | #include "ObjPool.h"
3 |
--------------------------------------------------------------------------------
/OcuInterface/ObjPool.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 |
4 | using std::set;
5 |
6 | template
7 | class CObjPool
8 | {
9 | public:
10 | ~CObjPool(void)
11 | {
12 | for each(T* cur in m_pool)
13 | delete cur;
14 | }
15 |
16 | private:
17 | // This is the collection of objects that have already been allocated
18 | set m_allocated;
19 |
20 | // These are objects that are waiting to be allocated
21 | set m_pool;
22 |
23 | public:
24 | ///
25 | /// Creates a new object to be used by the caller, or returns an object
26 | /// from the pool of known objects.
27 | ///
28 | /// An object of type T
29 | T* Create(void)
30 | {
31 | T* pRetVal;
32 | if(m_pool.size())
33 | {
34 | auto q = m_pool.begin();
35 | pRetVal = *q;
36 | m_pool.erase(q);
37 | }
38 | else
39 | pRetVal = new T;
40 | m_allocated.insert(pRetVal);
41 | return pRetVal;
42 | }
43 |
44 | ///
45 | /// Frees the passed object by returning it to the pool
46 | ///
47 | void Free(T* pObj)
48 | {
49 | m_allocated.erase(pObj);
50 | m_pool.insert(pObj);
51 | }
52 | };
53 |
54 |
--------------------------------------------------------------------------------
/OcuInterface/OcuHidInstance.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "ObjPool.h"
3 | #include "OcuInterfaceCodes.h"
4 | #include "Overlapped.h"
5 | #include "../Globals/Interface.h"
6 | #include