I need to build an executable which loads the dll # runtime and call the c++ function inside the dll with multiple parameters. I have seen plenty of examples which tells me about how to pass a parameter, but in my case it not exactly the same way. I need to pass 3 parameters.
Struct with 3 std::string elements
Struct pointer with std::map and std::string, and the map has std::string as key and structure as value
Struct with std::unordered_map which also has std::string as key and std::string as value, some bool, integer elements.
The dll class is derived from 2 base classes. ex: BaseClassA --> BaseClassB --> DerivedClassA
I have created the factory function and made all the __dllspec(dllexport) correctly but when I try to create DerivedClassA instance I got exceptions
Unhandled exception at 0x759FA6F2 in rte.exe: Microsoft C++ exception: std::length_error at memory location 0x016FF1C4
My Code Snippet (dllhelp.h):
#include <unordered_map>
#include <cinttypes>
typedef uint32_t ID;
typedef ID EVENT_UID;
typedef struct {
EVENT_UID m_unEventID;
uint8_t *m_ptrMemAddr;
size_t m_dataSize;
}stEvent_t;
typedef struct {
uint32_t m_unOffset;
uint32_t m_unArraySize;
std::string m_acTagName;
std::string m_acTagValue;
std::string m_acDataType;
} stTagElem_t;
typedef std::unordered_map<uint8_t, stTagElem_t> tagsList_t;
typedef struct {
EVENT_UID m_unBindedEvent;
uint16_t m_unMemSize;
tagsList_t m_stTagsList;
std::string m_acMapTypeName;
} stElem_t;
typedef std::unordered_map<std::string, stElem_t> ElemList_t;
typedef struct {
std::string m_acAppBlocName;
std::string m_acInstanceName;
std::string m_acDataMapInstanceName;
std::string m_acTypeName;
} stBlock_t;
typedef std::unordered_map<std::string, std::string > instanceTypeList_t;
typedef struct {
bool m_bIsItOutput;
uint8_t m_unIdxToEvtClient;
EVENT_UID m_acBindedEvent;
instanceTypeList_t m_acParamsList;
} stParams_t;
#ifdef EXPORTING_EXTN
#define RTE_EXTN __declspec(dllexport)
#else
#define RTE_EXTN __declspec(dllimport)
#endif
class RTE_EXTN BaseA {
public:
BaseA(){}
virtual ~BaseA(){}
void rxdEvent(stEvent_t pa_stEvent){ onRxdEvent(pa_stEvent);}
protected:
virtual void onRxdEvent(stEvent_t pa_stEvent);
};
class RTE_EXTN BaseB : public BaseA {
public:
BaseB(stParams_t pa_stParams){;}
virtual ~BaseB(){}
void sendOutput(size_t dataSize);
virtual int initialise() {return -1;}
virtual void onRxdEvent(stEvent_t pa_stEvent) {};
stBlock_t m_stBlock;
stElem_t *m_stElem;
protected:
stEvent_t m_stEvent;
stParams_t m_stParams;
};
class RTE_EXTN DerivedClassA : public BaseB {
public:
DerivedClassA(stBlock_t pa_stBlock, stElem_t *pa_stElem, stParams_t pa_stParams) : BaseB(pa_stParams){
m_stElem = pa_stElem;
m_stBlock = pa_stBlock;
}
int initialise(){return 0;}
void onRxdEvent(stEvent_t pa_stEvent);
};
extern "C" {
RTE_EXTN BaseB* CreateDerivedObj(stBlock_t pa_stBlock, stElem_t *pa_stElem, stParams_t pa_stParams);
};
typedef BaseB* (*CreateDrvObjType_t) (stBlock_t pa_stBlock, stElem_t *pa_stElem, stParams_t pa_stParams);
My dllmain.cpp:
#include "dllhelp.h"
BaseA* CreateDerivedObject(stBlock_t pa_stBlock, stElem_t *pa_stElem, stParams_t pa_stParams)
{
return new DerivedClassA(pa_stBlock, pa_stElem, pa_stParams);
}
My main executable:
stBlock_t m_siInfo;
stElem_t *pa_stElem;
stParams_t m_siParams;
//the above structures are initialized and updated with valid data..
HINSTANCE hGetProcIDDLL_derived;
typedef BaseB* (*CreateDrvObjType_t) (stBlock_t pa_stBlock, stElem_t *pa_stElem, stParams_t pa_stParams);
hGetProcIDDLL_derived = LoadLibrary(TEXT("dllhelp.dll"));
CreateDrvObjType_t oExtension = reinterpret_cast<CreateDrvObjType_t>(GetProcAddress(hGetProcIDDLL_derived, "CreateDerivedObj"));
BaseB* paDrvObj = oExtension(m_siInfo,pa_stElem,m_siParams);
When trying debug mode, I am able to see all the structures were filled with valid elements. But while debugging on the dllmain.cpp, I wasn't able to see any valid data on the structures. Some points to null address, and some to invalid data and many say "Error reading character string".
Note: I don't use dllhelp.h file in my main executable. Rather I have declared all the structures in main file itself.
Related
I am trying to initialize objects from other classes in my constructor as shared pointers. I need a shred pointer because I need a reference to use in another method in ...
header
class MyClass
{
public:
MyClass() ;
~MyClass() {};
void myMethod();
private:
std::shared_ptr<dds::pub::Publisher>m_pub;
std::shared_ptr<dds::domain::DomainParticipant>m_part;
};
cpp
MyClass::MyClass()
{
m_part = std::make_shared<dds::domain::DomainParticipant>(domain::default_id());
m_pub = std::make_shared<dds::pub::Publisher>(m_part);
}
MyClass::myMethod()
{
//m_part, m_pub are used here
}
what am I missing here?
Error C2039 'delegate': is not a member of 'std::shared_ptr<dds::domain::DomainParticipant>'
dds::pub::Publisher
namespace dds
{
namespace pub
{
typedef dds::pub::detail::Publisher Publisher;
}
}
Publisher
namespace dds { namespace pub { namespace detail {
typedef
dds::pub::TPublisher<org::eclipse::cyclonedds::pub::PublisherDelegate> Publisher;
} } }
PublisherDelegate
namespace dds { namespace pub { namespace detail {
typedef
dds::pub::TPublisher<org::eclipse::cyclonedds::pub::PublisherDelegate> Publisher;
} } }
class OMG_DDS_API PublisherDelegate : public
org::eclipse::cyclonedds::core::EntityDelegate
{
public:
typedef ::dds::core::smart_ptr_traits< PublisherDelegate >::ref_type ref_type;
typedef ::dds::core::smart_ptr_traits< PublisherDelegate >::weak_ref_type weak_ref_type;
PublisherDelegate(const dds::domain::DomainParticipant& dp,
const dds::pub::qos::PublisherQos& qos,
dds::pub::PublisherListener* listener,
const dds::core::status::StatusMask& event_mask);
TPublisher
template <typename DELEGATE>
class dds::pub::TPublisher : public dds::core::TEntity<DELEGATE>
{
public:
typedef dds::pub::PublisherListener Listener;
public:
OMG_DDS_REF_TYPE_PROTECTED_DC(TPublisher, dds::core::TEntity, DELEGATE)
OMG_DDS_IMPLICIT_REF_BASE(TPublisher)
TPublisher(const dds::domain::DomainParticipant& dp);
TPublisher(const dds::domain::DomainParticipant& dp,
const dds::pub::qos::PublisherQos& qos,
dds::pub::PublisherListener* listener = NULL,
const dds::core::status::StatusMask& mask = dds::core::status::StatusMask::none());
I tried the method given in answer got new error,
Error C2672 'std::dynamic_pointer_cast': no matching overloaded function in TPublisher.hpp
I guess m_pub should be initialised like this
m_pub = std::make_shared<dds::pub::Publisher>(*m_part);
The class dds::pub::Publisher a.k.a. dds::pub::TPublisher has the constructor taking const dds::domain::DomainParticipant by reference.
The answer is changed after the question has been updated.
I'm trying to do a C wrapper for a C++ third-party library because I need to use it in my C project.
I've seen examples of a C++ class wrapper but I don't undertood the process and I can't wrapper a C++ struct.
struct I want to wrapper:
struct confGlobal{
long int device;
string name;
int number;
string uid;
string message;
bool mode;
confiGlobal():device{LONG_MAX}, number{INT_MAX}{}
};
struct product{
string id;
string name;
};
struct category{
unsigned char id;
string name;
string description;
category():id{UCHAR_MAX}{}
};
struct subCategory{
unsigned char id;
string name;
string description;
unsigned char idRoot;
subCategory():id{UCHAR_MAX}, idRoot{UCHAR_MAX}{}
};
struct confPartner{
vector<struct product> tableProduct;
vector<struct category> tableCategory;
vector<struct subCategory> tableSubCategory;
};
For call to this method:
class my_API {
public:
static my_API* Instance(struct confGlobal cGlobal,
struct confPartner cPartner);
... another methods ...
private:
virtual ~my_API();
struct confGlobal cGlobal;
struct confPertner cPartner;
};
I need to fill this structs and call my_API::Instance() from C but my attempts have been unsuccessful.
wrapper.h
#ifdef __cplusplus
extern "C" {
#endif
struct confGlobal_wpr; // An opaque type that we'll use as a handle
typedef struct confGlobal_wpr confGlobal_wpr;
confGlobal_wpr *confGlobal_create(unsigned int device,
char *name,
int number,
char *uid,
char *message,
unsigned char mode);
struct product_wpr{
char id[4];
char name[30];
};
typedef struct product_wpr product_wpr;
struct category_wpr{
unsigned char id;
char name[3];
char description[30];
};
typedef struct category_wpr category_wpr;
struct subcategory_wpr{
unsigned char id;
char name[3];
char description[30];
unsigned char idRoot;
};
typedef struct subCategory_wpr subCategory_wpr;
struct confPartner_wpr; // An opaque type that we'll use as a handle
typedef struct confPartner_wpr confPartner_wpr;
confPartner_wpr *confPartner_create(Product_wpr tableProducts[],
unsigned char numProducts,
Category_wpr tableCategories[],
unsigned char numCategories,
SubCategory_wpr tableSubCategories[],
unsigned char numSubCategories);
struct my_api_wpr;
typedef struct my_api_wpr my_api_wpr;
my_api_wpr *my_api_create(struct confGlobal_wpr cGlobal,
struct confPartner_wpr cPartner);
#ifdef __cplusplus
}
#endif
wrapper.cpp
confGlobal_wpr *confGlobal_create(unsigned int device,
char *name,
int number,
char *uid,
char *message,
unsigned char mode)
{
confGlobal_wpr *cg;
struct confGlobal confiGlobal;
confiGlobal.name = name;
confiGlobal.device = device;
confiGlobal.number = number;
confiGlobal.uid = uid;
confiGlobal.message = message;
if (mode == 0)
confiGlobal.mode = false;
else
confiGlobal.mode = true;
return cg;
}
void confGlobal_destroy(confGlobal_wpr *cg)
{
if (cg == NULL)
return;
delete static_cast<confGlobal_wpr *>(cg->instance); // ERROR: invalid static_cast from type ‘confGlobal’ to type ‘confGlobal_wpr*’
free(cg);
}
confPartner_wpr *confPartner_create(product_wpr tableProducts_wpr[],
unsigned char numProducts,
category_wpr tableCategories_wpr[],
unsigned char numCategories,
subCategory_wpr tableSubCategories_wpr[],
unsigned char numSubCategories)
{
unsigned char i=0;
confPartner_wpr *cc;
struct confPartner cPartner;
vector< struct product> tableProduct;
vector< struct category> tableCategory;
vector< struct subCategory> tableSubCategory;
for (i=0; i<numProducts; i++)
{
struct product p;
p.id = tableProducts_wpr[i].id;
p.name = tableProducts_wpr[i].name;
tableProduct.push_back(p);
}
cPartner.tableProduct = tableProducts;
for (i=0; i<numCategories; i++)
{
struct category c;
c.id = tableCategories_wpr[i].id;
c.nombre = tableCategories_wpr[i].name;
c.descripcion = tableCategories_wpr[i].description;
tableCategory.push_back(c);
}
cPartner.tableCategory = tableCategory;
for (i=0; i<numSubCategories; i++)
{
struct subZona sc;
sc.id = tableSubCategories_wpr[i].id;
sc.name = tableSubCategories_wpr[i].name;
sc.description = tableSubCategories_wpr[i].description;
sc.idRoot = tableSubCategories_wpr[i].idRoot;
tableSubCategory.push_back(sc);
}
cPartner.tableSubCategory = tableSubCategory;
return cc;
}
my_api_wpr *my_api_create(struct confGlobal_wpr confiGlobal_wpr,
struct confPartner_wpr confiPartner_wpr)
{
my_api_wpr *my_api;
my_API *obj;
my_api = (typeof(my_api))malloc(sizeof(*my_api));
obj = my_API::Instance(confiGlobal_wpr, confiConsorcio_wpr);
/* With this compile and linked OK
confGlobal cg;
confPartner cc;
obj = my_API::Instance(cg, cc);
*/
my_api->obj = obj;
return my_api;
}
void my_api_destroy(ct_api_wpr *my_api)
{
if (my_api == NULL)
return;
delete static_cast<my_API *>(my_api->ptr_api); // ERROR: ‘virtual my_API::~my_API()’ is private within this context
free(my_api);
}
The output error when compile and linked with:
g++ -shared -o libwrapper.so *.cpp wrapper.h -l:libthird-party.a -L. -ldl -lrt -Wl,-rpath /usr/local/lib -lc
In function ‘my_api_wpr* my_api_create(confGlobal_wpr, confPartner_wpr)’:
error: no matching function for call to ‘my_API::Instance(confGlobal_wpr&, confPartner_wpr&)’
obj = my_API::Instance(confiGlobal_wpr, confiConsorcio_wpr);
^
my_API.h:30:20: note: candidate: static my_API* my_API::Instance(confGlobal, confPartner)
static my_API* Instance(struct confGlobal cGlobal, struct confiPartner cPartner);
^~~~~~~~
my_API.h:30:20: note: no known conversion for argument 1 from ‘confGlobal_wpr’ to ‘confGlobal’
You're forgetting that CT_API::Instance doesn't understand the "handle" types that you have created in C to wrap the C++ structures. This is precisely what the error message is telling you, if you read it. You must translate those back to the appropriate C++ types.
Firstly, since you are using "create"-style routines to build the structures and return them as a pointer, you should consider making your my_api_create function accept pointers instead. Particularly because the resulting handle types are forward-declared structs with no definition visible in C and it will not be possible for your C client to dereference them.
That highlights another issue. You are also not using these handles correctly from C++.
So, one thing at a time...
Your creation routine in C should be declared as:
my_api_wpr *my_api_create(struct confGlobal_wpr* cGlobal, struct confPartner_wpr* cPartner);
On the C++ side, you need to actually define your handle types. Something like:
extern "C" struct confGlobal_wpr {
struct confGlobal instance;
};
extern "C" struct confPartner_wpr {
struct confPartner instance;
};
extern "C" struct my_api_wpr {
my_API *ptr;
};
Now, your creation:
confGlobal_wpr *confGlobal_create(unsigned int device,
char *name,
int number,
char *uid,
char *message,
unsigned char mode)
{
confGlobal_wpr *cg = new confGlobal_wpr;
struct confGlobal& cGlobal = cg->instance; //<-- note the reference
// TODO: populate cGlobal as usual
return cg;
}
confPartner_wpr *confPartner_create(product_wpr tableProducts_wpr[],
unsigned char numProducts,
category_wpr tableCategories_wpr[],
unsigned char numCategories,
subCategory_wpr tableSubCategories_wpr[],
unsigned char numSubCategories)
{
confPartner_wpr *cc = new confPartner_wpr;
struct confPartner& cPartner = cc->instance; //<-- note the reference
// TODO: populate cPartner as usual
return cc;
}
my_api_wpr *my_api_create(struct confGlobal_wpr* cGlobal, struct confPartner_wpr* cPartner)
{
my_api_wpr *my_api = new my_api_wpr;
my_api->ptr = CT_API::Instance(cGlobal->instance, cPartner->instance);
return my_api;
}
You should also add corresponding _destroy methods for all the above.
To use C++ code in C project you need define wrapper functions with C calling convention - extern "C"(turning off C++ name mangling/decoration) , and call them and only them in your C project. Inside those C functions you can use C++ code. Pass to C wrapper functions only types that C understands. You can create intermediate structures for passing data to C wrapper functions. Then you need copy data to types that C++ class expects. In you particular case you incorrectly pass confGlobal_wpr wrapper struct but C++ method requires confGlobal, and compiler complains on this directly.
Below is observable snippet how to use C++ code from C code:
Foo.h
#include <string>
class Bar
{
public:
Bar(std::string s) : s_(s)
{
}
std::string s_;
};
class Foo
{
public:
Foo(Bar) {}
};
CWrappers.h // include this header to C project
struct BarWrapper
{
char data[100] = "";
};
#ifdef __cplusplus
extern "C" {
#endif
BarWrapper createFoo(char *c);
#ifdef __cplusplus
}
#endif
Wrapper.cpp
#include <algorithm>
#include "Foo.h"
#include "CWrappers.h"
// input and output to this C function should be understandable for C
BarWrapper createFoo(char *c)
{
// inside you can use C++
std::string data(c);
Bar bar(data);
Foo * foo = new Foo(bar);
BarWrapper barWrapper;
std::copy(data.begin(), data.end(), barWrapper.data);
return barWrapper; // pack data to C struct wrapper (that has no C++ specific)
}
C Project
#include "CWrappers.h"
int main()
{
BarWrapper barWrapper = createFoo((char *)"test");
}
Structs that contain anything other than primitive data types common to C and C++ largely can't be wrapped in the way you want. In this particular case, you have ::std::strings in your struct. And they definitely can't be accessed reasonably from C at all.
Additionally, the structs contain bool and I don't know if newer versions of the C standard have bool or define it in such a way that it will result in layout compatible structs with C++ implementations on the same platform.
There are solutions to this problem. But they involve using opaque pointers to the struct in C, and always calling functions to access its methods. I will try to whip up an example of how this might work for a really simple struct.
Looking more carefully at your code, it looks like you need a sort of thunk layer that takes the C struct and (in C++) hand-converts it to the C++ struct and returns a pointer to a dynamically allocated C++ struct that you can then pass to other C++ functions that have been exposed to C.
I am having difficulty resolving a redefinition error. Basically, I have a class object called houseClassType in my class header file and I also have to use houseClassType as my datatype for an array within my structure in my struct header file. Below are the two header files:
house header file:
#include "Standards.h"
#ifndef house_h
#define house_h
//Definition of class, house
class houseClassType
{
//Data declaration section
private:
int capacityOfGarage;
int yearBuilt;
int listingNumber;
double price;
double taxes;
double roomCounts[3];
string location;
string style;
//Private method to set the county name
string SetCountyName(string);
string SetSchoolDistrictName(string);
//Private method to set school district name
void SetSchoolDistrictName(void);
//Set function for the object
void ExtractLocationData(string& state, string& county, string& city,
string& schoolDistrictName, string& address);
//Methods declaration
public:
///Default Constructor
houseClassType(void);
///Get methods for data members - INLINE
int GetCapacity(void) { return capacityOfGarage; };
int GetYearBuilt(void) { return yearBuilt; };
int GetListingNumber(void) { return listingNumber; };
double GetPrice(void) { return price; };
double GetTaxes(void) { return taxes; };
string GetLocation(void) { return location; };
string GetStyle(void) { return style; };
void GetRoomCounts(double[]);
//Set methods for data members
void SetCapacityOfGarage(int);
void SetYearBuilt(int);
void SetListingNumber(int);
void SetPrice(double);
void SetTaxes(double);
void SetLocation(string);
void SetStyle(string);
void SetRoomCounts(double[]);
//Output methods for data members
void OutputLocationData(ofstream&);
void OutputStyle(ofstream&);
void OutputRoomCounts(ofstream&);
void OutputCapacityOfGarage(ofstream&);
void OutputYearBuilt(ofstream&);
void OutputPrice(ofstream&);
void OutputTaxes(ofstream&);
void OutputListingNumber(ofstream&);
void OutputHouse(ofstream&);
///Destructor
~houseClassType(void);
};
#endif
Realtor header file:
#include "Standards.h"
#ifndef Realtor_h
#define Realtor_h
const int NUMBER_OF_HOMES = 30;
typedef int houseClassType;
struct realtorStructType
{
string agentName;
houseClassType homes[NUMBER_OF_HOMES]; ///Redefinition error here
int numberOfHomes;
};
void InputHomes(ifstream& fin, string agentName, int& numberOfHomes);
#endif
Any help would be much appreciated.
The C++ language likes to have unique type names throughout a translation module. The following are not unique type names:
class houseClassType
typedef int houseClassType;
If you must use the same name, then you'll need to use namespaces to separate them:
namespace City
{
class houseClassType;
}
namespace Suburban
{
typedef int houseClassType;
}
struct realtorStructType
{
Suburban::houseClassType homes[MAX_HOMES];
};
I highly recommend you draw or design this issue first. This will help you with names too.
The simple solution is to use different names.
Also, do you need the suffix "ClassType" or "StructType" in your name? In a good design, whether it be a struct or class doesn't matter.
Your code is ambiguous. If you have
class houseClassType;
typedef int houseClassType;
What would the following code mean?
houseClassType x = new houseClassType();
You can resolve the ambiguity using a namespace, but it's better to change your second houseClassType type and name.
An example might look like this.
class House {
public:
enum class Type {
...
}
};
I am getting linker error, for the following code. I want to know how do I initialize stl map
#include <iostream>
#include <map>
#include <string>
class Test {
public:
Test() {
}
static void setSerializer(void* fnptr, std::string className) {
m_registry.insert(std::make_pair(className, fnptr));
}
static void* getSerializer(std::string className) {
return m_registry.find(className)->second;
}
private:
static std::map<std::string, void*> m_registry;
};
void fn() {
}
int main() {
Test::setSerializer(&fn,"abc");
return 0;
}
You need to define your static variable in class implementation - as you do for extern C++ variables. Just declaring it in class isn't sufficient!
To do this put the code below to the .cpp file:
std::map<std::string, void*> Test::m_registry;
You need to initialize your static member in .cpp file. Normally we declare class in .h file and put definition into .cpp file. I did a bit enhancement to your code as shown below:
Test.h
class Test
{
public:
Test() { }
static void setSerializer(std::string className, void* fnptr); // I swap the order of parameter. it makes more sense to have name and pointer pair
static void* getSerializer(std::string className);
private:
static std::map<std::string, void*> m_registry;
};
Test.cpp
std::map<std::string, void*> Test::m_registry; // initialize static member here
void Test::setSerializer(std::string className, void* fnptr)
{
m_registry.insert(std::make_pair(className, fnptr));
}
void* Test::getSerializer(std::string className) {
auto iter = m_registry.find(className); // check if iterator is valid
if (iter != m_registry.end() )
{
return (*iter).second;
}
return NULL;
}
I am getting an error at the line "void operation" when I compile, because I havent defined Gate_ptr yet. I thought of exchanging the "Gate_ptr" with just "Gate*" instead in the function def. However, is there a way to maintain my current style?
class Gate
{
public:
Gate();
void operation(Gate_ptr &gate_tail, string type, int input1, int input2=NULL);
private:
int cnt2;
int input_val1, input_val2;
int output, gate_number;
int input_source1, input_source2;
int fanout[8];
Gate* g_next;
string type;
};
typedef Gate* Gate_ptr;
Prefer this order:
//forward decleration
class Gate;
//typedef based on forward dec.
typedef Gate* Gate_ptr;
//class definition
class Gate
{
public:
//...
};
Forwared declare, do the typedef, then define the class:
class Gate;
typedef Gate* Gate_ptr;
class Gate
{
public:
Gate();
void operation(Gate_ptr &gate_tail, string type, int input1, int input2=NULL);
private:
int cnt2;
int input_val1, input_val2;
int output, gate_number;
int input_source1, input_source2;
int fanout[8];
Gate* g_next;
string type;
};