locked
Using std::string with .Net strings RRS feed

  • Question

  • Hi everyone,
    I currently have a fairly large project, that was coded using standard windows libraries. The problem now is, however, I want to integrate it with .Net (the project's output is a .dll). I changed the compiler options to get this to work, but I get "'Connect' is not supported by the language." I don't really want to go around changing everything, since this project is intended to work on more than just the .Net framework, I know somethings will have to change, but I don't want to have to re-code a whole bunch of it -- hence why I avoided System::String. I'm assuming the error occurs because std::string isn't managed, but, is there a way to get around it, rather than changing all the string types?
    Monday, June 1, 2009 12:11 PM

Answers

  • Using std::string is rather unwise, you really ought to switch to std::wstring.  Here's a sample program that does what you want:

    #include "stdafx.h"
    #include <string>

    using namespace System;
    public ref class StringConverter {
    public:
      static std::string FromNetString(String^ str) {
        IntPtr ansi = System::Runtime::InteropServices::Marshal::StringToCoTaskMemAnsi(str);
        std::string retval((const char*)(void*)ansi);
        System::Runtime::InteropServices::Marshal::FreeCoTaskMem(ansi);
        return retval;
      }
      static String^ FromCppString(std::string& str) {
        return System::Runtime::InteropServices::Marshal::PtrToStringAnsi((IntPtr)(void*)str.c_str());
      }
    };

    int main(array<System::String ^> ^args)
    {
      std::string test1 = StringConverter::FromNetString(gcnew String("hello world"));
      String^ test2 = StringConverter::FromCppString(test1);
      Console::WriteLine(test2);
      Console::ReadLine();
      return 0;
    }

    Hans Passant.
    • Marked as answer by easterbunny Tuesday, June 2, 2009 4:02 AM
    Tuesday, June 2, 2009 12:52 AM

All replies

  • You need to copy the string content from the native heap to the managed help so managed programs can use the string. Copying to a Systerm::String is preferred because many managed libraries require input data to be in this type.


    MSMVP VC++
    Monday, June 1, 2009 4:08 PM
  • "'Connect' is not supported by the language" doesn't help narrow down your problem.  There is no 'Connect' keyword.  Post some code that shows it being used.
    Hans Passant.
    Monday, June 1, 2009 5:28 PM
  • You've heard the story of the tortoise and the hare, right? This is the type of problem that can easily require more time by trying to do it the quick way.

    I am sorry if my reply is vague, but there is not enough information in the question to provide clear answers.
    Sam Hobbs; see my SimpleSamples.Info
    Monday, June 1, 2009 11:43 PM
  • Sorry, I forgot to mention what "Connect" is :P
    		std::string Connect(std::string);
    		std::string Connect(std::string, bool);
    		std::string Connect(std::string, int);
    		std::string Connect(std::string, bool, int);
    That is Connect. The reason I'm avoiding using System::String is because (as mentioned earlier), I intend on using this with more than the .Net framework, and also because the main Connect function (that the others just pass on to), requires std::string, wchar_t, and const char*, all comming from the input string, for the functions that it in turn calls, which are part of the Windows libraries ...
    Tuesday, June 2, 2009 12:20 AM
  • Using std::string is rather unwise, you really ought to switch to std::wstring.  Here's a sample program that does what you want:

    #include "stdafx.h"
    #include <string>

    using namespace System;
    public ref class StringConverter {
    public:
      static std::string FromNetString(String^ str) {
        IntPtr ansi = System::Runtime::InteropServices::Marshal::StringToCoTaskMemAnsi(str);
        std::string retval((const char*)(void*)ansi);
        System::Runtime::InteropServices::Marshal::FreeCoTaskMem(ansi);
        return retval;
      }
      static String^ FromCppString(std::string& str) {
        return System::Runtime::InteropServices::Marshal::PtrToStringAnsi((IntPtr)(void*)str.c_str());
      }
    };

    int main(array<System::String ^> ^args)
    {
      std::string test1 = StringConverter::FromNetString(gcnew String("hello world"));
      String^ test2 = StringConverter::FromCppString(test1);
      Console::WriteLine(test2);
      Console::ReadLine();
      return 0;
    }

    Hans Passant.
    • Marked as answer by easterbunny Tuesday, June 2, 2009 4:02 AM
    Tuesday, June 2, 2009 12:52 AM
  • Thanks for that, it does indeed do what I want it too :)

    That being said ... I do now have another, related, problem. I built another .dll to act as a wrapper which has all the functions that the old .dll had, just taking System::String^ as parameters, then passing them on to the old .dll after being converted to std::string. However, in the .h file, I have "SimpleSocket::Connection conn;" which produces 5 warnings, which are all the same: "Warning 1 warning C4679: 'SimpleSocket::Connection::Connect' : could not import member c:\users\chris\documents\visual studio 10\projects\wrapper\wrapper\Connection.h 10 1 Wrapper" (One of them is different, it's about the 'Send' function). I've looked the error up, and it says that it can't read from the metadata, or something to that effect ... But, why can't it read from the 4 Connect functions, and the Send function, but it works fine for receive, disconnect, and the constructor/destructor? These warnings, I believe, are causing errors saying that "Connect is not a member of SimpleSocket::Connection"

    New .h file:
    namespace Wrapper {
    
    	public ref class Connection
    	{
    		SimpleSocket::Connection conn;
    		Connection(void);
    		~Connection(void);
    		String^ Connect(String^);
    		String^ Connect(String^, bool);
    		String^ Connect(String^, int);
    		String^ Connect(String^, bool, int);
    		void Disconnect(void);
    		String^ Receive(void);
    		int Send(String^);
    	};
    
    }
    Old .h file, which the new class calls:
    namespace SimpleSocket {
    
    	//class __declspec(dllexport) Connection
    	public ref class Connection
    	{
    	public:
    		Connection(void);
    		~Connection(void);
    		std::string Connect(std::string);
    		std::string Connect(std::string, bool);
    		std::string Connect(std::string, int);
    		std::string Connect(std::string, bool, int);
    		void Disconnect(void);
    		std::string Receive(void);
    		int Send(std::string);
    	};
    
    }
    Tuesday, June 2, 2009 3:12 AM
  • Please start a new thread for your new question.

    Hans Passant.
    Tuesday, June 2, 2009 3:16 AM