Click here to Skip to main content
15,886,652 members
Please Sign up or sign in to vote.
3.00/5 (1 vote)
See more:
I have a native c++ dll and i want to use it from c# so i wrote a wrapper. I am trying to import a function of the class in the dll.
My wrapper
public  struct myclassUnman{    
        
    public:
        int size;        
        unsigned char* data;

        [DllImport("somedll.dll", 
                  EntryPoint="??0myclass@@QAE@H@Z", 
                  CallingConvention=CallingConvention::ThisCall)]
        static void ctor(myclassUnman*,int);

        [DllImport("somedll.dll", 
                  EntryPoint="??1myclass@@QAE@XZ", 
                  CallingConvention=CallingConvention::ThisCall)]
        static void dtor(myclassUnman*);    
        
        [DllImport("somedll.dll", 
                  EntryPoint="?getSize@myclass@@QAEHXZ", 
                  CallingConvention=CallingConvention::ThisCall)]
        static int getSize(myclassUnman*);    

        [DllImport("somedll.dll", 
                  EntryPoint="?getValueAsString@myclass@@QAE?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@XZ", 
                  CallingConvention=CallingConvention::ThisCall)]        
        static string getValueAsString(myclassUnman*);            
        
    };
    public ref class myclassWrap
    {
    public: 
        
        myclassWrap(int a)
        {
            tv = new myclassUnman();    
            tv->size = a;
            myclassUnman::ctor(tv,a);
        }
        
        ~myclassWrap()
        {
            myclassUnman::dtor(tv);
        }          
        
        int  getSize()
        {
          return myclassUnman::getSize(tv);            
        }   

        string getValueAsString(){    
            return myclassUnman::getValueAsString(tv);        
        }
        }        
    private:
        myclassUnman *tv;
    };



when i build this code it gives the error:
error C3385: 'myclassUnman::getValueAsString' : a function that has a DllImport custom attribute cannot return an instance of a class.

it doesn't allow to return 'string'.

'getValueAsString' function is defined in the dll :
string myclass::getValueAsString()
{
  string res = string(size,'0');
  for (int i=0;i<size;i++)
	  res[i]=data[i];
  return res;
}



what should i do?please help..
Posted
Updated 17-Feb-10 20:49pm
v2

You could try to build a "proxy"-DLL in C++,
that would load the original, allocate a TCHAR*/BYTE*,
fill it out and return it - at your sharp-process... :)
 
Share this answer
 
There are two options:

1. Throw the dll in the bit bucket and write some code of your own in .NET to resolve the issue that you have.

2. As Eugen suggested, write a wrapper class in C++ that can interface to the existing dll, take the result (the std::string) and convert it to a simple byte array or BStr type that it can return to the .NET code.

However unpleasant these options may be they are all you have, since you cannot modify the original dll. This is a good lesson in how not to write a dll that may be used by people beyond your own project.
 
Share this answer
 
if i understand your question correctly, i can't build c++ dll by binding some.dll i need to write a c++ wrapper for it.

Also Richard thank you very much for your help i will try your suggestions, i hope i could achive it
 
Share this answer
 
You need to change your wrapper class to return a basic type that can be marshalled by the interface code. .NET's string class is not the same as C++'s std::string.
 
Share this answer
 
Thank you for your answer.
I changed 'string' to 'IntPtr'
[DllImport("somedll.dll", EntryPoint="?getValueAsString@myclass@@QAE?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@XZ",                   CallingConvention=CallingConvention::ThisCall)] 
   static IntPtr getValueAsString(myclassUnman*);          


 IntPtr getValueAsString(){ 
      return myclassUnman::getValueAsString(tv);  
 } 


it builds without error but when i call it from c#, it gives an exception at the following line:
return myclassUnman::getValueAsString(tv);

Exception is :
"Attempted to read or write protected memory. This is often an indication that other memory is corrupt."

Do you have any idea about this problem?
 
Share this answer
 
You cannot just change the type in the .NET function and yet still return the same unmanaged type. You should consult the MSDN documentation on Interop Marshaling[^] to see which types you can use when consuming unmanaged code from .NET applications.
 
Share this answer
 
I changed the code :

 [DllImport("somedll.dll",   
        EntryPoint="?getValueAsString@myclass@@QAE?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@XZ",                   CallingConvention=CallingConvention::ThisCall)]  
              static [MarshalAs(UnmanagedType.BStr)]String getValueAsString(myclassUnman*); 

 [MarshalAs(UnmanagedType.BStr)]String getValueAsString()  {                
return myclassUnman::getValueAsString(tv);    
  }



but it gives the following errors:
syntax error : identifier 'String'
error C2238: unexpected token(s) preceding ';'
error C2144: syntax error : 'System::Runtime::InteropServices::UnmanagedType' should be preceded by ')'
error C2512: 'System::Runtime::InteropServices::MarshalAsAttribute::MarshalAsAttribute' : no appropriate default constructor available

i am doing something wrong but i couldn't understand
 
Share this answer
 
You still seem to think that changing the definition will change the underlying code; this is not true. The function you are calling returns a std::string which is not the same as an unmanaged Bstr. The function in the dll library needs to return a value that is capable of being marshalled into a type that .NET can understand.
 
Share this answer
 
but i can't change the dll. It is not my own dll and I don't have the whole code of the dll, just a piece of it. In this case do you have a suggestion?
 
Share this answer
 
sorry but i can't understand your answer , i am very new these topics, can you explain it more?
 
Share this answer
 
Can you build a C++ DLL with binding of your some.dll,

to instance an object of myclass and call its functions ? :)
 
Share this answer
 
I think something like
char* myGetValueAsString()
{
    string str;
    char* cPtr;

    str = myclass::getValueAsString();
    cPtr = str.c_str;

    return cPtr;
}

this gives you a pointer to an ASCII character string which (I think) can be marshalled into a managed type of some sort; sorry my experience of mixed mode is fairly limited.
 
Share this answer
 
thank you richard ,i will put this function into the my proxy dll,won't i, am i wrong?
 
Share this answer
 
You are correct, just create your own dll which calls the functions of some.dll and exposes (to your .NET code) the function to return simple type data.
 
Share this answer
 
Richard lastly i want to ask something more to be sure, after i write my proxy dll, will i write the wrapper that was in my first post by changing the code as following:
[DllImport("myproxydll.dll",EntryPoint="??0myclass@@QAE@H@Z",        CallingConvention=CallingConvention::ThisCall)]



[edit]From Richard: I think this should be OK but you may still need to check that a char* type from the wrapper dll will be marshalled into a string in the C# code. As I said before, I have not used this for a while, so perhaps one of the other forum members could clarify this.[/edit]
 
Share this answer
 
v2
ok Richard, thank you very much for your help
 
Share this answer
 
My pleasure, and I hope it works out well for you. It's nice to work with someone who tries hard to understand and resolve their own problems. Don't forget to mark this post as 'answered'.
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900