I have been trying to pass a class pointer from a native DLL to CLR. I am not so successful with it. I get to the point it returns the pointer using void * and later converting it to ClassType * using IntrPtr and ToPointer(). But the minute I try to access its member methods, its not able to get the old property values. I get instead 0 and some random values.
I have even tried to use VC100 as the toolset for both the CLR and native dll. Still I get the value "Error reading characters of string".
I tried to google and can't find much info on passing object pointers from native to CLR. I have referred to even the step-by-step available in code project.
Edited to add this:
I have a native dll where a function that returns object pointer
Native.dll:
#if defined EXPORTDLL // inside DLL
#define DLL_EXPORT __declspec(dllexport)
#else // outside DLL
#define DLL_EXPORT __declspec(dllimport)
#endif
.....
DLL_EXPORT void* SomeMethod(uint16_t num1, const char * str1, const char * str2)
{
Obj1 obj(...);
...
return (void*)&obj; // <- at this point it is still correct
}
....
class DLL_EXPORT Obj1{
....
const std::string var1;
const std::string var2;
const std::string var3;
....
DLL_EXPORT strct1 memberFunction1()
{
// do something with the variables
// here when its called by managed code, the var1, var2, var3 shows random values and bad ptr..
}
...
}
And later in managed code clr I call the memberFunct1 using the return pointer.
[DllImport("Native.dll", EntryPoint = "?SomeMethod##YAPAVstruct1#someSpace##GV?$basic_string#DU?$char_traits#D#std##V?$allocator#D#2##std##0#Z", CallingConvention = CallingConvention::Cdecl)]
IntPtr * SomeMethod(uint16_t num1, [In, MarshalAs(UnmanagedType::LPStr)]String^ str1, [In, MarshalAs(UnmanagedType::LPStr)] String^ str2);
.....
String^ str1 = gcnew String("1223568");
String^ str2 = gcnew String("1.2.3.5");
Obj1 *objptr = (Obj1*)(SomeMethod(1,str1, str2)).ToPointer();
// <- at this point the objptr properties are showing garbage
objptr->memberFunction1();
I use this obj1 pointer to call a member method but in the member method the member values are showing as bad ptr.
Can someone point me in the right direction please?
Thanks in advance.
I have added an additional method in my Native dll.
void DLL_EXPORT SomeMethod2(int i1, const char* var1, const char* var2, Obj1* retval);
And called it from my CLR project
[DllImport("Native.dll", EntryPoint = "?SomeMethod2##YAXHPBD0PAVObj1###Z", CallingConvention = CallingConvention::Cdecl)]
void SomeMethod2(int i1, [MarshalAs(UnmanagedType::LPStr)]String^ var1, [MarshalAs(UnmanagedType::LPStr)]String^ var2, Obj1* retval);
....
Obj1 * testPtr3;
SomeMethod2(1, (char*)(void*)Marshal::StringToHGlobalAnsi(str1), (char*)(void*)Marshal::StringToHGlobalAnsi(str2), testPtr3);
SomeMethod2(1, str1, str2, testPtr3);
Obj1 testPtr2 = Obj1(1, (char*)(void*)Marshal::StringToHGlobalAnsi(str1), (char*)(void*)Marshal::StringToHGlobalAnsi(str2));
But I get link errors? I have already linked it??!!??
error LNK2028: unresolved token (0A000356) "public: __thiscall Obj1::Obj1(int,char const *,char const *)" (??0Obj1##$$FQAE#HPBD0#Z) referenced in function "int __cdecl main(void)" (?main##$$HYAHXZ)
error LNK2028: unresolved token (0A00035B) "void __cdecl SomeMethod2(int,char const *,char const *,class Obj1 *)" (?SomeMethod2##$$FYAXHPBD0PAVObj1###Z) referenced in function "int __cdecl main(void)" (?main##$$HYAHXZ)
error LNK2019: unresolved external symbol "public: __thiscall Obj1::Obj1(int,char const *,char const *)" (??0Obj1##$$FQAE#HPBD0#Z) referenced in function "int __cdecl main(void)" (?main##$$HYAHXZ)
error LNK2019: unresolved external symbol "void __cdecl SomeMethod2(int,char const *,char const *,class Obj1 *)" (?SomeMethod2##$$FYAXHPBD0PAVObj1###Z) referenced in function "int __cdecl main(void)" (?main##$$HYAHXZ)
You do not use C++/CLI in this way!
The whole point of C++/CLI is to act as a glue between the .NET world and the native world.
What you do instead is to:
Include the C++ headers for SomeMethod and class Obj1 in the C++/CLI source file and
have the C++/CLI assembly reference the Native.dll project
Then, you can simply use it as you would normally in C++ - convert any CLR types to native representation first (System::String can be converted by MFC CString if you include MFC):
String^ str1 = gcnew String("1223568");
String^ str2 = gcnew String("1.2.3.5");
Obj1 *objptr = SomeMethod(1, CString(str1), CString(str2));
As for why you see garbage in the debugger: It is probably because you return the address of a local object:
DLL_EXPORT void* SomeMethod(uint16_t num1, const char * str1, const char * str2)
{
Obj1 obj(...);
...
return (void*)&obj; // <- at this point it is still correct
}
In this case, objwill be cleaned up (its D'tor invoked and its stack memory recycled) as soon as you return from SomeMethod.
Either return the object by value
or new up the object and return the pointer. (though that is leak-risking code)
Related
By some reason MSVC DO NOT compile boost serialization example with the following code:
class MyName
{
public:
MyName(std::string _name, std::string _family_name)
:name{ _name }, family_name{ _family_name }
{ }
private:
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{ ar & name; ar & family_name; } std::string name; std::string family_name;
};
int main()
{
// create and open a character archive for output
std::stringstream ofs;
// save data to archive
{
MyName my_name("MyName", "FamilyName");
boost::archive::text_oarchive oa(ofs);
// write class instance to archive
oa << my_name;
// archive and stream closed when destructors are called
}
// save data to archive
{
MyName my_name("afsf", "dgsass");
boost::archive::text_iarchive oa(ofs);
// write class instance to archive
oa >> my_name;
// archive and stream closed when destructors are called
}
return 0;
}
I get the follwing error:
Severity Code Description Project File Line Suppression State
Error LNK2019 unresolved external symbol "public: __thiscall boost::archive::archive_exception::archive_exception(enum boost::archive::archive_exception::exception_code,char const *,char const *)" (??0archive_exception#archive#boost##QAE#W4exception_code#012#PBD1#Z) referenced in function "protected: void __thiscall boost::archive::basic_text_iprimitive<class std::basic_istream<char,struct std::char_traits<char> > >::load<unsigned int>(unsigned int &)" (??$load#I#?$basic_text_iprimitive#V?$basic_istream#DU?$char_traits#D#std###std###archive#boost##IAEXAAI#Z) cpp11_cpp14_cpp17 D:\Projects_Programing\__Testing\cpp11_cpp14_cpp17\cpp11_cpp14_cpp17\cpp11_cpp14_cpp17.obj 1
But when I compiled it in release mode.
I have read that it could happen due to MSVC STRICT mode, but I have tried and it does not work neither.
Have anybody got such error ?
I have figured out the reason of this error.
It happens when I tried to compile with flag /Za (means zero extension from MSVC for C++).
When I removed this flag my code compiles succesfully.
#lakeweb Thank you for your help and support !!
Unfortunately I do not understand why some extensions from MSVC does allow to compile Boost, but without extentions it does not compile. It is very strange !!
Maybe it is either the bug on Boost side or on MSVC side.
Any assumption ?
To reproduce the issue,
Create a project > VC++ > CLR > Class library, name the project "ClassLibrary2" and use below two files as is.
// ClassLibrary2.h
#pragma once
#include <msclr\marshal.h>
#include <ShObjIdl.h>
using namespace System;
namespace ClassLibrary2 {
public ref class Class1
{
public : void ClassLibrary2::Class1::GetAllOpenWithProgs(String^ ext);
};
}
// ClassLibrary2.cpp
// This is the main DLL file.
#include "stdafx.h"
#include "ClassLibrary2.h"
void ClassLibrary2::Class1::GetAllOpenWithProgs(String^ ext)
{
msclr::interop::marshal_context ^ context = gcnew msclr::interop::marshal_context();
PCWSTR pszStr = context->marshal_as<const wchar_t*>(ext);
IEnumAssocHandlers *pEnumHandlers = NULL;
/* below line is producing problems */
SHAssocEnumHandlers(pszStr, ASSOC_FILTER_RECOMMENDED, &pEnumHandlers);
}
Now, if I build the project, I get following errors :
Error 2 error LNK2028: unresolved token (0A0000A2) "extern "C" long
__cdecl SHAssocEnumHandlers(wchar_t const *,enum ASSOC_FILTER,struct IEnumAssocHandlers * *)"
(?SHAssocEnumHandlers##$$J0YAJPEB_WW4ASSOC_FILTER##PEAPEAUIEnumAssocHandlers###Z)
referenced in function "public: void __clrcall
ClassLibrary2::Class1::GetAllOpenWithProgs(class System::String ^)"
(?GetAllOpenWithProgs#Class1#ClassLibrary2##$$FQE$AAMXPE$AAVString#System###Z) C:\Users\Anjum\Documents\Visual
Studio
2012\Projects\WpfApplication2\ClassLibrary2\ClassLibrary2.obj ClassLibrary2
Error 3 error LNK2019: unresolved external symbol "extern "C" long
__cdecl SHAssocEnumHandlers(wchar_t const *,enum ASSOC_FILTER,struct IEnumAssocHandlers * *)"
(?SHAssocEnumHandlers##$$J0YAJPEB_WW4ASSOC_FILTER##PEAPEAUIEnumAssocHandlers###Z)
referenced in function "public: void __clrcall
ClassLibrary2::Class1::GetAllOpenWithProgs(class System::String ^)"
(?GetAllOpenWithProgs#Class1#ClassLibrary2##$$FQE$AAMXPE$AAVString#System###Z) C:\Users\Anjum\Documents\Visual
Studio
2012\Projects\WpfApplication2\ClassLibrary2\ClassLibrary2.obj ClassLibrary2
How to remove those linker errors ?
I am upgrading my project from VS 6 to VS 2010, while building in release mode, I am facing the below error.
1>Creating library .\Release\JfFrpF32.lib and object .\Release\JfFrpF32.exp>
1>FLD_.obj : error LNK2019: unresolved external symbol __imp__debugf referenced in function "int __cdecl fld_new(char *,unsigned char,unsigned char,short,char,char,unsigned char,short,char,double,double,short,char *,char,short,short)" (?fld_new##YAHPADEEFDDEFDNNF0DFF#Z)
1>Release/JfFrpF32.dll : fatal error LNK1120: 1 unresolved externals
1>
1>Build FAILED.
Please help me .. thanks in advance..
Common problems that cause LNK2019 include:
The declaration of the symbol contains a spelling mistake, such that,
it is not the same name as the definition of the symbol.
A function was used but the type or number of the parameters did not
match the function definition.
The calling convention (__cdecl, __stdcall, or __fastcall) differs on
the use of the function declaration and the function definition.
Symbol definitions are in a file that was compiled as a C program and
symbols are declared in a C++ file without an extern "C" modifier. In
that case, modify the declaration.
For More Information See Here
In my case, even though I used extern "C", I got the unresolved symbol error.
The hpp was
extern "C"
{
class A
{
public:
void hi();
};
A* a;
DECLDIR int Connect();
}//extern
and the cpp was
#include "DatabasePlugin.hpp"// Include our header, must come after #define DLL_EXPORT
extern "C" // Get rid of name mangling
{
DECLDIR int Connect()
{
a = new A();
a->hi();
return 0;
}//Connect
}//extern
The problem was that I had not created an implementation for the hi() function. Adding it solved the problem. Like this:
extern "C" // Get rid of name mangling
{
void A::hi() {}
DECLDIR int Connect()
{
a = new A();
a->hi();
return 0;
}//Connect
}//extern
Having to declare Hi() before Connect() may also be significant.
I am trying to create a simple C++ class and a Matlab mex file. My code is as follows:
Matlab: mexTest1.cpp
#include "mex.h"
#include "K:\\My Documents\\Visual Studio 2010\\Projects\\HelloWorld\\HelloWorld\\Class1.h"
/* Input Arguments */
#define X prhs[0]
/* Output Arguments */
#define RESULT plhs[0]
void mexFunction( int nlhs, mxArray *plhs[],
int nrhs, const mxArray *prhs[] ){
/* Initialize input and output pointers
// Inputs */
double *x;
/* Outputs */
double r;
double *result;
mwSize m,n;
m = mxGetM(X);
n = mxGetN(X);
/* Create a matrix for the return argument */
RESULT = mxCreateDoubleMatrix(1, 1, mxREAL);
/* Assign pointers to the various parameters */
result = mxGetPr(RESULT);
x = mxGetPr(X);
/* Do the actual computations in a subroutine */
Class1 c1(2, 15.0);
r = c1.product();
result[0] = r;
return;
}
Class1.h:
#pragma once
#include <string> // Standard string class in C++
class Class1
{
public:
int a;
double b;
public:
Class1(const int& a, const double& b);
//virtual ~Class1();
void print() const;
double product() const;
};
Class1.cpp:
#include "stdafx.h"
#include <iostream>
#include "Class1.h"
Class1::Class1(const int& a, const double& b){
Class1::a = a;
Class1::b = b;
}
void Class1::print() const{
std::cout << "a=" << Class1::a << " * b=" << Class1::b << " = " << Class1::product() << std::endl;
}
double Class1::product() const{
return a*b;
}
Running the Matlab command mex mexTest1.cpp gives the error messages:
Creating library C:\DOCUME~1\K\LOCALS~1\TEMP\MEX_RH~1\templib.x and object C:\DOCUME~1\K\LOCALS~1\TEMP\MEX_RH~1\templib.exp
mexTest1.obj : error LNK2019: unresolved external symbol "public: double __thiscall Class1::product(void)const " (?product#Class1##QBENXZ) referenced in function _mexFunction
mexTest1.obj : error LNK2019: unresolved external symbol "public: __thiscall Class1::Class1(int const &,double const &)" (??0Class1##QAE#ABHABN#Z) referenced in function _mexFunction
mexTest1.mexw32 : fatal error LNK1120: 2 unresolved externals
C:\PROGRA~1\MATLAB\R2011A\BIN\MEX.PL: Error: Link of 'mexTest1.mexw32' failed.
??? Error using ==> mex at 208
Unable to complete successfully.
Can anyone help me fix this problem?
Thanks.
The linker is telling you that in trying to construct an executable, it wasn't supplied with an object file that contains Class1::product and Class1::Class1. That's because those functions would be supplied by compiling Class1.cpp, which your command line doesn't ask for.
You should use the syntax of mex for multiple files: mex mexTest1.cpp Class1.cpp
Your linker is unable to find deinitions(bodies) Class1 methods (constructor and product). This may be due to
You haven't provided any definition(body)
The definitions are in a lib file which you forgot to link to
On Windows, several arguments are passed to the DllMain constructor:
BOOL WINAPI DllMain(
__in HINSTANCE hinstDLL,
__in DWORD fdwReason,
__in LPVOID lpvReserved
);
From hinstDLL I can get the fully qualified file name of the DLL itself using GetModuleFileName():
LPTSTR str = new TCHAR[256];
int libNameLength = GetModuleFileName(hinstDLL, str, 256);
delete[] str;
In the example above, str now contains the full name of the DLL just loaded, e.g., C:\Windows\System32\MyFile.dll.
On Linux, no arguments are passed to the shared object constructor:
void `__attribute__` ((constructor)) on_load(void);
How do I get the full name of the DLL in this case? Extra credit if your solution works on Mac, too. :-)
I think the dladdr function might do what you want. From the man page:
The function dladdr() takes a function pointer and tries to resolve
name and file where it is located. Information is stored in the
Dl_info structure:
typedef struct {
const char *dli_fname; /* Pathname of shared object that
contains address */
void *dli_fbase; /* Address at which shared object
is loaded */
const char *dli_sname; /* Name of nearest symbol with address
lower than addr */
void *dli_saddr; /* Exact address of symbol named
in dli_sname */
} Dl_info;
If no symbol matching addr could be found, then dli_sname and
dli_saddr are set to NULL.
dladdr() returns 0 on error, and non-zero on success.
So you just give it a function pointer (like the address of the constructor itself), and it will give you the filename and a bunch of other information. Here's some sample code:
#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdio.h>
__attribute__((constructor))
void on_load(void) {
Dl_info dl_info;
dladdr(on_load, &dl_info);
fprintf(stderr, "module %s loaded\n", dl_info.dli_fname);
}
EDIT: It looks like this function exists on OS X, too, with the same semantics.
One supremely ugly and horrible way to do this is to look through /proc/pid/maps and look for the mapping that encompasses the address of the on_load function being executed.