Updated:
I created a project that can 100% reproduce the problem.
1. DLL Project
I named this DLL project TestDLL
The most important codes:
AddC.h:
#pragma once
class CTestDLL;
#include <string>
using namespace std;
//use AddC somewhere inside the DLL internally
class AddC{
private:
string _fake_string_ = "_fake_string_";
void _fake_method_();
public:
void add2Result(CTestDLL* test);
};
AddC.cpp:
#include "pch.h"
#include "AddC.h"
#include "TestDLL.h"
void AddC::_fake_method_()
{
_fake_string_ = "_fake_string_in_fake_method_";
}
void AddC::add2Result(CTestDLL * test)
{
test->result += 1;
}
TestDLL.h:
#ifdef TESTDLL_EXPORTS
#define TESTDLL_API __declspec(dllexport)
#else
#define TESTDLL_API __declspec(dllimport)
#endif
#include "AddC.h"
class TESTDLL_API CTestDLL {
public:
CTestDLL(void);
void test();
int getResult();
private:
friend class AddC;
private:
AddC addc;
int result=0;
};
TestDLL.cpp:
#include "pch.h"
#include "framework.h"
#include "TestDLL.h"
CTestDLL::CTestDLL(){
result = 0;
return;
}
void CTestDLL::test(){
auto _this = this;
addc.add2Result(_this);
}
int CTestDLL::getResult(){
return this->result;
}
2. SimpleTestApplication Project
The TestApplication has only two code files.
dll.hpp:
#pragma once
class AddC{};
class CTestDLL {
public:
CTestDLL(void);
void test();
int getResult();
private:
int result = 0;
AddC addc;
};
app.cpp:
#include "dll.hpp"
#include <iostream>
using namespace std;
#pragma comment(lib, "TESTDLL.lib")
int main(){
CTestDLL test;
test.test();
test.test();
test.test();
cout << test.getResult() << endl;
return 0;
}
The testApplication compile and link successfully.
But,But.When the main function exits, the program throws an exception that the stack was corrupted.
The key point is 'fake string_' variable in AddC.
But I don't how to do.
Previous:
Like this on a dll project:
class B;
class C;
class __declspec(dllexport) A{
private:
friend class B;
friend class C;
}
And I compiled the dll project;
Use .dll,.lib and the following header file on a simple console project:
dll.hpp:
class __declspec(dllimport) A{
private:
friend class B;
friend class C;
}
The main func:
#include "dll.hpp"
#pragma comment(lib, "dll.lib")
int main(){
A a;
return 0;
}
It compiled successfully.But the program threw an exception when running:
Run-Time Check Failure #2 - Stack around the variable 'a' was corrupted.
Who can help me?
#selbie's suggestion regarding the factory function / method creating is the cleanest way to go (would prevent you from ending in situations like this), and design-wise it makes the most sense, but it's not mandatory (after all there are lots of .dlls out there exporting classes).
What jumped into my eye, was the fact that (in both scenarios) a header file was present in the application that was (somewhat) duplicating the (main) one in the .dll. Every .dll comes with its own header file(s), and those are the ones that should be used by its clients (apps or other dlls). They are both maintained by the dll creators, and when updates come, they are both in sync. Doing otherwise is not scalable (each app creating its own header file version), makes no sense, and I don't know why would anyone do something like that.
With this in mind, I recreated the environment (both scenarios), doing things the right way, and everything worked fine, then I worked my way to your (wrong) way, trying to identify the culprit.
Example (numbered the 2 scenarios: 00 and 01):
DllExport.h:
#pragma once
#if defined(_WIN32)
# if defined(DLL_STATIC)
# define DLL_EXPORT_API
# else
# if defined(DLL_EXPORTS)
# define DLL_EXPORT_API __declspec(dllexport)
# else
# define DLL_EXPORT_API __declspec(dllimport)
# endif
# endif
#else
# define DLL_EXPORT_API
#endif
Scenario 00:
AddC.hpp:
#pragma once
#include <string>
using namespace std;
class CTestDLL;
//use AddC somewhere inside the DLL internally
class AddC {
private:
string _fake_string_ = "_fake_string_";
void _fake_method_();
public:
void add2Result(CTestDLL *pTest);
};
TestDLL.hpp:
#pragma once
#include <DllExport.h>
#include <AddC.hpp>
class DLL_EXPORT_API CTestDLL {
public:
CTestDLL();
void test();
int getResult();
private:
friend class AddC;
private:
AddC addc;
int result = 0;
};
dll:
AddC.cpp:
#include "AddC.hpp"
#include "TestDLL.hpp"
void AddC::_fake_method_()
{
_fake_string_ = "_fake_string_in_fake_method_";
}
void AddC::add2Result(CTestDLL *pTest)
{
pTest->result += 1;
}
TestDLL.cpp:
#define DLL_EXPORTS
#include <TestDLL.hpp>
CTestDLL::CTestDLL()
{
result = 0;
return;
}
void CTestDLL::test()
{
auto _this = this;
addc.add2Result(_this);
}
int CTestDLL::getResult()
{
return this->result;
}
app:
dll.hpp:
#pragma once
#define _WRONG_INNER_CLASS
#if defined(_WRONG_INNER_CLASS)
class AddC {};
#else
# include <AddC.hpp>
#endif
#define _WRONG_IMPORT_DIRECTIVE
#if defined(_WRONG_IMPORT_DIRECTIVE)
# define CLASS_IMPORT_API
#else
# define CLASS_IMPORT_API __declspec(dllimport)
#endif
class CLASS_IMPORT_API CTestDLL {
public:
CTestDLL();
void test();
int getResult();
private:
int result = 0;
AddC addc;
};
main.cpp:
#include <iostream>
#include <cstdio>
#define _DUPLICATE_DLL_HEADER_FILE
#if defined (_DUPLICATE_DLL_HEADER_FILE)
# include <dll.hpp>
#else
# include <TestDll.hpp>
#endif
#pragma comment(lib, "dll.lib")
using std::cout;
using std::endl;
int main()
{
CTestDLL test;
test.test();
test.test();
test.test();
cout << test.getResult() << endl;
printf("Done.\n");
return 0;
}
Scenario 01:
dll.hpp:
#pragma once
#include <DllExport.h>
class DLL_EXPORT_API A {
private:
friend class B;
friend class C;
};
dll:
dll.cpp:
#define DLL_EXPORTS
class B;
class C;
#include <dll.hpp>
app:
AppDll.hpp:
#pragma once
#define CLASS_IMPORT_API __declspec(dllimport)
class CLASS_IMPORT_API A {
private:
friend class B;
friend class C;
};
main.cpp:
#include <cstdio>
#define _DUPLICATE_DLL_HEADER_FILE
#if defined (_DUPLICATE_DLL_HEADER_FILE)
# include "AppDll.hpp"
#else
# include <dll.hpp>
#endif
#pragma comment(lib, "dll.lib")
int main()
{
A a;
printf("Done.\n");
return 0;
}
Project structure:
Results:
Scenario 00:
There were 2 mistakes:
Class AddC redefinition
Missing import directive for CTestDll
In dll.hpp there are 2 _WRONG* macros. If both are commented, it will work
Scenario 01:
I couldn't reproduce the crash (with / without friends)
Note: Tested with VStudio 2022 and MSSDK 10.0.22000.0
Related
I have a dll with lib.h:
#pragma once
#ifdef EXPORTS
#define API __declspec(dllexport)
#else
#define API __declspec(dllimport)
#endif
extern "C" API void test1(std::vector<ValueType*>* functions);
and lib.cpp:
#include "pch.h"
#include <iostream>
#include <vector>
#include "ValueType.h"
#include "NumberValue.h"
#include "TestLib.h"
void test1(std::vector<ValueType*>* functions) {
functions->push_back(new NumberValue(123321));
And main file, that uses this dll is:
#include <iostream>
#include <vector>
#include <Windows.h>
#include "ValueType.h"
using namespace std;
typedef void (__cdecl* importedInitFunction)(std::vector<ValueType*>*);
importedInitFunction test1F;
std::vector<ValueType*> values;
int main() {
while (1) {
HMODULE lib = LoadLibrary("DllTest1.dll");
test1F = (importedInitFunction)GetProcAddress(lib, "test1");
test1F(&values);
FreeLibrary(lib);
std::cout << values.at(0)->asString();
system("pause");
}
return 0;
}
When I'm trying to compile my code, I catch an error because values.at(0) is removed.
How to prevent deleting my variable when calling FreeLibrary(lib) ? or
How to implement alternative way ?
Another classes that used:
ValueType.h:
#pragma once
#include <string>
class ValueType {
public:
virtual double asDouble() { return 999; }
virtual std::string asString() { return ""; }
};
NumberValue.h:
#pragma once
#include <string>
#include "ValueType.h"
class NumberValue : public ValueType {
public:
double m_value;
NumberValue(double value) : m_value(value) {}
virtual double asDouble() {
return m_value;
}
virtual std::string asString() {
return std::to_string(m_value);
}
};
How can I define an integer in a header file so that each cpp file which includes the header will have static const int id=0 while giving the ability to cpps to redefine it with other value.
I tried to used weak symbol but couldn't make it work.
If you are ok with preprocessor definitions you could do this:
// header.h
#ifndef CLASSID
#define CLASSID 0
#endif
static int id=CLASSID;
// class.cpp
#define CLASSID 1
#include "header.h"
This way a source file may override the default, but may also omit it, which is the sort of weak approach you mentioned.
Here's another solution that uses static variables:
// log.h
#ifndef LOG_H
#define LOG_H
#include <iostream>
#define SETLOGID(v) static logidsetter _logidsetter(_logid, v);
#define LOG(v) std::cout << "id: " << _logid << ": " << (v) << std::endl;
class logidsetter
{
public:
logidsetter(int &id, int val)
{
id = val;
}
};
static int _logid = 0;
#endif
// myclass.h
class myclass
{
public:
myclass();
void run(void);
};
// myclass.cpp
#include "log.h"
#include "myclass.h"
SETLOGID(42)
myclass::myclass()
{
LOG("myclass::cons");
}
void myclass::run(void)
{
LOG("myclass::run");
}
// main.cpp
#include "myclass.h"
#include "log.h"
SETLOGID(1)
int main()
{
myclass mc;
LOG("here's main");
mc.run();
}
The log header defines the static int _logid and provides the macro SETLOGID and the class idsetter. The cpp file may use SETLOGID to redefine the static value. This is done with an instantiation of the class idsetter along with the address of _logid and the desired value. The trick allows to bypass C++'s One Definition Rule.
The output looks like:
id: 42: myclass::cons
id: 1: here's main
id: 42: myclass::run
Ok, so I have a struct defined as thus:
#ifndef __STRUCTS_H__
#define __STRUCTS_H__
struct counts {
int views = 0;
int inits = 0;
};
#endif
I have a class that is going to have entirely static methods and variables that are accesable by all classes.
#ifndef __HOLDER_H__
#define __HOLDER_H__
#include "Structs.h"
class Holder
{
public:
static counts menus;
Holder() {
menus = counts();
}
};
#endif
And so I tried to acess this method and the compiler spits out the error "Undefined reference to Holder::menus"
Here is the segment that triggers this (HelloWorldScene.cpp)
#include "HelloWorldScene.h"
#include "SimpleAudioEngine.h"
#include "Holder.h"
#include "Structs.h"
USING_NS_CC;
HelloWorld::HelloWorld(void)
{
//Constructor
Debug::crashLog("**__Menu Deinit__**");
//SUDO Missing stuff
Holder::menus.inits -= 1;
}
Why is it having issues?
in your Holder implementation file you need this:
counts Holder::menus;
if you don't have Holder.cpp file, (and you don't want one) you can put it directly into in HelloWorldScene.cpp.
I make a project in Eclipse to export a dll class with g++ compiler. My OS is Ubuntu and the application will run in Ubuntu OS. I created a shared project.
I have compile error as
expected constructor, destructor, or type conversion before ‘(’ token OCR_dll.h /OCR line 19 C/C++ Problem
The error happened at #define DLLCLASS __declspec(dllexport) and how to solve the error. Thank you.
My dll codes header file is
OCR_dll.h
#ifndef OCR_DLL_H_
#define OCR_DLL_H_
#include <stdio.h>
#include <opencv/cv.h>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <tesseract/baseapi.h>
#include <iostream>
#include "Define.h"
#ifdef EXPORT
#define DLLCLASS __declspec(dllexport)
#else
#define DLLCLASS __declspec(dllimport)
#endif
using namespace cv;
#ifdef __cplusplus
extern "C" {
#endif
namespace VIDEOANALYTICS_PLATFORM {
class iOCR{
public:
virtual ~iOCR(){}
virtual int preProcessing(Mat &img) = 0;
virtual int textExtraction(Mat &img) = 0;
};
class OCR : public iOCR{
public:
OCR(){}
~OCR(){ ; }
int preProcessing(Mat &img);
int textExtraction(Mat &img);
private:
};
extern "C"{ DLLCLASS iOCR* __stdcall createOCRObject(); };
}
#ifdef __cplusplus
}
#endif
#endif /* OCR_DLL_H_ */
I got the solution. In Linux environment, dll is called shared library.
The way I create the shared lib is
Headerfile
#ifndef OCR_DLL_H_
#define OCR_DLL_H_
#include <opencv/cv.h>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <tesseract/baseapi.h>
#include <iostream>
#include "Define.h"
using namespace cv;
namespace VIDEOANALYTICS_PLATFORM {
class iOCR{
public:
virtual ~iOCR(){}
virtual int preProcessing(Mat &img) = 0;
virtual int textExtraction(Mat &img) = 0;
};
class OCR : public iOCR{
public:
OCR(){}
~OCR(){ ; }
int preProcessing(Mat &img);
int textExtraction(Mat &img);
private:
};
}
#endif /* OCR_DLL_H_ */
CPP file
#include "OCR_dll.h"
namespace VIDEOANALYTICS_PLATFORM {
extern "C" iOCR* create_object(){
iOCR *p = new OCR();
return p;
}
extern "C" void destroy_object( iOCR* object )
{
delete object;
}
int OCR::preProcessing(Mat &img){
return SUCCESS;
}
int OCR::textExtraction(Mat &img){
return SUCCESS;
}
}
MAKEFILE
g++ -fPIC -shared OCR_dll.cpp -o OCR_dll.so
Then we can create shared lib object for a class.
I've looked this up and the closest thing I found was this except I don't have any forward declarations. I only have one pure virtual function in the base class which I'm implementing in the subclass as follows:
Command.h
#ifndef _COMMAND_H_
#define _COMMAND_H_
#include <string>
#include "Stack.h"
#include "Number.h"
class Command
{
public:
std::string cmdType;
Command(void);
Command (std::string cmdType);
virtual void executeCommand(Stack<Number> & stack) = 0;
~Command (void);
};
#endif // !defined _COMMAND_H_
Command.cpp
Command::Command(void)
:cmdType("")
{}
Command::Command(std::string cmdType)
:cmdType(cmdType)
{}
Command::~Command(void)
{}
Number.h
#ifndef _NUMBER_H_
#define _NUMBER_H_
#include "Command.h"
#include "Stack.h"
class Number : public Command
{
public:
Number (float num);
void executeCommand(Stack<Number> & stack);
float val;
~Number (void);
};
#endif // !defined _NUMBER_H_
Number.cpp
#include "Number.h"
Number::Number(float num)
:val(num)
{
cmdType = "hi";
}
void Number::executeCommand(Stack<Number> & stack)
{
stack.push((*this));
}
File error occurs:
Error 4 error C2259: 'Number' : cannot instantiate abstract class c:\...\add.cpp 34
Add.cpp
#include "Add.h"
Add::Add(void)
:Binary("+")
{
}
Add::~Add(void)
{
}
void Add::executeCommand(Stack<Number> & numStack)
{
Number num1 = numStack.top(); //THIS LINE HAS THE ERROR
numStack.pop();
Number num2 = numStack.top();
numStack.pop();
float tempVal = num2.val + num1.val;
num1.val = tempVal;
numStack.push(num1);
}
Add.h
#ifndef _ADD_H_
#define _ADD_H_
#include "Stack.h"
#include "Number.h"
#include "Binary.h"
class Add : public Binary
{
public:
Add (void);
void executeCommand (Stack<Number> & numStack);
~Add (void);
};
#endif // !defined _ADD_H_
This is a circular dependency problem.
Command.h includes Number.h
Number.h includes Command.h
Usually it is solved by replacing one of the includes with a forward declaration, try forward-declaring Number in Command.h instead of including Number.h; move that include to Command.cpp.