Say I have a DLL right that contains this:
//DLL
class foo {
static __declspec int Add(int a, int b)
{
return a+b
}
}
How Do I call it call the GetProc Address? I.e:
HINSTANCE hFoo = LoadLibrary("Foo.dll");
int* proc = NULL;
proc = (int*) GetProcAddress(hFoo, ??????);
//Main Exec linked to dll
How in the world would you get the address of a class created in a dll using GetProcAddress?
edtheprogrammerguy is right.
Here is more informations on how to get class properly exposed:
You need to prefix with the attribute :
__declspec(dllexport)...
all the features you want to expose.
See this.
Example for a C function:
__declspec(dllexport) int __cdecl Add(int a, int b)
{
return (a + b);
}
This can be simplified using MACROS: everything is explained on this helpful page.
For C++ classes, you only need to prefix each class (not every single method)
I usually do it that way :
Note : The following also ensures portability...
Include File :
// my_macros.h
//
// Stuffs required under Windoz to export classes properly
// from the shared library...
// USAGE :
// - Add "-DBUILD_LIB" to the compiler options
//
#ifdef __WIN32__
#ifdef BUILD_LIB
#define LIB_CLASS __declspec(dllexport)
#else
#define LIB_CLASS __declspec(dllimport)
#endif
#else
#define LIB_CLASS // Linux & other Unices : leave it blank !
#endif
Usage :
#include "my_macros.h"
class LIB_CLASS MyClass {
}
Then, to build, simply :
Pass the option -DBUILD_LIB to the usual compiler command line
Pass the option -shared to the usual linker command line
You can't get the address of a class from a .dll. If you want to use a class instance from a .dll, use dllexport/dllimport, which lets you export the class and use it as if it were declared locally.
Reference from Microsoft:
http://msdn.microsoft.com/en-us/library/81h27t8c(v=vs.80).aspx
I was trying to create an example of Explicit Linking Here is the example I finally came up with, I apologize for not specifically mentioning this earlier.
Here we go:
//DLL
#include "main.h"
#include <windows.h>
#include <stdexcept>
using namespace std;
class FOO{
static __declspec double ADD(double a, double b)
{
return a+b;
}
}
//EXEC
#include <windows.h>
#include <iostream>
#include <stdio.h>
using namespace std;
typedef double (*MYPROC)(double, double);
int main()
{
double d1 = 10;
double d2 = 30;
double retval;
MYPROC procx = NULL;
DWORD err;
HINSTANCE hDll = LoadLibrary("DynamicLinkTester.dll");
if(hDll != NULL)
{
cout << "Success";
procx = (MYPROC) GetProcAddress(hDll, "_ZN7MathDLL5MathX3ADDEdd");
if(NULL != procx )
{
retval= (procx)(d1, d2);
cout << retval;
}
}
}
If anyone was wondering the same thing as me:
While you can't explicitly call a class/object from a dll you can call its method.
Related
I have a class in C++ which I want to make a shared library from it and use in C or other languages. this is the class that I want to make a library from it:
getinfo.h
#ifndef GETINFO_H
#define GETINFO_H
#include "info.h"
char* getMaximumSpeedCpu();
char* getCoreNumbers();
#endif
getinfo.cpp:
#include <iostream>
#include "getinfo.h"
using namespace Morsa::Prd::SMC::SL;
char* getMaximumSpeedCpu()
{
info *inf = new info;
std::string str = inf->maximumSpeedCpu();
char* maxspeed = new char[str.length()+1];
strcpy(maxspeed, str.c_str());
free(inf);
return maxspeed;
}
char* getCoreNumbers()
{
info *inf = new info;
std::string corenum = inf->coreNumbers();
char* num = new char[corenum.length()+1];
strcpy(num, corenum.c_str());
free(inf);
return num;
}
and this is my wrapper class (smc.h):
#ifndef SMC_H
#define SMC_H
#include "getinfo.h"
#ifdef __cplusplus
extern "C"
{
#endif
//void smc_destroy(ctestsmc *a);
char* smc_getMaximumSpeedCpu();
char* smc_getCoreNumbers();
#ifdef __cplusplus
}
#endif
#endif // SMC_H
smc.cpp:
#include "smc.h"
char *smc_getMaximumSpeedCpu()
{
char* c = getMaximumSpeedCpu();
return c;
}
char *smc_getCoreNumbers()
{
char* c = getCoreNumbers();
return c;
}
I made a shared library from smc.cpp, now I want to use my library in for example a C code.
How am I supposed to do it without including any header file? Whenever I include header file of smc, my C code doesn't know libraries that I had used in getinfo.h, like fstream.EDIT:
info.h:
#ifndef INFO_H
#define INFO_H
#include <stdlib.h>
#include <cstring>
#include <sys/statvfs.h>
#include <libssh/libssh.h>
class info
{
private:
std::ifstream ifile;
std::ofstream ofile;
std::vector<std::string> lists;
std::string str;
ssh_session my_ssh_session ;
public:
info();
info(const void *ip, const char* pw, const void *hostName);
~info();
std::string maximumSpeedCpu();
std::string coreNumbers();
const void* _hostName;
const void* _ip;
const char* _password;
info.cpp:
#include "info.h"
info::info(const void *ip, const char* pw, const void *hostName)
{
int a;
_ip = ip;
_password = pw;
_hostName = hostName;
my_ssh_session = ssh_new();
}
info::info()
{
}
info::~info()
{
ssh_disconnect(my_ssh_session);
ssh_free(my_ssh_session);
}
std::string info::maximumSpeedCpu()
{
//maximum speed of cpu
getSSHState();
std::string cpuSpeed;
cpuSpeed = exec_ssh_command(my_ssh_session, "dmesg | grep 'MHz processor' | awk '{print $5}'" );
return cpuSpeed;
}
std::string info::coreNumbers()
{
//number of processors
getSSHState();
std::string coresNumber;
coresNumber = exec_ssh_command(my_ssh_session, "cat /proc/cpuinfo | grep processor | wc -l");
return coresNumber;
}
Theory
You can only access functions written in C from the world of C. Whenever calling C++ code from C, you must go through a wrapper function, in your case smc_* functions.
Now, note that the declaration of the wrapper functions, which is in the wrapper's header file smc.h does not need to include getinfo.hpp. This is the key insight. The wrapper's header merely tells any C program that includes it, the type of arguments and return values of the smc_* functions. The header must stick to C.
For example, see the image below. The functions foo and bar are declared in the wrapper.h file which only includes other C headers. The wrapper.cpp file which actually implements the wrapper, and uses other stuff from the C++ world (like the STL, or other classes) includes the C++ headers it needs.
In your case, smc.cpp will include getinfo.hpp, not smc.h.
However, the definitions of these wrapper functions needs to know the types of the C++ functions it is wrapping. Therefore, smc.cpp will include getinfo.h. Further, because this file will be compiled by a C++ compiler, it will understand any references to C++ STL in included headers.
EDIT: Code example
Suppose I want to wrap the class cppworld.
cppworld.hpp:
class cppworld {
public:
cppworld();
int one();
};
cppworld.cpp:
#include <iostream>
#include "cppworld.hpp"
cppworld::cppworld() {}
int cppworld::one() {
return 1;
}
I write a wrapper with wrapper.h and wrapper.cpp.
wrapper.h:
#ifdef __cplusplus
extern "C"
{
#endif
int get_one();
#ifdef __cplusplus
}
#endif
wrapper.cpp:
#include "wrapper.h"
#include "cppworld.hpp"
int get_one() {
cppworld obj = cppworld();
return obj.one();
}
I can compile wrapper.cpp and cppworld.cpp into a shared library.
Then, to use the library from C, I create the C program below.
cworld.c
#include <stdio.h>
#include "wrapper.h"
int main() {
printf("Calling one() returns: %d\n", get_one());
}
Whenever I include header file of smc, my C code doesn't know libraries that I had used in getinfo.h, like fstream.
Yeah, you need to give C the declarations (not the definition) of the functions you need, and those declarations cannot use C++ features (directly).
For instance, you cannot give C things like references, templates or overloaded functions. You cannot directly use arbitrary class objects either, like an std::string, but you can pass them around as opaque pointers since for C they are just pointers.
Regardless of how you do it, you need C to see only what appear to be C functions on the surface.
I'm working on a cross platform project where I have to load dynamic libraries. I therefore created a very basic platform independent templated wrapper class around dlopen/loadLibrary that act like a factory class and return unique_ptr<T>s of the lib object.
But this is very unpractical in most of the cases, I therefore wondered, how can I design a simple wrapper that can do the following:
Load a lib and become a factory on instances of that lib objects for when we have to use multiple instances of the lib object
Create a self managed entity (a struct containing a unique ptr on the object and the handle on the lib maybe ?) for when we want to use only one instance of a lib object and not bother with a factory
Use the library provided deleter (symbol "destroy") instead of the default one
Does this exist ? If not, what would be the best way to do this ?
My implementation so far:
#pragma once
#include <memory>
#include <iostream>
#if _WIN32
#include <Windows.h>
#else
#include <dlfcn.h> //dlopen
#endif
namespace utils
{
template <class T>
class DynLib
{
public:
DynLib() = default;
~DynLib()
{
if (handle_)
closeLib(handle_);
};
private:
bool printLibError()
{
#if _WIN32
std::cerr << GetLastError() << std::endl;
#else
std::cerr << dlerror() << std::endl;
#endif
return false;
}
void *openLib(const std::string &libName)
{
#if _WIN32
return LoadLibrary((libName + ".dll").c_str());
#else
return dlopen((libName + ".so").c_str(), RTLD_LAZY);
#endif
}
int closeLib(void *libHandle)
{
#if _WIN32
return FreeLibrary((HMODULE)libHandle);
#else
return dlclose(libHandle);
#endif
}
void *loadSymbol(void *libHandle, const char *sym)
{
#if _WIN32
return (void *)GetProcAddress((HMODULE)libHandle, sym);
#else
return dlsym(libHandle, sym);
#endif
}
public:
bool open(const std::string &filename, const char *csym = "create", const char *dsym = "destroy")
{
if (!(handle_ = openLib(filename)))
return printLibError();
if (!(create = (T * (*)()) loadSymbol(handle_, csym)))
return printLibError();
if (!(destroy_ = (void (*)(T *))loadSymbol(handle_, dsym)))
return printLibError();
return true;
}
std::unique_ptr<T> createUnique()
{
return (std::unique_ptr<T>(create()));
}
private:
void *handle_{nullptr};
T *(*create)();
void (*destroy_)(T *);
};
}
Have you considered Boost.DLL library?
It provides examples on how implement plugins/factory methods.
I'm developing a C++ library for export as a DLL in Visual Studio 2013 (C++ 11), and I'm running into a challenge where the library, once imported as an external dependency by another program, contains the classes that I wanted, but none of the functions of the classes are included.
View of classes within external dependency
I have included one particular class that is supposed to be part of this DLL export.
Here is my RegressionTrainer class header file:
#ifndef REGRESSION_TRAINER_H
#define REGRESSION_TRAINER_H
#include "MachineLearning.h"
#pragma once
#ifndef DLL_EXPORT
#define DLL_EXPORT __declspec(dllexport)
#endif
using namespace MachineLearning;
namespace MachineLearningTraining{
public class RegressionTrainer{
public:
DLL_EXPORT RegressionTrainer();
virtual DLL_EXPORT ~RegressionTrainer();
std::vector<sample_type> DLL_EXPORT getInputData();
std::vector<double> DLL_EXPORT getAugmentedOutputs();
std::vector<double> DLL_EXPORT getNonAugmentedOutputs();
protected:
pugi::xml_parse_result DLL_EXPORT setDataFile(pugi::xml_document &doc, char* file_name);
void DLL_EXPORT setDataFolder(char* folder_name);
std::vector<char*> DLL_EXPORT findDataFiles();
char* data_folder;
std::vector<char*> file_names;
std::vector<sample_type> input_data;
/*
sample_type m;
m(0, 0) = 14.86;
m(1, 0) = 0.24;
*/
std::vector<double> augmented_outputs;
std::vector<double> non_augmented_outputs;
pugi::xml_parse_result result;
void DLL_EXPORT setInputData();
void DLL_EXPORT setAugmentedOutputs();
void DLL_EXPORT setNonAugmentedOutputs();
virtual int DLL_EXPORT trainAugmentedModel();
virtual int DLL_EXPORT trainNonAugmentedModel();
};
}
#endif
Here are the contents of MachineLearning.h:
#include <vector>
#include <iostream>
#include <exception>
#include <fstream>
#include <string>
#include <dlib/svm.h>
#include "pugixml.hpp"
namespace MachineLearning{
// Here we declare that our samples will be 2 dimensional column vectors.
typedef dlib::matrix<double, 3, 1> sample_type;
// Now we are making a typedef for the kind of kernel we want to use. I picked the
// radial basis kernel because it only has one parameter and generally gives good
// results without much fiddling.
typedef dlib::radial_basis_kernel<sample_type> kernel_type;
}
And here is my RegressionTrainer.cpp file:
#include "Stdafx.h"
#include "RegressionTrainer.h"
#include "dirent.h"
using namespace std;
using namespace dlib;
using namespace MachineLearning;
namespace MachineLearningTraining{
RegressionTrainer::RegressionTrainer(){
file_names = findDataFiles();
}
RegressionTrainer::~RegressionTrainer(){
}
pugi::xml_parse_result RegressionTrainer::setDataFile(pugi::xml_document &doc, char *file_name){
return doc.load_file(file_name);
}
void RegressionTrainer::setDataFolder(char *folder_name){
data_folder = folder_name;
}
std::vector<char*> RegressionTrainer::findDataFiles(){
DIR *dir;
struct dirent *ent;
std::vector<char*> file_names;
if ((dir = opendir(data_folder)) != NULL) {
/* print all the files and directories within directory */
while ((ent = readdir(dir)) != NULL) {
file_names.push_back(ent->d_name);
}
closedir(dir);
}
else {
/* could not open directory */
perror("Could not open directory");
}
return file_names;
}
std::vector<sample_type> RegressionTrainer::getInputData(){
return input_data;
}
std::vector<double> RegressionTrainer::getAugmentedOutputs(){
return augmented_outputs;
}
std::vector<double> RegressionTrainer::getNonAugmentedOutputs(){
return non_augmented_outputs;
}
void RegressionTrainer::setInputData(){
pugi::xml_document doc;
for (unsigned i = 0; i < file_names.size(); i++){
setDataFile(doc, file_names[i]);
std::cout << "Load result: " << result.description() << endl;
pugi::xml_node measures = doc.child("case").child("measures");
sample_type m;
int count = 0;
for (pugi::xml_node measure = measures.first_child(); measure; measure = measure.next_sibling()){
m(count, 0) = measure.text().as_double();
count++;
}
input_data.push_back(m);
}
}
void RegressionTrainer::setAugmentedOutputs(){
pugi::xml_document doc;
for (unsigned i = 0; i < file_names.size(); i++){
setDataFile(doc, file_names[i]);
std::cout << "Load result: " << result.description() << endl;
pugi::xml_node output = doc.child("case").child("studyresults").child("averageangledeviation");
augmented_outputs.push_back(output.text().as_double());
}
}
void RegressionTrainer::setNonAugmentedOutputs(){
pugi::xml_document doc;
for (unsigned i = 0; i < file_names.size(); i++){
setDataFile(doc, file_names[i]);
std::cout << "Load result: " << result.description() << endl;
pugi::xml_node output = doc.child("case").child("studyresults").child("averageangledeviationAR");
augmented_outputs.push_back(output.text().as_double());
}
}
int RegressionTrainer::trainAugmentedModel(){
return 0;
}
int RegressionTrainer::trainNonAugmentedModel(){
return 0;
}
}
Would welcome any thoughts!
Your code is confusing:
public class RegressionTrainer
Is this C++ or C#? Some other part of your code clearly shows it is C++. Therefore you must always put exact (or syntactically same) code.
Back to your problem, you cannot export members of a class. You must export entire class from a DLL.
Then issues start to begin. For one, you must expose (export or not, doesn't matter) all types the class uses (pugi::xml_parse_result for example). Then, you need to take care of different compilers versions (Even VC2015, various versions, debug/release, compiler settings etc). For example a vector on VC2015 debug build would be different from a release version. Service pack would complicate the problem.
In short: Don't export entire class having data-members. Even if entire data is private, you will need to export entire class, so that client (consumer of DLL) can compile and link (to code) properly.
So, what's the solution?
Well, just export a helper class:
class DLL_EXPORT RegressionTrainerHelper
{
RegressionTrainer* pCoreClass;
};
Expose (export) all required methods (for the client) from this class. You'd just need to forward the calls from helper to real class.
Now, you might wonder, you will need to export the underlying type RegressionTrainer, and you are back to same problem.
Well, yes and no. If this helper class is being compiled within DLL, RegressionTrainer would be real thing. If not, just:
typedef int RegressionTrainer;
Pointer of anytype is of same size (32-bit or 64-bit). Hence the size of entire exported class would always match the size in DLL and in EXE.
EDIT
For example, there is a XML parser class, ParseXML, but it uses comlpex data members, you have a method Parse.
class ParseXML
{
// complex data members
// some private OR public datamembers and functions, you dont want/need to export
public:
void Parse(const char*); // or something different
};
You would want to export only Parse, through helper class.
class DLL_EXPORT Exported_ParseXML
{
private:
ParseXML* pCoreXMLInstance;
public:
Exported_ParseXML()
{
// implementation in CPP
pCoreXMLInstance = new ParseXML();
}
// The function!
void Parse(const char* pData)
{
// FORWARD
pCoreXMLInstance->Parse(pData);
}
The client will simply use the exported class:
Exported_ParseXML parser;
parser.Parse("XML-data");
The server compiler (DLL) would see ParseXML as real class type. But the client (EXE, or other DLL), would need see ParseXML as int. You got to figure out this!
I have a dll plugin ,myDLL.cpp, which has the following code:
#include "myDLL.h"
#include "MainApp.h"
class A{
public:
// NOTE: SomeType is defined in main application code.
A(SomeType* data) : m_data{data}
void MemberFunc(){
// NOTE: do_something should access data in main application.
m_data->do_something();
}
private:
SomeType* m_data;
};
// exported function
A* createInstance(SomeType* data){
return new A(data);
}
In the main application I have:
stc::vector<int> IntArray;
class SomeType{
SomeType(){
IntArray.resize(1000);
}
void do_something(){
// manipulate IntArray's contents.
IntArray[rand() % IntArray.size()] = rand();
}
};
typedef A*(_createInstance)(SomeType*);
void main(){
// Load the Dll and get createInstance()
_createInstance createInstance = LoadMyDLL();
SomeType someType;
A* a = createInstance(&someType);
a->MemberFunc();
// Free the instance of A and unload the DLL.
UnloadMyDLL(a);
}
The dll code now can use the API of the main application, but it can't access the right data. When I put a break point at m_data->do_something(); and enter the method call, then I see that IntArray is empty. What am I doing wrong and how do I solve the problem?
I could succesfully run your example without experiencing your problem:
I assumed that in your headers there are only the class definitions and not definition of its member functions
So I buid a DLL project. But it failed producing the dll because of the missing do_something() function. Normal, because with your architecture it should be defined in the application not in the DLL ! I could solve the problem by making do_something() virtual.
Then I build the application. I first chose for simplicity and linked the application with the DLL (no loading issues). Unfortunately it didn't find either MemberFunc() nor createInstance(). I could solve this by exporting the DLL entry.
FInally I updated the application, to have a dynamic load of the library. For avoiding unnecessary hassle of having to find back MemberFunc(), I made it virtual as well.
In all the tests above, I had absolutely no problem. IntArray was always correct. In debug mode I could see it with the expected content, as soon as it entered the scope.
My conclusion, from these tests and looking at your snippet (expecially with doSomething not being virtual): your problem is probably that have defined SomeType class with functions and eventually IntArray in Main.h.
If this is the case, your DLL refers to its own copy of these elements and not as you think to those in main ! THis explains why you don't see the expected values !
Solution:
File MainApp.h:
class SomeType{
public:
SomeType();
virtual void do_something();
};
File MyDLL.h:
#ifdef MYDLL_EXPORTS
#define MYDLL_API __declspec(dllexport)
#else
#define MYDLL_API __declspec(dllimport)
#endif
class A {
public:
A(SomeType* data);
virtual void MemberFunc(); // access through vtable. No need to link
private:
SomeType* m_data;
};
extern "C" { // use unmangled name for easo of use of dynamic loaded DLL
MYDLL_API A* createInstance(SomeType* data);
};
File MyDLL.cpp:
#define MYDLL_EXPORTS
#include "MainApp.h"
#include "MyDLL.h"
A::A(SomeType* data) : m_data{ data } {}
void A::MemberFunc(){ m_data->do_something(); }
extern "C" {
MYDLL_API A* cdecl createInstance(SomeType* data){ return new A(data); }
}
File main.cpp:
#include <Windows.h>
#include <iostream>
#include <vector>
#include "MainApp.h"
#include "MyDLL.h"
using namespace std;
vector<int> IntArray;
SomeType::SomeType(){
IntArray.resize(1000);
IntArray[0] = 1; IntArray[1] = 101; IntArray[2] = 10101;
}
void SomeType::do_something(){
for (int i = 0; i < 4; i++) // read
cout << IntArray[i] << endl;
IntArray[3] = 2702; // write
}
int main(int ac, char**av)
{
HINSTANCE LoadMe = LoadLibrary(L"MyDLL.dll");
if(LoadMe != 0)
cout << "DLL Library successfully loaded!\n";
else throw exception("DLL library failed to load!\n");
typedef A*(*_createInstance)(SomeType*);
_createInstance fcreateInstance = (_createInstance) GetProcAddress(LoadMe, "createInstance");
if (fcreateInstance)
cout << "DLL function found !\n";
else throw exception("Function not found in DLL!\n");
SomeType someType;
A* a = fcreateInstance(&someType);
a->MemberFunc();
cin.get();
}
Ok so I am trying to create a runtime DLL for another application that can be called using GetProcAddress.
So I have built the DLL in VS2012 C++ Express (Header and source below) and it returns NULL even when dll is in same folder as exe. So this lead me to believe there was an issue with the dllmain function. So I began looking through MSDN and found the following link
http://msdn.microsoft.com/en-us/library/vstudio/988ye33t.aspx
It states that it is already taken care for me when I create dll template which I did following this MSDN link.
http://msdn.microsoft.com/en-us/library/ms235636%28v=vs.80%29.aspx
So I decided to try build the DLL in release mode (thinking something about this might be the issue) but I get a linker error saying entry point must be define. It builds fine in debug mode but not in release mode. I assume I am missing something simple here.
Error 1 error LNK1561: entry point must be defined C:\Users\ProRip\Documents\Visual Studio 2012\Projects\PhantomAdapter\AdapterDLL\LINK AdapterDLL
Header
#ifdef PHANTOMADAPTER_EXPORTS
#define PHANTOMADAPTER_API __declspec(dllexport)
#else
#define PHANTOMADAPTER_API __declspec(dllexport)
#endif
#using <mscorlib.dll>
#using <system.dll>
using namespace System;
using namespace System::IO::Ports;
using namespace System::Threading;
namespace PhantomAdapter
{
class PhantomAdapter
{
public:
static PHANTOMADAPTER_API int open();
static PHANTOMADAPTER_API int close();
//static PHANTOMADAPTER_API double init(bool );
//static PHANTOMADAPTER_API int noDevices();
static PHANTOMADAPTER_API int angle(double& angle);
static PHANTOMADAPTER_API int torque(double torque);
static PHANTOMADAPTER_API int ready();
};
public ref class SerialPort
{
private:
static System::IO::Ports::SerialPort^ p1;
public:
static int openPort();
static void closePort();
static int read();
static void send(Byte data);
static int check();
};
}
Source
#include "stdafx.h"
#include "stdafx.h"
#include "PhantomAdapter.h"
#include <stdexcept>
using namespace std;
namespace PhantomAdapter
{
int PhantomAdapter::open()
{
int flag=0;
flag=SerialPort::openPort();
return flag;
}
int PhantomAdapter::close()
{
SerialPort::closePort();
return 1;
}
int PhantomAdapter::angle(double& angle)
{
SerialPort::send(0x82);
angle = (SerialPort::read() * 255) + (SerialPort::read());
angle = angle*(6.2832/512);
return 1;
}
int PhantomAdapter::torque(double torque)
{
return 1;
}
int PhantomAdapter::ready()
{
return SerialPort::check();
}
int SerialPort::openPort()
{
bool check=0;
p1 = gcnew System::IO::Ports::SerialPort();
p1->BaudRate = 57600;
p1->PortName = "COM3";
if(p1->IsOpen)
return 0;
else {
p1->Open();
return 1;
}
}
int SerialPort::check()
{
array<String^>^ serialPorts = nullptr;
int flag=0;
serialPorts = p1->GetPortNames();
for each(String^ port in serialPorts)
{
if(port=="COM3")
flag=1;
}
return flag;
}
void SerialPort::closePort()
{
p1->Close();
}
void SerialPort::send(Byte data)
{
array<unsigned char>^ buffer = gcnew array<Byte>(1);
buffer[0] = (char)data;
p1->Write(buffer,0,1);
}
int SerialPort::read()
{
return p1->ReadByte();
}
}
In your VS project, can you check the settings:
1. Configuration Properties > General > Configuration Type? Is this set to .dll in case of Release mode?
2. Configuration Properties > Linker > System > SubSystem? Is this the same between the 2 modes?
You cannot call a .NET method (and C++/CLI methods are .NET methods) from native code via LoadLibrary/GetProcAddress. .NET methods and classes are not exported that way. You will always get a NULL pointer.
What you can do:
Write a COM component in .NET to reference in plain C++
Export normal, plain C++ methods that call .NET code only internally
Import a managed dll into a managed (the same C++/CLI or C# or any other .NET language) executable by using the Assembly class and it's methods.