1

I’m currently having some problems trying to implement an integration with a Verifone PoS.

The bank we are working with provided us with one .dll file, one .h file and one .hpp file.

I’m usually a Java or PHP developer, so for the last days I consumed everything I found on the web about DLL files and how to use them, but none seemed to work so far. I got a lot of errors, many of them being something like “invalid dll”.

I found on the web that alongside a dll file there should have been a .lib file. I asked the third party about this, but apparently

There is no .lib file. The .dll file contains all the required info for an integration

From their documentation of library I found this:

The form of the supplied binary is a dynamic library. By its nature, a dynamic library allows for easier updates and corrections, not requiring recompilation or relinking of the client (calling) code, as long as the procedures prototypes (function parameters and return types) remain the same.

The language used for the library implementation is C++.

To access the functionalities implemented in the library binary, a C-style header interface is provided. This is comprised of the function prototypes available to be called as well as the types of the result-structures through which the returned data needs to be interpreted to make sense for the previously accessed functionality (the specific requested transaction).

So yeah, the .h file includes only the data types, and the .hpp file contains some declarations that looks like this:

extern "C" __declspec(dllexport) bool doSomething(int param);

Also in their documentation there is an example of how an implemetation should look (and it is fairly simple):

bool someVar = doSomething(1); 

It looks like those functions can be called as simple as that, but they cannot. If I try to do that I get an “undefined function” (or similar) error.

At this point the only thing that seemed to have somehow worked (maybe) is loading the DLL with the LoadLibrary function. But besides the fact that whatever function I try to call, with whatever parameters, it returns false, it seems kind of wrong that I do not use the .hpp file at all.

So here we are. How I should aproach this? Is there a way to load the DLL and use the provided HPP file as function definitions? If not, is there another way beside LoadLibrary + GetProcAddress combo to do this?

Thank you!

AcerX
  • 21
  • 6
  • Is it a .net DLL? You could use #using. https://learn.microsoft.com/en-us/cpp/preprocessor/hash-using-directive-cpp?view=msvc-160 – cup Mar 30 '21 at 08:47
  • Are you trying to use a 64-bit DLL on a 32-bit process or vice-versa. Have a look at the contents of the DLL in https://dependencywalker.com/ – cup Mar 30 '21 at 08:51
  • 1
    Does the header file really contain declarations with `__declspec(dllexport)` or are they hidden behind some macros? Because `__declspec(dllexport)` only works if you are the library **author**. These annotations will make sure that the import library (which is a .lib file in msvc) contains all the functions that you want to export. If you are the **user** of a dll those should be `__declspec(dllimport)`, but you still need a .lib file or else you have to `GetProcAddress` manually, afaik. If it's a managed dll, like cup says, you can `#using` it, but the given header files look like native. – Timo Mar 30 '21 at 09:14
  • @cup I used the dependency walker, It looks like a 32-bits (has many other dependencies like user32.dll, shell32.dll, kernel32.dll etc). Also that application is generating warnings while parsing: Error: At least one required implicit or forwarded dependency was not found. Warning: At least one delay-load dependency module was not found. Warning: At least one module has an unresolved import due to a missing export function in a delay-load dependent module. – AcerX Mar 30 '21 at 15:12
  • @Timo the header file is starting with something like this: #ifndef PROTOCOL_V4_INTERFACE #define PROTOCOL_V4_INTERFACE the next line is exactly like I described, with dllexport. I read that the dll export are for those who generate the dll, but I am the user here. Should I change those with dllimport? – AcerX Mar 30 '21 at 15:13
  • @AcerX I have a few other questions about the same dll and header file I received (probably from the same bank). Is there any way I could contact you privately? – George Grigorita Jul 06 '21 at 16:40
  • @George Grigorita Sure, I added my email and discord user to my account description. – AcerX Jul 07 '21 at 17:42

1 Answers1

1

I'm assuming the dll is a native dll, not a managed assembly (.net dll).

Usually, the dll author adds a preprocessor definition to the build system, like DLL_EXPORT. So if the author compiles the dll, the import library (a small .lib file) will contain all functions that used the DLL_API macro. Then the author can ship the very same header to a user. Because that user won't have the DLL_EXPORT macro defined, DLL_API will resolve to a dllimport, which basically says that the annotated function is defined in the import library.

