Failed to resolve symbols (Windows)
-
I received a Windows shared library ( xxxapi.dll ) that I would like to load at runtime. It is provided with headers (that actually refuse the MinGW compiler if I include them in the code !).
As an example, one of the functions I would like to use is declared as this in those headers:extern "C" long __stdcall xxxInitialize( void );
I attempt to use the following code to load this call:
QString libName( "xxxapi" ); if ( !libName.isNull() ) { QLibrary lib( libName ); if ( lib.load() ) { typedef long __stdcall (*InitFunction)( void ); InitFunction init = reinterpret_cast<InitFunction>( lib.resolve("xxxInitialize") ); if ( init ) { qDebug() << "Found the xxxInitialize function :-)"; init(); } else qCritical() << lib.errorString(); } else { qCritical() << "Failed to load the " << libName << " library !"; qCritical() << lib.errorString(); } }
The error is always:
Cannot resolve symbol \"xxxInitialize\" in xxxapi: The specified procedure could not be found.
I'm using Qt 5.12.1 with MinGW 7.3, everything in 64 bits (the DLL also is mentioned x64).
I probably do something wrong. Could someone give some support ?
Thanks.Regards.
-
@gav007
From http://doc.qt.io/qt-5/qlibrary.html#resolve the original needs to have been compiled with__declspec(dllexport)
. How do you know whether the code (.c
/.cpp
) did that? Does documentation tell you thatxxInitialize
has been exported from the DLL for you to use?I am wondering whether it could matter if that DLL was compiled with MSVC while you are using MinGW. I don't think so, as Windows calls
LoadLibrary()
&GetProcAddress()
should work regardless of compiler, it's just a niggle if that DLL is not MinGW... -
@JonB
I'm not expert of the Windows environment. And your question is also mine.
I did not notice any _declspec(dllimport) in the header files. Does it mean that the library has not been compiled with the exporting declaration ? And if not exported, would it work anyway with MSVC ? -
@gav007
As per the code in the link I gave, I think that the__declspec(dllexport)
only has to go against the function definition --- i.e. its code implementation in its C/C++.c
/.cpp
source file --- not against the function's declaration in the header.h
file you are seeing. You don't have its source code to look at? Also I asked how you know that this function has been suitably marked for export for you to use by its developers? If they have not said you can call it it may (well) not have been designated with the__declspec(dllexport)
by them.Suggest you Google for
windows dll list exported symbols
or similar, e.g. https://social.msdn.microsoft.com/Forums/windowsdesktop/en-US/ab3cd884-fcb3-442a-9798-62d9ed31c1cb/list-of-exported-functions-of-a-dll?forum=windowssdk. There are various tools you can use to inspect the DLL to see just what it exports, e.g. I thinkdumpbin /exports file.dll
. -
@JonB
Nice trick !
Usingdumpbin.exe
, I could notice that the export call isXxxInitialize
(starting with an upper character), while the header file really mentions the call starting with a lower case character ! I did not know that MSVC could manage this.
I updated the code above and it worked.
Many many thanks.@mrdebug
Thanks also for the reaction.Best regards.
-
Ooops ! Too fast !
The exported calls I got with the
dumpbin.exe
are actually the C++ interface. That's the reason why they starts with an upper case character. And unfortunately, this interface makes use of class interfaces Qt Creator is not able to understand (until now) since many MSVC keywords are used.
So how comes that the C calls are not visible ? -
@gav007
This is all a bit outside my pay-grade. But if that shows what has actually been exported, and there simply isn't a plain C one corresponding to yourextern "C" long __stdcall xxxInitialize( void );
, then that indicates to me that such a symbol is not actually exported. I go back to: how do you know that line in a header file actually corresponds to a function which was DLL-exported by them?P.S.
This is way beyond me now, but have a read of https://stackoverflow.com/a/41910450/489865. He's talking aboutextern "C"
in combination with__stdcall
. Then again, he may be saying it is not a problem if you are x64 rather than x86... ! -
@mrdebug
But the OP does not have the sources to the DLL he wants, it's third-party. And he can't get the name he believes he wants to import to work. So I really do not mean to be impolite, please don't take it that way, but how is anything you are writing relevant to his situation? -
@mrdebug
No problem :) While your code would work fine in itself, I think you missed the point that the OP is trying to import against a third-party DLL over which he has no control. He's doing the right stuff to load the library and try to resolve a symbol, like your code, but we're not sure how the DLL was written/compiled/linked. -
Hi, thanks for your reflections.
I know that the C calls are usable because the small SDK (intended for MSVC) also provides some sample codes.
Other question : for the C++ interface, if I translate the class declarations into a standard that Qt could understand, could it give a chance ? Here is a sample declaration:
#define OUT ... #define THIS_ ... #define DECLSPEC_NOVTABLE ... #define __STRUCT__ struct #undef interface #define interface __STRUCT__ #define STDMETHOD(method) virtual COM_DECLSPEC_NOTHROW long STDMETHODCALLTYPE method #define DECLARE_INTERFACE_(iface, baseiface) interface DECLSPEC_NOVTABLE iface : public baseiface ... #undef INTERFACE #define INTERFACE IXxxFifo DECLARE_INTERFACE_(IXxxFifo, IUnknown) { //~~~ IUnknown methods ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ STDMETHOD(QueryInterface)(THIS_ IN REFIID riid, OUT PVOID *ppv) PURE; STDMETHOD_(ULONG,AddRef )(THIS) PURE; STDMETHOD_(ULONG,Release)(THIS) PURE; //~~~ IXxxFifo methods ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ STDMETHOD(GetCapacity )(THIS_ OUT PUINT16 pwCapacity) PURE; STDMETHOD(GetEntrySize)(THIS_ OUT PUINT16 pwSize) PURE; STDMETHOD(GetFreeCount)(THIS_ OUT PUINT16 pwCount) PURE; STDMETHOD(GetFillCount)(THIS_ OUT PUINT16 pwCount) PURE; STDMETHOD(GetFillLevel)(THIS_ OUT PUINT16 pwLevel) PURE; }; #undef INTERFACE
Worth a try ?
Regards
-
I installed MSVC 2017 Community edition for tests.
The C functions cannot be linked as well. The sample codes cannot be compiled.
As @JonB stated it, those calls are not exported !I will attempt to use the provided C++ class interfaces, but I'm afraid that something goes wrong at a certain point.
Best regards.
-
Hi, that sample declaration above looks like an ancient version of the CAN bus driver, for example see here: http://gitlab.unique-conception.org/qt-can-2.0/qt-can-driver-ixxat/blob/master/VciWindows_4.0/inc/vcisdk.h
Perhaps you have more luck if you try a newer version: https://www.ixxat.com/support/file-and-documents-download/drivers/vci-v4-driver
Edit: anyways as you say, those interfaces are not callable directly with C or C++, you have to use an ancient technology called COM :-(
This is still supported in Qt, through something called ActiveQt, see more hereEdit again: forgot to mention, if indeed you're developing with a CAN bus card, Qt supports the CAN bus as well, see here
-
@hskoglund
Damn ! I'm discovered. ;-) For an unknown reason, i did not wish to divulge it ;-)I already used Qt CAN for other projects. In the current case, I have to use the VCI driver (in the version 4) on a Windows platform.
I'm currently in a test phase and I did not decide the way I will use this driver yet.
I attempt to use the C interface to be able to load the library at runtime and also because of the troubles I face when compiling with MinGW.
I already found a plugin implementation here but I could not set it up.
I'm currently checking with MSVC 2017 but this cannot be a solution.Thanks for the link to ActiveQt. I will check.
Regards.
-
@gav007 There should be plenty of examples on how to call the VCI driver through COM I think. Perhaps you'll be not 100% covered by using ActiveQt and instead have to go native and call COM directly. And doing that is much easier with the MSVC compiler as compared to the MinGW compiler.
-
So.
It works using MSVC 2017 Community edition, but the result is really unstable. And I cannot get a debugging session (?). One of the reasons may be that I'm unfamiliar with such Windows environment ;-).
Investigation in this way will stop here and we abandon the VCI driver. We will choose a new USB-to-CAN device that can be easily used within a Qt Can plugin implementation (and with MinGW).Many thanks for your support.
Best regards.