Need to convert String^ to char *

2019-01-27 15:49发布

问题:

I am using the .NET DateTime to get the current date and time. I am converting it to a string to use as part of a file name. The problem is the OpenCV command to save an image requires a char * not a string type, and DateTime will only output a String^ type. How do I make this work? Heres the code not completed

String^ nowString = DateTime::Now.ToString("yyyy-MM-dd-HH:mm");
        IplImage* toSave;
        CvCapture* capture = cvCreateCameraCapture(0);
        toSave = cvQueryFrame( capture );
        cvSaveImage(nowString, toSave);
        cvReleaseImage(&toSave);
        cvReleaseCapture(&capture);

回答1:

Your best bet is to use StringToHGlobalAnsi. Here is complete code showing how its done and remembering to free the memory allocated.

using namespace System::Runtime::InteropServices;

void MethodName()
{
    String^ nowString = DateTime::Now.ToString("yyyy-MM-dd-HH:mm");
    IntPtr ptrToNativeString = Marshal::StringToHGlobalAnsi(nowString);
    try
    {
        CvCapture* capture = cvCreateCameraCapture(0);
        IplImage* toSave = cvQueryFrame(capture);
        cvSaveImage(static_cast<char*>(ptrToNativeString.ToPointer()), toSave);
        cvReleaseImage(&toSave);
        cvReleaseCapture(&capture);
    }
    catch (...)
    {
        Marshal::FreeHGlobal(ptrToNativeString);
        throw;
    }
    Marshal::FreeHGlobal(ptrToNativeString);
}

You might want to rethink using a ':' character in the filename, as I don't believe windows likes this very much.



回答2:

Actually, I found the easiest way to get a char * from a String^ is to use good ol' sprintf(). So in your case, you can simple do this:

char cNow[17] = { 0 };
String^ nowString = DateTime::Now.ToString("yyyy-MM-dd-HH:mm");
if (nowString->Length < sizeof(cNow)) // make sure it fits & allow space for null terminator
  sprintf(cNow, "%s", nowString);

No need to call the Marshal functions!

Update

So it appears that VS 2015 adheres more closely to the C++11 standards, so using sprintf() with the .NET String won't work. The easiest way is to use the marshal_as() function like this:

Include these lines before your code:

#include <msclr/marshal_cppstd.h>
using namespace msclr::interop;

Then this should work:

char cNow[17] = { 0 };
String^ nowString = DateTime::Now.ToString("yyyy-MM-dd-HH:mm");
string sNow = marshal_as<string>(nowString);
if (sNow.length() < sizeof(cNow)) // make sure it fits & allow space for null terminator
  sprintf(cNow, "%s", sNow.c_str());

Otherwise, if you don't want to use the marshal_as() function, you can copy the string character by character like this:

char cNow[17] = { 0 };
String^ nowString = DateTime::Now.ToString("yyyy-MM-dd-HH:mm");
if (nowString->Length < sizeof(cNow)) // make sure it fits & allow space for null terminator
{
    for (int i = 0; i < nowString->Length; i++)
        cNow[i] = static_cast<char>(nowString[i]);
}


回答3:

You need to read about C++ interop and data marshalling.

Basically: you need to "cast" the .NET String to a C++ TCHAR array.

See this: http://msdn.microsoft.com/en-us/library/ef4c3t39(VS.80).aspx



回答4:

Use the StringToXxxAnsi functions in the Marshal class to allocate a char* buffer, then the appropriate functions from the same class to free them.



回答5:

Random Googling got me this. Maybe someone can shorten it?

cli::array<char>^ bytes = Encoding::ASCII::GetBytes(nowString);
pin_ptr<char> pinned = &bytes[0];
std::string nativeString((char*)pinned, bytes->Length);
char const* chars = nativeString.c_str();

Edit: This is longer than the operations of the Marshal class, but works with more encodings. In your case, it sounds like the simpler StringToHGlobalAnsi approach will do everything you need.