This article describes a useful technique for using a closed source C++ DLL, loaded at run-time, to access an API for a popular consumer peripheral. It’s assumed the developer does not have access to import libraries or source code.
This is a technical follow-up to my Continuum blog post describing how I automated a simple software task to enable an automatic pan-and-zoom feature of a consumer webcam that didn't provide an API. We needed to do this without disturbing the user experience, so standard program automation tools like AutoIt were off the table.
Throughout the process, I realized some of the pitfalls in making calls on C++ DLLs and identified workarounds. The inspiration for this article was a blog post from Recx Ltd, Working with C++ DLL Exports without Source or Headers. An example project is provided, but our specific case relied on a proprietary DLL that could not be included due to licensing.
API Monitor is an invaluable tool for monitoring the activity of API calls. It has more comprehensive features for Windows API calls, but it can also be used to view calls to external DLLs. You can spawn processes
from within the tool or attach to a running process. The state of the call stack can be seen before and after API calls are made, return values are visible, and it even provides breakpoint functionality.
With API Monitor, I spawned an instance of the web cam controller application, which allowed me to see which DLLs were being loaded. Monitoring from process execution (as opposed to attaching to running process) can be important when trying to see initialization behavior.
The module dependency view revealed a large list of DLLs. Most of them were Windows system DLLs or related to the Qt framework. One in particular stood out for what we needed: CameraControls_Core.dll. I set up the API Monitor to log all calls to this DLL and this was the relevant output:
LWS::CameraControls::CameraControls_Core::Init ( ... )
LWS::CameraControls::CameraControls_Core::GetCurrentVideoDevice ( ... )
LWS::CameraControls::CameraControls_Core::SetCurrentVideoDevice ( ... )
LWS::CameraControls::CameraControls_Core::GetFaceTracking ( ... )
Monitoring the API activity live, I checked and unchecked the facial recognition box. I noticed calls to SetFaceTracking () were being made. A quick look at the call stack revealed Boolean values being sent as parameters to the method. I used the Microsoft dumpbin utility on CameraControls_Core.dll to view the exported method list. It was quickly evident that I was dealing with a C++ DLL (due to the use of name decoration).
The method names were like so:
1 0 00001366 ??0CameraControls_Core@CameraControls@LWS@@QAE@XZ
2 1 000015C3 ??1CameraControls_Core@CameraControls@LWS@@UAE@XZ
3 2 00038740 ??_7CameraControls_Core@CameraControls@LWS@@6B@
I ran the output of the dumpbin tool into Microsoft’s undname utility to undecorate the names.
Read more: Codeproject