extern function call under windows make undefined reference - c++

There is my problem:
All the code is in C++11.
Part 1
I've build a library (named socket).
somwhere in the code, I declare a function:
namespace ntw {
extern int dispatch(int id,Socket& request));
}
This function is user defined (most of the case, simply a big switch)) and by this way the body of it, is not define in the socket lib.
I use this function in server.cpp (which is part of the socket lib).
All is fine under linux, it build the .so perfectly.
But under windows it create a
undefined reference to ntw::dispatch(int,Socket&)
So the .dll is not build.
Part2
I create the main program that use the socket lib.
And in this code, I make :
namespace ntw {
int dispatch(int id,Socket& request)){
/// some code
return ...;
}
}
finaly
So now, that i want is:
the user define int dispatch(int id,Socket& request)) have to be call by the socket libary.
Under Ubuntu, all is fine (coppilation, adn run),
but under windows .... it's the hell.
What can I do to make it work under windows xp and over ?
linux
Ubuntu 12.04, gcc 4.8.1
windows
windows xp, mingw 4.8.1
code
github: https://github.com/Krozark/cpp-Socket
It use cmake (if someone want to try).

What you are attempting won't work on Windows which has a quite different linking model from Linux. You need run time binding. I think you want the function to be provided by the host executable. In which case you need the host to export it with either a .def file or __declspec(dllexport). And then run time binding like this:
HMODULE hMod = GetModuleHandle(NULL); // gets host executable module handle
void *fn = GetProcAddress(hMod, FunctionName);
You can then cast fn to an appropriately declared function pointer before calling the function.
This is probably a reasonable approximation to how your Linux code operates. But it's not a very natural way to operate on Windows. More normal would be for the host to register callback functions or interfaces with the library. Once the host has informed the library of its callbacks, the library can use them.

Related

Cygwin 64-bit cannot early-bind to DLL created by MSVC , giving __cxa_atexit error

Here is the C++ program compiled by up-to-date Cygwin64 (gcc/x86_84-pc-cygwin/9.3.0):
extern "C"
__declspec(dllimport) void foo(void);
int main(void)
{
foo();
return 0;
}
with commandline:
g++ -o mre.exe mre.cc /f/temp/simpledll/x64/Debug/simpledll.lib
For SimpleDLL I created a new Windows C++ DLL using VS Community 2019, switched to x64 target, disabled PCH, and added simpledll.cpp:
extern "C" __declspec(dllexport) void foo(void);
void foo(void)
{
MessageBoxA(NULL, "In simpledll foo", "Title", MB_OK);
}
leaving the rest of the DLL boilerplate unchanged.
The compilation in Cygwin64 runs successfully, but then running the executable under the Cygwin shell exits with no output. Running the executable in command prompt (and the cygwin1.dll and simpledll.dll in the same directory as the executable, to eliminate any path errors) produces a message box with the text:
The procedure entry point __cxa_atexit could not be located in the dynamic link library F:\temp\mre.exe
Via a debugger (WinDBG) and ProcMon64 I can see that during startup, simpledll.dll is opened correctly and read; and then this error appears (with a C0000139 error code visible in WinDBG when the __cxa_atexit messagebox appears). This happens even if the main() function never calls the function (e.g. I change it to if (argc > 1) foo(); and provide no commandline arguments).
However the following work correctly, showing the messagebox from foo:
The exact same procedure under a mingw-w64 standalone (either from MSYS2 shell, or command prompt).
The exact same procedure under MSYS2 (x86_64-pc-msys2).
Under Cygwin or MSYS2, loading the same DLL via LoadLibrary and GetProcAddress, instead of linking to the .lib file. That is, late binding works fine whereas early binding crashes.
I've been unable to figure out what is happening differently in the Cygwin targets versus any of the above bullet points. Using -fuse-cxa-atexit makes no difference (I think this is on by default anyway), and strings mre.exe shows __cxa_atexit and __imp___cxa_atexit existing. Furthermore, in the standalone mingw-w64 builds, strings does not find any cxa at all, and yet the code runs correctly.
My question is: what is going wrong and how do I fix it (i.e. how can I call a function in the MSVC-created x64 DLL from a Cygwin64-target build).

Loading DLL fails on Windows

As a Xcode developer I have to use my written code on windows, too. I think I have successful master all cross platform issues but now I have a real problem understanding the DLL hell on Windows.
I used my code with Xcode and Gcc (Ubuntu) successful. On Windows I get a error message:
Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call. This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention.
I read much about this uses but I have my problems to understand the issue.
Normally on windows I have something like
#define MYLIB_API __declspec(dllimport)
I cannot find this inside the header of the Bass Library (bass.h). There is only one line
#define BASSDEF(f) WINAPI f
Now, I try to dynamic load the DLL functions in my code. You can see the dynamic loading header as link on bottom. To much to copy here. This dynamic loading is working for .dylib and .so libs well, not for .dll
My target is to load the DLL dynamic and not static with an additional lib.
In my code I use the bass.h and the bassdecode.h. In my code I call as sample:
bool returnVar = _BASS_SetConfig(BASS_CONFIG_DEV_DEFAULT,1);
And here I get the calling convention message.
What I have to do in my header file to successful import DLL functions on Windows?
You can download the files at: header files to download
Ok, for all who run into the same problem, the solution is the Answer from Hans Passant. I cannot mark this answer as solution so I want to give him the reputation.
My original typedef of the function:
typedef BOOL (*BASS_SetConfig_Type)(DWORD option, DWORD value);
Was searched in DLL
_BASS_SetConfig = (BASS_SetConfig_Type)DllFindSym(m_hMod, "BASS_SetConfig")
Where DLLFindSym is defined as:
#define DllFindSym(handle,name) (GetProcAddress(handle,name))
Now changed the typedef to
typedef BOOL (__stdcall *BASS_SetConfig_Type)(DWORD option, DWORD value);
Now everything works like a charm in Windows. Many thanks to the quick hint from Hans Passant.

DLL calling conventions & access violation

after reading and learning for years on this great platform its my first post now.
My Problem:
In C++ I am trying to create a dynamic linked library (32 bit) that will serve as a AQMP Communication Client (based on SimpleAmqpClient). The dll file will then be used inside a third party application (32 bit).
During my tests where I invoke the dll in a custom executable everything works fine. But when I try to use the dll in the third party application I get an access violation error (0x00000000). I found out that the problem may be the function calling convention.
With the few code lines presented below that error can be reproduced. It disappears if I remove the __stdcall expression in mytest.dll. Normally I would expect the code to work because it uses the same calling convention in custom_test.exe and mytest.dll.
(Sidenote: the third party application expects a __stdcall function thats why I rely on it)
I would like to understand this behavior. Thanks in advance!
My Setup:
OS: Windows 7
32 bit Compiler: gcc 5.3 (Cygwin)
My Code (custom_test.exe):
#include <stdio.h>
#include <windows.h>
int main(void) {
HINSTANCE hInstance;
hInstance=LoadLibrary("mytest.dll");
FARPROC lpfnGetProcessID = GetProcAddress(HMODULE(hInstance), "test");
// Function prototype
typedef void (__stdcall *myFunction)(void);
myFunction test;
test = myFunction(lpfnGetProcessID);
// Call Function
test();
FreeLibrary(hInstance);
}
My Code (mytest.dll):
extern "C" __declspec(dllexport) void __stdcall test(void) {
printf("Inside Function \n");
}
I compile the code via
dll: g++ mytest.cpp -o mytest.dll -shared -std=gnu++11
exe: g++ custom_test.cpp -o custom_test.exe -std=gnu++11
The __stdcall convention makes it the responsibility of the called function to clean up the stack on return, while __cdecl makes it the caller's responsibility.
We can't see the actual declaration in the third-party DLL, but my initial assumption would be that the DLL expects arguments and is either using what it believes to be stack arguments in error, or is cleaning up the stack based on it's assumption of the stack arguments and generally messing with your stack.
EDIT
In this instance though, I see that when compiling in 32 bit, the test function is exported with a name of 'test#0'. If you change your GetProcAddress to use this decorated name instead it will work.
Ok now several hours later I can see clear again! Thx IanM_Matrix1 for the suggestion, the so called name decoration was indeed the point.
After my research I can now share some helpful ressources I found:
It is important to know that some compilers add different decorations to the function names, see here:
http://wyw.dcweb.cn/stdcall.htm
With that in mind one can read this page about Win32 calling conventions in general:
http://www.unixwiz.net/techtips/win32-callconv.html
When using gcc the decorations can also be disabled via the flag -Wl,--kill-at.

Debugging embedded Lua 5.2.2 code

How can I debug Lua 5.2.2 code that is embedded inside of my C++ application?
I have already taken a look at this question and all the IDEs provided in it deal with 5.1 and lower and when I try to use them with 5.2.2 they crash.
You should be able to debug your application using ZeroBrane Studio by following instructions for Lua 5.2 debugging. Note that you'll need to have luasocket compiled against Lua5.2. (The crash you see is likely because your application loads luasocket that is compiled against Lua5.1, which in turn loads Lua5.1 DLL or fails to find required symbols.)
If you don't want to compile luasocket, you can get binaries for Windows/OSX/Linux from this folder and its subfolders; just make sure that these libraries are in LUA_CPATH before any folders that may have luasocket compiled against Lua5.1.
[Updated based on chat discussion] The reason you may be getting multiple VM issue is that your app is probably statically compiles Lua interpreter. You then load luasocket (directly or through mobdebug), which is compiled against lua52.dll, which loads another copy of the interpreter. To avoid this you have two choices: (1) compile luasocket into your app the same way you include lua interpreter itself; you won't need anything else except one mobdebug.lua file to debug your app, or (2) use proxy dll; it will look like lua52.dll, but will actually proxy your calls to your statically compiled lua library, avoiding problems with multiple VMs. The proxy dll is for Lua 5.1, but you can tweak the script to make it work for Lua 5.2.
(If your interpreter is not statically compiled, you may still get two interpreters if the Lua DLL you load is named differently from lua52.dll.)
In response to OP's commented request, here's how you should open the lua standard library "base" from C++:
#include "lua.hpp"
//...
int main ()
{
lua_State* L = luaL_newstate();
luaL_requiref(L, "base", luaopen_base, 0);
// ...
int error = luaL_loadfile(L, mainLua);
lua_call(L, 0, 0);
lua_close(L);
}
Note that you can open all the standard libraries at once by replacing:
luaL_requiref(L, "base", luaopen_base, 0);
with
luaL_openlibs(L);
The Lua 5.2 reference manual Section 6 has more info about this.

How to declare and link to RoInitialize,RoUninitialize,RoGetActivationFactory and HSTRING Functions in Mingw Gcc

UPDATED: Added what RoInitialize looks like in roapi.h
I am in the process of writing a pure C++11 WinRT library. I do not use WRL or C++/CX (Obviously if I want pure C++11).
I got my code to compile and run on MSVC, but I want to see if I can get the code to compile and run on Mingw Gcc. Specifically, I am using GCC 4.7.2 obtained from nuwen.net.
What I need at this point is a way to call the Windows API Functions RoInitialize, RoUnitialize, RoGetActivationFactory and the HSTRING Functions WindowsCreateString, WindowsDuplicateString, WindowsDeleteString.
I tried compiling this program in G++ but got the error
extern "C"{
__declspec(dllimport)int __stdcall RoInitialize(int);
}
int main(){
RoInitialize(1);
}
I tried to compile but got:
c:\Users\jrb\Desktop>g++ gccwinrt.cpp
C:\Users\jrb\AppData\Local\Temp\ccy7y1V9.o:gccwinrt.cpp:(.text+0x1e): undefined
reference to `_imp__RoInitialize#4'
collect2.exe: error: ld returned 1 exit status
If anybody can point me in the right direction on how to declare these functions and what libraries I need to link to, I would appreciate it. Even if it requires LoadLibrary/GetProcAddress I would still be ok with that
Update: Here is what RoInitialize looks like in the header roapi.h
ROAPI
_Check_return_
HRESULT
WINAPI
RoInitialize(
_In_ RO_INIT_TYPE initType
);
ROAPI is just a define for __declspec(dllimport)
_Check_return_ is part of SAL (Secure Annotations Language?)
HRESULT maps to int32
WINAPI is a define for __stdcall
RO_INIT_TYPE is an enumeration so int should cover it
The import library for these functions is runtimeobject.lib (which the MSDN documentation fails to mention). It can be found in the Windows SDK for Windows 8.
The library you need to link against is windowsapp.lib (and only this lib, remove all others).
This topic lists the Win32 APIs that are part of the Universal Windows Platform (UWP) and that are implemented by all Windows 10 devices. For convenience, an umbrella library named WindowsApp.lib is provided in the Microsoft Windows Software Development Kit (SDK), which provides the exports for this set of Win32 APIs. Link your app with WindowsApp.lib (and no other libraries) to access these APIs.
APIs present on all Windows 10 devices - Microsoft Docs
See that page for a complete list of functions that implements; it includes RoInitialize, RoUnitialize, RoGetActivationFactory and WindowsCreateString, WindowsDuplicateString, & WindowsDeleteString (among many, many others). If you need other functions, you may need to link extension APIs also.
Similar guidance was originally on
https://msdn.microsoft.com/en-gb/windows/uwp/get-started/universal-application-platform-guide#writing-code but is no longer present:
Windowsapp.lib is an "umbrella" lib that provides the exports for the UWP APIs. Linking to Windowsapp.lib will add to your app dependencies on dlls that are present on all Windows 10 device families.
For delay loading, you will need to load api-ms-win-core-winrt-l1-1-0.dll, which is an API set, a collection of APIs that Windows can load regardless of where the actual DLLs are. This specific set is listed as a Windows 8.1 API set, however if you check the documentation for RoInitialize it says the minimum supported client is Windows 8. Assuming you use LoadLibrary and GetProcAddress, it shouldn't matter.
The actual DLL that the method is implemented in is combase.dll, but they use these API set DLLs as a level of indirection so that they are free to change or update that original DLL in the future.
For future reference, the API sets for Windows 10 (UWP) are listed on a separate page to the API sets for Windows 8 (and 8.1). The stub DLL (for delay loading) is the same. https://msdn.microsoft.com/library/windows/desktop/mt186421
Many other APIs also list their corresponding API set in their own documentation. For example, MSDN gives AllowSetForeground as an example.
If you don't have the import lib that contains RoInitialize, you'll need to use LoadLibrary/GetProcAddress to resolve the types.
Run-time link it like this:
#include <roapi.h>
namespace
{
FARPROC LoadComBaseFunction(const char* function_name)
{
static HMODULE const handle = ::LoadLibraryA("combase.dll");
return handle ? ::GetProcAddress(handle, function_name) : nullptr;
}
decltype(&::RoInitialize) GetRoInitializeFunction()
{
static decltype(&::RoInitialize) const function = reinterpret_cast<decltype(&::RoInitialize)>(LoadComBaseFunction("RoInitialize"));
return function;
}
}
HRESULT RoInitialize(RO_INIT_TYPE init_type)
{
auto ro_initialize_func = GetRoInitializeFunction();
if (!ro_initialize_func)
return E_FAIL;
return ro_initialize_func(init_type);
}
Source