0

I'm using Visual Studio 2012, managed C++, to make a bridge between a third party SDK and our system which is written in C#. I have succesfully wrapped and consumed several functions from said SDK. Except one, which only result in a Unresolved External Error.

The SDK's header file defines the function's signature:

#if defined WIN32
    #if defined BUILD_ADS_SHARED_LIB
        #define ADS_LINK_SPEC __declspec (dllexport)
        #define ADS_CALLING_CONVENTION __stdcall
    #elif defined USE_ADS_SHARED_LIB
        #define ADS_LINK_SPEC __declspec (dllimport)
        #define ADS_CALLING_CONVENTION __stdcall
    #else
        #define ADS_LINK_SPEC
        #define ADS_CALLING_CONVENTION
    #endif
#else
    #define ADS_LINK_SPEC
    #define ADS_CALLING_CONVENTION
#endif

DatabaseResult ADS_LINK_SPEC ADS_CALLING_CONVENTION
createDatabase(
    const Settings& settings, Artec::SdkDatabase::iDatabase *& instance);

The error says:

Error   10  error LNK2028: unresolved token (0A000089) "enum Artec::SdkDatabase::DatabaseResult __cdecl Artec::SdkDatabase::createDatabase(class Artec::SdkDatabase::Settings const &,class Artec::SdkDatabase::iDatabase * &)" (?createDatabase@SdkDatabase@Artec@@$$FYA?AW4DatabaseResult@12@ABVSettings@12@AAPAViDatabase@12@@Z) referenced in function "private: static enum Artec::SdkDatabase::DatabaseResult __clrcall Broadway3dWrapper::Broadway3dWrapper::GetConn(wchar_t const *,wchar_t const *,wchar_t const *,wchar_t const *,char const *,class Artec::SdkDatabase::iDatabase * &)" (?GetConn@Broadway3dWrapper@1@$$FCM?AW4DatabaseResult@SdkDatabase@Artec@@PB_W000PBDAAPAViDatabase@34@@Z) C:\bioap\tfs\Identitum\Dev\src\BA.Identitum.Devices.Broadway3d\Broadway3dWrapper.obj    BA.Identitum.Devices.Brodway3D

So it's looking for the mangled name:

?createDatabase@SdkDatabase@Artec@@$$FYA?AW4DatabaseResult@12@ABVSettings@12@AAPAViDatabase@12@@Z

Making a little dumpbin on the referenced dll, I found there is in fact a function called like that exported, thing is the name is mangled slightly different:

?createDatabase@SdkDatabase@Artec@@YG?AW4DatabaseResult@12@ABVSettings@12@AAPAViDatabase@12@@Z

Can anyone help me here? I cannot contact the SDK vendor, and I'm completely lost here.

Fabzter
  • 505
  • 5
  • 16
  • Try to demangle names (see http://www.gershnik.com/tips/vc.asp#undname for example) and see what exactly is different. – queen3 Mar 12 '13 at 18:21
  • I hope for you sanity the version of the DLL you're using was not built with a *prior* version of CL (the VC++ compiler). if it was, all bets are off as to the mangling algorithm they used (which notoriously changes between major versions). Are you ***sure*** you're not linking a 64-bit import library against a 32-bit app, or vice-versa? – WhozCraig Mar 12 '13 at 18:24
  • I did demangled it. It is exactly like in the function declaration. enum Artec::SdkDatabase::DatabaseResult Artec::SdkDatabase::createDatabase(class Artec::SdkDatabase::Settings const &,class Artec::SdkDatabase::iDatabase * &) – Fabzter Mar 12 '13 at 18:51
  • @WhozCraig : I'm using windows 64 bits. How can I make sure I'm compiling asa 32 bit app? – Fabzter Mar 12 '13 at 18:54
  • @WhozCraig: It was indeed compiled with a prior version but I'm lucky the mangling is the same. – Fabzter Mar 12 '13 at 19:04

2 Answers2

5

The difference between those two lies in the calling convention section.

createDatabase@SdkDatabase@Artec@@YG?AW4DatabaseResult@12@ABVSettings@12@AAPAViDatabase@12@@Z is stdcall: enum Artec::SdkDatabase::DatabaseResult __stdcall Artec::SdkDatabase::createDatabase(class Artec::SdkDatabase::Settings const &,class Artec::SdkDatabase::iDatabase * &)

The demangler I used does not understand ?createDatabase@SdkDatabase@Artec@@$$FYA?AW4DatabaseResult@12@ABVSettings@12@AAPAViDatabase@12@@Z, but the part where they differ (@@$$FYA? vs @@YG?) is the calling convention (if I change YG to YF, the calling convention changes and nothing else does).

Change your declaration of the function to return-type __stdcall function-name[(argument-list)].

When you included the header file, did you #define USE_ADS_SHARED_LIB explicitly or on the compiler command line? Are you targeting 32 bit windows?

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
3

Use the undname.exe utility to undecorate names. It is looking for:

enum Artec::SdkDatabase::DatabaseResult 
__cdecl 
Artec::SdkDatabase::createDatabase(
    class Artec::SdkDatabase::Settings const &,
    class Artec::SdkDatabase::iDatabase * &
)

The one you found is:

enum Artec::SdkDatabase::DatabaseResult 
__stdcall 
Artec::SdkDatabase::createDatabase(
    class Artec::SdkDatabase::Settings const &,
    class Artec::SdkDatabase::iDatabase * &
)

Everything matches, except the calling convention, __cdecl vs __stdcall. Note how the SDK header allows this to happen, it doesn't raise a stink when neither BUILD_ADS_SHARED_LIB nor USE_ADS_SHARED_LIB is #defined. And that will produce a __cdecl function. Bad idea btw.

So very high odds that you simply forgot to define USE_ADS_SHARED_LIB. Project + Properties, C/C++, Preprocessor, Preprocessor Definitions setting.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • Thanks, you're right, unfortunately I already accepted @Yakk's answer. And yes, I also thinks it's a very bad idea not even raising a warning, but tell that to my russian vendors ;) – Fabzter Mar 12 '13 at 19:02
  • @Hans The third condition (neither macro defined) is apparently for the case where the client code is statically linking to the library. I don't think this is "bad", especially if static linking is the most common usage pattern for this library. – Owen Wengerd Mar 13 '13 at 03:31
  • The linker doesn't care where the symbol comes from. The dllimport optimization is miniscule, not worth the lousy error. – Hans Passant Mar 13 '13 at 03:40