locked
WinRT to Win32 string converstions

    General discussion

  • Here are Sample code for converting WinRT String^ to char*

    char* ToCharPtr(String^ str)
    {
    	int iSize = str->Length();
    	std::wstring ws1( str->Data() );
    	char* ascii = new char[iSize+1];
    	ascii[iSize] = 0;
    	for(int y= 0; y< iSize; y++)
    	{
    		ascii[y] = (char)ws1[y];
    	}
    	return ascii;
    }

    Here are Sample code for converting WinRT String Array ^  to char Array*

    string* ToCharArrayPtr(const Array<String^>^ str)
    {
    	int i = 0;
    	for each (String^ var in str)
    	{
    		i++;
    	}
    	if( i > 0)
    	{
    		string* sArray = new string[i];
    		i = 0;
    		for each (String^ var in str)
    		{
    			sArray[i++] = ToCharPtr(var);
    		}
    		return sArray;
    	}
    	else
    		return NULL;
    }

    Here are Sample code for converting Win32 String to WinRt String^

    String^ ToStringHat(char* ch)
    {
    	std::string s_str = std::string(ch);
    	std::wstring wid_str = std::wstring(s_str.begin(), s_str.end());
    	const wchar_t* w_char = wid_str.c_str();
    	String^ p_string = ref new String(w_char);
    	return p_string;
    }



    • Edited by J.S.Murthy Friday, April 12, 2013 6:49 AM
    Friday, April 12, 2013 6:47 AM

All replies

  • Using naked new statements like that is really bad coding practice. You should be using an exception-safe smart pointer such as std::unique_ptr instead. Also, for converting from Unicode to "ASCII" you should use either the wcstombs_s or the wcstombs_s_l function (see: http://msdn.microsoft.com/en-us/library/s7wzt4be.aspx ). The need for char* strings these days in Windows is almost non-existent. To the extent that you do need one it's likely that you need a utf-8 string to pass to the internet, in which case you should definitely be using wcstombs_s_l so that the string converts properly.

    I strongly recommend reading this summary of modern C++ coding techniques and usages - http://msdn.microsoft.com/en-us/library/hh279654.aspx .


    Visual C++ MVP | Website | Blog | @mikebmcl | Windows Store DirectX Game Template

    Friday, April 12, 2013 10:46 AM
  • Hi Mike,

    I agree with you, wcstombs_s or the wcstombs_s_l will work well.

    Thanks for your suggestion.

    Saturday, April 13, 2013 1:25 PM
  • FYI, I use

    Platform::String^ UiUt::fromWstr(const std::wstring& ws)
    {
       Platform::String^ plStr = ref new Platform::String(ws.c_str());
       return(plStr);
    }
    
    std::wstring UiUt::toWstr(Platform::String^ s)
    {
       if (s == nullptr)
       {
          return(L"");
       }
       std::wstring ws(s->Data());
       return(ws);
    }
    


    Monday, April 15, 2013 12:41 PM
  • Hi Mike,

    SQLite will keep the requirement alive...   Below was my solution for the conversion (partially borrowed from an MSDN site).  Would std::unique_ptr remove the memory management requirement while providing a non-local variable that will remain when the stack heap is reclaimed and the function returns?  Preventing "warning C4172: returning address of local variable"

    The following is from my blog on the topic


    MCAD.NET C# - http://www.Global-webnet.com/Blog

    Sunday, April 28, 2013 3:44 PM
  • Hi Bill,

    SQLite uses UTF-8 strings so the conversion code you have won't work as expected when the system locale isn't en_* and/or when the connection string contains non-ASCII characters.

    The following is what I'd do for the conversion:

    std::string ConvertCxStringToUTF8(Platform::String^ stringToConvert)
    {
    	const wchar_t* data = stringToConvert->Data();
    
    	auto requiredBufferSize = WideCharToMultiByte(
    		CP_UTF8,
    		WC_ERR_INVALID_CHARS,
    		stringToConvert->Data(),
    		static_cast<int>(stringToConvert->Length()),
    		nullptr,
    		0,
    		nullptr,
    		nullptr
    		);
    
    	if (requiredBufferSize == 0)
    	{
    		auto error = GetLastError();
    		throw Platform::Exception::CreateException(HRESULT_FROM_WIN32(error));
    	}
    
    	requiredBufferSize++;
    
    	std::string buffer(requiredBufferSize, 0);
    
    	auto numBytesWritten = WideCharToMultiByte(
    		CP_UTF8,
    		WC_ERR_INVALID_CHARS,
    		stringToConvert->Data(),
    		static_cast<int>(stringToConvert->Length()),
    		const_cast<char *>(buffer.data()),
    		requiredBufferSize - 1,
    		nullptr,
    		nullptr
    		);
    
    	if (numBytesWritten != (requiredBufferSize - 1))
    	{
    		throw Platform::Exception::CreateException(E_UNEXPECTED, L"WideCharToMultiByte returned an unexpected number of bytes written.");
    	}
    
    	return buffer;
    }

    and then in the SqliteConnection::Open(void) member function, I'd have:

    	auto str = ConvertCxStringToUTF8(ConnectionString);
    	auto connStr = str.c_str();
    
    	...

    Though you could probably also just use:

    	rc = sqlite3_open16(static_cast<const void *>(ConnectionString->Data()), &db);

    The ConvertCxStringToUTF8 way is probably safer though since it bypasses any issues of endianness.

    Visual C++ MVP | Website | Blog | @mikebmcl | Windows Store DirectX Game Template


    Sunday, April 28, 2013 6:36 PM
  • Thank you Mike, I appreciate the source and information - I'll update my code.


    MCAD.NET C# - http://www.Global-webnet.com/Blog

    Sunday, April 28, 2013 11:31 PM