I've got a dll from a vendor I want to use in a C++ Visual Studio 2012 project. It comes with a .lib file.
When linking I get:
Error 1 error LNK2019: unresolved external symbol __imp__FT_CreateDeviceInfoList referenced in function "int __cdecl Ftexam(void)" (?Ftexam##YAHXZ) C:\Users\Terry\Documents\Visual Studio 2012\Projects\Win32Project1\Win32Project1\ftexam.obj ftexample
I've read similar posts but I'm not getting anywhere. I think I'm doing everything according to those answers, but I still get a undefined reference error when linking.
I've added the dll.lib file to the /Linker/Addional Dependencies list.
I've made sure the dll.h file is included in my source
I've put the dll.lib file with in my project directory and made sure that if I remove it from there,I get cannot find dll.lib when linking (i.e., it is "in the build")
In my supplied dll.h header file I have this:
#ifdef DLL_EXPORTS
#define DLL_API __declspec(dllexport)
#else
#define DLL_API __declspec(dllimport)
#endif
.
.
#ifdef __cplusplus
extern "C" {
#endif
typedef ULONG FT_STATUS;
.
.
DLL_API FT_STATUS FT_CreateDeviceInfoList(
LPDWORD lpdwNumDevs
);
and my calling code is:
#include dll.h
int Ftexam(){
FT_STATUS ftStatus=0;
DWORD numDevs = 0;
// create the device information list
ftStatus = FT_CreateDeviceInfoList(&numDevs);
}
I realize there is probably some name mangling going on so I looked at the DLL symbols using depends. It lists these exports with the "Undecorate C++ functions" option disabled, (so, these are the unmangled exports):
FT_Open
FT_Close
FT_Read
....
FT_CyclePort
FT_CreateDeviceInfoList< <<<<<this reference!!!!
FT_GetDeviceInfoList
The identified export above obviously does not match __imp__FT_CreateDeviceInfoList
Is there a tool around that can look at the definitions in a .lib file, or some way for visual studio to display that?
UPDATE:
With the use of dumpbin I was able to see the symbol in the .lib was
__imp_FT_CreateDeviceInfoList
instead of
__imp__FT_CreateDeviceInfoList
this I tracked to the .lib for the 64 bit version of the DLL instead of the 32 bit version. (One of the combinations I tried to solve this in the first place).
To simplify the post, I had indicated that the header contained:
DLL_API FT_STATUS FT_CreateDeviceInfoList(LPDWORD lpdwNumDevs);
When in fact, it actually contains:
DLL_API FT_STATUS WINAPI FT_CreateDeviceInfoList(LPDWORD lpdwNumDevs);
because WINAPI was #defined
so changing
#define WINAPI
to
#define WINAPI __stdcall
along with having the correct .lib fixed the issue.
FT_CreateDeviceInfoList() is not declaring any calling convention in the .h file, so it uses whatever the compiler's default calling convention is. Your compiler is defaulting to __cdecl, which is normal behavior for most C++ compilers. Chances are that the compiler that created the DLL is actually using a different default calling convention instead. Try editing the .h file to specify __stdcall, for example, and see if it makes any difference, eg:
DLL_API FT_STATUS __stdcall FT_CreateDeviceInfoList(LPDWORD lpdwNumDevs);
Most DLL vendors use __stdcall for compatibility with the widest selection of compilers, not just C/C++ compilers, though some vendors do use __cdecl or even __fastcall (which is implemented differently by different compiler vendors, so watch out with that one).
Worse case scenario, you can use a disassembler, like IDA or WinDASM, or just use your IDE's own debugger, to look at the actual assembly code for FT_CreateDeviceInfoList() inside the DLL and see how it is managing the call stack when accessing the lpdwNumDevs parameter and returning the FT_STATUS value. That will tell you exactly which calling convention it is actually using.
UPDATE: doing some online searches, I see many examples of .NET code that call FT_CreateDeviceInfoList() with the __stdcall calling convention applied to its declaration, so that is a good place to start. If that works, then you should contact the DLL vendor and ask them to fix their .h file accordingly.
Open a Visual Studio command prompt. Fire the following command to list the symbols in the lib file:
dumpbin /all dll.lib
Redirect the above to a text file, as the output scrolls off quickly
What you're doing should work as far as I can see. But you can always just forget about the .lib file and use the DLL directly, loading it with LoadLibrary and getting the addresses of the functions you want to use with GetProcAddress.
Related
I'm playing with DirectShow filters from here: http://tmhare.mvps.org/downloads.htm.
The example Capture Source Filter works fine if I use the included binary on a Windows 10 64-bit machine.
Instead, re-compiling the source code leads to the following error when I try to register the filter:
The module "..." was loaded but the entry-point DllRegisterServer was not found.
As far as I know this is might due to some mismatches in architectures.
This is what I did:
from here: https://github.com/cplussharp/graph-studio-next, I compiled both x86_MT and x64_MT lib for BaseClasses
I created a new project, added the existing Capture Source Filter source files, added the correct paths for includes and libs of the previous point, set the code generation to MT and build again both x86_MT and x64_MT.
I tried to register the output filters with DirectShow Filter Manager (http://www.softella.com/dsfm/index.en.htm) - it worked fine with the pre-compiler binary. Of course I've unregistered the old filter before try with the fresh compiled one.
Dependency Walker seems say nothing interesting. It complains about the missing of a lot of API-MS-WIN*.dll but they are actually on file-system and anyway those errors there are also for the working binaries.
At this point, to avoid to give random trials, what one should do to narrow down the source of errors?
Is there any tool available that might help me to understand where I was wrong?
UPDATE
I found the root of the problem: the original code uses a def file to export the function, but they aren't actually exported.
This is the def file:
LIBRARY Vcam.ax
EXPORTS
DllMain PRIVATE
DllGetClassObject PRIVATE
DllCanUnloadNow PRIVATE
DllRegisterServer PRIVATE
DllUnregisterServer PRIVATE
but adding this file to the sources isn't enough.
Reading other posts here leads me to understand I need to use __declspec(dllexport) instead of the def file.
Hence I added an header file for the dll.cpp with this code:
#pragma once
#include <winnt.h>
#include <minwindef.h>
#define DLLEXPORT __declspec(dllexport)
STDAPI DLLEXPORT DllRegisterServer();
STDAPI DLLEXPORT DllUnregisterServer();
DLLEXPORT BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved);
STDAPI DLLEXPORT DllCanUnloadNow();
STDAPI DLLEXPORT DllGetClassObject(__in REFCLSID rClsID, __in REFIID riid, __deref_out void **pv);
But still dumpbin tells me that functions are not exported.
Here is described how to use the def files:
https://msdn.microsoft.com/en-us/library/34c30xs1.aspx
The missing step was add it to Property Page > Linker > Input > Module Definition File.
The module "..." was loaded but the entry-point DllRegisterServer was not found.
With such error Dependency Walker should be able to confirm whether DllRegisterServer is available or not - the utility shows exported functions.
If the function is exported, the problem might be with dependency or wrong bitness, that is the problem that results in inability to LoadLibrary the DLL.
If the function is not exported, the project is likely to be missing a .DEF file or otherwise does not define an exportable symbol (e.g. using respective #pragma).
I have a dll, which accesses some classes outside of its project (I'm using Visual Studio, so I have two projects). The thing is, in the header that the dll includes, which is outside of the dll's project, there are only bodies of functions, like this:
x.h
class x
{
void myFunc();
}
And in another cpp file, outside of the dll file:
#include "x.h"
x::myFunc()
{
//.....
}
The dll is only getting the bodies of the functions, so when I compile, I get lots of unresolved external symbols (I'm quite sure that this is the issue, because I tested with another class fully built in a .h file, in another project, and no errors). So how can I solve this mystery?
It is normal for the import headers to only have function signatures; the actual function bodies are already compiled into the DLL binary and are resolved at link time by linking into the actual DLL.
The first thing to try is to make sure you are actually linking to the said DLL. It isn't enough to just include the header, you also need to link to the binary. So in your project configuration, you need to add a link to (for example) the .lib file that gets created along-side the DLL when the DLL is compiled (if in MSVC). This lib file lets the linker know how to connect the function signatures you included via the import header to the actual implementations contained in the DLL. If you're on a different platform, the mechanics might be a little different, but the concepts will be similar.
Edits:
The next step is to make sure the binary is actually exporting the symbols you're trying to link against. Make sure that all interface signatures are being exported via __declspec(dll_export) prefixes. Normally this is wrapped up in an IFDEF so that the header is declared export while the DLL is being compiled, but not when that header is included in a client project. Next, you could use dumpbin to check the mangled export names, and see if there is anything unexpected.
Here's a modified version of your example that illustrates this style of export (note, I haven't tested if this compiles, apologies for any typos):
#ifdef BUILDING_MYDLL
#define MYDLL_API __declspec(dllexport)
#else
#define MYDLL_API __declspec(dllimport)
#endif
class MYDLL_API x
{
void myFunc();
}
You would then set your configuration to define BUILDING_MYDLL when compiling the dll, but not when compiling the executable. This way the functions are only marked export when compiling the library dll. Now you can mark your public API functions with MYDLL_API and they should get exported during build.
Please note that dll_export, dll_import, and declspec are all very MSVC-specific constructs. Other compilers/runtimes handle symbol export in different ways.
There's multiple ways to link DLL into your app on Windows, check out this existing question/answer:
https://stackoverflow.com/a/2060508/1701823
A friend of mine gets a bunch of error when creating a DLL. Visual Studio complains about unresolved external symbols. I am mainly an Unix user so I might be mistaken there. On Unix, when you create a static library (an archive), it does not do much more than concatenating the different object files into an archive file. I would expect dynamic objects to be created the same way, but apparently, an extra link stage takes place.
First question: Why is there a link stage for the dll?
In this case, the DLL indeeds contains undefined symbols because we expect the DLL to find those symbols within the EXE file. This is quite opposite the typical DLL behaviour, where an EXE uses the symbols defined in the DLL. To make it clear, I expect those symbols to be found right when the DLL is loaded in memory.
Second question: How can I make a DLL use symbols defined in the EXE file?
EDIT:
I reformulated the question, as I think I did not state the problem clearly enough.
You described the origin of your problem as: "I want the DLL to import some symbols from the exe file" in the comment to the answer of Luchian Grigore. You wrote additionally in the text of your question that you want "the DLL to find those symbols within the EXE file. we expect the DLL to find those symbols within the EXE file."
Mostly it's design question whether to export functions or data from the exe or not. Typically one creates export only from DLL. If EXE need to provide some information to DLL it provide the information by parameters. For example you an call in EXE some function MyFunc implemented and exported in the DLL. As additional parameter of MyFunc you get context pointer which can get DLL directly or indirectly all information for EXE which needed.
In some seldom situations you do can export data or functions from EXE. For example you an use DumpBin.exe utility (just start "Visual Studio Command Prompt (2010)" to use it) to verify that Outlook.exe exports
DumpBin.exe /exports "C:\Program Files\Microsoft Office\Office14\OUTLOOK.EXE"
File Type: EXECUTABLE IMAGE
Section contains the following exports for outlook.exe
00000000 characteristics
4E79B6C8 time date stamp Wed Sep 21 12:04:56 2011
0.00 version
1 ordinal base
66 number of functions
66 number of names
ordinal hint RVA name
1 0 00B58A88 CleanupAddressComponents
2 1 00B58A88 CleanupNameComponents
3 2 00228DC4 DllCanUnloadNow
4 3 004848F8 DllGetClassObject
...
65 40 0038EF30 UpdateContactTracker
66 41 00902788 dwIsLoggingEnabled
I can explain how you can implement the scenario without long discussion when and whether you really should do this.
First of all the LIB file contains OBJ files which has another format as Program Executable (PE). During compilation different common section will be placed in OBJ file. It's very important, that program executable (EXE or DLL) contains not only from the code, but it has many additional information in the header part of the PE. The most important are
Export Directory
Import Directory
Import Address Table Directory
Base Relocation Directory
Resource Directory
You can use DumpBin.exe utility (just start "Visual Studio Command Prompt (2010)" to easy use it). To see information about the headers you can use DumpBin.exe /headers my.exe. To see contain of the Export Directory you can use DumpBin.exe /exports my.exe and so on.
If you compile DLL which exports some functions or data the LIB file will be additionally created. It's so named import library. If you use the LIB in your EXE project which uses some functions or data from the DLL the linker will resolve the external references and places in import directory of EXE information about the functions which should be resolved at the load time.
So the import library contains only the templates for filling Import Directory and Import Address Table Directory in EXE.
In general one can in the same way export some data of functions from EXE, create LIB, uses the LIB in the DLL project and in the way implement importing some information in DLL from EXE.
I made the demo project which demonstrate the way. Please, read carefully the compilation instructions at the end of my answer if you want delete all LIBs from the Project and create all yourself. The code of ExportFromExe.c (the EXE):
//#define CREATE_IMPORT_LIBRARY_ONLY
#include <Windows.h>
EXTERN_C __declspec(dllexport) int someData = 0;
EXTERN_C __declspec(dllexport) int __stdcall myFunc (int x);
EXTERN_C __declspec(dllexport) int __stdcall MyFunc();
int __stdcall myFunc (int x)
{
return x + 10;
}
#ifndef _DEBUG
int mainCRTStartup()
#else
int main()
#endif
{
someData = 5;
#ifndef CREATE_IMPORT_LIBRARY_ONLY
return MyFunc();
#endif
}
The code of MyDll.c (the DLL):
#include <Windows.h>
EXTERN_C __declspec(dllexport) int myData = 3;
EXTERN_C __declspec(dllimport) int someData;
EXTERN_C __declspec(dllimport) int __stdcall myFunc (int x);
#ifndef _DEBUG
EXTERN_C BOOL WINAPI _DllMainCRTStartup (HINSTANCE hinstDLL, DWORD fdwReason,
LPVOID lpvReserved)
#else
BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
#endif
{
if (fdwReason == DLL_PROCESS_ATTACH)
DisableThreadLibraryCalls(hinstDLL);
return TRUE;
UNREFERENCED_PARAMETER (lpvReserved);
}
EXTERN_C __declspec(dllexport) int WINAPI MyFunc()
{
return someData + myFunc(myData);
}
To be able to create the project successfully at the first time we have to solve the problem: "who was first: the chicken or the egg?" because the EXE project depend from MyDll.lib and the DLL project depends from ExportFromExe.lib. For the first compilation of EXE we can temoprary remove $(OutDir)MyDll.lib from the linker setting of EXE project and define CREATE_IMPORT_LIBRARY_ONLY. As the result we'll create ExportFromExe.exe and ExportFromExe.lib. In more large projects one can use Undefined Symbol Only (/FORCE:UNRESOLVED) option of linker instead. Then we can build MyDll project which creates MyDll.dll and MyDll.lib. Now you can remove CREATE_IMPORT_LIBRARY_ONLY from the EXE and include $(OutDir)MyDll.lib as the linker setting ("Additional Depandencies" in "Input" part of settings). The next build of EXE project produce the final solution.
I used some small tricks to remove C-Runtime and reduce the size of EXE and DLL to 2,5 or 3 KB. So you can use /all switch of DumpBin.exe to examine full information from EXE and DLL inclusive RAW binary data.
Because the EXE return results as ERRORLEVEL you can test the application in the commend prompt:
echo %ERRORLEVEL%
0
ExportFromExe.exe
echo %ERRORLEVEL%
18
First question: Why is there a link stage for the dll ?
Because that's the way it is. There's a linking stage everytime you want to create a binary. The symbols need to be resolved somehow, right?
Second question: How can I do that ?
You add the lib file that is generated alongside the dll to the Additional Dependencies from your project - Properties -> Configuration Properties -> Linker -> Input
Note:
In case you don't already do this, in order to be exported to the lib, symbols must be declared with _declspec(dllexport). When you include the headers, you tell the compiler that those symbols are to be imported with _declspec(dllimport).
I am importing an C++ DLL in an Inno Setup install script. The DLL code is as follows:
void __stdcall SetFbParam(
char *dbFileName,char *dbTableName,char *dbParamName,char *dbParamValue) {
// of no use here and doesn't change anything
}
In the Inno Setup, I import it using
procedure FBset(dbFileName,dbTableName,dbParamName,dbParamValue: String;);
external 'SetFbParam#files:MyDll.dll stdcall setuponly';
However, I always get a runtime error during launch of the installer, saying that it cannot import my dll. I tried it with various calling conventions, but it always fails.
If it's of any importance, I'm running Win7 x64 with UAC on (the installer requests rights elevation and crashes after that).
The exact message is:
Error
Runtime error (at -1:0):
Cannot import
dll:C:\Users\Nevod\AppData\Local\Temp\is-6LOEC.tmp\MyDll.dll
The dll is there.
Thanks!
Is MyDll.dll 32-bit?
Does MyDll.dll depend on any other DLLs in the same directory? If so, you need to list the name(s) of those DLLs after MyDll.dll to ensure that they are extracted before MyDll.dll is loaded, and you likely need the loadwithalteredsearchpath option as well. Example from the help:
procedure ADllFunc(hWnd: Integer; lpText, lpCaption: String; uType: Cardinal);
// A.dll depends on B.dll
external 'ADllFunc#files:A.dll,B.dll stdcall loadwithalteredsearchpath';
(I know it is old but maybe some other hits this one too)
Most probably the name of the function is mangled in the C++ DLL. I had the same problem and I was able to solve it by recompiling the dll. In short:
If you export from C++ something like:
void __stdcall foo()
you will get a function called (Visual Studio):
?foo##YGXXZ
To prevent name mangling you should use extern "C" directive. Example (Visual Studio)
extern "C" __declspec( dllexport ) void __stdcall foo()
However I have found that Visual Studio will continue to mangle and you get something like:
_foo#0
The sole way I was able to get clean names is explained here:
C++ DLL Export: Decorated/Mangled names
And the culprit is indeed __stdcall. If you remove that from your declaration:
extern "C" __declspec( dllexport ) void foo()
you will again get a clean export, even without a DEF file. IMO this should be good enough, as the code above declares a "C" exported function and the default calling convention for C is stdcall. However I haven't had the time and disposition to validate this as adding a DEF file is way easier than navigating asm code and check stack pointers :)
In order to use DLLs in Inno Setup's [Code] section please make sure:
DLL is in 32 bit mode (even if the installer is built for 64bit and is running in 64bit mode)
exported functions have
extern "C" __declspec( dllexport )
modifier
use cdecl calling convention because stdcall mangles name (https://learn.microsoft.com/en-us/cpp/cpp/stdcall). Of course it is possible to specify mangled name in Inno Setup import statement. But it seems easier to just use cdecl.
As mentioned in other answers, do not forget to embed all dependencies of your DLL. Though if it is your DLL, better might be to get rid of (or at least reduce) the dependencies.
For example when building C++ DLL in Visual Studio, link the runtime statically, not dynamically.
In project Properties, go to C/C++ > Code Generation > Runtime Library and select Multi-threaded (not DLL).
There are also tools that can embed other external dependencies.
See Embedding DLLs in a compiled executable
I've managed to get input hooks working, but now I'm kinda lost with putting them into a library.
I have a simple header with INPUTHOOK_EXPORTS defined in the IDE, so the dll exports (Visual Studio).
#pragma once
#ifdef INPUTHOOK_EXPORTS
#define INPUTHOOK_API __declspec(dllexport)
#else
#define INPUTHOOK_API __declspec(dllimport)
#endif
INPUTHOOK_API void InstallInputHook();
INPUTHOOK_API void RemoveInputHook();
and of course:
The cpp file
The thing is, when I try to compile this library, I get two unresolved externals, one for SetWindowsHookEx and for UnhookWindowsHookEx respectively. Why these two functions are not available, while others are and without any problem? As far as I see, I do have the includes right.
Thank you
SetWindowsHookEx is a macro that should turn into SetWindowsHookExA' for ascii orSetWindowsHookExWfor wchar. Similary forUnhookWindowsHookEx` .
The error reported should be specific to which function is missing - A or W - which seems to indicate for some reason the macro is not in place.
You seem to be missing winuser.h in the cpp, however this or an equivalent may be in the pre-compiled stdafx.h header.
You need to include user32.lib while building (linking) your library (normally in the default included libs).
From MSDN topic LowLevelKeyboardProc:
This hook is called in the context of the thread that installed it. The call is made by sending a message to the thread that installed the hook. Therefore, the thread that installed the hook must have a message loop.