Trying to build a DLL with C++ code with mingw does not work like it should...
I am trying to wrap a larger C++ class in a dll for use in other .net environments. But it keeps crashing when calling.
It has nothing to do with the .net stuff because first I tried to call the DLL from a little testprogram made with C and Visual Studio.
The small testprogram I made opens the lib, gets functions pointers, and calls a function adding 2 integers. Up to there it works. The next call passes in a string, and it it jumps into invliad memoryspace.
I am getting the feeling that the Mingw built lib contains parts in its libstdc++, which needs to be initialized? (stuff normally called by framework code before calling your main() in a program?)
Using Mingw g++ 10.2.0 with this commandline to build the little DLL:
g++ -o gehtnichdll.dll -s -Wl,--subsystem,windows src/dllmain.cpp
A strange thing I nodted is that I need to add a function called 'WinMain', otherwise G++ complains about it missing.
I picked up the info on building DLL from https://www.transmissionzero.co.uk/computing/building-dlls-with-mingw/ .
Noting that mingw has an option -mdll , I tried that and got a dll which no longer loads (LoadLibrary fail 193)
I found a link to a page http://mingw.org/wiki/MSVC_and_MinGW_DLLs , but that page is no longer available.
Here is the source of the DLL. Stripped down to the almost minimum to show the problem. The class I tried to wrap is also completely removed as even the simple calls in here already fail.
#include <windows.h>
#include <stdint.h>
#include <stdio.h>
#include <string>
extern "C" __declspec(dllexport)
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
#define IID_OFFSET 0x07C007EC
typedef float A; // removed class A, not related to problem.
extern "C" __declspec(dllexport)
uint64_t AA__create(int var)
{
A *a;
a = new A(var); // There was the class constructor here.
// Removed as it is not related to the problem.
printf("called create (%d)\n",var);
return (uint64_t)a;
}
extern "C" __declspec(dllexport)
void AA__destroy(uint64_t iid)
{
A *a = (A*)iid;
if(!a)return;
delete a;
}
extern "C" __declspec(dllexport)
void AA__reset(uint64_t iid)
{
A *a = (A*)iid;
if(!a)return;
}
extern "C" __declspec(dllexport)
void AA__step(uint64_t iid)
{
A *a = (A*)iid;
if(!a)return;
(*a)++;
}
extern "C" __declspec(dllexport)
uint16_t strlen2(const char *str)
{
uint16_t res=0;
while( str && str[res] )res++;
return res;
}
extern "C" __declspec(dllexport)
void printstring(const char *str)
{
printf("string: '%s'\n",str);
}
// Without this WinMain, G++ exits with undefined reference to `WinMain'
// So providing a dummy function. Never called when loading as DLL.
extern "C" __declspec(dllexport)
int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR pCmdLine, int nCmdShow)
{
printf("dll as main.\n");
uint64_t iid = AA__create(100);
AA__destroy(iid);
return 0;
}
extern "C" __declspec(dllexport)
int dummy_add(int a,int b)
{
return a+b;
}
The C program calling this up, buit with MSVC++, is this (is C, not C++):
#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>
#include <Windows.h>
typedef void __declspec(dllimport) (*c_step)(uint64_t);
typedef uint64_t __declspec(dllimport) (*c_create)(int);
typedef int __declspec(dllimport) (*c_add)(int,int);
typedef void __declspec(dllimport) (*c_print)(const char *);
typedef uint16_t __declspec(dllimport) (*c_strlen)(const char *);
int main()
{
printf("Hello World!\n");
HMODULE h;
h = LoadLibrary("C:\\muell\\gehtnichdll\\gehtnichdll.dll");
if(!h)
{
int er = GetLastError();
fprintf(stderr,"loadlib failed, err = %d\n",er);
return 1;
}
c_create func_create = (c_create)GetProcAddress(h,"AA__create");
c_step func_step = (c_step)GetProcAddress(h,"AA__step");
c_add func_add = (c_add)GetProcAddress(h,"dummy_add");
c_print func_prn = (c_print)GetProcAddress(h,"strlen2");
c_strlen func_strl = (c_strlen)GetProcAddress(h,"printstring");
if(!(func_create&&func_step&&func_add&&func_prn&&func_strl))
{fprintf(stderr,"could not get function pointers.\n");return 1;}
int x = func_add(4,7);
printf("x = %d\n",x);
// this function call fails with an invalid jump.
uint16_t l = func_strl("lenth of this string");
printf("l = %u\n",(unsigned int)l);
// this call passes, but does not do output.
func_prn("hello world");
// These calls also fail (if commenting out the ones before)
uint64_t iid = func_create(0xBB1BE);
printf("Created, iid = 0x%" PRIXPTR "\n",(void*)iid);
func_step(iid);
return 0;
}