I am trying to determine if it is possible at all to create a static library that:
Internally uses Microsoft/STL, static release runtime (/MT)
Can be linked to objects not using /MT (e.g., Dynamic DLL Release, Static Debug, etc.)
The specific test code I'm trying to get working is as follows:
Header:
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
int EncapLibConcatenate(int a, int b);
#ifdef __cplusplus
}
#endif
Source:
#include "EncapLib.h"
#include <string>
int EncapLibConcatenate(int a, int b)
{
try {
return std::stoi(std::to_string(a) + std::to_string(b));
} catch (...) {
return 0;
}
}
Linking to the above predictably results in a /FAILIFMISMATCH error when not using /MT for the project that links to the above library. I would like to learn of any compiler / linker options to circumvent this issue. If such do not exist, then any other approaches (such as modifying the .obj COFF files post-build) would also be welcome.
As a side note, I am aware that creating a dynamic library is the idiomatic approach to encapsulating library dependencies; this is a question regarding technical possibilities, not best practices. I have also been able to create a runtime-agnostic static library by eschewing any use of the standard library (restricting to C runtime and win32). This question is specifically about a static library that uses the C++ standard library internally (though pointedly not at its interface).
I am currently not sure how I should seperate my code best. I currently programming a software which should run on Linux and Windows. So I decided to put all OS-secificstuff in thier own folder/files.
For example
This is the header file:
#ifdef __linux__
#include <unistd.h>
#elif _WIN64
#include <Windows.h>
#endif
#include <string>
#include <iostream>
#pragma once
class SystemTools
{
public:
// Delay in secounds until the programm continues
static void sleep(int delay);
private:
};
and the OS specific implementation is in the linux/windows folder
Linux:
#ifdef __linux__
#include "../SystemTools.h"
void SystemTools::sleep(int delay)
{
usleep(delay*1000000);
}
#endif
Windows:
#ifdef _WIN64
#include "../SystemTools.h"
void SystemTools::sleep(int delay)
{
Sleep(delay*1000);
}
#endif
This works and I have no problems so far, but when I now have methods which don´t need any OS specific code I created an additional folder "Generic" so I can write the code in there and don´t have to mantain the same code in the linux and windows file. For example like that:
Generic:
#include "../SystemTools.h"
void SystemTools::sleepMin(int delay)
{
sleep(delay*60);
}
#endif
That still workes on Linux but not on Windows (no error but does not compile, used codeblockes for that on windows). So how do I organize my code correct? Should I use only one file with ifdef even it that gets very fast ugly?
(compiler Linux: g++, Windows: should be MinGW)
Firstly I'd suggest you to use the most recent of C++ (C++20 or so) on your project. This way, we can abstract many OS related calls (like threading, synchronization, random numbers and etc).
That means, you won't really need to use too many of OS specific APIs. IE: C++11 and earlier already have a standard way to sleep:
https://en.cppreference.com/w/cpp/thread/sleep_for
In the end, if you really need to call OS specific things on windows and on linux, using a library could be interesting and pay attention that windows C++ compiler (visual studio) really like to use 'pre compiled headers' so, it's interesting to have a single header file where all windows specific headers can be included.
Basically that. You can have a standard Cmake or makefile for your linux build and use .sln Visual Studio project to build it to windows.
That's the way I would do that
I'm working with VC9 on Windows.
I have a library (lets call it libfoo) which is made of the following files ("include guards" and "#include" directives omited for clarity's sake):
// foo.hpp
class Foo
{
public:
static const std::string SOME_CONST;
};
And:
// foo.cpp
#include "foo.hpp"
const std::string Foo::SOME_CONST = "hello";
Foo::SOME_CONST is exported using a .def file.
The library compiles fine: a libfoo.lib file and a libfoo.dll file are generated.
I used this library in a sample program, like:
// main.cpp
#include <foo.hpp>
int main()
{
std::cout << Foo::SOME_CONST << std::endl; // std::bad_alloc here
return EXIT_SUCCESS;
}
A std::bad_alloc is thrown whenever I attempt to use Foo::SOME_CONST.
This only happens if I link dynamically to libfoo. Linking statically results in a perfectly working program.
What could possibly be going on here ? Is it legal to export a std::string constant that way ?
Check if dll actually does dynamic initialization, because it might not, standard has no requirements for dynamic libraries. Wrapping globals in static functions can be the solution.
Use __declspec(dllexport) and __declspec(dllimport). Stop worrying about .def files and all of that rubbish- let the compiler do the work.
Are the library and the main application linking to the same version of the standard library and/or CRT and/or MFC, with exactly the same settings? I've seen allocation issues when using different versions of the CRT, and also fought bugs caused by different iterator debugging settings between a library and its including application.
Recently I was trying to add unit tests to an existing binary by creating a extra (DLLMain) entry point to an application that already has a main entry point (it is a console exe). The application seemed to compile correctly although I was unable to use it as a DLL from my python unit test framework, all attempts to use the exe as a dll failed.
Has anyone any ideas or experience in adding extra application entry point with any input as to why this would or wouldn't work?
There are some problems which you should solve to implement what you want:
The exe must have relocation table (use linker switch /FIXED:NO)
The exe must exports at least one function - it's clear how to do this.
I recommend use DUMPBIN.EXE with no some switches (/headers, /exports and without switches) to examine the exe headers. You can compare the structure of your application with Winword.exe or outlook.exe which exports some functions.
If all this will not helps, I'll try to write a test EXE application which can be loaded as an exe and post the code here.
UPDATED: Just now verified my suggestion. It works. File Loadable.c looks like following
#include <windows.h>
#include <stdio.h>
EXTERN_C int __declspec(dllexport) WINAPI Sum (int x, int y);
EXTERN_C int __declspec(dllexport) WINAPI Sum (int x, int y)
{
return x + y;
}
int main()
{
printf ("2+3=%d\n", Sum(2,3));
}
The only important linker switch is /FIXED:NO which one can find in advanced part of linker settings. The program can run and produced the output "2+3=5".
Another EXE loaded the EXE as a DLL and calls Sum function:
#include <windows.h>
#include <stdio.h>
typedef int (WINAPI *PFN_SUM) (int x, int y);
int main()
{
HMODULE hModule = LoadLibrary (TEXT("C:\\Oleg\\ExeAsDll\\Loadable.exe"));
PFN_SUM fnSum = (PFN_SUM) GetProcAddress (hModule, "_Sum#8");
int res = fnSum (5,4);
printf ("5+4=%d\n", res);
return 0;
}
The program also can run and produced the output "5+4=9".
I don't know for sure, but I would guess that Windows simply refuses to load an EXE in-process and a DLL as a new process, plain and simple.
These questions appear to contain more detail:
Can the DllMain of an .exe be called?
DllMain in an exe?
The simplest way to get both behaviours in one executable image is to design it as a DLL, then use rundll32.exe to execute it standalone. There's no need to write your own wrapper.
I want to make a simple, simple DLL which exports one or two functions, then try to call it from another program... Everywhere I've looked so far, is for complicated matters, different ways of linking things together, weird problems that I haven't even begun to realize exist yet... I just want to get started, by doing something like so:
Make a DLL which exports some functions, like,
int add2(int num){
return num + 2;
}
int mult(int num1, int num2){
int product;
product = num1 * num2;
return product;
}
I'm compiling with MinGW, I'd like to do this in C, but if there's any real differences doing it in C++, I'd like to know those also. I want to know how to load that DLL into another C (and C++) program, and then call those functions from it.
My goal here, after playing around with DLLs for a bit, is to make a VB front-end for C(++) code, by loading DLLs into visual basic (I have visual studio 6, I just want to make some forms and events for the objects on those forms, which call the DLL).
I need to know how to call gcc (/g++) to make it create a DLL, but also how to write (/generate) an exports file... and what I can/cannot do in a DLL (like, can I take arguments by pointer/reference from the VB front-end? Can the DLL call a theoretical function in the front-end? Or have a function take a "function pointer" (I don't even know if that's possible) from VB and call it?) I'm fairly certain I can't pass a variant to the DLL...but that's all I know really.
update again
Okay, I figured out how to compile it with gcc, to make the dll I ran
gcc -c -DBUILD_DLL dll.c
gcc -shared -o mydll.dll dll.o -Wl,--out-implib,libmessage.a
and then I had another program load it and test the functions, and it worked great,
thanks so much for the advice,
but I tried loading it with VB6, like this
Public Declare Function add2 Lib "C:\c\dll\mydll.dll" (num As Integer) As Integer
then I just called add2(text1.text) from a form, but it gave me a runtime error:
"Can't find DLL entry point add2 in C:\c\dll\mydll.dll"
this is the code I compiled for the DLL:
#ifdef BUILD_DLL
#define EXPORT __declspec(dllexport)
#else
#define EXPORT __declspec(dllimport)
#endif
EXPORT int __stdcall add2(int num){
return num + 2;
}
EXPORT int __stdcall mul(int num1, int num2){
return num1 * num2;
}
calling it from the C program like this worked, though:
#include<stdio.h>
#include<windows.h>
int main(){
HANDLE ldll;
int (*add2)(int);
int (*mul)(int,int);
ldll = LoadLibrary("mydll.dll");
if(ldll>(void*)HINSTANCE_ERROR){
add2 = GetProcAddress(ldll, "add2");
mul = GetProcAddress(ldll, "mul");
printf("add2(3): %d\nmul(4,5): %d", add2(3), mul(4,5));
} else {
printf("ERROR.");
}
}
any ideas?
solved it
To solve the previous problem, I just had to compile it like so:
gcc -c -DBUILD_DLL dll.c
gcc -shared -o mydll.dll dll.o -Wl,--add-stdcall-alias
and use this API call in VB6
Public Declare Function add2 Lib "C:\c\dll\mydll" _
(ByVal num As Integer) As Integer
I learned not to forget to specify ByVal or ByRef explicitly--I was just getting back the address of the argument I passed, it looked like, -3048.
Regarding building a DLL using MinGW, here are some very brief instructions.
First, you need to mark your functions for export, so they can be used by callers of the DLL. To do this, modify them so they look like (for example)
__declspec( dllexport ) int add2(int num){
return num + 2;
}
then, assuming your functions are in a file called funcs.c, you can compile them:
gcc -shared -o mylib.dll funcs.c
The -shared flag tells gcc to create a DLL.
To check if the DLL has actually exported the functions, get hold of the free Dependency Walker tool and use it to examine the DLL.
For a free IDE which will automate all the flags etc. needed to build DLLs, take a look at the excellent Code::Blocks, which works very well with MinGW.
Edit: For more details on this subject, see the article Creating a MinGW DLL for Use with Visual Basic on the MinGW Wiki.
Here is how you do it:
In .h
#ifdef BUILD_DLL
#define EXPORT __declspec(dllexport)
#else
#define EXPORT __declspec(dllimport)
#endif
extern "C" // Only if you are using C++ rather than C
{
EXPORT int __stdcall add2(int num);
EXPORT int __stdcall mult(int num1, int num2);
}
in .cpp
extern "C" // Only if you are using C++ rather than C
{
EXPORT int __stdcall add2(int num)
{
return num + 2;
}
EXPORT int __stdcall mult(int num1, int num2)
{
int product;
product = num1 * num2;
return product;
}
}
The macro tells your module (i.e your .cpp files) that they are providing the dll stuff to the outside world. People who incude your .h file want to import the same functions, so they sell EXPORT as telling the linker to import. You need to add BUILD_DLL to the project compile options, and you might want to rename it to something obviously specific to your project (in case a dll uses your dll).
You might also need to create a .def file to rename the functions and de-obfuscate the names (C/C++ mangles those names). This blog entry might be an interesting launching off point about that.
Loading your own custom dlls is just like loading system dlls. Just ensure that the DLL is on your system path. C:\windows\ or the working dir of your application are an easy place to put your dll.
There is but one difference. You have to take care or name mangling win C++. But on windows you have to take care about
1) decrating the functions to be exported from the DLL
2) write a so called .def file which lists all the exported symbols.
In Windows while compiling a DLL have have to use
__declspec(dllexport)
but while using it you have to write
__declspec(dllimport)
So the usual way of doing that is something like
#ifdef BUILD_DLL
#define EXPORT __declspec(dllexport)
#else
#define EXPORT __declspec(dllimport)
#endif
The naming is a bit confusing, because it is often named EXPORT.. But that's what you'll find in most of the headers somwhere. So in your case you'd write (with the above #define)
int DLL_EXPORT add....
int DLL_EXPORT mult...
Remember that you have to add the Preprocessor directive BUILD_DLL during building the shared library.
Regards
Friedrich
The thing to watch out for when writing C++ dlls is name mangling. If you want interoperability between C and C++, you'd be better off by exporting non-mangled C-style functions from within the dll.
You have two options to use a dll
Either use a lib file to link the symbols -- compile time dynamic linking
Use LoadLibrary() or some suitable function to load the library, retrieve a function pointer (GetProcAddress) and call it -- runtime dynamic linking
Exporting classes will not work if you follow the second method though.
For VB6:
You need to declare your C functions as __stdcall, otherwise you get "invalid calling convention" type errors. About other your questions:
can I take arguments by pointer/reference from the VB front-end?
Yes, use ByRef/ByVal modifiers.
Can the DLL call a theoretical function in the front-end?
Yes, use AddressOf statement. You need to pass function pointer to dll before.
Or have a function take a "function pointer" (I don't even know if that's possible) from VB and call it?)
Yes, use AddressOf statement.
update (more questions appeared :)):
to load it into VB, do I just do the usual method (what I would do to load winsock.ocx or some other runtime, but find my DLL instead) or do I put an API call into a module?
You need to decaler API function in VB6 code, like next:
Private Declare Function SHGetSpecialFolderLocation Lib "shell32" _
(ByVal hwndOwner As Long, _
ByVal nFolder As Long, _
ByRef pidl As Long) As Long