Such a header might look like this (the whole #if condition is usually in its own header file which is then included in all headers that export functions):

#ifdef DLL_EXPORT
#   define DLL_API __declspec(dllexport)
#else
#   define DLL_API __declspec(dllimport)
#endif

extern "C" 
{
    void DLL_API SomeFunction(int x);
    void DLL_API AnotherFunction(int x);
}

If the author builds the project (in msvc) the compiler will generate the dll file and a small .lib file, which is the import library. This lib will essentially do what you have to do now: calling LoadLibrary and GetProcAddress to resolve all the functions that have been annotated with __declspec(dllexport).

The following part is a bit speculative and I'm guessing a bit here.

All __declspec(dllimport) does, is tell consumers that this dll contains those functions. But the linker has to link a declaration to its definition (implementation) so the function must be defined somewhere at compiletime. And that place is the import library (.lib). If you don't link with the import library, you will get a linker error when you build your project.

This means simply changing the dllexport to a dllimport won't solve your problems. Without an import library your only option is to load the dll manually with LoadLibrary and search for each function.

If I were you, I'd ask the author for an example project that uses the dll. AFAIK, the only ways to use a native dll is either by linking to an import library or by loading everything manually.

Manually generating the import library from the dll

I've tested this to make sure it works.

First of all, fix the header file to either use the macros like I did in the example above, or just use dllimport directly.

Second, open the developer command prompt for VS and follow the steps from this answer. Make sure to use the correct file names and target architecture (x64 or x86). Now you should have a .lib file.

Thrid, add the lib to your project.

  1. Add the directory of the lib (place it somewhere close to the project so you can use relative paths). Open the project properties and follow the steps in this image: Make sure that Configuration and Platform are correct (you probably want it like in the image). You can also use relative paths. Click on the Macros button to see all predefined paths available to you.
  2. Add the lib to the linker dependencies:
  3. Put the header somewhere in your project where you can access it.

Now you can simply include the header anywhere in your project and use the functions declared inside it. But note that the dll file has to be placed somewhere where LoadLibrary can find it. Preferably this is the same directory where your project's executable is located.

Bonus facts

The definition file (.def) is actually very simple. The def file for my sample code above is:

LIBRARY MyLibrary
EXPORTS
AnotherFunction
SomeFunction

If I remove the extern "C" block around my declarations, my function names will be mangled and the def file looks like this:

LIBRARY MyLibrary
EXPORTS
?AnotherFunction@@YAXH@Z
?SomeFunction@@YAXH@Z

If you put those functions inside a namespace (for example FooSpace), that namespace name will also be part of the function name:

LIBRARY MyLibrary
EXPORTS
?AnotherFunction@FooSpace@@YAXH@Z
?SomeFunction@FooSpace@@YAXH@Z

Note that all extern "C" entities will ignore namespaces, meaning all extern "C" functions, variables, types, ... will be put into the global namespace, no matter if you define them inside a namespace or not.

These are also the names that you'd have to pass to GetProcAddress if you did it manually.

Timo
  • 9,269
  • 2
  • 28
  • 58
  • Strongly agree with this excellent comment. The next thing to do, I think, is to ask for an example. It does indeed seem strange to me that they didn't provide a "stub" for their DLL – or, source-code – to make calling the thing easier. Intuition tells me that "this ought to be a no-brainer," so maybe you're just missing something. – Mike Robinson Mar 30 '21 at 18:34
  • Thank you for the answer. Unfortunately I already asked for an example project that uses this dll and all they could say is that they are not responsible with implementing it, so they do not have any example code...It is strange I know... – AcerX Mar 30 '21 at 18:49
  • Also, I've tried some things today and I have some questions. Can I be 100% sure that using the `LoadLibrary` + `GetProdAddress` will access the correct function? Also, I've seen some sugesting that you can generate the .lib file. Is this an option, to generate the lib and pretend it is the one provided? (I've also had errors trying to do this, but maybe I missed something else) – AcerX Mar 30 '21 at 18:53
  • @AcerX good point. I've added an explanation on how to create and use your own import lib. And yes, if you spell the name correctly, `GetProcAddress` will get the correct function. Dll members are uniquely identified by their name. However, if you use C++ linkage (that is omitting the `extern "C"` part), your function name will be mangled and look pretty weird. In that case `GetProcAddress("SomeFunction")` will give you a `nullptr`, because that functions name is different inside the dll. With `extern "C"` entities, this will be fine, though. – Timo Mar 30 '21 at 20:34
  • @Timo creating the lib as described in that link + changing dllexport with dllimport worked like a charm. Now the program compiles with the dll included and functions can be called without any other hustle. Thank you and have a nice day :D – AcerX Mar 31 '21 at 06:51