Click here to Skip to main content
12,830,304 members (43,966 online)
Click here to Skip to main content
Add your own
alternative version

Tagged as


51 bookmarked
Posted 17 Jan 2013

Accessing an API through a closed source C++ DLL

, 21 Jan 2013 CPOL
Rate this:
Please Sign up or sign in to vote.
Making calls on a C++ DLL without source code or header files, even when the DLL depends on C run-time libraries


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.

This provided a more coherent output:

1    0 00001366 public: __thiscall LWS::CameraControls::CameraControls_Core::CameraControls_Core(void)
2    1 000015C3 public: virtual __thiscall LWS::CameraControls::CameraControls_Core::~CameraControls_Core(void)
3    2 00038740 const LWS::CameraControls::CameraControls_Core::`vftable'
40   27 000012E9 public: bool __thiscall LWS::CameraControls::CameraControls_Core::Init(class QString)  
86   55 000016D1 public: long __thiscall LWS::CameraControls::CameraControls_Core::SetFaceTracking(unsigned long,long) 

It was around this point in time that I stumbled on the above mentioned Recx Ltd article. I realized that our particular DLL would present a few challenges that made a simple script-kiddie application of this technique impossible. I moved a copy of the DLL into my application’s working directory and attempted to write some code to load it dynamically.

static HINSTANCE CameraControlDllHandle = NULL;
CameraControlDllHandle = LoadLibrary(L"CameraControls_Core.dll"); 

Stepping through the code revealed the first dependency library of many: Qt4Gui4. As the errors presented themselves, I copied the dependencies into the working directory. It turns out ten additional DLLs were required. I ran through the code one last time, and got an error about MSVCR90.DLL being missing.

Placing this DLL in the directory results in an error about the C-runtime being loaded improperly.

MSVCR90.DLL is the C-runtime library for Visual C++ 2008. I tried re-building my project to run with this runtime, so it would use the same runtime as the DLL, but it didn't mitigate the problem. As it turns out, Microsoft introduced a new form of system-wide DLL management in Windows 98 for allowing conflicting DLLs to exist simultaneously in memory (Wikipedia DLL Hell). DLL’s complying with this standard have a manifest file that is imported into the DLL to inform a calling process which dependencies need to be loaded.

To overcome the C run-time dependency, I needed to create a manifest file pointing to the run-time library and embed it into my CameraControls_Core.dll. This MSDN article outlines how to use Microsoft’s MT.EXE utility to embed a manifest file into an already built executable or DLL.

The manifest file I needed to use for MSVCR90.DLL is as follows:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
      <assemblyIdentity type="win32" name="Microsoft.VC90.DebugCRT" 
        version="9.0.21022.8" processorArchitecture="x86" 
      <assemblyIdentity type="win32" name="Microsoft.VC90.CRT" 
        version="9.0.21022.8" processorArchitecture="x86" 

After this step, the library was loading into memory without exceptions! Now, I just needed to verify method calls would work. Early attempts at calling essentially any of the methods were throwing exceptions. I realized this was because some critical init function was probably not being called. The reader should read through Working with C++ DLL Exports without Source or Headers first.

I’ll jump straight to the working solution and explain it:
 #include <QString>
// Function Pointer Typedefs
typedef long (__thiscall *_SetFaceTracking)(DWORD *pThis, unsigned long, long boolValue);
typedef long (__thiscall *_GetFaceTracking)(DWORD *pThis, unsigned long, long *boolValue);
typedef void (__thiscall *_CameraControls_Core)(DWORD *pThis);
typedef bool (__thiscall *_Init)(DWORD *pThis, class QString param1);
typedef long (__thiscall *_GetCurrentVideoDevice)(DWORD *pThis, unsigned long *param);
typedef long (__thiscall *_SetCurrentVideoDevice)(DWORD *pThis, unsigned long param);
// Static Variables
static BOOL            freeResult;
static _SetFaceTracking    CameraSetFaceTracking;
static _GetFaceTracking     CameraGetFaceTracking;
static DWORD            dwFakeObject[512];
static HINSTANCE        CameraControlDllHandle = NULL;
static unsigned long    currentVideoDevice = 0;
    long retValue = 0;
    QString inputString = "";
    CameraControlDllHandle = LoadLibrary(L"CameraControls_Core.dll");
    if (CameraControlDllHandle == NULL)
        return E_FAIL;
    _CameraControls_Core CameraImportedConstructor = (_CameraControls_Core) GetProcAddress(
    if (CameraImportedConstructor == NULL)
        return E_FAIL;
    CameraSetFaceTracking = (_SetFaceTracking) GetProcAddress (CameraControlDllHandle,
    if (CameraSetFaceTracking == NULL)
        return E_FAIL;
    CameraGetFaceTracking = (_GetFaceTracking) GetProcAddress (CameraControlDllHandle, 
    if (CameraGetFaceTracking == NULL)
        return E_FAIL;
    _Init CameraInitializer = (_Init) GetProcAddress (CameraControlDllHandle, 
    if (CameraInitializer == NULL)
        return E_FAIL;
    _SetCurrentVideoDevice CameraSetCurrentVideoDevice = (_SetCurrentVideoDevice) GetProcAddress (
      CameraControlDllHandle, "?SetCurrentVideoDevice@CameraControls_Core@CameraControls@LWS@@QAEJK@Z");
    if (CameraSetCurrentVideoDevice == NULL)
        return E_FAIL;
    _GetCurrentVideoDevice CameraGetCurrentVidDevice = (_GetCurrentVideoDevice) GetProcAddress (
      CameraControlDllHandle, "?GetCurrentVideoDevice@CameraControls_Core@CameraControls@LWS@@QAEJPAK@Z");
    if (CameraGetCurrentVidDevice == NULL)
        return E_FAIL;
    memset (dwFakeObject, 0x00, 512);
    retValue = CameraInitializer(dwFakeObject, inputString);
    retValue = CameraGetCurrentVidDevice (dwFakeObject, &currentVideoDevice);
    retValue = CameraSetCurrentVideoDevice (dwFakeObject, currentVideoDevice);
    return S_OK;
A function or method's calling convention determines how information is passed and returned from the caller to the callee. The calling convention our DLL used differed from those presented in the above
article. Their example used __cdecl, which I just learned is now a standard calling convention for all functions on Win x64 systems ( this was done to eliminate the problem of so many complicated calling conventions).

In __cdecl, all the parameters are passed on the call stack. The object instance this pointer is passed last. Our DLL used the __thiscall convention. __thiscall, it turns out, informs the callee that the this pointer is being passed via the ECX register (not on the call stack). The __thiscall keyword tells the compiler that the first parameter should be placed in the ECX register. Technically, the first parameter should be a pointer to the object instance.

Since our DLLs Init() function requires a QString as a parameter, I needed to determine the version of Qt being used by the target DLL, build Qt, and statically link it to my DLL. Fortunately, passing an empty QString to the Init function completed initialization without errors and allowed the other methods to be called. The dwFakeObject array is required because C++ instance methods expect to be passed a reference to the object they are designed to work on. We reserve an area in memory and treat this as a
reference to a dummy object that is passed to the methods within the DLL.

Points of Interest

Hopefully this will prove insightful to someone going through a similar situation with attempting to use third party DLLs. Without access to source for the definitions of the underlying interface and data
types, the problem can be more or less complex than this example. However, it serves to illustrate that there isn’t always a general purpose solution for accessing DLL functions and some cases will require an ad-hoc approach.

Topics touched on:

  • Embedded DLL Manifest files
  • Viewing export functions and making calls from C++ DLLs
  • APIMonitor as a tool for spying on API calls
  • Calling conventions


17 Jan 2013 - Initial publication.


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Robert Bermani
Software Developer Continuum LLC
United States United States
I am an embedded software engineer with almost 10 years of experience in the industry. I currently work at Continuum Advanced Systems, a global design innovation consultancy specializing in consumer and medical products. My specializations and interests cover embedded systems, mobile application development, and various web software technologies.

You may also be interested in...


Comments and Discussions

SuggestionLooking for some deep insight resources Pin
anhdung8817-Feb-15 2:17
memberanhdung8817-Feb-15 2:17 
SuggestionGood article! And one suggestion. Pin
Shawn-USA5-Aug-13 15:07
memberShawn-USA5-Aug-13 15:07 
GeneralMy vote of 5 Pin
Mihai MOGA16-Feb-13 20:20
memberMihai MOGA16-Feb-13 20:20 
GeneralVersion Dependency Pin
Sharjith21-Jan-13 8:10
memberSharjith21-Jan-13 8:10 
GeneralRe: Version Dependency Pin
Robert Bermani25-Jan-13 4:08
memberRobert Bermani25-Jan-13 4:08 
Thanks for the feedback- you brought up some great points! I agree with you entirely that encapsulation is one of the cornerstones of OOP.

As for the DLL functions being accessible (either private or public). I believe this can be the case with export functions from any DLL, regardless of if you have the source available or not. Although it probably depends on the compiler. The compiler depends on the contents of the header file to enforce access specifiers, as they are front-end features, not security mechanisms.

As a developer, you could possibly write an intermediate layer in between the end-user and the DLL itself, to expose only the intended functionality.

The method described was only intended as a hack. If the name mangling scheme of the compiler changes between revs, and the DLL is rebuilt, it would no longer work without modification. Since the DLL loading scheme occurs at run-time, one method to mitigate the name mangling between DLL revisions issue would be to create an application-specific definition file that maps the mangled names their respective functions. The map could be released with the DLL and the application would be written to parse and process it before loading begins. The other option is that the specific DLL must be shipped with the release.

In our particular use case, the application we used this technique for was merely for a proof of concept. Unfortunately it is difficult to turn this into a robust, general purpose solution.

Best Regards,
QuestionAPI Monitor Pin
alexquisi18-Jan-13 17:51
memberalexquisi18-Jan-13 17:51 
AnswerRe: API Monitor Pin
Robert Bermani21-Jan-13 3:13
memberRobert Bermani21-Jan-13 3:13 
QuestionAre you sure that the author of the DLL allows reverse-engineering? Pin
Philippe Mori17-Jan-13 13:55
memberPhilippe Mori17-Jan-13 13:55 
AnswerRe: Are you sure that the author of the DLL allows reverse-engineering? Pin
Robert Bermani17-Jan-13 14:08
memberRobert Bermani17-Jan-13 14:08 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.170326.1 | Last Updated 21 Jan 2013
Article Copyright 2013 by Robert Bermani
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid