Shared global variable with DLL not working - c++

I'm trying to get some code that works on the Mac to work on Windows. The code involves sharing data between a DLL, a static library and the main program. I suspect the problem arises because of the differences in the way that Unix and Windows handle global variables (see, for example, the answers here). However, I haven't figured out how to fix it. Here's a minimal example:
My Visual Studio 2019 solution contains three projects.
Project 1 makes the static library MarinaLib.lib
Header is MarinaLib.h
#pragma once
#include "Marina.h"
Class header is Marina.h
#pragma once
class Marina
{
public:
static Marina* get_marina();
protected:
static Marina* marina_instance;
};
Source file is Marina.cpp
#include "Marina.h"
Marina* Marina::marina_instance { nullptr };
Marina* Marina::get_marina()
{
if( !marina_instance )
marina_instance = new Marina();
return marina_instance;
}
Project 2 makes the DLL MarinaDLL.dll . It #defines MARINADLL_EXPORTS
First source file dllmain.cpp
// dllmain.cpp : Defines the entry point for the DLL application.
#include "framework.h"
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;
}
Header file MarinaDLL.h is
#pragma once
#ifdef MARINADLL_EXPORTS
#define QUERY_DECLSPEC __declspec(dllexport)
#else
#define QUERY_DECLSPEC __declspec(dllimport)
#endif
QUERY_DECLSPEC void query_marina();
Second source file is marinaDLL.cpp
#include "MarinaDLL.h"
#include "..\MarinaLib\Marina.h"
void query_marina()
{
auto inst = Marina::get_marina();
}
Project 3 makes the executable MarinaExample.exe and does not #define MARINADLL_EXPORTS. It links in MarinaLib.lib and MarinaDLL.lib
The source file MarinaExample.cpp is
#include "MarinaLib.h"
#include "MarinaDLL.h"
int main()
{
auto instance = Marina::get_marina();
query_marina();
}
In the first line of main(), the code enters Marina::get_marina(). marina_instance is nullptr so the code creates a new Marina and makes marina_instance point to it. This is fine.
In the second line of main(), the code enters query_marina() and from there goes into Marina::get_marina(). At this point marina_instance is nullptr which is not what I want. I would like it to maintain its previous non-null value.
I've seen some examples of solutions to problems in similar code but they don't seem to work in my situation. Any suggestions on how to fix this?
Thanks.

add export modifier to class definition and export the whole class.
In dll and lib build define QUERY_DECLSPEC=export , in exe build as import :
class QUERY_DECLSPEC Marina
{
public:
static Marina* get_marina();
protected:
static Marina* marina_instance;
};

Related

how to make a function return an array? for making DLL to use in VB.NET

i am trying to make a c++ DLL project in VS2017 to use in a VB.NET VS2017 project.
the c++ code;
MyCudaLib.h
#ifndef DLL3_H
#define DLL3_H
#ifdef DLL3_EXPORTS
#define DLL3_API __declspec(dllexport)
#else
#pragma message("automatic link to MyCudaLib.LIB")
//#pragma comment(lib, "MyCudaLib.lib")
#define DLL3_API __declspec(dllimport)
#endif
int* __stdcall test_array();
#endif //DLL3_H
MyCudaLib.cpp
#include <stdio.h>
#include "MyCudaLib.h"
#include <Windows.h>
#include <stdexcept>
#include <sstream>
using namespace std;
#define DLL3_EXPORTS
BOOL APIENTRY DllMain(HANDLE /*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;
}
int* __stdcall test_array()
{
int arr[]{ 30,50,60,70 };
return arr;
}
in VB part of the code
Private Declare Function test_array Lib "MyCudaLib.dll" () As Integer()
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Console.WriteLine(test_array(0))
End Sub
is my exporting part of code is wrong? c++ part compiled wtihout error but VB part of the code wont work gives error.
System.Runtime.InteropServices.MarshalDirectiveException: ''return value' cannot arranged.
Note: My point to make a proper working function in c++ is to write a CUDA code to program the GPU. I can write and compile code in CUDA in c++ without problem. But students in my class cannot program in c++ and i can't write more complex code with c++. So, i thought, if i can use the cuda function outside the c++ environment, we all can code it with vb or other languages.
Sure your function compiles fine - it is defined as a function returning a single int and does so as well (return *arr; is equivalent to return arr[0];).
From MarshalDirectiveException
The exception that is thrown by the marshaler when it encounters a MarshalAsAttribute it does not support.
As you did not provide an English error message, I can only guess what's happening now, but there are only few options available:
You have yet another error with your marshaling not visible here.
The function is not recognised due to C++ name mangling (see below).
Incompatibility between int returned in function and expected array is recognised.
The int is interpreted as pointer – but pointer size does not match and the type cannot be marshaled at all.
If you want to return an array, you need to define your function as such:
int* getArray()
// ^
{
static int a[] = {1, 2, 3};
// ^^^^^^ we cannot return an array with local storage duration, so make it
// static, global, or allocate one on heap (new int[]; but assure the
// array to be delete[]d appropriately again to avoid memory leak)
return a; // NOT dereferenced!
}
Be aware that you have C++ name mangling applied. You might possibly prefer a C-kompatible interface:
extern "C" int* getArray();
However, you cannot return C++ data types this way like std::vector – which in most cases even is preferrable, though, as those types usually are incompatible across different implementations (DLL compiled with MSVS, EXE with GCC/MinGW) anyway.
Finally be aware that via a pointer, you lose information about array size! You need to find other means to provide this information to the user of your library.

Can a dll file be initialized - A Dll constructor

I am currently importing a function out of my dll in the following way in a C# application.
[DllImport("C:\\File.dll")]
public static extern int SomeMethod(int A);
My dll file is written in C++. This method is also defined in the .def file of the dll.
Currently whenever this method is called in the first ever attempt a couple of other methods are called , these methods set up the grounds for this method. However these methods only need to be called once. These methods are never called again/ I wanted to know is there a way to call a group of methods (initializers) as soon as a dll file is loaded. Is there anything as a dll constructor ?
I have something like this in my dllmain.cpp could entering something in there accomplish this task
// dllmain.cpp : Defines the entry point for the DLL application.
#include "stdafx.h"
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;
}
DllMain is the closest to a DLL "constructor" (and the correct place to do initialization is in the case label for DLL_PROCESS_ATTACH). However a more realistic constructor would be that of a COM class instantiated by the C# code. In that case the constructor would be called for every instance of the class that you create (just like for a C# class). Create an ATL project in Visual C++ and it will generate code like this for you:
class ATL_NO_VTABLE CMyClass :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CMyClass, &CLSID_MyClass>,
public IMyClass
{
public:
CMyClass()
{
}
DECLARE_REGISTRY_RESOURCEID(IDR_MYCLASS1)
BEGIN_COM_MAP(CMyClass)
COM_INTERFACE_ENTRY(IMyClass)
END_COM_MAP()
DECLARE_PROTECT_FINAL_CONSTRUCT()
HRESULT FinalConstruct()
{
return S_OK;
}
void FinalRelease()
{
}
...
In the CMyClass constructor or in the FinalConstruct method you can perform the initialization code for the object. Also add your SomeMethod method to this class (and to the IDL interface in the IDL file).
Then you would use that class in C# like this:
MyClass mc = new MyClass(); // CMyClass::CMyClass and CMyClass::FinalConstruct are called in C++
mc.SomeMethod(); // CMyClass::SomeMethod is called in C++

Import unmanaged "QT" dll to C# give dllNotFoundException but exists

I am trying to import a dll to a C# console application just to see if I can get a dll to work as a want, when trying this and exporting functions with C-code everything works fine and the functions can be imported in my C# application.
The problem starts when I try to add some kind of linkage to some QT methods in my unmanaged dll. I'm using DllImport to import the functions from the dll.
[DllImport("cDLL.dll", EntryPoint = "_Add#16")]
static extern double Add(double a, double b);
1 - This is how the unmanaged dll (don't look at the functionality of the code, this is just for testing purposes) looks like when it works fine.
main.cpp working
#include <stdexcept>
#include "Windows.h"
using namespace std;
extern "C" __declspec(dllexport) double __stdcall Add(double a, double b)
{
return a + b;
}
extern "C" __declspec(dllexport) const char* getText()
{
return "hello world";//returnBufferString.c_str();
}
BOOL __stdcall DllMain(HINSTANCE hInst, DWORD dwReason, LPVOID lpReserved) {
return TRUE;
}
2 - When I try to add a help function with some QT code, just an ordinary QString the DllImport starts throwing dllNotFoundException.dumpbin.exe shows all the exported functions as well after including the qt code...
main.cpp dllNotFoundException
#include <QString>
using namespace std;
class testa
{
public:
static char* test()
{
QString a = "hejsan";
return qString2Char(a);
}
static char* qString2Char(QString a)
{
return a.toUtf8().data();
}
};
This is called from the getText() function like this:
string returnBufferString;
extern "C" __declspec(dllexport) const char* getText()
{
returnBufferString = testa::test();
return returnBufferString.c_str();
}
When I try to access the dll from DllImport I get dllNotFoundException in the 2:nd part. How do I solve this? have I missed any dependencies or anything. My dll is build using msvc2010 compiler and the .pro file looks like this:
cDLL.pro
TEMPLATE = lib
CONFIG += dll
QT += core
# Input
SOURCES += main.cpp
I'm stuck...
It doesn't tell you exactly what DLL it cannot find. Which is almost surely not your DLL, it is one of the DLLs that QT requires. You'd have to copy them to the EXE folder as well. If you have no idea and can't find it in the Nokia documentation then you can find out with SysInternals' ProcMon utility.
However, in this scenario you surely want to link QT into your DLL since the odds that those DLLs can be shared are small. Use this SO question for guidance in setting up your QT project.
You need to put the DLL in the same folder as your executable.
See http://msdn.microsoft.com/en-us/library/windows/desktop/ms682586%28v=vs.85%29.aspx

How can i set an entrypoint for a dll

First i thought entry point in dlls DLLMain but then when i try to import it in C# i get an error that entrypoint wasn't found Here is my code:
#include <Windows.h>
int Test(int x,int y)
{
return x+y;
}
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
MessageBox(0,L"Test",L"From unmanaged dll",0);
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
How can i set an entry point for my dll? And if you dont mind can you give me little explanation about entry point?
Like do i have to set import the same dll again and changing the entry point so i can use other functions in same dll? thanks in advance.
In your example, it seems you intend Test() to be an entry point however you aren't exporting it. Even if you begin exporting it, it might not work properly with C++ name "decoration" (mangling). I'd suggest redefining your function as:
extern "C" __declspec(dllexport) int Test(int x,int y)
The extern "C" component will remove C++ name mangling. The __declspec(dllexport) component exports the symbol.
See http://zone.ni.com/devzone/cda/tut/p/id/3056 for more detail.
Edit: You can add as many entry points as you like in this manner. Calling code merely must know the name of the symbol to retrieve (and if you're creating a static .lib, that takes care of it for you).

Automatic initialization routine in C++ library?

If i have a header file foo.h and a source file foo.cpp, and foo.cpp contains something along the lines of:
#ifdef WIN32
class asdf {
asdf() { startup_code(); }
~asdf() { cleanup_code(); }
};
asdf __STARTUP_HANDLE__
#else
//unix does not require startup or cleanup code in this case
#endif
but foo.h does not define class asdf, say i have an application bar.cpp:
#include "foo.h"
//link in foo.lib, foo.dll, foo.so, etc
int main() {
//do stuff
return 0;
}
If bar.cpp is compiled on a WIN32 platform, will the asdf() and ~asdf() be called at the appropriate times (before main() and at program exit, respectively) even though class asdf is not defined in foo.h, but is linked in through foo.cpp?
Yes -- but be very careful. The order in which static objects (like your asdf object) are initialized is undefined. So it is undefined behavior if any other object tries to reference your object before main().
Also, __STARTUP_HANDLE__ is not a valid identifier. Double-underscores are not allowed in any identifier (even macros), and a single-underscore followed by a capital letter is also not allowed.
If it ain't broke, don't fix it. Look out for the static initialization order issue, as the other answers say. But you really should fix that reserved identifier.
__STARTUP_HANDLE__ does work similar to a runtime library, and runtime libraries use names like that, but it's not part of the runtime library so that name isn't allowed.
#ifdef WIN32
namespace { // anonymous namespace - no outside access
class asdf {
asdf() { startup_code(); }
~asdf() { cleanup_code(); }
} x; // to create an instance
}
As long as the objects (foo.o) themselves are linked into the executable, this will work (assuming the static initialization order fiasco doesn't hit you). If you're pulling it in from a library (foo.lib), though, it won't unless you explicitly mark the object as an "active object," but I don't remember how to do that in MSVC.
On Windows and with DLL's you have the possibility to use the function DllMain that will be called at load etc
BOOL WINAPI DllMain(HINSTANCE hinstDLL,
DWORD fdwReason,
LPVOID lpvReserved) {
switch (fdwReason) {
case DLL_PROCESS_ATTACH:
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
break;
default:
break;
}
return TRUE;
}