Written in C (into a C++ project):
I have two projects in VS08 under the same solution. One is a DLL file and the other ("runner") is the a console application for using/testing the DLL file. The header file has a header file with all the functions (__declspec(dllexport)). When I use functions without any arguments, by the runner console application, they run OK. When I try to call a function with arguments I get unable to resolve symbol... error. The strange thing is that VS08 recognizes the function and I can open it from the runner main() with the right-click menu, however it can't find it.
Worth mentioning that I am including the header file and not importing the DLL with function pointers... My feeling is that the functions get renamed somehow in the compiling process and the linker can't find the functions with the arguments. If I would be able to to see the list of new names (inside the object file?) maybe I could include them in the header file to fix this?
Thanks.
Written in C (into a C++ project):
That's possibly a pretty good lead. A C program cannot consume functions that were written in C++. When you use __declspec(dllexport), the function gets exported with its C++ name. Which is decorated by the compiler, a trick to allow overloaded functions to link properly. A C compiler doesn't apply the same kind of decoration, the linker will complain that it can't find the function.
To make this work, you have to declare the function with the extern "C" declarator. Make the .h file look like this:
#ifdef __cplusplus
extern "C" {
#endif
#undef DLLEXPORT
#ifdef BUILDING_MYDLL
# define DLLEXPORT __declspec(dllexport)
#else
# define DLLEXPORT __declspec(dllimport)
#endif
DLLEXPORT void Foo(int arg);
// etc..
#ifdef __cplusplus
}
#endif
In your DLL project, use Project + Properties, C/C++, Preprocessor and add BUILDING_MYDLL to the Preprocessor Definitions settings.
A short explanation for this macro madness: the #ifdef __cplusplus ensures that all the DLL declarations are declared extern "C" when they are compiled by the C++ compiler so that they'll match the C compiler symbols. The DLLEXPORT macro ensures that the functions are exported when you build the DLL, imported when you link the DLL import library in another project.
You can get additional troubleshooting from the dumpbin.exe utility by running it with the /exports option on your DLL. It shows the exact names of exported functions. Run it from the Visual Studio command prompt. A mismatch between the names you see in the output verses the linker error messages is a sure sign of trouble.
First off: Intellisense finding it ('open for the rightclick menu' eeeeck?) is no proof; it proves you put the declaration in a header file;
You are probably right about the name mangling thing: If you have C externals you need to declare them inside an extern "C" {} block:
extern "C" {
void dostuff(int param1, char* param2);
}
instead of
extern void dostuff(int param1, char* param2);
The most flexible approach is probably to include the extern "C" around the complete C header file conditionally:
// Sample.h
#if defined(__cplusplus)
extern "C"
{
#endif
// Function declarations
#if defined(__cplusplus)
}
#endif
See MSDN for more info
Related
Let me begin by saying, I know what the purpose of the __declspec(dllexport) keyword is. But experimenting for the sake of it, when importing functions with this keyword vs when not using the keyword, I don't see any difference in the import/export table of the EXE that gets generated.
To illustrate, I have a DLL project that includes a header file with the following declaration:
__declspec(dllexport) int somefunc(int, int)
And then another project that builds an EXE importing functions from the DLL:
#include "path_to_header_file_of_dll"
int main() {
somefunc();
}
When I build this EXE, it seems to compile and build fine even though I have declared the function as exporting that symbol, when it is clearly not exporting it, only importing it. Why doesn't the compiler complain? Also this doesn't cause the generated EXE to have an export table. But builds an import table instead. The compiler seems to have figured out the correct thing to do and does it.
If this works, then why bother with code like this below:
#ifdef BLEH
#define DLLEXPORT __declspec(dllexport)
#else
#define DLLEXPORT __declspec(dllimport)
#endif
DLLEXPORT int somefunc(int, int);
I'm writing a program to convert image and compare the speed of processing data in C and assembly. I have 3 projects:
main project in C
DLL in C to convert image
DLL in ASM to convert image
In C DLL header, I simply wrote:
#ifdef PROJEKTC_EXPORTS
#define PROJEKTC_API __declspec(dllexport)
#else
#define PROJEKTC_API __declspec(dllimport)
#endif
...
extern PROJEKTC_API unsigned int ThreadID;
PROJEKTC_API void __cdecl funkcjaC(void* Args);
and after including this header, I can access variable ThreadID both in main project and C DLL.
The problem starts when I try to do the same in ASM. I tried constructions like extern ASMThreadID:dword in .code block, but it won't work.
The error I got: error LNK2019: unresolved external symbol _ASMThreadID referenced in function _MyProc1
I have a feeling that it's a matter of 1-2 lines of code, but I can't figure out which instruction should I use.
I link the projects by module definition file in ASM and adding ASM.lib file into the Linker->Input of main project.
Do you have any suggestions?
With small help from old posts in asmcommunity.net, I managed to get it working:
In .asm file, before .data segment:
EXTERNDEF C ASMThreadID:DWORD
In .data segment:
ASMThreadID dd 0
In .def file of ASM DLL:
LIBRARY "nameOfProject"
EXPORTS
...
ASMThreadID
In main C program header (like global declaration):
extern __declspec(dllimport) unsigned int ASMThreadID;
Now it works like a charm.
The 'public' declaration sent me to the right way of searching. Thanks for your help, mate!
Here's my library Lib.c file:
#include <stdio.h>
int helloworld(){
printf("Hello World DLL");
}
Here's my exe Main.c file:
int helloworld();
int main(int argc, char** argv){
helloworld();
}
I would like to create Lib.dll, and Main.exe, where Lib.dll comes from Lib.c and Main.exe links against Lib.dll.
What are the specific steps to achieve this?
See this related question on how to build the DLL.
Your library code as it stands does not export any symbols and your executable does not import the symbols from your library. Two typical patterns for doing that are shown below but you might want to read up on that first.
The first method uses __declspec() to declare in the code what functions (or other items) are exported from your DLL and imported by other executables. You use a header file to declare the exported items and have a preprocessor flag used to control whether the symbols are exports or imports:
mylib.h:
#ifndef MYLIB_H
#define MYLIB_H
#if defined(BUILDING_MYLIB)
#define MYLIB_API __declspec(dllexport) __stdcall
#else
#define MYLIB_API __declspec(dllimport) __stdcall
#endif
#ifdef __cplusplus
extern "C" {
#endif
int MYLIB_API helloworld(void);
#ifdef __cplusplus
}
#endif
#endif
I have also specifically set the calling convention to __stdcall as are most DLL functions (I could have used WINAPI instead of __stdcall if I had included windows.h) and have declared the functions as extern "C" so their names do not get mangled when compiled as C++. Not such a problem here as it's all C, but if you were to build the DLL from C source and then try to use it from a C++ executable then the imported names would be incorrect.
The code could then look like this:
mylib.c
#include "mylib.h"
#include <stdio.h>
int MYLIB_API helloworld(void)
{
printf("Hello World DLL");
return 42;
}
You'd build your DLL using the following command line. As well as creating the DLL it will create the import library (.lib) required to use your DLL from another executable (as well as the export file, but that is only required in certain circumstances):
cl /DBUILDING_MYLIB mylib.c /LD
The /DBUILDING_MYLIB argument defines the preprocessor symbol used to control whether the functions in the DLL are exports (if it is defined) or imports (not defined). So you'd define it when building the DLL but not when building your application.
The /LD parameter tells cl to produce a DLL.
The second method is to use module definition files as mentioned in the comments. You can use the code you already have but you also need to create the module definition file. At it's simplest it looks like this:
LIBRARY mylib
EXPORTS
helloworld
In this case to build the DLL you require the following command line:
cl /LD mylib.c /link /DEF:mylib.def
You could then code your application so that it used your library header with the imported version of your DLL function:
main.c
/* No need to include this if you went the module definition
* route, but you will need to add the function prototype.
*/
#include "mylib.h"
int main(void)
{
helloworld();
return (0);
}
Which you could then compile with the following command line (assuming the import library from the DLL creation is in the same directory as your main.c). This step is the same whether you used declspec or module definition files:
cl main.c /link mylib.lib
Arguments passed after the /link argument are passed onto the linker command line as they appear, so as just a filename it is used as extra input to link into the executable. In this case we specify the import library generated when we built the DLL.
The command lines I've shown here are pretty much the absolute minimum you'd need but it'll allow you to create a DLL and link an application to it.
I have assumed the calling convention is correct in all of the above and I have not experimented much to see whether I got it wrong at any point.
I have a third party application that allows you to call C functions from DLL files. Provided sample to this app shows you can call MessageBoxW from user32.dll. It also allows you to call C functions from your DLL files.
I've did a DLL from a file.h file like this:
_declspec (dllexport) void example(int);
and file.c like this:
#include <stdio.h>
#include "file.h"
_declspec (dllexport) void example(int s1)
{
printf("dsa");
}
And compile it with C/C++ Compiler Version 15 from Windows SDK like this:
cl file.c /DLL /LD
And i get proper compilation with DLL file. In DLL functions examiner I see my function. I drop this file into System32 folder and call it from this third party application.
Application finds the file, but is unable to find the function.
I think the cause of the problem is that i declare (or compile) my DLL in other fashion/way/standard that Windows libraries (like user32.dll) because user32.dll works fine.
I've found that the third party app uses this kind of calling functions in DLL:
winapi_abi Used for calling Windows system functions. These are
declared as stdcall on Windows, but do not have mangled names.
So my question is: how to prepare and compile DLL file in the user32.dll fashion (stdcall?) so it will work with third party app?
The easy answer is:
__declspec(dllexport) void __stdcall example(int);
And the same in the implementation, of course.
If you look into windows.h and friends you'll see:
#define WINUSERAPI __declspec(dllexport)
#define WINAPI __stdcall
And then:
WINUSERAPI int WINAPI MessageBoxW(HWND,LPCWSTR,LPCWSTR,UINT);
But if you just define a few functions there is no need for the macros.
Include a .def file to defeat stdcall name decoration. Then you can get rid of the __declspec(dllexport) clutter.
You are not specifying any calling convention in your function declaration, so the compiiler will default to __cdecl, which decorates the exported name. Also, if you compile in C++ instead of C, additional decorating occurs as well. You need to do something like the following in your code to get around all of that:
file.h:
#ifndef fileH
#define fileH
#ifdef _BUILDING_DLL_
#define MYEXPORT __declspec (dllexport)
#else
#define MYEXPORT __declspec (dllimport)
#endif
#ifdef __cplusplus
extern "C" {
#endif
MYEXPORT void __stdcall example(int);
#ifdef __cplusplus
}
#endif
#endif
file.c:
#include <stdio.h>
#define _BUILDING_DLL_
#include "file.h"
void __stdcall example(int s1)
{
printf("dsa");
}
Thank you all. The solution was to add def file with exports, include it in compiler by /DEF:file.def, use Remy version (without #define _BUILDING...) and remove _stdcall.
I desperatly need your help.
Im trying to compile statically the poppler library (specially for qt4) on windows with the visual c++ 2008 compiler. To achieve this task I needed to compile a bunch of other libraries as dependencies for poppler statically too. When I finally generate the static version of poppler I got a linking error when building my app:
error LNK2019: unresolved external symbol "__declspec(dllimport)...
I already added the new include path and linked the poppler-qt4.lib but i get the error anyways.
Searching for a solution I found this discussion here in stackoverflow
How to link a static library in Visual C++ 2008?
whit this information I looked on the include files of the libraries (dependencies of poppler like zlib, libpng, cairo, ...) and I found, in various cases, that they don't have a preprocessor directive to especify the static version of the lib.
Example static directive (openjpeg.h):
#if defined(OPJ_STATIC) || !(defined(_WIN32) || defined(WIN32) || defined(__WIN32__))
# define OPJ_API
# define OPJ_CALLCONV
#else
# define OPJ_CALLCONV __stdcall
# ifdef OPJ_EXPORTS
# define OPJ_API __declspec(dllexport)
# else
# define OPJ_API __declspec(dllimport)
# endif /* OPJ_EXPORTS */
#endif /* !OPJ_STATIC || !WIN32 */
Example without static directive (jconfig.h from jpeg lib):
#if defined(_WIN32)
#if defined(libjpeg_EXPORTS)
#define JPEG_EXPORT __declspec(dllexport)
#else
#define JPEG_EXPORT __declspec(dllimport)
#endif
#else
#define JPEG_EXPORT
#endif
My question is: Is not enough to change the properties of the project from dynamic to static so I have to change this headers too?, and if this is true, where can I define this new directives for making a difference between static or dynamic compilation?
Thanks in advance.
First please note Windows does not have any dynamic linkage at all. Surprise! Instead, it uses thunks. So what happens is: if you make a symbol dllexport, it has its actual name, the same name as if it were not dllexport. However it is marked in the object file for exporting.
If you say dllimport, on the other hand, the name is changed, in C roughly by prepending __imp_ to the name, more nasty in C++.
Now, when you link a DLL, you get a DLL (of course) but you also get a LIB file. That is a static link library. Which is the only kind the linker can handle. For each symbol exported from the DLL there is a dllimport symbol in that LIB file, in particular with __imp_ prefix or whatever for C++.
So now in a program or DLL you want to link to that DLL you made you link instead against the import LIB. The import LIB routines are thunks that patch up to the actual load time addresses from the DLL.
So now, if you try to do ordinary static linkage against a LIB file made by LIB.EXE by simply combining OBJ files which contained some dllexport, it will fail if the reference is a dllimport. Because you're refering to __imp_function() when the library actually contains plain function().
So with static linkage, you have to drop the dllimport. AFAIK dllexport is irrelevant. Note that this applies to the client of the library, not the library itself.
What does that mean? Well it is perfectly fine to statically link to a library which in turn dynamically links to another library. In fact by default static links on Windows dynamically link to the C runtime and OS DLLs. So the rule is: the client must chose the method of linking to a library, the provider should provide both versions. But take care they have different names!! (Otherwise the LINK making the DLL will make fred.LIB and the LIB will also make fred.LIB)
If you are changing the project properties from dynamic to static linkage as specified in the openjpeg.h you have to specify preprocessor that can use the static linkage..so in addition to changing the property from dynamic to static, add the preprocessor OPJ_STATIC...
For example:
#if defined(_WIN32)
#if defined(OPJ_STATIC)
# define OPJ_CALLCONV __stdcall
#el if defined(libjpeg_EXPORTS)
#define JPEG_EXPORT __declspec(dllexport)
#else
#define JPEG_EXPORT __declspec(dllimport)
#endif
#else
#define JPEG_EXPORT
#endif